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

Assembly 这是在堆栈上传递变量的正确方法吗?,assembly,x86,stack,nasm,Assembly,X86,Stack,Nasm,我写了一个简单的程序,它将一个预定义的数字转换成一个预定义的幂,然后返回结果。它位于NASM汇编中,用于Linux。我一直在尝试了解如何使用堆栈将变量传递给函数,并希望确保这一点正确无误。它返回正确的数字,但我不知道它是否正确: section .text global _start _start: push dword 3 ;(power) push dword 2 ;(num) call power mov ebx,

我写了一个简单的程序,它将一个预定义的数字转换成一个预定义的幂,然后返回结果。它位于NASM汇编中,用于Linux。我一直在尝试了解如何使用堆栈将变量传递给函数,并希望确保这一点正确无误。它返回正确的数字,但我不知道它是否正确:

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 

任何建议都将不胜感激

大部分看起来都不错。但是,在电源恢复后,应该从堆栈中删除变量。在这些情况下,这并不重要,因为_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

如果允许我问一下,编写一种看起来尽可能像是出自C编译器的汇编语言(此时优化器已关闭)有什么意义?使用注册表!我知道我可能只是使用了寄存器,但我尝试学习汇编只是为了好玩-这只是一个练习,学习如何使用堆栈传递参数。使用堆栈传递参数在某种程度上是可以接受的(在与C代码等接口时是必要的),但是在完全没有必要的情况下在堆栈上创建局部变量是一个完全不同的故事(无论如何,在我看来)。太棒了,非常感谢您的详细回复!这些东西终于开始有意义了:)