在汇编语言中比较字符串时出错:0xC0000005:访问冲突读取位置0x00000043

时间:2018-04-13 18:26:41

标签: x86 inline-assembly

该代码应该将输入的字符串与各种硬编码选项进行比较以提供菜单。

这是我使用

的代码
.stack 4096
 ...
    GetStdHandle proto :dword
    ReadConsoleA  proto :dword, :dword, :dword, :dword, :dword
    WriteConsoleA proto :dword, :dword, :dword, :dword, :dword
    STD_INPUT_HANDLE equ -10
 ...
.data
 ...
    bufSize = 80
    inputHandle DWORD ?
    buffer db bufSize dup(?)    
    choice DWORD ?
    letterC DWORD "C"
 ...
.code
 ...
    invoke GetStdHandle, STD_INPUT_HANDLE
    mov inputHandle, eax
    invoke ReadConsoleA, inputHandle, addr buffer, bufSize, addr choice,0
    mov ESI, choice
    mov EDI, letterC
    CLD            
    MOV ECX,10        
    REPE CMPSB        
 ...

它总是在最后一行REPE CMPSB给我一个错误:

  

Application.exe中的0x00F6195F抛出异常:0xC0000005:访问冲突读取位置0x00000043。

1 个答案:

答案 0 :(得分:3)

问题是您将源寄存器和目标寄存器都设置为错误的值 我会解释一下:

函数ReadConsole具有以下签名:

BOOL WINAPI ReadConsole(
  _In_     HANDLE  hConsoleInput,
  _Out_    LPVOID  lpBuffer,
  _In_     DWORD   nNumberOfCharsToRead,
  _Out_    LPDWORD lpNumberOfCharsRead,
  _In_opt_ LPVOID  pInputControl
);

使用

mov ESI, choice

您正在将ReadConsolechoice的第四个参数复制到ESI
choice包含NumberOfCharsRead,因此它不是内存指针,而是长度值。这不起作用。

mov EDI, letterC

您将letterC移至EDI而不是其地址。要将地址设为EDI,您必须使用

mov EDI, OFFSET letterC

此错误在您的错误消息中显而易见,其中包含

  

访问冲突读取位置0x00000043。

0x00000043的值等于字符C的0x char值,0x43。要获取其地址 - 这是正确的 - 您可以使用LEA指令,如lea EDI, letterCOFFSET指令,它更有效。读取或写入值作为地址几乎总是会导致错误。

为了使其正确,请考虑以下方法:

invoke ReadConsoleA, inputHandle, addr buffer, bufSize, addr choice,0
CLD            
MOV  ESI, OFFSET buffer   ; address of buffer is source
MOV  EDI, OFFSET letterC  ; address of letterC is destination
MOV  ECX, choice          ; length of string is choice (bytes read)
REPE CMPSB                ; execute

此解决方案更好,但它包含一个主要错误:REPE CMPSB比较字符并继续比较它们,只要它们相等。但是你的letterC只有一个字符长,所以你在传递C字符后会出现溢出 - 第二次迭代。

你的问题不清楚你真正的期望,所以以下只是猜测:
可能的替代方法是使用REPNE SCASB letterC AL中的MOV AL, letterC来搜索C的第一个匹配项:

invoke ReadConsoleA, inputHandle, addr buffer, bufSize, addr choice,0
CLD            
MOV   EDI, OFFSET buffer  ; address of buffer is search source
MOV   EAX, letterC        ; value of letterC
MOV   ECX, choice         ; length of string is choice (bytes read)
REPNE SCASB               ; execute