在浅尝辄止24-Linux系统调用2以及前面的分析文章中,没有说明
__NR_***是什么东西,今天来说一下。
寻找__NR_write
我们在内核代码中grep一下,可以很容易找到以下内容。可以看到,__NR_write只是一个数字,其实就是系统调用号。
include/uapi/asm-generic/unistd.h:#define __NR_write 64
include/uapi/asm-generic/unistd.h:__SYSCALL(__NR_write, sys_write)
uapi即user api,也就是说,下面的头文件是用户可以引用到的。平常情况下,这个用户就是glibc,我们使用系统调用时,用的是glibc另外提供的头文件。在浅尝辄止24-Linux系统调用2中,我用的头文件是#include <linux/unistd.h>,有了它,就能找到__NR_write,我没有仔细验证,linux/unistd.h应该就是linux/include/uapi/linux/unistd.h,然后由#include <asm/unistd.h>再引用到linux/include/uapi/asm-generic/unistd.h的。
调用系统调用
网上有很多讲系统调用的文章,会讲“处理swi中断的就是vector_swi”,我们就直接看这里好了,我认为关键的就是linux/arch/arm/kernel/entry-common.S中下面的内容。
#define CALL(x) .long x
/*=============================================================================
* SWI handler
*-----------------------------------------------------------------------------
*/
.align 5
ENTRY(vector_swi)
...
adr tbl, sys_call_table @ load syscall table pointer
...
ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine
...
ENDPROC(vector_swi)
...
.type sys_call_table, #object
ENTRY(sys_call_table)
#include "calls.S"
adr tbl, sys_call_table是说,tbl就是sys_call_table,看意思就是系统调用表(表中放着系统调用函数的地址)。看注释,跳转到系统调用的指令就是ldrcc pc, [tbl, scno, lsl #2],tbl是表的首地址,scno(system call No)显然是调用号,将调用号左移2位(一个地址4字节),加上调用表首地址,再赋给pc,这样就跳转到对应系统调用的地址了。
谁说scno是系统调用号?调用表的内容在哪里定义的?