程序集Win32 _printf代码崩溃

时间:2015-08-01 02:12:26

标签: assembly nasm

我是NASM汇编程序的新手,并试图编写自己的汇编代码。在编译时,我没有收到任何错误,但在运行时,代码崩溃。在调试时,似乎代码在push或_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

提前致谢!我希望这不是太高兴。

1 个答案:

答案 0 :(得分:2)

我自己尝试编译和运行代码(唉,不在Windows上;谁说程序集不可移植?),而且它不是在call _printfpush行上崩溃,而是在{{{ 1}}。 mov [a], ebx段的权限是读取和执行,但不是写入。 .text位于a.text尝试写入mov [a], ebx,因此它会尝试写入不可写的部分,程序崩溃时会出现一般性保护错误。解决这个问题的方法是将a放在不同的部分,例如a

这应该解决你的(第一个)问题,但还有两件事你应该知道:

  1. 您有.data作为jp _loop的第一条指令。如果设置了奇偶校验标志,则跳转到_main。我认为你实际上并不打算测试奇偶校验标志;在这种情况下,它要么跳转,要么测试失败,无论如何它都会落到_loop。你可以做一个明确的_loop,但实际上没有必要。如果我是你,我会完全省略该指示,jmp_main重合。

  2. 我相信_loop使用C调用约定,调用者负责弹出参数(与用于Windows API函数的stdcall不同);你把很多东西都推到了堆栈上,从不弹出它们。这意味着您执行的迭代次数越多,您使用的堆栈内存就越多。这似乎不是你想要的。此外,您稍后_printf,由于您在同一时间推送东西,因为堆栈顶部不是返回地址,因此不会返回正确的位置。您需要在调用ret后显式弹出或调整堆栈指针:

    _printf

    可替换地:

    1. 在循环之前,保留适当的堆栈空间:

      add esp, 8
      
    2. 循环后,释放堆栈空间:

      sub esp, 8
      
    3. 不是推送参数,而是修改堆栈中已有的数据:

      add esp, 8