在程序集中访问参数

Accessing parameters in Assembly

概览

我正在用 x86 汇编 (NASM) 编写一个程序,它基本上从用户那里得到一个股息和除数,然后调用一个程序来进行除法,返回 EAX 中的值供我打印.我将 Paul Carter 的 asm_io.inc 库用于 C I/O 函数 (http://pacman128.github.io/pcasm/)。这是我在命令行中输入的用于获取程序 运行 的内容: nasm -f win32 source.asm gcc source.obj driver.c asm_io.obj.

问题

现在的问题是,当我将两个参数传递给过程(称为 divide)时,我尝试通过间接访问参数(例如 [ebp + 8] 用于第一个参数),但是它会产生内存地址代替。我试过调试它,但无济于事。是不是我做错了什么导致了错误的结果?我的代码:

%include "asm_io.inc"

segment .data
        prompt1 db "Enter a dividend: ", 0
        prompt2 db "Enter a divisor: ", 0        
        answer1 db " divided by ", 0
        answer2 db " equals ", 0

segment .bss
        dividend resd 1
        divisor  resd 1

segment .text
        global  _asm_main
_asm_main:
        enter   0,0
        pusha

        mov     eax, prompt1
        call    print_string
        call    read_int
        mov     [dividend], eax

        mov     eax, prompt2
        call    print_string
        call    read_int
        mov     [divisor], eax

        mov     eax, [dividend]
        call    print_int

        mov     eax, answer1
        call    print_string

        mov     eax, [divisor]
        call    print_int

        mov     eax, answer2
        call    print_string

        push    dword dividend
        push    dword divisor
        call    divide
        add     esp, 8
        
        call    print_int

        popa
        mov     eax, 0
        leave                     
        ret
divide:
        push    ebp
        mov     ebp, esp

        mov     eax, [ebp + 8]
        div     dword [ebp + 4]

        pop     ebp
        ret

使用 push 指令,您突然放弃了间接寻址并要求它简单地推送地址。根据先前的说明(例如 mov eax,[divisor],您确实要求间接访问。

   push    dword dividend
   push    dword divisor

在NASM中这些指令将推送变量的地址。您需要使用方括号来获取它们的实际值。

    push    dword [dividend]
    push    dword [divisor]

您的除法例程在执行div指令之前忘记将edx寄存器归零!
您的 除法 例程当前将 除数 除以 return 地址.
位移相差 4。这是正确的代码:

divide:
        push    ebp
        mov     ebp, esp
        mov     eax, [ebp + 12]   ; Dividend
        xor     edx, edx
        div     dword [ebp + 8]   ; Divisor
        pop     ebp
        ret

您当然可以选择在子例程中传递地址和取消引用:

divide:
        push    ebp
        mov     ebp, esp
        mov     ecx, [ebp + 8]    ; Address of Divisor
        mov     ecx, [ecx]
        mov     eax, [ebp + 12]   ; Address of Dividend
        mov     eax, [eax]
        xor     edx, edx
        div     ecx
        pop     ebp
        ret