Linux 中 x86 系统调用的实现原理

以 Linux 2.6.36 为例

1. 将中断号与系统调用函数绑定

系统调用函数 (system_call) 是系统调用的总入口,将其与中断号 0x80绑定。

arch/x86/kernel/traps.c

#define SYSCALL_VECTOR 0x80
set_system_trap_gate(SYSCALL_VECTOR, &system_call);

2. 系统调用函数的实现

该中断,由于需要从用户态栈切换到内核态栈,需要栈切换,因此CPU会将用户态的栈相关的参数(oldss, oldesp)压栈,再调用system_call。

在 system_call 内部:

  1. 将所有寄存器压入内核栈,其中 ebx, ecx, edx 存放程序的参数
  2. 以 eax 为偏移量,在 sys_call_table 中找到指定的系统调用的地址,其中sys_call_table 定义了所有的系统函数的地址。

从以上可以看出参数传递的方式:

  1. 从用户态到内核态通过寄存器传递
  2. 内核函数通过栈读取,即通过栈传递

arch/x86/kernel/entry_32.S

.macro SAVE_ALL
	cld
	PUSH_GS
	pushl %fs
	pushl %es
	pushl %ds
	pushl %eax
	pushl %ebp
	pushl %edi
	pushl %esi
	pushl %edx
	pushl %ecx
	pushl %ebx
	movl $(__USER_DS), %edx
	movl %edx, %ds
	movl %edx, %es
	movl $(__KERNEL_PERCPU), %edx
	movl %edx, %fs
	SET_KERNEL_GS %edx
.endm

ENTRY(system_call)
	pushl %eax			# save orig_eax
	SAVE_ALL
	GET_THREAD_INFO(%ebp)		# system call tracing in operation / emulation
	testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
	jnz syscall_trace_entry
	cmpl $(nr_syscalls), %eax
	jae syscall_badsys
syscall_call:
	call *sys_call_table(,%eax,4)
	movl %eax,PT_EAX(%esp)		# store the return value

arch/x86/kernel/syscall_table_32.S

ENTRY(sys_call_table)
	.long sys_restart_syscall	/* 0 - old "setup()" system call, used for restarting */
	.long sys_exit
	.long ptregs_fork
	.long sys_read
	.long sys_write
	.long sys_open		/* 5 */
	.long sys_close
	...
	.long sys_rt_tgsigqueueinfo	/* 335 */
	.long sys_perf_event_open
	.long sys_recvmmsg
	.long sys_fanotify_init
	.long sys_fanotify_mark
	.long sys_prlimit64		/* 340 */

3. 系统函数原型

以 read 函数为例,系统调用函数原型前面都有限定符 asmlinkage 修饰,这个修饰符的作用是限定函数的参数不通过寄存器传递,即通过栈传递。

结合前面可以看出,系统调用函数都是在内核栈上读取函数的参数。

include/linux/syscalls.h

asmlinkage long sys_read(unsigned int fd, char __user *buf, size_t count);

arch/x86/include/asm/linkage.h

#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lylhw13_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值