Andrew Robinson
Andrew Robinson

Reputation: 258

NASM Can you explain to me why my code is returning a segmentation fault?

My code returns a segmentation fault on the second call to subroutine prntlf.

_start:
mov     ecx, msg
call prntlf

call prntlf ; Here is where the issue is

After experimentation, I found that it only occurs when I don't set the value of ecx back to the string I want it to print, but what I want to know is why I have to do that. Given I popped the value of the registers off the saved stack, shouldn't ecx still hold a valid string to print?

Full source:

File 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

File: 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

Upvotes: 1

Views: 179

Answers (1)

Andrew Robinson
Andrew Robinson

Reputation: 258

The Stack is a Last-in-First-out structure, meaning that the last thing you pushed into the stack will be the first thing popped out, no matter the register you pop it into.

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

Upvotes: 2

Related Questions