比较汇编语言中的字符串时出错:0xC0000005:访问冲突读取位置 0x00000043
Error comparing strings in assembly language: 0xC0000005: Access violation reading location 0x00000043
该代码应该将输入的字符串与各种硬编码选项进行比较以提供菜单。
这是我正在使用的代码
.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
:
Exception thrown at 0x00F6195F in Application.exe: 0xC0000005: Access violation reading location 0x00000043.
问题是您将源寄存器和目标寄存器都设置为错误的值。
我要解释一下:
函数 ReadConsole
具有以下签名:
BOOL WINAPI ReadConsole(
_In_ HANDLE hConsoleInput,
_Out_ LPVOID lpBuffer,
_In_ DWORD nNumberOfCharsToRead,
_Out_ LPDWORD lpNumberOfCharsRead,
_In_opt_ LPVOID pInputControl
);
有
mov ESI, choice
您正在将 ReadConsole
、choice
的第四个参数复制到 ESI
。
choice
包含 NumberOfCharsRead
,因此它不是内存指针,而是一个 长度值 。这行不通。
与
mov EDI, letterC
您将 letterC
的值 移动到 EDI
而不是其地址。要获取 EDI
的地址,您必须使用
mov EDI, OFFSET letterC
此错误在您的错误消息中变得很明显
Access violation reading location 0x00000043.
0x00000043
的值等于字符C
的ASCII字符值,0x43。要获得它的地址 - 这是正确的 - 您可以使用 LEA
指令,如 lea EDI, letterC
或更有效的 OFFSET
指令。读取或写入一个值作为地址几乎总是会导致错误。
为使其正确,请考虑以下方法:
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
和 AL
(MOV AL, letterC
) 中的字符 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
该代码应该将输入的字符串与各种硬编码选项进行比较以提供菜单。
这是我正在使用的代码
.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
:
Exception thrown at 0x00F6195F in Application.exe: 0xC0000005: Access violation reading location 0x00000043.
问题是您将源寄存器和目标寄存器都设置为错误的值。
我要解释一下:
函数 ReadConsole
具有以下签名:
BOOL WINAPI ReadConsole(
_In_ HANDLE hConsoleInput,
_Out_ LPVOID lpBuffer,
_In_ DWORD nNumberOfCharsToRead,
_Out_ LPDWORD lpNumberOfCharsRead,
_In_opt_ LPVOID pInputControl
);
有
mov ESI, choice
您正在将 ReadConsole
、choice
的第四个参数复制到 ESI
。
choice
包含 NumberOfCharsRead
,因此它不是内存指针,而是一个 长度值 。这行不通。
与
mov EDI, letterC
您将 letterC
的值 移动到 EDI
而不是其地址。要获取 EDI
的地址,您必须使用
mov EDI, OFFSET letterC
此错误在您的错误消息中变得很明显
Access violation reading location 0x00000043.
0x00000043
的值等于字符C
的ASCII字符值,0x43。要获得它的地址 - 这是正确的 - 您可以使用 LEA
指令,如 lea EDI, letterC
或更有效的 OFFSET
指令。读取或写入一个值作为地址几乎总是会导致错误。
为使其正确,请考虑以下方法:
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
和 AL
(MOV AL, letterC
) 中的字符 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