YouTip LogoYouTip

Assembly Syscall

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.

Image 1: Linux 32-bit System Call Flow

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:

  1. Put the system call number in the EAX register
  2. Put parameters in EBX, ECX, EDX, ESI, EDI, and other registers
  3. Execute the int 0x80 instruction to trigger a software interrupt
  4. CPU switches to kernel mode, and the kernel executes the corresponding service based on the call number in EAX
  5. 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 0x80 is 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).

← Assembly VariablesAssembly Memory Segment β†’