林万喜 原创作品 转载请注明出处 USTC 2015.3
《Linux内核分析》MOOC课程:在线课程链接http://mooc.study.163.com/course/USTC-1000029000
-
Linux系统调用是Linux内核为我们提供的一些访问硬件的接口,为我们使用和访问硬件提供了方便。如我们平常使用的rm,mkdir,touch等处理硬盘上文件的命令,其实现过程中都要用到对应的系统调用。但是作为普通用户的我们运行的程序只能运行在用户空间,并不能直接调用处于系统内核态的系统调用,所以系统给我们封装了对应的API[Application Program Interface]来让用户程序可以使用系统调用。下面简单说明系统调用实现过程:
-
- 应用程序调用相关API
- API将对应的系统调用号存入eax,如果需要传参,还要在其他寄存器中传入相关参数,然后调用int $0x80触发中断进入内核中的中断处理函数
- 内核中的中断处理程序根据系统调用号调用对应的系统调用
- 系统完成相应功能,将返回值存入eax,返回到中断处理函数
- [根据视频中的描述,这里是一个进程调度时机,所以可能会发生进程调度]
- 中断处理函数返回到API中
- API将eax,即系统调用的返回值返回给应用程序
使用库函数调用 API。
- #include <stdio.h>
- #include <unistd.h>
- int main()
- {
- pid_t fpid;//fpid表示 fork 函数返回的值
- fpid = fork();
- if(fpid < 0)
- printf("error in fork!\n");
- else if (fpid == 0)
- printf("I am the child process,my process id is %d\n",getpid());
- else
- printf("I am the parent process, my process id is %d\n",getpid());
- return 0;
- }
调用 fork()后,返回一个 fpid 的值,根据 fpid 的值来判断是父进程还是子进程,或者是库函数 API调用错误。
下面是 C 语言中嵌入汇编代码调用库函数 fork()函数
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- pid_t _fork_asm_()
- {
- pid_t tt;
- asm volatile(
- "mov $0x2, %%eax\n\t"
- "int $0x80\n\t"
- "mov %%eax, %0\n\t"
- :"=m" (tt)
- );
- return tt;
- }
- int main(int argc, const char *argv[])
- {
- pid_t tt;
- tt = _fork_asm_();
- if (tt == 0)
- {
- printf("I am the child process,my pid is %d\n",getpid());
- }
- else
- {
- printf("I am the parent process,my pid is %d\n",getpid());
- }
- return 0;
- }
- mov $0x2, %%eax
2 i386 fork sys_fork stub32_fork由于 fork 函数在 i386机器中为2号系统调用,所有直接调用2号进程。
- int $0x80
- mov %%eax, %0
执行结果如图
总结:
参数传递过程:可以看出来这个实验只需要使用eax传递系统调用编号,然后使用eax接受返回值,最后进行写入内存。
系统调用分析:
- 用户设置参数,调用中断,保护现场。
- 中断向量表,进行系统调用,进入内核态
- 内核处理,返回参数
- 返回参数,恢复现场。