我是 NASM 汇编程序的新手,并尝试编写自己的汇编代码。编译后,我没有收到任何错误,但在运行时,代码崩溃了。调试时,代码似乎在推送或 _printf 调用时崩溃。
我对代码进行了注释,使其更具可读性。
global _main
extern _printf
section .text
_main:
jp _loop ;jump to loop
_loop:
mov ebx, [a] ;move double word 'a' into register ebx
inc ebx ;increment register ebx
mov [a], ebx ;move contents of ebx into double word 'a'
add ebx, '0' ;add char 0 (0x30)
push ebx ;push ascii character on to stack
push format ;push format string on to stack
call _printf ;call print function
cmp dword [a], 10 ;compare if value of a is equal to 10
jne _loop ;loop if not equal to 10
ret ;return if equal to 10
a:
dd 0 ;initialize dword as 0
format:
db "%i", 0 ;format string for printf
提前致谢!我希望这不是太菜鸟。
最佳答案
我尝试自己编译并运行您的代码(可惜不是在 Windows 上;谁说程序集不可移植?),并且它不是在 call _printf
或 push
上崩溃的> 行,但位于 mov [a], ebx
上。 .text
段的权限是读取和执行,但不是写入。 a
位于 .text
中,并且 mov [a], ebx
尝试写入 a
,因此它会尝试写入不可写的部分,并且程序因一般保护错误而崩溃。解决这个问题的方法是将 a
放在不同的部分中,例如.data
.
这应该可以解决您的(第一)问题,但您还应该了解两件事:
您将
jp _loop
作为_main
的第一条指令。如果设置了奇偶校验标志,则会跳转到_loop
。我不认为你真的想测试奇偶校验标志;在这种情况下,它要么跳转到那里,要么测试失败并且无论如何都会落入_loop
。您可以执行显式jmp
,但这实际上没有必要。如果我是你,我会完全省略该指令,以便_main
和_loop
重合。我相信
_printf
使用 C 调用约定,其中调用者负责弹出参数(与 Windows API 函数使用的 stdcall 不同);你把很多东西压入堆栈,却从不弹出它们。这意味着迭代次数越多,使用的堆栈内存就越多。这似乎不是你想要的。此外,您稍后ret
,由于您同时推送了内容,因此不会返回到正确的位置,因为堆栈顶部不是返回地址。您需要在调用_printf
后显式弹出或调整堆栈指针:add esp, 8
或者:
在循环之前,保留适当数量的堆栈空间:
sub esp, 8
循环结束后,释放堆栈空间:
add esp, 8
不要压入参数,而是修改堆栈上已有的数据:
mov [esp+4], ebx mov [esp], format
关于汇编 Win32 _printf 代码崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31757526/