使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

来源:互联网 发布:儿童认字软件 编辑:程序博客网 时间:2024/05/29 16:04

刘森林
原创作品转载请注明出处《Linux内核分析》MOOC课程

实验目的

  • 使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用,理解系统调用的工作机制。

实验过程

这一次的实验使用的是我的Linux虚拟机Ubuntu 14.04.2 LTS 64bit
这里写图片描述

  • 实验截图
    系统调用号

time的系统调用号为13,获取当前的系统时间。

  • 编写两段代码,分别使用库函数API和C代码中嵌入汇编代码,源码如下:
  • time.c(使用库函数API方式)
#include<stdio.h>#include<time.h>int main(){        time_t tt;        struct tm *ptr;        tt=time(NULL);        ptr=localtime(&tt);        printf("second:%d\n",ptr->tm_sec);        printf("minute:%d\n",ptr->tm_min);        printf("hour:%d\n",ptr->tm_hour);        printf("mday:%d\n",ptr->tm_mday);        printf("month:%d\n",ptr->tm_mon+1);        printf("year:%d\n",ptr->tm_year+1900);        return 0;}                                                                                                                                                  

time-asm.c(使用C代码中嵌入汇编代码方式):

#include<stdio.h>#include<time.h>int main(){        time_t tt;        struct tm *ptr;asm volatile(                "mov $0,%%ebx\n\t"//将ebx寄存器清零                "mov $0xd,%%eax\n\t"//time的系统调用号为0x13,赋值给eax                "int $0x80\n\t"//通过0x80中断向量,执行系统调用                "mov %%eax,%0\n\t"//                :"=m"(tt)//输出tt        );        ptr=localtime(&tt);        printf("second:%d\n",ptr->tm_sec);        printf("minute:%d\n",ptr->tm_min);        printf("hour:%d\n",ptr->tm_hour);        printf("mday:%d\n",ptr->tm_mday);        printf("month:%d\n",ptr->tm_mon+1);        printf("year:%d\n",ptr->tm_year+1900);        return 0;}  
  • 运行结果如下
  • 这里写图片描述

Linux的系统调用机制分析

整个系统调用的过程可以总结如下:

1.执行用户程序(如:time)

2. 取得系统调用号并执行int $0x80产生中断。

3.进行地址空间的转换和堆栈的切换,执行SAVE_ALL。(进行内核模式)

4. 进行中断处理,根据系统调用表调用内核函数。

5. 执行内核函数。

6. 执行RESTORE_ALL并返回用户模式

在i386体系中,Linux的系统调用是通过调用软中断指令“int 0x80”使进程从用户态进入内核态的,这个过程也叫做“trap”。当系统调用接口调用软中断指令“int 0x80”时,这个指令会发生一个中断向量码为128的中断请求,并在中断响应过程中将进程由用户态切换为内核态。

因为Linux只允许系统调用接口使用128这一个软中断向量,这也就意味着所有的系统调用接口必须共享这一个中断通道,并在同一个中断服务例程中调用不同的内核服务例程,所以,系统调用接口除了要引发“int 0x80”软中断之外,为了进人内核后能调用不同的内核服务例程,还要提供识别内核服务例程的参数,这个参数叫做“系统调用号”。也就是说,所有可为进程提供服务的内核服务例程都应具有一个唯一的系统调用号。当然,系统调用接口还应为内核服务例程准各必要的参数。

两种方式调用的分析

用API进行系统调用,实际是在各个API系统调用函数中封装了系统调用接口,用户使用API系统调用函数时,则跳转向该接口,从而进入内核态;而直接用嵌入式汇编进行系统调用则是直接用汇编代码启动中断向量,从而进入内核态。

0 0