系统调用实验

原创作品转载请注明出处 

《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000


系统调用的意义:

操作系统为用户态进程与硬件设备进行交互提供了一组接口——系统调用


1.把用户从底层的硬件编程中解放出来

2.极大的提高了系统的安全性

3.使用户程序具有可移植性

API和系统调用的关系:

(很多人认为这是同一个概念,其实不然)

API只是一个函数定义系统调用通过软中断向内核发出一个明确的请求(unix/linux系统是这样,windows内核不开源但也是软中断),不是每个API都对应一个特定的系统调用

比如:c标准库的一些数学函数abs(),div()... ...

一个单独的API可能调用几个系统调用

比如:
printf()调用 fprintf(stdout...)
文件的操作也调用 fprintf(pFile..)
又比如:
scanf()调用 fscanf(stdin)
malloc、calloc、relloc...
这样都是很常用的


当用户态进程调用一个系统调用时,CPU切换到内核态并开始执行一个内核函数。
在Linux中是通过执行int $0x80来执行系统调用的,这条汇编指令产生向量为128的编程异常(陷阱),学过汇编都知道中断后会跳转到中断向量表去执行中断处理程序,从而完成系统调用。


内核实现了很多不同的系统调用,进程必须指明需要哪个系统调用,这需要传递一个名为系统调用号的参数
x86下 使用eax寄存器
所有系统调用的编号定义在 arch/XXX/include/asm/unistd.h中:

#define __NR_restart_syscall          (__NR_SYSCALL_BASE+  0)
#define __NR_exit               (__NR_SYSCALL_BASE+  1)
#define __NR_fork               (__NR_SYSCALL_BASE+  2)
#define __NR_read               (__NR_SYSCALL_BASE+  3)
#define __NR_write               (__NR_SYSCALL_BASE+  4)
#define __NR_open               (__NR_SYSCALL_BASE+  5)
.................
#define __NR_pipe2               (__NR_SYSCALL_BASE+359)
#define __NR_inotify_init1          (__NR_SYSCALL_BASE+360)
#define __NR_preadv               (__NR_SYSCALL_BASE+361)
#define __NR_pwritev               (__NR_SYSCALL_BASE+362)
#define __NR_rt_tgsigqueueinfo          (__NR_SYSCALL_BASE+363)
#define __NR_perf_event_open          (__NR_SYSCALL_BASE+364)
#define __NR_recvmmsg               (__NR_SYSCALL_BASE+365)


system_call是linux中所有系统调用的入口点,每个系统调用至少有一个参数即由eax传递的系统调用号。一个应用程序调用fork()封装例程,那么在执行int $0x80之前就把eax寄存器的值置为2(即__NR_fork)。这个寄存器的设置是libc库中的封装例程进行的,因此用户一般不关心系统调用号,进入sys_call之后,立即将eax的值压入内核堆栈。

寄存器传递参数具有如下限制:

1、每个参数的长度不能超过寄存器的长度,即32位
2、在系统调用号(eax)之外,参数的个数不能超过6个(ebx,ecx,edx,esi,edi,ebp)
3、如果超过6个就将某个寄存器作为指针传递地址来访问多个内存空间



内嵌汇编含义:

mov $0,%ebx	;对应time(NULL)的第一个参数,传0x00
mov $0xd,%eax	;传递系统调用号(#define __NR_time 13) 
int $0x80	;中断
mov %eax,%0	;将返回值赋值给%0对应的出口参数即:tt



Linux中,在用户态和内核态运行的进程使用的栈是不同的,分别叫做用户栈和内核栈,两者各自负责相应特权级别状态下的函数调用。当进行系统调用时,进程不仅要从用户态切换到内核态,同时也要完成栈切换,这样处于内核态的系统调用才能在内核栈上完成调用。系统调用返回时,还要切换回用户栈,继续完成用户态下的函数调用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值