【问题标题】:NASM Can you explain to me why my code is returning a segmentation fault?NASM 你能解释一下为什么我的代码会返回分段错误吗?
【发布时间】:2018-04-14 02:35:05
【问题描述】:

我的代码在第二次调用子例程prntlf 时返回分段错误。

_start:
mov     ecx, msg
call prntlf

call prntlf ; Here is where the issue is

经过实验,我发现只有当我没有将ecx的值设置回我想要它打印的字符串时才会出现这种情况,但我想知道的是为什么我必须这样做。鉴于我从保存的堆栈中弹出了寄存器的值,ecx 不应该仍然保留一个有效的字符串来打印吗?

完整来源:

文件hello.asm

; RUN WITH `nasm -f elf32 hello.asm -o hello.o && ld -m elf_i386 hello.o -o hello && ./hello`

%include 'subroutines.inc'

section .data
    msg         db      "Hello, World!", 0x0
    msg2         db      "Goodbye, Moon!", 0x0
    linefeed    db      0xA, 0xD

section .text
    global _start:

_start:
    mov     ecx, msg
    call prntlf

    call prntlf

    jmp     end

文件:subroutines.inc

    ; subroutines.inc


;===============================================================================
    ; getstrlen | Gets String Length and pushes the value to register edx
    ;===============================================================================
    getstrlen:
        push    eax
        push    ebx
        mov     eax, ebx

    findnterm:
        cmp     byte [eax], 0
        jz      gotstrlen
        inc     eax
        jmp     findnterm

    gotstrlen:
        sub     eax, ebx
        mov     edx, eax
        pop     eax
        pop     ebx
        ret

    ;===============================================================================
    ; printstr | Prints a String using a dynamic algorithm to find null terminator
    ;===============================================================================
    printstr:
        push    eax
        push    ebx
        push    edx

        mov     ebx, ecx
        call getstrlen

        mov     ebx, 0x01
        mov     eax, 0x04
        int 0x80

        pop     eax
        pop     ebx
        pop     edx
        ret

    ;===============================================================================
    ; prntlf | Prints a String and appends a Linefeed.
    ;===============================================================================
    prntlf:
        push    eax
        push    ebx
        push    ecx
        push    edx

        mov     eax, ecx

    movetoendloop:
        cmp     byte [eax], 0
        jz      donemoving
        inc     eax
        jmp     movetoendloop

    donemoving:
        call printstr
        mov     ecx, linefeed
        call printstr

        pop     eax
        pop     ebx
        pop     ecx
        pop     edx
        ret

    ;===============================================================================
    ; end | calls kernel and tells it to End the program
    ;===============================================================================
    end:
        mov     eax, 0x01
        mov     ebx, 0x00
        int 0x80

【问题讨论】:

  • 当你将东西压入堆栈时,你需要以相反的顺序将它们弹出。你像printlf 这样的函数不会以相反的顺序弹出它们。您在大多数其他功能中也犯了同样的错误(您需要修复所有功能)。例如,如果您这样做push eaxpush ebxpush ecxpush edx,您需要按此顺序弹出它们pop edx@ 987654336@pop ebxpop eax。由于您以错误的顺序弹出内容,因此寄存器获得的值与预期不同,因此 ECX 似乎没有在函数调用中保留,从而导致您看到的问题。
  • 使用调试器单步执行此操作以测试您的假设并发现您交换了ebxecx
  • @MichaelPetch 就是这样,非常感谢!我不敢相信这本书没有说你需要以相反的顺序弹出它们。
  • 本书/教程可能假设您了解堆栈的工作原理。这里有一个合理的描述:en.wikibooks.org/wiki/X86_Disassembly/The_Stack。堆栈是后进先出结构。
  • @MichaelPetch 你想把它做成答案格式,以便我接受并关闭问题吗?

标签: linux assembly x86 segmentation-fault nasm


【解决方案1】:

堆栈是一种后进先出结构,这意味着您压入堆栈的最后一个内容将是第一个弹出的内容,无论您将其弹出到哪个寄存器。

prntlf:
    push    eax
    push    ebx
    push    ecx
    push    edx

    ...

    pop     edx       ; Pop them back from the stack in the reverse order in which you pushed them.
    pop     ecx
    pop     ebx
    pop     eax
    ret

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2021-12-18
    • 2021-09-15
    • 1970-01-01
    • 2013-10-22
    相关资源
    最近更新 更多