2015年(6)
分类: LINUX
2015-03-28 17:44:42
4 i386 write sys_write
来完成实验。
首先说一下,这个其实就是我们最常用的printf()中引起的系统中断。
其工作原理如下:
1,用户程序写了一个代码中包含printf()函数,该函数被运行。
2,函数将调用(这个词的准确性有待商榷)C库中的printf()。
3,C库的printf()中有一段代码引起中断。
4,当用户态进程调用一个系统调用时,CPU将切换到内核态并开始执行一个内核函数。
插入一点补充知识:
(1),Linux的中断是int $0x80引起的,int是interrupt的意思,初学者容易混淆成C语言中的int。
(2),大部分函数调用都要传递参数,系统调用也不例外。在使用int之前,用户必须准确告诉系统要调用哪个函数。(函数表见链接:)。如何告诉系统呢,答案是使用eax寄存器。
(3),但是,除了告诉系统调用函数要调用哪个系统调用之外,很多时候还需要传入其他的信息。这时候可以使用其他的寄存器(ebx,ecx,edx,esi,edi等等)。但是不能超过六个。值得一提的是,在汇编中有一种重要的思想是:一切内容皆地址。假设你要做一个printf("Hello Mengning!");函数实际会做的是把这段字符压到堆栈里,并且记住开始内存的地址,把该地址传递到系统调用程序里面去。
5,中断发生后,系统首先会派system_call过来接驾,再由system_call来确定要调用哪一个系统函数,在本次作业中,system_call将会调用sys_write()。(补充:所有的系统函数都会有sys_开头)
6,syswrite()调用完成后,CPU将返回到system_call执行代码,而system_call将执行ret_from_sys_call,然后执行iret,返回到用户态。
其过程图解如下:
好,原理解释完了后,就到实际操作部分了。
首先用C代码写了一段简单的小程序:
程序运行结果如下:
下面使用汇编代码实现printf();
点击(此处)折叠或打开
- char* str = "Hello Mengning!\n";
- void print()
- {
- asm(
- "movl $13, %%edx \n\t"
- "movl %0, %%ecx \n\t"
- "movl $0, %%ebx \n\t"
- "movl $4, %%eax \n\t"
- "int $0x80 \n\t"
- ::"r" (str):"edx","ecx", "ebx"
- );
- }
- int main()
- {
- print();
- return 0;
- }
运行结果如下图所示:
一切正常,接下来我们分析代码(具体分析见图):
谢谢你批改我的作业!
后话:
终于受不了新浪博客的代码不友好环境~终于受不了CSDN的审查制度,昂首阔步迈进ChinaUnix的世界~
这次的作业我一开始并没有信心完成,后来参阅了许多技术博客,还有在MOOC讨论区网友们的热心帮助下,终于明白了系统调用的函数传递问题,所以才有今天的作业,谢谢各位。希望与各位互勉。