How Are Linux Kernel Calls Implemented?

System calls aren't handled like regular function calls. It takes special code to make the transition from user space to kernel space, basically a bit of inline assembly code injected into your program at the call site. The kernel side code that "catches" the system call is also low-level stuff you probably don't need to understand deeply, at least at first.

In include/linux/syscalls.h under your kernel source directory, you find this:

asmlinkage long sys_mkdir(const char __user *pathname, int mode);

Then in /usr/include/asm*/unistd.h, you find this:

#define __NR_mkdir                              83
__SYSCALL(__NR_mkdir, sys_mkdir)

This code is saying mkdir(2) is system call #83. That is to say, system calls are called by number, not by address as with a normal function call within your own program or to a function in a library linked to your program. The inline assembly glue code I mentioned above uses this to make the transition from user to kernel space, taking your parameters along with it.

Another bit of evidence that things are a little weird here is that there isn't always a strict parameter list for system calls: open(2), for instance, can take either 2 or 3 parameters. That means open(2) is overloaded, a feature of C++, not C, yet the syscall interface is C-compatible. (This is not the same thing as C's varargs feature, which allows a single function to take a variable number of arguments.)

Have questions or suggestions? @ us on Twitter and Facebook, and stay updated on new releases and articles.

December 01 2021

Add or review comments

Please leave your comment

Existing comments

Comments 0