Assembly Language - System Calls
A System Call is the only way for user programs to interact with the operating system kernel. Through system calls, assembly programs can read and write files, allocate memory, create processes, and more.
What is a System Call
User programs run in restricted User Mode and cannot directly access hardware or execute privileged operations.
When a program needs to perform kernel-level functions such as I/O operations or memory allocation, it must use a system call to request services from the operating system kernel.
The system call flow is: user program initiates system call β CPU switches to kernel mode β kernel executes corresponding service β returns to user mode to continue execution.
You can think of a system call as: a user program making a phone call to the operating system, asking for help with something it doesn't have permission to do itself.
Linux System Call Mechanism
In Linux 32-bit systems, system calls are completed through the following steps:
- Put the system call number in the EAX register
- Put parameters in EBX, ECX, EDX, ESI, EDI, and other registers
- Execute the
int 0x80instruction to trigger a software interrupt - CPU switches to kernel mode, and the kernel executes the corresponding service based on the call number in EAX
- The kernel places the return value in EAX and switches back to user mode to continue execution
Common System Calls Overview
| System Call | Call Number (EAX) | Function | Parameters |
|---|---|---|---|
| sys_exit | 1 | Exit program | EBX = return value (exit code) |
| sys_fork | 2 | Create child process | No parameters |
| sys_read | 3 | Read file/input | EBX=fd, ECX=buf, EDX=count |
| sys_write | 4 | Write file/output | EBX=fd, ECX=buf, EDX=count |
| sys_open | 5 | Open file | EBX=filename, ECX=flags, EDX=mode |
| sys_close | 6 | Close file | EBX=fd |
| sys_creat | 8 | Create file | EBX=filename, ECX=mode |
| sys_lseek | 19 | Move file pointer | EBX=fd, ECX=offset, EDX=whence |
| sys_brk | 45 | Adjust data segment size (memory allocation) | EBX=new address |
The complete list of system calls can be found in
/usr/include/asm/unistd_32.h. Note that system call numbers differ between 32-bit and 64-bit systems.
sys_write - Output String
The most commonly used system call, for printing content to the screen:
Example
; File path: write_syscall.asm
; Use sys_write to output a string
section .data
msg db 'Hello, tutorial! Welcome to assembly.', 0xA
len equ $ - msg
section .text
global _start
_start:
; Call sys_write (4)
mov eax, 4 ; System call number 4 = sys_write
mov ebx, 1 ; File descriptor 1 = stdout (standard output)
mov ecx, msg ; Address of data to output
mov edx, len ; Data length (number of bytes)
int 0x80 ; Trigger system call
; On success, EAX returns the actual number of bytes written
; Exit program
mov eax, 1
mov ebx, 0
int 0x80
Running result:
$ nasm -f elf32 write_syscall.asm -o write_syscall.o
$ ld -m elf_i386 write_syscall.o -o write_syscall
$ ./write_syscall
Hello, tutorial! Welcome to assembly.
sys_read - Read User Input
Read data from standard input (keyboard):
Example
; File path: read_syscall.asm
; Use sys_read to read user input and echo it back
section .bss
buffer resb 64 ; Reserve 64-byte input buffer
section .data
prompt db 'Please enter your name: '
prompt_len equ $ - prompt
output_msg db 'Hello, '
output_msg_len equ $ - output_msg
section .text
global _start
_start:
; Output prompt message
mov eax, 4
mov ebx, 1
mov ecx, prompt
mov edx, prompt_len
int 0x80
; Read user input
mov eax, 3 ; System call number 3 = sys_read
mov ebx, 0 ; File descriptor 0 = stdin (standard input)
mov ecx, buffer ; Input buffer address
mov edx, 64 ; Read up to 64 bytes
int 0x80
; EAX returns the actual number of bytes read (including the trailing newline)
mov esi, eax ; Save actual input length to esi
; Output "Hello, "
mov eax, 4
mov ebx, 1
mov ecx, output_msg
mov edx, output_msg_len
int 0x80
; Output user input content
mov eax, 4
mov ebx, 1
mov ecx, buffer
mov edx, esi ; Use actual number of input bytes
int 0x80
; Exit program
mov eax, 1
mov ebx, 0
int 0x80
Running result:
$ nasm -f elf32 read_syscall.asm -o read_syscall.o
$ ld -m elf_i386 read_syscall.o -o read_syscall
$ ./read_syscall
Please enter your name: tutorial
Hello, tutorial
sys_exit - Exit Program
Every program must call sys_exit to terminate normally; otherwise, the CPU will continue executing garbage data, causing a segmentation fault.
Example
; Exit with different exit codes
mov eax, 1 ; System call number 1 = sys_exit
mov ebx, 0 ; Exit code 0 = normal exit (can also be non-zero)
int 0x80
The exit code can be checked in the shell using $?:
$ ./program
$ echo $?
0
System Call General Template
When writing system calls, you can follow this general template:
Example
; System call general template
; For Linux 32-bit systems
; Step 1: Put system call number in EAX
mov eax, system_call_number
; Step 2: Put parameters in order
mov ebx, first_parameter
mov ecx, second_parameter
mov edx, third_parameter
mov esi, fourth_parameter
mov edi, fifth_parameter
; Step 3: Trigger system call
int 0x80
; Step 4: Check return value (in EAX)
; Usually negative value indicates error
cmp eax, 0
jl error_handler ; If EAX < 0, jump to error handler
After
int 0x80is triggered, EAX holds the return value. Most system calls return a non-negative value on success, and a negative error code on failure (e.g., -1 means EPERM).
YouTip