Reputation: 4567
I was looking into asmlinkage tag.
From https://kernelnewbies.org/FAQ/asmlinkage
This is a #define for some gcc magic that tells the compiler that the function should not expect to find any of its arguments in registers (a common optimization), but only on the CPU's stack.
Looking into definition, it is defined to empty for x86_64:
#ifdef __cplusplus
#define CPP_ASMLINKAGE extern "C"
#else
#define CPP_ASMLINKAGE
#endif
#ifndef asmlinkage
#define asmlinkage CPP_ASMLINKAGE
#endif
Also, I read that the ABI spec says that we should place system call number in a register, and parameters in some other registers.
Then why we are looking for function parameters in stack. Is system call number also placed in stack?
Upvotes: 2
Views: 488
Reputation: 509
System calls are not part of your userland program nor shared libraries, they are system services provided by the kernel and are executed in kernel space .. in order to move from user space to kernel space one needs to execute a few special assembly instructions to tell the processor to jump into supervisor mode and before that it will want to push a few bits of information in registers so that the kernel side knows what system call to execute - it has a table of function pointers which point to the various functions that 'service' each system call) -
#include "SYS.h"
ENTRY(syscall)
pop %ecx /* rta */
pop %eax /* syscall number */
push %ecx
KERNCALL
push %ecx /* need to push a word to keep stack frame intact
upon return; the word must be the return address. */
jb 1f
ret
where KERNCALL is architecture-dependent and is a few assembly language instructions that tell the cpu to jump into supervisor mode in kernel space -
./lib/libc/amd64/SYS.h:#define KERNCALL movq %rcx, %r10; syscall
./lib/libc/i386/SYS.h:#define KERNCALL int $0x80
So here's the thing .. when you compile a program the optimizer will occasionally throw a function's parameters in registers instead of putting them on the program's stack .. this optimization works because the compiler is emitting code for both the caller and the callee and so both sides are made aware of this slight-of-hand. Not so for the kernel however .. it has no idea what to look for in which register and so all parameters intended for a system call must be on the userland program's stack.
Upvotes: 3
Reputation: 3533
asmlinkage tells your compiler to look on the CPU stack for the function parameters, instead of registers
In fact, it uses GCC's regparam attribute (Function-Attributes), or syscall_linkage
for IA64:
#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))
But your question is why this is necessary. System calls are services that userspace can call to request the kernel to perform something for them (and therefore execute in kernel space). These functions are quite unorthodox in the sense that you cannot expect them to behave like normal functions, where parameters are typically passed by writing to the program stack, but instead they are written to registers. While still in userspace, calling a syscall requires writing certain values to certain registers is translated. The system call number will always be written in eax, while the the rest of the parameters will go into ebx, ecx, etc. Now when a software interrupt occurs the CPU switches to kernel mode, to then execute system_call(). When the CPU switches to kernel mode it starts by saving all the registers in the CPU stack (eax, ebx, ecx, etc). After checking other things such as validating parameters, it will call the respective system call if everything is in order.So, since all the information about the parameters passed all the way from userspace to this point is nicely stored in the stack, the compiler must be instructed about this, hence the asmlinkage.
Another reason is that anyhow the kernel needs to save all the registers onto stack (in order to restore the environment before returning to the userspace) when handling the system call requests from userspace, so after that the parameters are available on stack, it doesn't need extra effort.
Upvotes: 2