3
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?

Peter Cordes
  • 286,368
  • 41
  • 520
  • 731
maxiperez
  • 1,440
  • 2
  • 20
  • 40
  • 1
    Should be the return code not be something like this (Linux): `mov eax, 1 mov ebx, 0 int 80h` On my opinion you are getting the segmentation fault due to the `ret` in the last line. – pearcoding Nov 04 '13 at 00:38
  • 1
    Related: [What happens if there is no exit system call in an assembly program?](https://stackoverflow.com/q/49674026) – Peter Cordes Mar 13 '22 at 16:06

1 Answers1

15

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.

Peter Cordes
  • 286,368
  • 41
  • 520
  • 731
Gunner
  • 5,582
  • 2
  • 23
  • 38
  • 2
    @maxiperez Not a stupid question at all :). It shows that programs are not just a 'main' functions and that they interact with the OS in different ways. – Guido Nov 04 '13 at 01:02