I am writing a C function that will be invoked from assembly code.
(Specifically, I want to do some checking job in the path of system call handling in linux kernel, so I will call the c function before a system call is dispatched in entry_32.S)
I am confused with the "asmlinkage" modifier when defining my c function.
I know asmlinkage is to tell the compiler that the parameters will be passed through stack.
#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))
Questions:
(1) Is asmlinkage required when defining such a function that will be invoked from assembly code?
(2) what is the default calling convention in gcc. If I omit "asmlinkage" when defining a c function, does it imply _cdecl or fastcall?
(3) if the default calling convention is cdecl, why is asmlinkage needed, considering cdecl is equal to asmlinkage modifier? (am I correct here?)
(4) why are those system call functions all declared with asmlinkage. Can we copy the parameters to registers first, then call those system call functions? From my point of view, in x86, when issuing a system call, the parameters are readily saved in registers; then why bother to save then in stack to enforce such passing parameters via stack convention?
Finally, can anybody recommend some resources/books that I can refer to for such mix assembly/c programming?
The idea, I believe, is to allow the kernel to be compiled with gcc options that would change the default calling convention to something more efficient (i.e. passing more arguments in registers). However, functions that need to be called from asm cannot be allowed to vary in calling convention based on the gcc options in use, or there would have to be separate versions of the asm for every supported set of gcc options. Thus, functions that need to use a fixed calling convention (which happens to match the default with no special gcc options) are declared with special attributes so that their calling convention will remain fixed.
After several hours' research, I got the following empirical points:
(1) Is asmlinkage required when defning such a function that will be invoked from assembly code?
No. Actually the fastcall is frequently used.
For example, in entry_32.S, if you search "call", you can obtain all the c functions invoked from this assembly file. Then you can see, many use fastcall instead of asmlinkage as the calling convention. For example,
(2) what is the default calling convention in gcc. If I omit "asmlinkage" when defining a c function, does it imply _cdecl or fastcall?
(3) if the default calling convention is cdecl, why is asmlinkage needed, considering cdecl is equal to asmlinkage modifier? (am I correct here?)
For C functions not invoked from assembly code, we can safely assume the default calling convention is cdecl (or fast call; it doesn't matter, because gcc will take care of the caller and callee for parameter passing. The default calling convention can be specified when compiling). However, for C functions invoked from assembly code, we should explicitly declare the function's calling convention, because the parameter passing code in assembly side has been fixed. For example, if patch_espfix_desc is declared as asmlinkage, then gcc will compile the function to retrieve parameters from stack. This is inconsistent with the assembly side, which put the parameters into registers.
But I am still not clear when to use asmlinkage and when to use fastcall. I really need some guideline and resources to refer to.
I would like to try to answer question (4) myself:
Why do all the system call functions sys_*, e.g. sys_gettimeofday, use stack to pass parameters?
The 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. I.e., it doesn't need extra effort.
On the other hand, if you want to use fastcall for the calling convention, more work has to be done. We first need to know, when a user program issues a system call, in x86-linux, %eax is for syscall number, and %ebx, %ecx, %edx, %esi, %edi, %ebp are used for passing 6 parameters to system calls (before "int 80h" or "sysenter"). However, the calling convention of fastcall is to pass the first parameter in %eax, the 2nd one in %edx, the 3rd %ecx, others are pushed onto stack from right to left. In this way, to enforce such fastcall convention in kernel, you need to somehow arrange these in addition to save all the registers on the stack.