|
本文以x86_64平台为例,分析linux下的系统调用是如何被执行的。
假设目标系统调用是,其对应的内核源码为:
// fs/read_write.cSYSCALL_define3(write, unsigned int, fd, const char __user *, buf,size_t, count)return ksys_write(fd, buf, count);
这里主要看下SYSCALL_DEFINE3这个宏定义:
// include/linux/syscalls.h#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)#define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)#define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)#define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)#define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)#define SYSCALL_DEFINEx(x, sname, ...) \__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
该宏又引用了__SYSCALL_DEFINEx,继续看下:
// arch/x86/include/asm/syscall_wrapper.h#define __SYSCALL_DEFINEx(x, name, ...) \asmlinkage long __x64_sys##name(const struct pt_regs *regs); \static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\asmlinkage long __x64_sys##name(const struct pt_regs *regs) \return __se_sys##name(SC_X86_64_REGS_TO_ARGS(x,__VA_ARGS__));\static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \long ret = __do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__));\return ret; \static INLINE long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
该宏的参数中,x为3,name为_write,...代表的__VA_ARGS__为unsigned int, fd, const char __user *, buf, size_t, count。
接着,在宏的定义中,先声明了三个函数,分别为__x64_sys_write、_se_sys_write、__do_sys_write,紧接着,定义了__x64_sys_write和_se_sys_write的实现,__x64_sys_write内调用_se_sys_write,_se_sys_write内调用__do_sys_write。
__do_sys_write只是一个方法头,它和最开始的write系统调用的方法体构成完整的方法。
由上可以看到,三个方法中,只有__x64_sys_write方法没有static,即只有它是外部可调用的,所以我们看下哪里引用了__x64_sys_write。
// arch/x86/entry/syscalls/syscall_64.tbl# 64-bit system call numbers and entry vectors# The format is:# The __x64_sys_* stubs are created on-the-fly for sys_* system calls# The abi is "common", "64" or "x32" for this file.0 common read __x64_sys_read1 common write __x64_sys_write
我们会在一个非c文件中,找到了对__x64_sys_write方法的引用,但这个文件又是怎么被使用的呢?
根据arch/x86/entry/syscalls/Makefile我们可以知道,是有对应的shell脚本,根据上面的文件来生成c版的头文件,比如下面两个。
kernel内部使用的:
// arch/x86/include/generated/asm/syscalls_64.h#ifdef CONFIG_X86__SYSCALL_64(0, __x64_sys_read, )#else /* CONFIG_UML */__SYSCALL_64(0, sys_read, )#endif#ifdef CONFIG_X86__SYSCALL_64(1, __x64_sys_write, )#else /* CONFIG_UML */__SYSCALL_64(1, sys_write, )#endif
给用户使用的:
// arch/x86/include/generated/uapi/asm/unistd_64.h#define __NR_read 0#define __NR_write 1
那生成的这两个头文件又是给谁使用的呢?看下下面这个文件:
// arch/x86/entry/syscall_64.c#define __SYSCALL_64(nr, sym, qual) [nr] = sym,asmlinkage const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {* Smells like a compiler bug -- it doesn't work* when the ) no-repeat content-box;background-size:cover;">作者
来源:http://www.yidianzixun.com/article/0ig72alA
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |
|