Chinaunix首页 | 论坛 | 博客
  • 博客访问: 330351
  • 博文数量: 69
  • 博客积分: 2090
  • 博客等级: 大尉
  • 技术积分: 708
  • 用 户 组: 普通用户
  • 注册时间: 2008-09-23 09:31
文章分类

全部博文(69)

文章存档

2012年(1)

2011年(4)

2010年(48)

2009年(14)

2008年(2)

我的朋友

分类: LINUX

2010-05-19 15:21:39

1.         系统调用和函数库的关系。

系统调用通过软中断int 0x80从用户态进入内核态。

函数库中的某些函数调用了系统调用。

函数库中的函数可以没有调用系统调用,也可以调用多个系统调用。

编程人员可以通过函数库调用系统调用。

高级编程也可以直接采用int 0x80进入系统调用,而不必通过函数库作为中介。

如果是在核心编程,也可以通过int 0x80进入系统调用,此时不能使用函数库。因为函数库中的函数是内核访问不到的。

2.         从用户调用库函数到系统调用执行的流程。

1)        假设用户调用ssize_t write (int fields, cont void *buff, size_t nbytes);库函数。

2)        库函数会执行int 0x80中断。因为中断使得进程从用户态进入内核态,所以参数通过寄存器传送。

3)        0x80中断对应的中断例程被称为system call handler。其工作是:

                         i.              存储大多数寄存器到内核堆栈中。这是汇编代码写的。

                       ii.              执行真正的系统调用函数――system call service routine。这是C代码。

                      iii.              通过ret_from_sys_call ()返回,回到用户态的库函数。这是汇编代码。

3.         前面2.2)提到的的参数和返回值传输方法。

eax存放系统调用序号。因为所有系统调用都是通过0x80中断完成的,必须将系统调用序号作为传入以区别多个系统调用。

ebxecxedxesiedi分别传送五个真正的参数。若多余5个参数,则将参数存放在内存中,而让某个寄存器存放指向这个内存地址。另外因为寄存器是32字节,所以参数不能超过4bytes

2.3).i中,这些寄存器中包含的参数又被存储到内核堆栈中。之后的system call service roution可以像一般C函数那样使用堆栈来读取参数了。

返回值是通过eax传送的。

4.         前面2.3)中的system call handlerLinux中是system_call()函数,由汇编写成。

iii之间以及iiiii之间,system_call判断PT_TRACESYS标志是否设置。如果设置,则system_call会两次调用system_trace,一次在就要执行system call service routine之前,另一次是在刚刚离开system call service routine之后。

5.         前面2.3).ii中,system_call会根据不同的放在ax的系统调用序号来调用不同的system call service routineLinux使用了一个系统调用表,其中按序号保存了所有系统调用服务例程(system call service routine)的起始地址。system_call中的语句

call *system_call_table (0, %eax, 4)

指明每个表项4bytes,内核通过(系统调用表头 系统调用号 × 4)的方法得到相应系统调用服务例程的起始地址。然后开始执行。

6.         在内核初始化期间, trap_init()来初始化中断描述表(Interrupt Description TableIDT),trap_init通过调用set_system_gate (0x80, &system_call)添加了0x80中断对应system_call处理例程。

7.         为了方便执行2.2) Linux提供了一组预处理宏指令。它们可以用在程序中,也可以用在内核中。这些宏指令取一定的参数,然后扩展为2.2)的语句。

  这些宏指令具有类似下面的名称格式:

  _syscallN(parameters)

其中N 是系统调用所需的参数数目,而parameters则用一组参数代替。每个宏都包括2+N×2个参数。第一个参数表明返回类型,第二个表示函数名,其余参 数两个一组。每组第一个表示真正参数类型,第二个是真正参数名称。 Linux一共定义了6个不同的_syscallN()宏指令,从_syscall0()、_syscall1()直到_syscall5()。 一旦_syscallN()宏指令用特定系统调用的相应参数进行了扩展,得到的结果是一个与系统调用同名的函数,它可以在用户程序中或内核中执行这一系统 调用。

阅读(852) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~