Почему у меня ошибка сегментации в рекурсивной функции сборки?

Привет, я пишу рекурсивный код Фибоначчи в сборке с соглашением о вызовах amd64 abi, но всегда получаю ошибку сегментации: / Я компилирую его с помощью:

nasm -f elf64 -o fibo.o fibonacci.asm

ld -o fibo fibo.o

./fibo

У меня нет ошибок компиляции, но есть ошибка сегментации, поэтому я думаю, что что-то пошло не так с моими Stackframes.

Спасибо за любую помощь :)

SECTION .data

; define the fibonacci number that should be calculated
n:      dq   10

SECTION .text

global _start

_start:
    ; call Fibonacci function f(n)
    mov     rdi, [n]    ; parameter: fibonacci number to calculate
    call    f           ; call function

    ; print calculated Fibonacci number on stdout
    ;call    printnumber

    ; exit process with exit code 0
    mov     rax, 60
    mov     rdi, 0
    syscall

; f: Calculates a Fibonacci number
;   f(n) = {n, if n<=1; f(n-1)+f(n-2), else}.
;   Parameter: Integer n >= 0, passed on stack
;   Returns:   Fibonacci number f(n), returned in rax
f:
    push rbp            ; neuen stackframe
    mov rbp, rsp        
    push rdi            ; rdi auf stack speichern
    add rbp, 16         ; 
    mov rdi, [rbp]      ; rdi = parameter

    cmp rdi, 1          ; check for base case
    jle base            ; n <= 1

    dec  rdi            ; n-1
    push rdi
    call f              ; f(n-1)
    pop rdi

    dec  rdi            ; n-2
    push rdi
    call f              ; f(n-2)
    pop rdi
    pop rdi
    add rax, rdi

    jmp end
base: 
    mov rax, 1

end:
    pop rdi
    pop rbp
    mov rsp, rbp

    ret



person Jan Wolfram    schedule 12.11.2019    source источник


Ответы (1)


Вы правильно настроили фрейм стека в f, но затем вы начинаете ошибаться с добавлением в rbp. Вы должны оставить rbp в покое и вместо этого добавить смещение в выборку переменной:

push rdi
move rdi,[rbp+16]

Вы выходите из неправильной последовательности. Добавление 16 к rbp в записи является здесь проблемой (решается без изменения rbp), и у вас rsp восстановление не в том месте.

pop rdi
mov rsp,rbp    ; Unnecessary here (see below)
pop rbp
ret

Однако, поскольку вы никогда не меняете rsp для выделения памяти для локальных переменных, переход к rsp не нужен и его можно опустить.

Обратите внимание, что с кодом есть и другие проблемы, не связанные с последовательностью входа / выхода и сбоями.

person 1201ProgramAlarm    schedule 12.11.2019