2020-2021-1 20209328 《Linux内核原理与分析》第五周作业
1.实验目的
使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用,选择一个系统调用(13号系统调用time除外)。
2.实验内容
可以通过/LinuxKernel/linux-3.18.6/arch/x86/syscalls,在里面选择一个系统调用,我选择了64号getppid系统调用。
在选择了64号系统调用后,先man getppid
对此函数进行了解。该系统调用用于返回当前进程的父进程进程号数。
函数原型为
编写ppid.c:
内嵌汇编形式调用:
出现问题:
经过李明帅同学教学后,系统调用的返回值放到eax
里,把n改成a,编译通过。
3.实验总结
应用程序 (application program)与 库函数 (libc)之间, 系统调用处理函数 ( system call handler )与 系统调用服务例程 ( system call service routine )之间, 均是普通函数调用,应该不难理解。 而 库函数 与 系统调用处理函数 之间,由于涉及用户态与内核态的切换,要复杂一些。
Linux 通过 软中断 实现从 用户态 到 内核态 的切换。 用户态 与 内核态 是独立的执行流,因此在切换时,需要准备 执行栈 并保存 寄存器 。
内核实现了很多不同的系统调用(提供不同功能),而 系统调用处理函数 只有一个。 因此,用户进程必须传递一个参数用于区分,这便是 系统调用号 ( system call number )。 在 Linux 中, 系统调用号 一般通过 eax 寄存器 来传递。
总结起来, 执行态切换 过程如下:
1.应用程序 在 用户态 准备好调用参数,执行 int 指令触发 软中断 ,中断号为 0x80 ;
2.CPU 被软中断打断后,执行对应的 中断处理函数 ,这时便已进入 内核态 ;
3.系统调用处理函数 准备 内核执行栈 ,并保存所有 寄存器 (一般用汇编语言实现);
4.系统调用处理函数 根据 系统调用号 调用对应的 C 函数—— 系统调用服务例程 ;
5.系统调用处理函数 准备 返回值 并从 内核栈 中恢复 寄存器 ;
6.系统调用处理函数 执行 ret 指令切换回 用户态 ;