NASM中的堆栈问题

时间:2013-05-04 18:40:33

标签: assembly stack nasm

我正在NASM编写一个计算Fibonacci序列并打印它的程序。它需要用户输入两个种子值和迭代次数,将它们存储在堆栈上,然后调用'fib'子程序进行计算和打印。我正在使用here中的库来执行读取输入/打印等操作。

这是我的asm_main:

asm_main:
        enter   0,0                 ; setup routine
        pusha

    mov eax, prompt1        ; access first prompt
    call    print_string        ; print prompt
    call    read_int        ; read input and stores in eax
    push    eax         ; store input on stack

    mov eax, prompt2        ; access second prompt
    call    print_string        ; print prompt
    call    read_int        ; read input and stores in eax
    push    eax         ; store input on stack

    mov eax, prompt3        ; access third prompt
    call    print_string        ; print prompt
    call    read_int        ; read input and stores in eax
    push    eax         ; store input on stack

    call    fib         ; call fib subroutine to calculate sequence
    call    print_nl        ; end with a newline

这是fib子程序:

fib:
    pop ecx         ; retrieve number of iterations from stack
    pop ebx         ; retrieve second seed value from stack
    pop eax         ; retrieve first seed value from stack

    _looper:            ; section to be looped
        mov edx, eax
        add edx, ebx    ; sum = a + b
        call    print_int
        call    print_nl
        mov eax, ebx    ; a = b
        mov ebx, edx    ; b = sum
        loop _looper
    ret

然而,这种推动和弹出不正常,我无法弄清楚为什么。当我输入“3”作为第一个种子值,“5”作为第二个种子值,并且“7”表示迭代次数,这里是在fib中调用的寄存器转储的结果:

Register Dump # 1
EAX = 00000005 EBX = 00000007 ECX = 080484D4 EDX = BF97A1B4
ESI = 00000000 EDI = 00000000 EBP = BF97A168 ESP = BF97A144
EIP = 08048480 FLAGS = 200282       SF 
我在这里错过了什么吗?根据我的理解,堆栈应该是后进/先出,我无法弄清楚出了什么问题。感谢

1 个答案:

答案 0 :(得分:1)

当您call fib然后在fib内时,您将从堆栈中弹出的第一件事就是返回地址。只要你确保在弹出参数后再将其推回去,弹出那个就可以了,否则最后的ret指令会把你送到你不想要的地方。

例如,您可以

fib:
    pop edx         ; pop return address
    pop ecx         ; retrieve number of iterations from stack
    pop ebx         ; retrieve second seed value from stack
    pop eax         ; retrieve first seed value from stack
    push edx        ; put return address back on stack
    ...

但更常规的方法是使用

设置堆栈帧
    push ebp
    mov ebp, esp

然后使用

访问参数
    mov ecx, [ebp+8]
    mov ebx, [ebp+12]

等等

然后弹出堆栈框架和最后的参数:

    mov esp, ebp
    pop ebp
    ret 12

后一种方法允许您在需要时访问参数 - 而不仅仅是在进入例程时。