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

林万喜 原创作品 转载请注明出处  USTC  2015.3

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

微笑微笑微笑微笑微笑微笑微笑微笑微笑微笑微笑微笑微笑微笑微笑微笑微笑微笑微笑微笑微笑微笑微笑微笑微笑微笑



  1. Linux系统调用是Linux内核为我们提供的一些访问硬件的接口,为我们使用和访问硬件提供了方便。如我们平常使用的rm,mkdir,touch等处理硬盘上文件的命令,其实现过程中都要用到对应的系统调用。但是作为普通用户的我们运行的程序只能运行在用户空间,并不能直接调用处于系统内核态的系统调用,所以系统给我们封装了对应的API[Application Program Interface]来让用户程序可以使用系统调用。下面简单说明系统调用实现过程:

    • 应用程序调用相关API
    • API将对应的系统调用号存入eax,如果需要传参,还要在其他寄存器中传入相关参数,然后调用int $0x80触发中断进入内核中的中断处理函数
    • 内核中的中断处理程序根据系统调用号调用对应的系统调用
    • 系统完成相应功能,将返回值存入eax,返回到中断处理函数
    • [根据视频中的描述,这里是一个进程调度时机,所以可能会发生进程调度]
    • 中断处理函数返回到API中
    • API将eax,即系统调用的返回值返回给应用程序


使用库函数调用 API。

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <unistd.h>  
  3.   
  4. int main()  
  5. {  
  6.     pid_t fpid;//fpid表示 fork 函数返回的值  
  7.     fpid = fork();  
  8.       
  9.     if(fpid < 0)  
  10.         printf("error in fork!\n");  
  11.     else if (fpid == 0)  
  12.         printf("I am the child process,my process id is %d\n",getpid());  
  13.     else   
  14.         printf("I am the parent process, my process id is %d\n",getpid());  
  15.   
  16.     return 0;  
  17.   
  18. }  

调用 fork()后,返回一个 fpid 的值,根据 fpid 的值来判断是父进程还是子进程,或者是库函数 API调用错误。

下面是 C 语言中嵌入汇编代码调用库函数 fork()函数

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <string.h>  
  4. #include <unistd.h>  
  5. pid_t _fork_asm_()  
  6. {  
  7.     pid_t tt;  
  8.     asm volatile(  
  9.             "mov $0x2, %%eax\n\t"  
  10.             "int $0x80\n\t"  
  11.             "mov %%eax, %0\n\t"  
  12.             :"=m" (tt)  
  13.             );  
  14.     return tt;  
  15. }  
  16. int main(int argc, const char *argv[])  
  17. {  
  18.     pid_t tt;  
  19.     tt = _fork_asm_();  
  20.     if (tt == 0)  
  21.     {  
  22.         printf("I am the child process,my pid is %d\n",getpid());  
  23.     }  
  24.     else  
  25.     {  
  26.         printf("I am the parent process,my pid is %d\n",getpid());  
  27.     }  
  28.     return 0;  
  29. }  
由于没有参数传入,在嵌入汇编代码时,直接调用
[cpp]  view plain copy
  1. mov $0x2, %%eax  

2	i386	fork			sys_fork			stub32_fork
由于 fork 函数在 i386机器中为2号系统调用,所有直接调用2号进程。

[cpp]  view plain copy
  1. int $0x80  
系统调用函数结束会产生80号系统中断来还原系统调用之前的现场,程序继续往下执行。

[cpp]  view plain copy
  1. mov %%eax, %0  
返回值存储到 eax 中。

执行结果如图











总结:


参数传递过程:可以看出来这个实验只需要使用eax传递系统调用编号,然后使用eax接受返回值,最后进行写入内存。

系统调用分析:

  1. 用户设置参数,调用中断,保护现场。
  2. 中断向量表,进行系统调用,进入内核态
  3. 内核处理,返回参数
  4. 返回参数,恢复现场。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

vinci587

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

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

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

打赏作者

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

抵扣说明:

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

余额充值