面试题:谈谈对系统调用的理解
uc系统调用函数:open read write lseek socket bind listen accept recv fork …
1.系统调用的作用
保证用户空间以安全的方式访问内核中的函数
2.系统调用是如何实现的
当产生系统调用时
用户空间受限会向特定寄存器中填入一个编号
然后执行一个特殊的指令,该指令的执行会导致内核收到一个软中断异常
软中断异常后,会跳转到异常向量表执行软中断处理代码
软中断处理代码根据填入寄存器的编号
在内核中找到对应的函数,并执行该函数
执行完毕后,将执行结果原路返回到用户空间去
编号:系统调用号 arch/arm/include/asm/unistd.h
特定寄存器:以ARM为例 使用R7
特殊的指令:ARM,swi指令 X86,INT指令
软中断异常处理代码:entry-common.S
ENTRY(vector_swi)
Get the system call number. //保存到r7
//获取系统调用表地址
adr tbl,sys_call_table @load syscall table pointer
//根据系统调用号调用系统调用表中的函数
sys_call_table(r7)
系统调用表:call.S
3.在内核中增加一个新的系统调用函数
cd ~/linux/kernel //切换到内核源码目录
vi arch/arm/kernel/sys_arm.c
asmlinkage int sys_add(int x,int y){
printk("<2>" "enter %s\n",__func__);
return x+y;
}
vi arch/arm/kernel/calls.S //修改系统调用表
#line 390 CALL(sys_add)
vi arch/arm/include/asm/unistd.h //增加新的系统调用号
#line 407 #define __NR_add (__NR_SYSCALL_BASE+378)
make uImage //重新编译内核
cp uImage /tftpboot //使用内核
重启开发板
4. 在用户空间调用
vi test.c
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
int main(void)
{
int res = 0;
res = syscall(378,100,200);
printf("res=%d\n",res);
return 0;
}
arm-cortex_a9-linux-gnueabi-gcc test.c -o test //编译程序
cp test ../../rootfs/ //复制到开发板使用的nfs文件系统中
开发板上执行 ./test
原理:
open("a.text",O_RDWR); 等价于 syscall(5,"a.txt",O_RDWR);
read(fd,buf,len); 等价于 syscall(3,fd,buf,len);