NASM 你能向我解释为什么我的代码返回分段错误吗?



我的代码在第二次调用子例程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

堆栈是一种后进先出结构,这意味着无论您将其弹出到哪个寄存器中,您推入堆栈的最后一件事将是弹出的第一个东西。

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

相关内容

  • 没有找到相关文章

最新更新