Fundamentals 15 min read

Why Do System Calls Cost So Much? Exploring Linux’s Three Execution Methods

This article explains how Linux implements system calls via software interrupts, fast syscall/sysenter instructions, and the virtual dynamic shared object (vDSO), comparing their performance to regular function calls and showing concrete code examples and step‑by‑step execution details.

ITPUB
ITPUB
ITPUB
Why Do System Calls Cost So Much? Exploring Linux’s Three Execution Methods

Overview of Linux System Calls

System calls are the kernel‑level interface that user‑space programs use to request services such as file I/O, process creation, and time retrieval. Typical programs invoke many system calls during startup; only the calls directly caused by user code (e.g., write from printf) are essential for the program’s logic.

#include <stdio.h>
int main() {
    printf("Hello, World!");
    return 0;
}

Running the program under strace shows dozens of calls, most of which belong to the dynamic loader and runtime initialization.

Three Execution Paths for System Calls

Software interrupt (INT 0x80)

Fast entry instructions (SYSENTER / SYSCALL)

Virtual Dynamic Shared Object (vDSO)

1. Software Interrupt (INT 0x80)

On 32‑bit x86 Linux the classic path uses the INT 0x80 instruction. The sequence is:

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

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

Processor executes INT 0x80, switching to kernel mode.

Kernel entry point entry_INT80_32 saves all registers ( SAVE_ALL) on the kernel stack.

Kernel validates the syscall number via do_syscall_32_irqs_on.

Implementation is looked up in ia32_sys_call_table.

Arguments are checked, data is copied between user and kernel space, and the result is placed back in eax.

Kernel restores registers and returns to user space; the libc wrapper translates the result into a return value or sets errno.

This path involves full context saving, an interrupt‑descriptor‑table lookup, and data copying, which adds noticeable latency.

2. Fast Entry Instructions (SYSENTER / SYSCALL)

Modern kernels replace the interrupt with dedicated entry instructions. On 64‑bit systems the SYSCALL / SYSRET pair is used; on 32‑bit systems SYSENTER / SYSEXIT are used. These instructions bypass the IDT and avoid saving a full stack frame, reducing the number of clock cycles by roughly 25 % compared with the software‑interrupt method.

void syscall_init(void) {
    wrmsr(MSR_STAR, 0, (__USER32_CS << 16) | __KERNEL_CS);
    wrmsrl(MSR_LSTAR, (unsigned long)entry_SYSCALL_64);
    /* other MSR setup */
}

During boot the kernel writes the address of entry_SYSCALL_64 to the model‑specific register MSR_LSTAR. When a user program executes SYSCALL, the CPU jumps directly to this entry point, which then calls do_syscall_64 to dispatch the request via the 64‑bit syscall table.

3. vDSO (Virtual Dynamic Shared Object)

vDSO is a small kernel‑provided shared object mapped into every process’s address space. It implements a limited set of “safe” syscalls (e.g., gettimeofday, clock_gettime, clock_getres, rt_sigreturn) entirely in user space, eliminating the kernel transition.

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

During program start‑up the ELF loader records the vDSO base address in the auxiliary vector entry AT_SYSINFO_EHDR. The dynamic linker reads this entry, and libc resolves symbols such as __vdso_gettimeofday to function pointers inside the vDSO. Calls to these functions execute with the same cost as ordinary function calls, providing performance improvements of dozens of times over the traditional syscall path.

Practical Implications

Software‑interrupt syscalls involve full context saving and IDT lookup, resulting in the highest overhead.

Fast entry instructions are the default on modern Linux kernels and reduce unnecessary work, offering a lower‑latency path for most syscalls.

vDSO provides the fastest path for a small, non‑privileged subset of syscalls, effectively flattening their cost to that of a regular function call.

Understanding these mechanisms helps developers diagnose performance bottlenecks and choose the appropriate interface when writing low‑level Linux applications.

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.

LinuxAssemblysyscallvDSO
ITPUB
Written by

ITPUB

Official ITPUB account sharing technical insights, community news, and exciting events.

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.