Nasm segmentation fault on RET in _start

section .text
     global _start
_start:
     nop
main:
     mov eax, 1
     mov ebx, 2
     xor eax, eax
     ret

I compile with these commands:

nasm -f elf main.asm
ld -melf_i386 -o main main.o

When I run the code, Linux throw a segmentation fault error

(I am using Linux Mint Nadia 64 bits). Why this error is produced?


Because ret is NOT the proper way to exit a program in Linux, Windows, or Mac!!!!

_start is not a function, there is no return address on the stack because there is no user-space caller to return to. Execution in user-space started here (in a static executable), at the process entry point. (Or with dynamic linking, it jumped here after the dynamic linker finished, but same result).

On Linux / OS X, the stack pointer is pointing at argc on entry to _start (see the i386 or x86-64 System V ABI doc for more details on the process startup environment); the kernel puts command line args into user-space stack memory before starting user-space. (So if you do try to ret, EIP/RIP = argc = a small integer, not a valid address. If your debugger shows a fault at address 0x00000001 or something, that's why.)


For Windows it is ExitProcess and Linux is is system call - int 80H using sys_exit, for x86 or using syscall using 60 for 64Bit or a call to exit from the C Library if you are linking to it.

32 bit Linux

mov     eax, sys_exit ; sys_exit = 1
xor     ebx, ebx
int     80H

64 bit Linux

mov     rax, 60
xor     rdi, rdi
syscall

Windows

push    0
call    ExitProcess

Or Windows/Linux linking against the C Library

call    exit

exit (unlike a raw exit system call or libc _exit) will flush stdio buffers first. If you used printf from _start, use exit to make sure all output is printed before you exit, even if stdout is redirected to a file (making stdout full-buffered, not line-buffered).

It's generally recommended that if you use libc functions, you write a main function and link with gcc so it's called by the normal CRT start functions which you can ret to.

Defining main as something that _start falls through into doesn't make it special, it's just confusing to use a main label if it's not like a C main function called by a _start that's prepared to exit after main returns.