Linux内核分析(四)实现一个系统调用
来源:互联网 发布:知乎个性域名修改 编辑:程序博客网 时间:2024/05/19 12:13
原创作品转载请注明出处
《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
********************************************************************************************
本周实验主要内容是使用两种方式实现一种系统调用,我选择了实现getpid系统调用。
实验过程:
1.方法一,直接调用库函数API
getpid.c的源代码如下:
#include <stdio.h>#include <unistd.h>void main(){ pid_t myPid; myPid=getpid(); printf("the PID of current process is %u\n",myPid);}
输入如下命令编译:
gcc getpid.c -o AppGetPID
运性./AppGetPID,查看结果如下:
2.方法二,使用汇编语句进行系统调用
getpid_asm.c的源代码如下:
#include <stdio.h>#include <unistd.h>void main(){ pid_t tt; asm volatile ( "movl $0x14,%%eax\n\t" "int $0x80\n\t" "movl %%eax,%0\n\t" :"=m"(tt) ); printf("the PID of current process is %u\n",tt);}
输入如下命令编译:
gcc getpid_asm.c -o AppGetPID_asm
运行./AppGetPID_asm结果如下:
分析:
如果是使用系统调用,函数getpid()中已经将系统调用封装好,执行int 0x80语句后即进入内核态中的System_call()。System_call()中会执行中断服务程序sys_getpid(),中断服务完成后如没有进程间调度,则执行iret返回用户态继续执行,如有进程间调度,则执行进程间调度。
如果是直接使用汇编指令,则执行int 0x80语句后,即会进入System_call()中执行中断服务程序sys_getpid(),后续的执行顺序和上面相同。
(1)getpid()是一个POSIX标准的API,用于用户程序从用户态进入到内核态,在内核态读取当前进程的(tack_struct)的Pid,然后返回给用户态的程序。
(2)getpid()函数在/usr/include/unistd.h里面声明。你可以试着找到这个声明。
(3)getpid()函数在glibc函数库里面实现。gcc 编译程序时,会到glibc函数库里面寻找getpid()的实现代码,然后编译。
(1)getpid()是通过软中断的方式使程序进入内核态的。getpid()编译成汇编代码时,里面会有条这样的指令:int 0x80,当执行到这条指令时,getpid()的工作暂停,内核开始工作。
(2)getpid()的功能是返回当前进程的ID,它本身是不能完成的,必须请求操作系统服务,让操作系统把当前进程的ID告诉给getpid().操作系统能够提供很多服务,那么,getpid()就得告诉操作系统提供什么服务,所以,getpid()给内核一个参数__NR_getpid(系统调用号),把__NR_getpid这个服务号(系统调用号),放在了一个寄存器eax里面。内核就从eax这个寄存器里面取出值,就明白了。
ebx --- 置第一个参数
ecx --- 置第二个参数
edx --- 置第三个参数
esi --- 置第四个参数
edi --- 置第五个参数
ebp --- 置第六个参数 (系统调用最大参数个数为6)]
(3)getpid()自然从内核得到当前进程的ID号,因为内核已经把ID号放在了getpid()的堆栈里面。
int 0x80 ; 进入软中断,cpu进入高级特权模式
CPU到地址(中断描述符表IDT地址+ 0x80),取出指令并执行。执行结果,跳到标号system_call处执行;
system_call:
保存现场;
读取exa寄存器的值__NR_getpid;
读取数组 sys_call_table[__NR_getpid]的值;这个值就是__NR_getpid()服务程序的地址;
跳到__NR_getpid()服务程序的地址,执行。即,执行内核函数,sys_getpid();
[sys_getpid()读取用户进程数据结构task_struct的成员变量pid,把用户进程的pid放在了eax寄存器中。]
把eax寄存器的值复制到用户态”eax寄存器栈单元“里面。
恢复现场,返回到用户态。
最后,getpid()在eax寄存器栈单元里面取出pid,给用户程序,系统调用全部结束。
- Linux内核分析(四)实现一个系统调用
- Linux内核分析四:系统调用
- linux内核--系统调用(四)
- Linux内核分析(四)系统调用,用户态及内核态
- Linux内核分析(四):系统调用,用户态及内核态
- Linux内核分析:实验四--使用嵌入汇编系统调用
- Linux内核(四)系统调用
- linux内核分析---系统调用实现代码分析(By e4gle)
- linux内核分析---系统调用实现代码分析
- linux内核分析---系统调用实现代码分析
- 《Linux内核分析》(四)——扒开系统调用的三层皮(上)
- linux内核文件IO的系统调用实现分析
- linux内核文件IO的系统调用实现分析(open)
- Linux系统调用详解(实现机制分析)--linux内核剖析(六)
- Linux内核学习之四--进程、进程调度、系统调用、proc文件系统和内核异常分析
- linux内核剖析---Linux系统调用详解(实现机制分析)
- Linux内核分析(五):系统调用深入分析
- linux 2.6.11内核文件IO的系统调用实现分析(read,write)(转载)
- Pycharm project share to Github
- 栈的压入、弹出序列
- React学习之进阶ref的必要性(十三)
- GCC主要数据结构之spec_list
- 随时随地退出安卓程序
- Linux内核分析(四)实现一个系统调用
- 时空航道 网络流 最小割 动态规划dp
- POJ 3734 (矩阵快速幂+染色问题)
- strtok,strtok_s
- ButterKnife框架原理
- DBSCAN算法的Python实现
- SQL中的char、varchar、nvarchar
- Oracle数据库导入导出命令总结
- go操作操作mysql(增删改查)