section .text
global _start
_start:
nop
main:
mov eax, 1
mov ebx, 2
xor eax, eax
ret
I compile with these commands:
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.