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

刘文 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

本次的实验要求我们选择一个系统调用,然后参考这一周的课程使用库函数APIC代码中嵌入汇编代码两种方式来使用同一个系统调用。首先我们先再复习一下系统调用的原理和系统调用的过程。首先我们看一下课堂上孟宁老师给出的“系统调用三层皮”的原理图:


系统调用的三层皮分别指的是:APIsystem_call以及系统调用封装例程。它们各自的作用如下:

API:第一层是指Libc中定义的API,这些API封装了系统调用,使用int 0x80触发一个系统调用中断;当然,并非所有的API都使用了系统调用,如完成数学加减运算的API就没有使用系统调用;也有可能某个API使用了多个系统调用;这一层存在的价值就是为应用程序员提供易于使用的API来调用系统调用;

system_call:运行于内核态。system_call是所有系统调用在内核的入口点,在其中的开始处保护用户态程序执行上下文,结束处恢复用户态程序执行上下文,在中间根据传入的系统调用号对应的中断服务程序;

sys_xyz 系统调用封装例程:执行具体的系统调用操作,完成用户的系统调用请求;每个系统调用都对应一个封装例程。

由上面的分析可以知道,理论上要请求一个系统调用,我们既可以使用Libc提供的API,也可以直接在C中内嵌汇编代码触发0x80中断来完成。这次实验,我们就用实际的例子来演示这两种方法使用同一个系统的调用。我们选择的是比较简单的系统调用sys_write,通过查阅系统调用列表发现它对应的系统调用号是4;利用这个系统调用可以在屏幕上打印输出“hello world”;而这个系统调用函数对应的API就是printf

首先使用API来显示“hello world”,这个代码非常简单:


然后对其进行编译,之后运行,结果如下:


接着我们使用第二种方法,也就是使用C代码中嵌入汇编的方法进行打印。代码如下:


代码中将字符串msg和字符串长度len作为输入,并通过系统调用号4调用了系统调用函数sys_write,然后用int $0x80触发系统调用中断即可。我们对这个程序进行编译并运行,结果显示如下:


总结:

   即便是最简单的程序,也难免要用到诸如输入、输出以及退出等操作,而要进行这些操作则需要调用操作系统所提供的服务,也就是系统调用。Linux 下的系统调用是通过中断(int 0x80)来实现的。在执行 int 0x80 指令时,寄存器 eax 中存放的是系统调用的功能号,而传给系统调用的参数则必须按顺序放到寄存器 ebxecxedxesiedi 中,当系统调用完成之后,返回值可以在寄存器 eax 中获得。

   所有的系统调用功能号都可以在文件 /usr/include/bits/syscall.h 中找到,为了便于使用,它们是用 SYS_<name> 这样的宏来定义的,如 SYS_writeSYS_exit 等。例如,经常用到的 write 函数是如下定义的:

ssize_t write(int fd, const void *buf, size_t count);

该函数的功能最终是通过 SYS_write 这一系统调用来实现的。根据上面的约定,参数 fbbuf count 分别存在寄存器 ebxecx edx 中,而系统调用号 SYS_write 则放在寄存器 eax 中,当 int 0x80 指令执行完毕后,返回值可以从寄存器 eax 中获得。

   当一个系统调用所需的参数个数大于 5 时,执行int 0x80 指令时仍需将系统调用功能号保存在寄存器 eax 中,所不同的只是全部参数应该依次放在一块连续的内存区域里,同时在寄存器 ebx 中保存指向该内存区域的指针。系统调用完成之后,返回值仍将保存在寄存器 eax 中。

   由于只是需要一块连续的内存区域来保存系统调用的参数,因此完全可以像普通的函数调用一样使用栈(stack)来传递系统调用所需的参数。但要注意一点,Linux 采用的是 C 语言的调用模式,这就意味着所有参数必须以相反的顺序进栈,即最后一个参数先入栈,而第一个参数则最后入栈。如果采用栈来传递系统调用所需的参数,在执行int 0x80 指令时还应该将栈指针的当前值复制到寄存器 ebx中。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值