Fundamentals 16 min read

Why System Calls Are So Expensive: From INT 0x80 to vDSO

This article explains how Linux system calls work, compares their overhead to regular function calls, and details the three implementation methods—software interrupts, fast syscall instructions, and the virtual dynamic shared object (vDSO)—including their performance trade‑offs and practical usage.

Liangxu Linux
Liangxu Linux
Liangxu Linux
Why System Calls Are So Expensive: From INT 0x80 to vDSO

Background

System calls are the interface through which user‑space programs request services from the operating system kernel, such as file I/O, process creation, or hardware access. The GNU C Library (glibc) wraps these kernel services in well‑defined functions, but the underlying mechanism is often hidden from developers.

Simple Example

A minimal #include <stdio.h> "Hello, World!" program triggers dozens of system calls when executed. Using strace reveals the sequence of calls, from execve to write and finally exit_group. Most of these calls occur during program start‑up; only the write call is directly caused by printf.

#include <stdio.h>
int main() {
    printf("Hello, World!");
    return 0;
}
$ gcc hello.c -o hello
$ strace ./hello
execve("./hello", ["./hello"], ...) = 0
brk(NULL) = 0x557b449db000
... 
write(1, "Hello, World!", 13) = 13
exit_group(0) = ?
+++ exited with 0 +++

System Call vs. Function Call Overhead

Unlike a normal function call, which only saves a few registers and jumps to the target address, a system call must switch from user mode to kernel mode, validate arguments, and possibly copy data between address spaces. Benchmarks show that a system call can be dozens of times slower than a plain C function call.

The figure also introduces the virtual dynamic shared object (vDSO), which can reduce the cost of certain calls.

Three Linux System‑Call Mechanisms

Software interrupt (INT 0x80)

Fast syscall instructions (SYSENTER / SYSCALL)

vDSO – a user‑space mapping of selected kernel functions

1. Software Interrupt

On 32‑bit x86, the INT 0x80 instruction triggers a software interrupt. The kernel registers an entry point ( entry_INT80_32) to handle the call. The execution flow is:

Application calls a libc wrapper (e.g., write).

The wrapper copies arguments to registers and places the syscall number in eax.

The wrapper executes INT 0x80, causing a mode switch.

The interrupt handler saves registers ( SAVE_ALL) and jumps to do_int80_syscall_32.

The kernel validates the syscall number, looks it up in ia32_sys_call_table, and executes the implementation.

Result is placed back in eax, registers are restored, and control returns to the user‑space wrapper.

If an error occurs, errno is set and a negative integer is returned.

2. Fast Syscall Instructions

Modern CPUs provide dedicated instructions ( SYSENTER / SYSEXIT on 32‑bit, SYSCALL / SYSRET on 64‑bit) that bypass the interrupt descriptor table, eliminating unnecessary checks and stack saves. The kernel stores the entry point ( entry_SYSCALL_64) in a Model‑Specific Register (MSR) during initialization:

void syscall_init(void) {
    wrmsr(MSR_STAR, 0, (__USER32_CS << 16) | __KERNEL_CS);
    wrmsrl(MSR_LSTAR, (unsigned long)entry_SYSCALL_64);
    ...
}

When the user program executes SYSCALL, the CPU jumps directly to entry_SYSCALL_64, which then calls do_syscall_64 to look up the syscall in the table and execute it. Because the path avoids the interrupt descriptor table and stack frame setup, it can reduce the number of clock cycles by roughly 25 % compared with software interrupts.

3. vDSO (Virtual Dynamic Shared Object)

vDSO is a small shared library that the kernel maps into every process’s address space. It contains implementations of a few “safe” syscalls (e.g., gettimeofday, clock_gettime, clock_getres, rt_sigreturn) that can be executed entirely in user mode, eliminating the kernel‑mode transition.

During process start‑up, the ELF loader records the base address of vDSO in the auxiliary vector entry AT_SYSINFO_EHDR. The dynamic linker then resolves symbols such as __vdso_gettimeofday and patches the libc wrapper to call the vDSO function directly.

$ ldd /bin/cat
linux-vdso.so.1 (0x00007fff2709c000)
...
$ cat /proc/self/maps
7ffe8ca90000-7ffe8ca92000 r-xp 00000000 00:00 0 [vdso]

Because only non‑privileged, time‑related syscalls are exposed via vDSO, the security risk is limited, and the performance gain can be dozens of times faster than a traditional syscall.

Summary

Software‑interrupt syscalls ( INT 0x80) involve full context saving, interrupt‑descriptor lookup, and are now rarely used except on legacy platforms.

Fast syscall instructions ( SYSCALL / SYSENTER) are the dominant method on modern x86, offering a streamlined path with about 25 % fewer cycles.

vDSO provides the fastest path for a small set of safe syscalls by executing them entirely in user space, effectively flattening the overhead to that of a regular function call.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

LinuxsyscallvDSOINT 0x80kernel performance
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.