1

My OS: Linux debian 4.19.0-9-amd64 #1 SMP Debian x86_64 GNU/Linux Compiler: NASM version 2.14

I try play with conditional jumps, function calling and comparing expressions. I wrote something simple, and it seems to by work, but i don't understand what cause error: EnSegmentation fault

For compilation purpose i'm use: nasm -f elf64 sample_file.asm -o sample_file.o and: ld sample_file.o -o sample_file

section .data
msg: db 'Hello world',10
end: db 'Ending program', 10
section .text

global _start

hello_world:

        mov rax, 1
        mov rdi, 1
        mov rsi, msg
        mov rdx , 14

        syscall

        ret

exit:

        mov rax, 1
        mov rdi, 1
        mov rsi, end
        mov rdx, 20
        syscall

        mov rax, 60
        xor rdi, rdi
        syscall

        ret
_start:

        mov rax, 10
        mov rdx, 10
        cmp rax, rdx 
        je hello_world
        jne exit

        call hello_world
        mov rax, 60
        xor rdi,rdi
        syscall

        call exit

But the output is :

Hello world
EnSegmentation fault
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
reg3x_mr
  • 75
  • 1
  • 10
  • 2
    The `je hello_world` jump is taken, so you jump to that label. As you did not call it, the `ret` instruction will try to pop a return address off the stack that was never initialised. This may jump to an invalid address, or fault from a stack underflow already. – ecm Aug 07 '20 at 19:56
  • 1
    Unrelated to your question, you can add the line `msg_length: equ $ - msg` right after the `msg: db ...` line, then later use `msg_length` where you want to put the message's length into a register. – ecm Aug 07 '20 at 19:59
  • 1
    @ecm: The x86-64 System V ABI says that `rsp` points at `argc` on entry to `_start`. You don't need to "initialize the stack" in a user-space process, but it's essentially guaranteed that what's there is *not* a valid return address. The actual problem is a duplicate of [Nasm segmentation fault on RET in \_start](https://stackoverflow.com/q/19760002), but the real problem is thinking that `je` is a `call`. I think I've seen that problem before in SO questions, but https://stackoverflow.com/tags/x86/info only has links to the opposite problem (call without ret / falling off the end) – Peter Cordes Aug 07 '20 at 20:30
  • 1
    @Peter Cordes: Right, to clarify my comment I could phrase it like "it tries to pop a return address off the stack but at this point the stack top doesn't hold a return address". – ecm Aug 07 '20 at 20:39
  • 2
    @reg3x: Note that the extra line of `En` output is from the first `write` system call, which writes 14 bytes, including the first 2 of the string at `end:`. If you didn't want that, let the assembler calculate the length for you as @ecm showed using `$ - msg`, instead of hard-coding the wrong number. Use `strace ./sample_file` to see the system calls, and single-step with a debugger like GDB to see the path of execution. – Peter Cordes Aug 07 '20 at 20:47
  • Thank you very match for answer, but if i can by honest i don't understand. It is possible to mark place, where i make mistake ? I'm new in assembly, but i know how use GDB :)) – reg3x_mr Aug 07 '20 at 20:55
  • 2
    Your mistake is `je hello_world`. Remove that instruction so execution falls through to `call hello_world`. Jumping to `hello_world` (instead of calling) ends up reaching `ret` without a return address on the stack. Also, if you want someone to see a reply, use @username to notify them. – Peter Cordes Aug 08 '20 at 20:42

0 Answers0