一、实验要求:
1.选择一个系统调用(13号系统调用time除外),系统调用列表参见http://codelab.shiyanlou.com/xref/linux-3.18.6/arch/x86/syscalls/syscall_32.tbl
2.参考视频中的方式使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用,推荐在实验楼Linux虚拟机环境下完成实验。
二、实验过程:
首先,选择使用的系统调用:我选择的是64号 getppid。网上找到关于该函数的使用与说明:getppid(取得父进程的进程识别码)
表头文件 #include<unistd.h>
定义函数 pid_t getppid(void);
函数说明 getppid()用来取得目前进程的父进程识别码。
返回值 目前进程的父进程识别码。
确定好函数后,写下相关的代码:
编译后执行结果如下:
接着将函数调用的部分改为嵌入式汇编语句:
最后执行嵌入式汇编文件,查看执行结果:
三、实验结果分析
首先附上完整的代码:
c语言代码:
#include<unistd.h>
void main()
{
printf("My parent pid =%d
",getppid());
}
嵌入式汇编代码:
include <unistd.h>
int main()
{
int a=0;
asm volatile(
"mov $0,%%ebx
"
"mov $0x40,%%eax
"
"int $0x80
"
"mov %%eax,%0
"
:"=m"(a)
);
// a = getppid();
printf("the number of pid is:%d
",a);
}
分析一下这段汇编代码,首先将ebx置零,汇编调用时的初始化做法,然后把相应函数的终端号写入eax寄存器。可能有人会怀疑,上文中写到了getppid()函数的中断号是64,为何在这里写的是40,这是因为这里写出的是16进制的64,由于寄存器的大小而决定的需要写16进制的数字。两个16进制的数字刚好一字节。接着的int $0x80 为AT&T语法的中断指令,通过中断的调用,将把调用号装入eax寄存器实现,然后实现相应的值的个改变的过程。将数值由EAX给到a中。这是整个汇编语句执行的过程。
可能会有同学怀疑我的实验是不是做的有问题,为什么汇编的结果和C语言出来的结果完全不同。这就涉及到这个函数的功能问题了。getppid()是用来取得目前进程的父进程识别码,每个程序在执行的时候分配的进程是不同的,所以其父进程自然也不同,所以输出两个不同的数字是十分正常的。
结合书中所学和本周的视频和实验,我在这里简单说说我对中断的理解。中断是操作系统当中很重要的一个工作方式,首先所有程序和硬件设备都需要占用CPU,而且有的程序需要占用大量的CPU时间,但是CPU该如何分配工作呢,举一个简单的例子,比如我现在打字用的键盘,这个硬件设备在不使用时是不需要占用CPU的,但是当我敲击键盘的时候我就需要我打的字能够马上出现,因此它不可能一直占有CPU,而是在我打字的时候向CPU发送中断,这时CPU会响应它的请求,在我们看来键盘打字马上就会有反应就会认为CPU一直在等着键盘,有东西就输出,但其实CPU很忙的,它不会等你给它东西,它会忙自己的事,当你准备好的时候,向它发送一个中断,它响应你的要求而已。不过这个过程很快我们根本察觉不到。
那么一个中断来临时究竟经过怎样的工作呢?当一个中断来临时应该先设置断点,保存当前的中断现场,然后按照中断表去找到相应的中断程序进行执行,然后再执行完当前的中断程序之后返回之前的断点,回复中断现场继续执行程序,这是一个完整的中断执行的过程。那么当执行中断程序的时候会不会还能进行中断呢,答案是可以的,但是并不是一定会打断当前的程序,中断也是有等级的,低级的中断自然无法打断高级的中断程序。但是当比其中断等级高的程序来到时自然还是要响应中断的,这就是中断嵌套。但是操作系统并不会由于中断过多而导致出现问题,只要在每次中断来临时保存断点,然后执行中断后进行恢复就好了,这里的记录断点和恢复断点的工作当然就是通过压栈和弹栈来实现的。这就是我对中断的简单理解。