【问题标题】:Fibonacci in NASM - seg faultNASM 中的斐波那契 - 段错误
【发布时间】:2012-05-29 22:34:32
【问题描述】:

我们必须在汇编中编写代码,这您可能很难知道。或者教授没有给我们任何关于如何正确编码或链接的信息。我们必须自学。明天我必须交作业。 目的是将第 n 个斐波那契数打印到控制台。

section .data
    fmt: db "fib=%d",10,0

section .text
extern _printf
global _main, fib

_main:
    mov eax, 10     ; e.g. n=10
    mov ebx, 1      ; we know f_0 and f_1
    sub eax, ebx    ; thats why n--
    push eax        ; push n
    push 0      ; f_0 = 0 
    push 1      ; f_1 = 1

    call fib

    push eax        ; in eax the result is stored
    push fmt
    call _printf

    mov ebx, 0
    mov eax, 1      ; exit(0)
    int 0x80    


fib:
    mov ecx, eax
    pop esi
    calc:
    pop ebx
    pop edx
    add ebx, edx
    mov eax, ebx
    push edx
    push ebx
    sub ecx, 1
    cmp ecx, 0
    jne calc
    push esi
    ret

在与链接器斗争之后,我终于设法组装和链接我的程序。但它不起作用 - 我每次都会遇到分段错误。

编辑: 更正的代码 - 我在控制台上收到了一些文本,但遗憾的是没有正确的数字,它总是显示“fib=1”并再次出现段错误。

【问题讨论】:

    标签: assembly segmentation-fault nasm fibonacci


    【解决方案1】:

    你有

    push 0      ; f_0 = 0 
    push 1      ; f_1 = 1
    
    call fib
    

    然后

    fib:
        mov ecx, eax
        calc:
        pop ebx
        pop edx
    

    你不能这样做——调用指令会将返回地址压入堆栈,这是你将在 fib 中弹出的第一件事。

    【讨论】:

    • 所以在第一行通过 pop 保存值并在最后一行(在 ret 之前)通过 push 恢复应该可以吗?有什么建议可以选择保存吗?
    • 是的,如果有点不合常规的话,这会起作用 - 正如 Gunnar 建议的那样,最常见的方法是设置一个堆栈帧,并将参数从堆栈读取到寄存器中。暂存寄存器通常是 EAX、ECX 和 EDX——当您返回最外层调用范围时,通常必须保留其余寄存器。但请注意,这些约定是特定于操作系统的。
    【解决方案2】:

    我并不觉得组装很难,而是觉得它简单直接。如果您的老师没有正确地教您,您最好在互联网上搜索信息。几年前,当我们大多数人开始学习时,没有那么多信息,所以我们通过反复试验来学习。

    我建议你从简单开始学习堆栈。将此用作工作示例:

     extern printf
        section .data
        msg:    db "Your sum is %d",10 ,0
    
        section .text
        global _start
    
        _start:
            push    20
            push    2
            push    6
            call    AddEm
    
            push    eax
            push    msg
            call    printf
            add     esp, 4 * 2  ; printf is C calling convention, we have to adjust stack
    
            mov     ebx, 0
            mov     eax, 1      ; exit(0)
            int     0x80    
    
        AddEm:
            push    ebp     ; set up a stack frame
            mov     ebp, esp    ; we could just use esp but we won't
    
            mov     eax, [ebp + 8]  ; 1st param - 6
            add     eax, [ebp + 12] ; 2nd param - 2
            add     eax, [ebp + 16] ; 3rd param - 20
    
            mov     esp, ebp    ; restore the stack
            pop     ebp
            ret     4 * 3       ; passed 3 params, clean up stack
    

    这就是我组装、链接和输出的方式。

    【讨论】:

    • 很好的例子,我下课后看看。我现在将提交有缺陷的版本,我浪费了太多时间来解决链接器错误,例如:“未解决的引用”、“无法识别的格式”(使用 64 位作为目标文件输出格式时)
    猜你喜欢
    • 2019-04-23
    • 2013-10-13
    • 2016-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-04
    • 1970-01-01
    • 2013-11-30
    相关资源
    最近更新 更多