NASM - JBE 指令给出分段错误

NASM - JBE instruction gives segmentation fault

我正在尝试使用 NASM 汇编器在汇编中实现斐波那契算法。 这是算法的伪代码

fibonacci_it(n):
    int f_i-1 = 1;
    int f_i-2 = 1;

    if (n==0):
        return 1;
    else:
        int i = 1;
        int f_i = 1;
        while (i < n):
            f_i = f_i-1 + f_i-2
            f_i-2 = f_i-1
            f_i-1 = f_i
            i = i + 1
        return f_i

我试过的是这样的:

%include "asm_io.inc"

segment .data
prompt      db  "Enter number: ", 0

segment .bss
fibnum      resd 1

segment .text
    global asm_main

asm_main:
    enter   0,0
    pusha   

    mov         eax, prompt
    call        print_string
    call        read_int
    mov         [fibnum], eax

    push        dword [fibnum]
    call        fib_it
    call        print_int

    popa
    mov         eax, 0
    leave
    ret



fib_it:
    enter   12,0                ; 3 local variables: f_i, f_i-1, f_i-2
    pusha

    mov     dword [ebp-4], 1    ; initialize f_i
    mov     dword [ebp-8], 1    ; initialize f_i-1
    mov     dword [ebp-12], 1   ; initialize f_i-2
    mov     ecx, 1              ; i = 1
    mov     edx, 1              ; comparison operator for n
    cmp     [ebp+8], edx        ; n <= 1 ?
    jbe     end_fib_it          ; if n <= 1 -> end and return 1

fib_it_while:
    dump_regs 1
    mov     eax, [ebp-8]        ; eax = f_i-1
    add     eax, [ebp-12]       ; eax = f_i-1 + f_i-2
    mov     [ebp-4], eax        ; f_i = f_i-1 + f_i-2
    mov     eax, [ebp-8]        ; eax = f_i-1
    mov     [ebp-12], eax       ; f_i-2 = f_i-1
    mov     eax, [ebp-4]        ; eax = f_i
    mov     [ebp-8], eax        ; f_i-1 = f_i
    inc     ecx                 ; i += 1
    cmp     ecx, [ebp+8]        ; i < n ?
    jae     end_fib_it          ; end while loop if i < n
    jmp     fib_it_while        ; else -> loop again

end_fib_it:
    mov     eax, [ebp-4]        ; return f_i
    popa
    leave
    ret

程序首先从终端读取一个整数。然后它将其作为 fib_it 的参数推入堆栈 当我 运行 程序出现分段错误时。我发现每次 jbe end_fib_itjae end_fib_it 为真并且程序必须跳转然后它给出分段错误。我用 dump_regs 进行了更多调试,发现 while 循环 运行 非常完美并且 jmp fib_it_while 没有问题。

I found out that every time jbe end_fib_it or jae end_fib_it is true and the program has to jump then it gives a segmentation fault.

您的观察可能根本不是问题所在。

push        dword [fibnum]
call        fib_it

当您调用 fib_it 时,您将一个双字压入堆栈 ,之后您不会将其弹出。

最简单的解决方案可能是以 ret:

的替代形式结束 fib_it
popa
leave
ret 4      ; The 4 will remove the parameter from the stack

不要使用 pusha/popa

end_fib_it:
  mov     eax, [ebp-4]        ; return f_i
  popa

您想 return 得到 EAX 的结果,但随后的 popa 指令会立即破坏您刚刚放入其中的内容!

因为您只使用附加寄存器 ECXEDX,最好将 pusha 更改为 push ecx push edx。同时将 popa 更改为 pop edx pop ecx.


优化

mov     edx, 1              ; comparison operator for n
cmp     [ebp+8], edx        ; n <= 1 ?

如果您只将它用于单个比较,为什么还要使用附加寄存器 EDX
如果把这对指令改成:

cmp     dword [ebp+8], 1        ; n <= 1 ?

上述 pusha/popa 的替换只会是 push ecx/pop ecx.