20169203《Linux内核原理与分析》 第六周作业
对于本周的实验部分是使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用
首先通过了解了下系统调用的有关知识
1)当用户态进程调用一个系统调用时,cpu切换到内核态并开始执行一个内核函数。
在Linux中是通过int $0x80来执行系统调用的,这条汇编指令产生向量为128的编程异常
2)传参:内核实现了很多不同的系统调用,进程必须指明需要哪个系统调用,这需要传递一个名为系统调用号的参数(使用eax寄存器)
3)系统调用也需要输入输出参数,例如:实际的值、用户态进程地址空间的变量的地址、包含指向用户态函数的指针的数据结构的地址
4)system_call是Linux中所有系统调用的入口点,每个系统调用至少有一个参数,即由eax传递的系统调用号。
下面开始做试验我选的是第24号系统调用即获取当前用户的Uid.对应的十六进制是18.
下面编写APi调用程序test.c
本程序就是通过API函数getuid()让getuid()函数来调用系统函数来达到获取用户id的目的
编写使用C代码中嵌入汇编代码的程序test1.c
首先将ebx寄存器清零,mov $0,%%ebx。
然后分别将0x18赋值给eax寄存器,表示需要调用的系统调用号,24为getuid.
执行int 0x80来执行系统调用。
之后eax寄存器保存了返回值,将它分别赋值给输出uid或gid变量。
完成整个汇编代码的系统调用。
我第一次实验时最后忘记将eax寄存器的值通过mov %%eax,%0传递给Uid导致系统调用错误,这里需要注意.
之后分别编译两个程序得出结果如下
两个程序多的结果都是1000 说明通过这两种方式运行的结果是一样的.Linux 下的系统调用是通过中断(int 0x80)来实现的。在执行 int 80 指令时,寄存器 eax 中存放的是系统调用的功能号,而传给系统调用的参数则必须按顺序放到寄存器 ebx,ecx,edx,esi,edi 中,当系统调用完成之后,返回值可以在寄存器 eax 中获得。
对于其中的/n/t是换行操作,%%eax 对于里面出现的双%,第一个%代表转译第二个百分号是对于要引用的寄存器前面要加百分号 对于"=m"asm中输出部分描述输出操作数,不同的操作数描述符之间用逗号格开,每个操作数描述符由限定字符串和C 语言变量组成。每个输出操作数的限定字符串必须包含"="表示他是一个输出操作数 m表示内存变量
对于课本的学习主要是对Linux的中断系统做了介绍,Linux中断分为两个半部:上半部(tophalf)和下半部(bottom half)。上半部的功能是"登记中断",当一个中断发生时,它进行相应地硬件读写后就把中断例程的下半部挂到该设备的下半部执行队列中去。因此,上半部执行的速度就会很快,可以服务更多的中断请求。但是,仅有"登记中断"是远远不够的,因为中断的事件可能很复杂。因此,Linux引入了一个下半部,来完成中断事件的绝大多数使命。下半部和上半部最大的不同是下半部是可中断的,而上半部是不可中断的,下半部几乎做了中断处理程序所有的事情,而且可以被新的中断打断!下半部则相对来说并不是非常紧急的,通常还是比较耗时的,因此由系统自行安排运行时机,不在中断服务上下文中执行。