nasm-know-hows

nasm assembly related stuff

View on GitHub

int 0x80 vs syscall - When to Use Which?

Question

When to use int 0x80, and when to use syscall?


Quick Answer

Method Architecture Use When
int 0x80 32-bit Writing 32-bit programs or need legacy compatibility
syscall 64-bit Writing modern 64-bit programs (preferred)

Detailed Comparison

1. Architecture Requirement

int 0x80 - Legacy 32-bit Method

syscall - Modern 64-bit Method


2. Register Usage - CRITICAL DIFFERENCE!

int 0x80 (32-bit registers)

mov eax, 4          ; syscall number in EAX
mov ebx, 1          ; arg1 in EBX
mov ecx, msg        ; arg2 in ECX
mov edx, len        ; arg3 in EDX
mov esi, arg4       ; arg4 in ESI (if needed)
mov edi, arg5       ; arg5 in EDI (if needed)
int 0x80            ; trigger interrupt

syscall (64-bit registers)

mov rax, 1          ; syscall number in RAX
mov rdi, 1          ; arg1 in RDI
mov rsi, msg        ; arg2 in RSI
mov rdx, len        ; arg3 in RDX
mov r10, arg4       ; arg4 in R10 (if needed)
mov r8, arg5        ; arg5 in R8 (if needed)
mov r9, arg6        ; arg6 in R9 (if needed)
syscall             ; fast system call

Key Difference:


3. Syscall Numbers - DIFFERENT VALUES!

The same system call has different numbers in 32-bit vs 64-bit!

Operation 32-bit (int 0x80) 64-bit (syscall)
sys_read 3 0
sys_write 4 1
sys_open 5 2
sys_close 6 3
sys_exit 1 60

Example - Exit syscall:

; 32-bit exit
mov eax, 1          ; exit is syscall #1 in 32-bit
xor ebx, ebx        ; exit code 0
int 0x80

; 64-bit exit
mov rax, 60         ; exit is syscall #60 in 64-bit!
xor rdi, rdi        ; exit code 0
syscall

4. Performance

syscall is MUCH faster than int 0x80:

syscall was designed specifically to be faster by avoiding the overhead of interrupt handling.


5. Practical Examples

Complete 32-bit Program (int 0x80)

C Equivalent (same for both 32-bit and 64-bit):

#include <unistd.h>

int main() {
    const char *msg = "32-bit mode!\n";
    size_t len = 13;
    
    // write(1, msg, len)
    write(1, msg, len);
    
    // exit(0)
    return 0;
}

Assembly (32-bit):

; Build: nasm -f elf32 prog32.asm && ld -m elf_i386 -o prog32 prog32.o

section .data
    msg db "32-bit mode!", 10
    len equ $ - msg

section .text
    global _start

_start:
    ; write(1, msg, len)
    mov eax, 4          ; sys_write = 4
    mov ebx, 1          ; stdout
    mov ecx, msg        ; buffer
    mov edx, len        ; count
    int 0x80

    ; exit(0)
    mov eax, 1          ; sys_exit = 1
    xor ebx, ebx        ; status 0
    int 0x80

Complete 64-bit Program (syscall)

C Equivalent (same as 32-bit version):

#include <unistd.h>

int main() {
    const char *msg = "64-bit mode!\n";
    size_t len = 13;
    
    // write(1, msg, len)
    write(1, msg, len);
    
    // exit(0)
    return 0;
}
// Note: The C code is identical - only the assembly differs!

Assembly (64-bit):

; Build: nasm -f elf64 prog64.asm && ld -o prog64 prog64.o

section .data
    msg db "64-bit mode!", 10
    len equ $ - msg

section .text
    global _start

_start:
    ; write(1, msg, len)
    mov rax, 1          ; sys_write = 1
    mov rdi, 1          ; stdout
    mov rsi, msg        ; buffer
    mov rdx, len        ; count
    syscall

    ; exit(0)
    mov rax, 60         ; sys_exit = 60
    xor rdi, rdi        ; status 0
    syscall

6. What Happens If You Mix Them Up?

❌ Using int 0x80 in 64-bit mode

; This WILL work but is WRONG and SLOW
section .text
    global _start
_start:
    mov eax, 4          ; Wrong! Using 32-bit syscall numbers
    mov ebx, 1
    mov ecx, msg
    mov edx, len
    int 0x80            ; Works but uses compatibility layer (slow!)

Problems:

❌ Using syscall in 32-bit mode

; This will CRASH!
mov rax, 1
syscall             ; ILLEGAL INSTRUCTION on 32-bit CPU!

Result: Illegal instruction (core dumped)


7. How to Detect Your Architecture

Check what you’re running:

# Check if your kernel is 64-bit
uname -m
# Output: x86_64 (64-bit) or i686/i386 (32-bit)

# Check what format your program is
file ./your_program
# Output examples:
# ELF 32-bit LSB executable  -> use int 0x80
# ELF 64-bit LSB executable  -> use syscall

8. Decision Tree

Are you writing for 64-bit Linux?
│
├─ YES → Use `syscall`
│        • Use 64-bit registers (rax, rdi, rsi, rdx...)
│        • Use 64-bit syscall numbers
│        • Assemble with: nasm -f elf64
│        • Link with: ld (default)
│
└─ NO (32-bit or compatibility)
         → Use `int 0x80`
         • Use 32-bit registers (eax, ebx, ecx, edx...)
         • Use 32-bit syscall numbers
         • Assemble with: nasm -f elf32
         • Link with: ld -m elf_i386

9. Modern Best Practice

For new code in 2025:

Only use int 0x80 if:


10. Quick Reference Card

╔════════════════════════════════════════════════════════╗
  32-BIT (int 0x80)         64-BIT (syscall)          
╠════════════════════════════════════════════════════════╣
  nasm -f elf32             nasm -f elf64             
  ld -m elf_i386            ld                        
                                                      
  mov eax, 4  ; write   │    mov rax, 1    ; write    ║
  mov ebx, 1                mov rdi, 1               
  mov ecx, msg              mov rsi, msg             
  mov edx, len              mov rdx, len             
  int 0x80                  syscall                  
                                                      
  mov eax, 1  ; exit    │    mov rax, 60   ; exit     ║
  xor ebx, ebx              xor rdi, rdi             
  int 0x80                  syscall                  
╚════════════════════════════════════════════════════════╝

TL;DR

Since you’re on a modern Linux system (x86_64), stick with syscall for all your 64-bit programs!


See Also:


← Back to Q&A Index