Linux内核4.14.255中sys_mount等sys_前缀函数的定义问询
Linux 4.14.255内核中sys_前缀函数的定义机制
在4.14.255版本内核里,sys_前缀的系统调用函数并不是用你猜想的简单宏直接定义的,而是靠一套宏包装+系统调用表注册的机制实现的,下面拆解具体细节:
1. 核心宏:SYSCALL_DEFINE*系列
sys_xxx函数的定义是通过SYSCALL_DEFINE*宏展开生成的,这个宏族定义在include/linux/syscalls.h中。
比如你提到的sys_unlink,实际代码里是用SYSCALL_DEFINE1(unlink, const char __user *, pathname)来定义的,这个宏会被预处理器展开为:
asmlinkage long sys_unlink(const char __user *pathname) { // 函数实现逻辑 }
其中asmlinkage是内核属性,强制函数从栈中获取参数——这是系统调用的标准要求,因为用户态和内核态的参数传递规则不同。
2. 为什么直接搜sys_xxx找不到定义?
因为sys_xxx是宏展开后的产物,你直接用文本搜索sys_unlink(大概率找不到,得搜SYSCALL_DEFINE1(unlink才能定位到实际实现:
sys_mount的实现在fs/namespace.c里,用SYSCALL_DEFINE5(mount, ...)定义;sys_unlink的实现在fs/namei.c里,用SYSCALL_DEFINE1(unlink, ...)定义。
3. 系统调用表的关联
定义好的sys_xxx函数需要注册到系统调用表,才能被内核的系统调用入口逻辑找到。不同架构的表位置不一样:
- x86_64:
arch/x86/entry/syscalls/syscall_64.tbl,每行格式是调用号 ABI 函数名,比如87 common unlink sys_unlink; - x86_32:
arch/x86/entry/syscalls/syscall_32.tbl; - ARM:
arch/arm/kernel/syscall_table.S。
看宏的具体展开逻辑
如果你想深入看SYSCALL_DEFINE*是怎么生成sys_xxx的,打开include/linux/syscalls.h,核心展开逻辑是这样的(简化版):
#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__) #define SYSCALL_DEFINEx(x, sname, ...) \ asmlinkage long sys##sname(__SC_DECL##x(__VA_ARGS__)) \ __attribute__((alias(__stringify(SyS##sname)))); \ static inline long SYSC##sname(__SC_DECL##x(__VA_ARGS__)); \ asmlinkage long SyS##sname(__SC_DECL##x(__VA_ARGS__)) \ { \ return SYSC##sname(__SC_ARGS##x(__VA_ARGS__)); \ } \ static inline long SYSC##sname(__SC_DECL##x(__VA_ARGS__))
这个宏会生成sys_xxx的函数声明,并把它和实际实现的SyS_xxx函数做别名关联,最终完成系统调用的定义。
内容的提问来源于stack exchange,提问作者Yanel
相关产品推荐
相关产品推荐

