这是在堆栈上传递变量的正确方法吗?

时间:2011-04-06 02:55:23

标签: assembly x86 stack nasm

我写了一个简单的程序,它将预定义的数字带到预定义的幂并返回结果。这是针对Linux的NASM程序集。我一直试图了解如何使用堆栈将变量传递给函数,并希望确保我正确地执行此操作。它返回正确的数字,但我不知道它是否正确:

section .text
    global _start

_start:
    push dword 3        ;(power)
    push dword 2        ;(num)

    call power

    mov ebx, eax
    mov eax, 1
    int 0x80

power:
    push ebp
    mov ebp, esp
    sub esp, 8      ;reserve space for two local vars
    push dword [ebp+8]
    pop dword [ebp-4]   ;store original num as a local var
    push dword [ebp+12] 
    pop dword [ebp-8]   ;store power in a local counter var
    dec dword [ebp-8]
    mov eax, [ebp-4]    ;store original num in eax (current val)    
    jmp power_loop  

power_loop:
    imul eax, dword [ebp-4] ;multiply current val by original num
    dec dword [ebp-8]   ;decrement counter

    cmp dword [ebp-8], 0
    jne power_loop

    mov esp, ebp        ;restore stack pointer
    pop ebp
    ret 

非常感谢任何建议!

1 个答案:

答案 0 :(得分:1)

它在大多数情况下都很好看。但是,在电源恢复后,您应该从堆栈中删除变量。在这些情况下并不重要,因为_start不返回,但是如果你试图从一个返回但不清理的函数调用一个函数,那就很重要了。函数的返回地址存储在堆栈中并由ret指令弹出,因此如果堆栈顶部还有其他内容,则会返回错误的位置。

_start:
    push dword 3
    push dword 2
    call power
    add esp,8 ; Removes two dwords from stack

如果编写一个调用许多其他函数的函数,最好在函数开头为堆栈参数分配空间,在每次函数调用之前写入它,并在结束时从堆栈中删除它。功能。这样,您可以花更少的时间推送和弹出,因为您可以使用mov代替正确的地址。

_start:
    sub esp,8 ; Make room for two dwords
    mov dword [esp+4], 3
    mov dword [esp], 2
    call power
    add esp,8 ; Removes two dwords from stack

作为对电源功能的评论:它目前仅在功率至少为2时才有效。您可以通过以下方式将最小功率更改为0:

  • 以1
  • 启动eax
  • 不要在循环
  • 之前递减计数器变量
  • 检查循环开始时计数器是否为0

示例:

    ; dec dword [ebp-8] ; Don't do this
    mov eax, dword 1
    jmp power_loop  

power_loop:
    cmp dword [ebp-8], 0
    je end_loop

    imul eax, dword [ebp-4] ;multiply current val by original num
    dec dword [ebp-8]   ;decrement counter
    jmp power_loop

end_loop:
    mov esp, ebp