Assembly Language - System Calls
System calls are the only way for user programs to interact with the operating system kernel. Through system calls, assembly programs can read/write files, allocate memory, create processes, and more.
What is a system call?
User programs run in restricteduser modeand 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 go throughsystem callsto request services from the operating system kernel.
The system call flow is: the user program initiates a system call → the CPU switches to kernel mode → the kernel executes the corresponding service → returns to user mode and continues execution.
You can think of a system call as:The user program makes a phone call to the operating system, asking it to do something it doesn't have permission to do.
Linux system call mechanism
In Linux 32-bit systems, a system call is completed through the following steps:
- willSystem call numberPlaced into the EAX register
- Put parameters into registers such as EBX, ECX, EDX, ESI, EDI
- Execute
int 0x80The instruction triggers a software interrupt - The CPU switches to kernel mode, and the kernel executes the corresponding service based on the call number in EAX.
- The kernel puts the return value into EAX, switches back to user mode, and continues execution.
Overview of common system calls
| System call | Call number (EAX) | Function | Parameters |
|---|---|---|---|
| sys_exit | 1 | Exit program | EBX = return value (exit code) |
| sys_fork | 2 | Fork a 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 system call list can be found in
/usr/include/asm/unistd_32.hView it there. Note that 32-bit and 64-bit system call numbers are different.
sys_write - output string
The most commonly used system call, used to print content to the screen:
Example
; Use sys_write to output a string
section .data
msg db 'Hello, example! 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 (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
Output:
$ nasm -f elf32 write_syscall.asm -o write_syscall.o $ ld -m elf_i386 write_syscall.o -o write_syscall $ ./write_syscall Hello, example! Welcome to assembly.
sys_read - read user input
Read data from standard input (keyboard):
Example
; Use sys_read to read user input and echo it
section .bss
buffer resb 64 ; Reserve a 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 at most 64 bytes
int 0x80
; EAX returns the actual number of bytes read (including the trailing newline)
mov esi, eax ; Save the 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 the user's input content
mov eax, 4
mov ebx, 1
mov ecx, buffer
mov edx, esi ; Use the actual number of bytes entered
int 0x80
; Exit the 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: example Hello, example
sys_exit - exit program
Every program must call sys_exit to exit normally; otherwise, the CPU will continue executing the following garbage data, causing a segmentation fault.
Example
mov eax, 1 ; System call number 1 = sys_exit
mov ebx, 0 ; Exit code 0 = normal exit (a non-zero value is also allowed)
int 0x80
The exit code can be checked in the shell via$?View:
$ ./program $ echo $? 0
Generic system call template
When writing system calls, you can follow the following general template:
Example
; Applicable to Linux 32-bit systems
; Step 1: Put the system call number into EAX
mov eax,System call number
; Step 2: Put the arguments in order
mov ebx,No.1argument(s)
mov ecx,No.2argument(s)
mov edx,No.3argument(s)
mov esi,No.4argument(s)
mov edi,No.5argument(s)
; Step 3: Trigger the system call
int 0x80
; Step 4: Check the return value (in EAX)
; A negative value usually indicates an error
cmp eax, 0
jl error_handler ; If EAX < 0, jump to error handling
Other extensions
int 0x80After triggering, 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 indicates EPERM).