【问题标题】:Accessing parameters in Assembly在 Assembly 中访问参数
【发布时间】:2021-10-28 18:37:11
【问题描述】:

概述

我正在用 x86 程序集 (NASM) 编写一个程序,它基本上从用户那里得到一个除数和除数,然后调用一个执行除数的过程,返回 EAX 中的值供我打印。我将 Paul Carter 的 asm_io.inc 库用于 C I/O 函数 (http://pacman128.github.io/pcasm/)。这是我在命令行中输入的内容以使程序运行: nasm -f win32 source.asmgcc 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

【问题讨论】:

    标签: assembly parameters x86 procedure


    【解决方案1】:
       push    dword dividend
       push    dword divisor
    

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

        push    dword [dividend]
        push    dword [divisor]
    

    您的除法例程忘记归零在执行div 指令之前将edx 寄存器!
    您的 divide 例程当前将 divisor 除以返回地址
    位移减少了 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
    

    【讨论】:

    • 非常感谢。那么此时,堆栈看起来像这样?将EBP保存在顶部,然后是返回地址,然后是参数?如果我是对的,那就意味着如果我没有参数,那么地址仍然是 EBP + 4?
    • @Adon 不,前提是你在函数入口处压入了EBP,然后复制EBP寄存器中的新堆栈指针(如上面的代码),堆栈返回正上方的地址地址将始终保持为EBP+8。如果碰巧没有参数,这不会改变。
    • @Adon [EBP+0]EBP 的旧值,[EBP+4] 是返回地址,[EBP+8] 可能是第一个参数,[EBP+12] 可能是第二个论据,等等……
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-22
      • 1970-01-01
      • 2014-10-25
      • 1970-01-01
      • 1970-01-01
      • 2017-05-29
      相关资源
      最近更新 更多