2019-2020-6 20199317《Linux内核原理与分析》第六周作业
第5章 系统调用的三层机制(下)
1 给MenuOS增加命令
首先进入LinuxKernel目录下,用rm -rf menu强制删除当前的menu目录,然后用git clone重新克隆一个新版本的menu,如下图所示:
新版本的menu中已经将上一章做的两个系统调用添加进去了,在test.c里我们看到添加的两个系统调用,如下图所示:
可以看到在test.c里的main()函数增加了增加了两行代码,一个是MenuConfig("time"),另一个是MenuConfig("time-asm"),从这里看出如果要给MenuOS增加新的命令,只需要使用MenuConfig命令,并增加对应的函数即可。
接下来进入menu目录下,运行make rootfs脚本就可以自动编译并自动生成根文件系统,这时打开了menu镜像,如下图所示:
在MenuOS菜单中输入help命令可以看到新增了 两条命令,输入time命令和time-asm命令可以看到运行结果,如下图所示:
2 使用gdb跟踪系统调用内核函数sys_time
用“qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S”命令先把内核启动一下,可以看到被冻结起来了,代码没有被运行,如下图所示:
再另外打开一个shell窗口,用Ctrl+Shift+O实现水平分割
启动gdb,把内核加载进来,建立连接。这里用到的代码为:
file linux-3.18./vmlinux
target remote:
在这个地方可以看到出现了一个问题:在输入target remote:1234命令时,显示连接超时,这是因为我关掉了另一个Shell打开的MenuOS菜单,重新输入qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S命令打开之后,显示的是连接成功。
接下来就可以设置断点了,在这里用break start_kernel设置一个断点,在此之前内核一直是stop状态,如果按“c”则继续执行,系统开始启动,并启动到start_kernel函数的位置停在断点处,如下图所示:
time系统调用是13号系统调用对应的内核处理函数,即sys_time。接下来在这里用break sys_time设置一个断点,按“c”继续执行,启动MenuOS后执行time命令,程序会停到sys_time这个函数的位置,time命令执行到一半将卡在那里,如下图所示:
通过list命令列出sys_time对应的代码如下图所示:
使用s命令单步执行进入get_seconds(),然后用gdb的finish命令把这个函数全部执行完,再单步执行,一直到return i,获得的就是当前系统时间time的数值。
当执行int 0x80时,CPU会自动跳转到system_call函数,所以我们把断点设置到system_call,并继续执行,如下图所示:
可以看到在MenuOS中执行time-asm命令时,还是停在了原先设定的sys_time这个位置,在system_call这个位置并不能停下。sys_call是一段特殊的汇编代码,只能调试系统调用的内核函数和其他内核函数的处理过程,且system_call还有一个函数原型声明,但它并不是一个普通的函数,,只是一段汇编代码的起点,且内部没有严格遵守函数调用堆栈机制,所以gdb不能完成跟踪执行过程的任务。
3 系统调用在内核代码中的处理过程
3.1 中断向量0x80和system_call中断服务程序入口的关系
在用户态中有一个系统调用xyz(),xyz()系统调用库函数里面用了SYSCALL(在这里即为int 0x80)来触发系统调用,其中中断向量0x80对应system_call中断服务程序入口。
在start_kernel函数里调用的trap_init函数中有一段代码如下:
#ifdef CONFIG_x86_32
set_system_trap_gate(SYSCALL_VECTOR, &system_call);
set_bit(SYSCALL_VECTOR, used_vectors);
#endif
这里通过set_system_trap_gate函数绑定了中断向量0x80(这里的SYSCALL_VECTOR是系统调用的中断向量0x80)和system_call中断服务程序入口后,一旦执行int 0x80,CPU就直接跳转到system_call这个位置来执行,即系统调用的工作机制在start_kernel里初始化好之后,CPU一旦执行到Int 0x80指令就会立即跳转到system_call的位置。
3.2 在system_call汇编代码中的系统调用内核处理函数
system_call这一段代码就是系统调用的处理过程,系统调用是一个特殊一点的中断(或称之为软中断),这一段代码中也有保存现场SAVE_ALL和恢复现场restore_all的过程。同时,system_call_table是一个系统调用的表,EAX寄存器传递的系统调用号,使用者在调用它时会根据EAX寄存器来调用对应的系统调用内核处理函数。
简化后的system_call代码为:
ENTRY(system_call)
RING0_INT_FRAME
ASM_CLAC
pushl_cfi %eax #保存系统调用号
SAVE_ALL #保存现场,将用到的所有CPU寄存器保存到栈中
GET_THREAD_INFO(%ebp) #ebp用于存放当前进程thread_info结构的地址
testl $_TIF_WORK_SYSCALL_ENTRY, TI_flags(%ebp)
jnz syscall_trace_entry
cmpl $(nr_syscalls), %eax #检查系统调用号(系统调用号应小于NR_syscalls)
jae syscall_badsys #不合法,跳入异常处理
syscall_call:
call *sys_call_table(,%eax,) #通过系统调用号在系统调用表中找到相应的系统调用内核处理函数,比如sys_time
movl %eax, PT_EAX(%esp) #保存返回值到栈中
syscall_exit:
testl $_TIF_ALLWORK_MASK, %ecx #检查是否有任务需要处理
jne syscall_exit_work #需要,进入syscall_exit_work,这里是最常见的进程调度时机
restore_all:
TRACE_IRQS_TRET #恢复现场
irq_return:
INTERRUPT_RETURN #iret
从entry(system_call)开始看这段代码,根据系统调用号来查sys_call_table表中的位置,调用系统调用对应的处理函数,在syscall_exit里面判断当前的任务是否需要处理syscall_exit_work,进入syscall_exit_work,这是最常见的进度调度时机点。
sys_call_table(,%eax,4)中每个表项占4个字节,所以先把系统调用号(EAX寄存器)乘以4,再加上sys_call_table分派表的起始地址,即得到系统调用号对应的系统调用内核处理函数的指针。sys_call_table分派表是由一段脚本根据linux-3.18.6/arch/x86/syscalls/syscall_32.tbl来自动生成的。
3.3 整体上理解系统调用的内核处理过程
system_call流程如下图所示:
总结一下:从系统调用处理过程的入口开始,可以看到SAVE_ALL保存现场,然后找到syscall_call和sys_call_table。call *sys_call_table(,%eax,4)就是调用了系统调用的内核处理函数,之后restore_all和最后有一个INTERRUPT_RETURN(iret)用于恢复现场并返回系统调用到用户态结束。在这个过程当中可能会执行syscall_exit_work,里面有work_pending,其中的work_notifysig是处理信号的。work_pending里还有可能调用schedule,这是一个非常关键的部分。
4 总结
在第四章的基础上,这一章进一步深入内核系统调用处理过程:在用户态下的xyz()就是一个API函数,是系统调用对应的API,其中封装了一个系统调用,这个系统调用 SYSCALL(即为int 0x80汇编语句)来触发中断,对应system_call内核代码的起点,即中断向量0x80对应的中断服务程序入口。从system_call内核代码的起点开始,先是SAVE_ALL保存现场,再是检查EAX寄存器中保存的系统调用号的正确性,接着根据系统调用号在sys_call_table这个分派表查找相对应的系统调用内核处理函数sys_xyz()的入口,得到这个函数的返回值保存到栈中,然后在syscall_exit里面判断当前的任务是否需要处理syscall_exit_work,进入sys_exit_work,进行进程调度,调度完之后就会跳转到restore_all,恢复现场返回系统调用到用户态。
2019-2020-6 20199317《Linux内核原理与分析》第六周作业的更多相关文章
- 2019-2020-1 20199329《Linux内核原理与分析》第九周作业
<Linux内核原理与分析>第九周作业 一.本周内容概述: 阐释linux操作系统的整体构架 理解linux系统的一般执行过程和进程调度的时机 理解linux系统的中断和进程上下文切换 二 ...
- 2019-2020-1 20199329《Linux内核原理与分析》第二周作业
<Linux内核原理与分析>第二周作业 一.上周问题总结: 未能及时整理笔记 Linux还需要多用 markdown格式不熟练 发布博客时间超过规定期限 二.本周学习内容: <庖丁解 ...
- 20169212《Linux内核原理与分析》第二周作业
<Linux内核原理与分析>第二周作业 这一周学习了MOOCLinux内核分析的第一讲,计算机是如何工作的?由于本科对相关知识的不熟悉,所以感觉有的知识理解起来了有一定的难度,不过多查查资 ...
- 20169210《Linux内核原理与分析》第二周作业
<Linux内核原理与分析>第二周作业 本周作业分为两部分:第一部分为观看学习视频并完成实验楼实验一:第二部分为看<Linux内核设计与实现>1.2.18章并安装配置内核. 第 ...
- 2018-2019-1 20189221 《Linux内核原理与分析》第九周作业
2018-2019-1 20189221 <Linux内核原理与分析>第九周作业 实验八 理理解进程调度时机跟踪分析进程调度与进程切换的过程 进程调度 进度调度时机: 1.中断处理过程(包 ...
- 2017-2018-1 20179215《Linux内核原理与分析》第二周作业
20179215<Linux内核原理与分析>第二周作业 这一周主要了解了计算机是如何工作的,包括现在存储程序计算机的工作模型.X86汇编指令包括几种内存地址的寻址方式和push.pop.c ...
- 2019-2020-1 20209313《Linux内核原理与分析》第二周作业
2019-2020-1 20209313<Linux内核原理与分析>第二周作业 零.总结 阐明自己对"计算机是如何工作的"理解. 一.myod 步骤 复习c文件处理内容 ...
- 2018-2019-1 20189221《Linux内核原理与分析》第一周作业
Linux内核原理与分析 - 第一周作业 实验1 Linux系统简介 Linux历史 1991 年 10 月,Linus Torvalds想在自己的电脑上运行UNIX,可是 UNIX 的商业版本非常昂 ...
- 《Linux内核原理与分析》第一周作业 20189210
实验一 Linux系统简介 这一节主要学习了Linux的历史,Linux有关的重要人物以及学习Linux的方法,Linux和Windows的区别.其中学到了LInux中的应用程序大都为开源自由的软件, ...
- 2018-2019-1 20189221《Linux内核原理与分析》第二周作业
读书报告 <庖丁解牛Linux内核分析> 第 1 章 计算工作原理 1.1 存储程序计算机工作模型 1.2 x86-32汇编基础 1.3汇编一个简单的C语言程序并分析其汇编指令执行过程 因 ...
随机推荐
- linux sudo root 权限绕过漏洞(CVE-2019-14287)
0x01 逛圈子社区论坛 看到了 linux sudo root 权限绕过漏洞(CVE-2019-14287) 跟着复现下 综合来说 这个漏洞作用不大 需要以下几个前提条件 1.知道当前普通用户的密 ...
- C函数库errno.h概况
在linux中使用c语言编程时,errno是个很有用的动动.他可以把最后一次调用c的方法的错误代码保留.但是如果最后一次成功的调用c的方法,errno不会改变.因此,只有在c语言函数返回值异常时,再检 ...
- CSPS模拟 72
状态..找不回来了.. T2 简单的期望 考试的时候忘考虑一个事,就是连续多位进位的情况 考试的时候打出$n^2$复杂度dp还没引起怀疑真是不应该. T3 简单的操作 最后一刻才想到图不联通,已经想不 ...
- FastJson稍微使用不当就会导致StackOverflow
GitHub 9.4k Star 的Java工程师成神之路 ,不来了解一下吗? GitHub 9.4k Star 的Java工程师成神之路 ,真的不来了解一下吗? GitHub 9.4k Star 的 ...
- Function题解
这个题最优策略一定是向左上走到某一列再往上一直走. n*q在线暴力可做,离线按y排序,单调栈维护凸壳. 具体来说:对于i<j若A[i]>A[j] 即j的斜率小而且纵截距小,一定比i优,并且 ...
- 学习 Git
Git 简介 Git是目前比较流行的分布式版本控制系统之一,能够记录文件的每次修改,还实现了多人并行开发; Git 组成 工作区(写东西之地) 暂存区 本地仓库(.git) 远程仓库(.repro) ...
- 深入理解@LoadBalanced注解的实现原理与客户端负载均衡
前提 在阅读这篇博客之前,希望你对SpringCloud套件熟悉和理解,更希望关注下微服务开发平台 概述 在使用springcloud ribbon客户端负载均衡的时候,可以给RestTemplate ...
- 一条查询语句在MySQL中是如何执行的?
前言 我们在学习一种技术的时候,首先要鸟瞰其全貌,千万不要一开始就陷入到细节中去,这样有助于我们站在高维度其理解问题 —— 丁奇. 学习MySQL也是一样,所以我们可以从一条查询语句的执行开始看起. ...
- python面向对象<三>
类属性.实例属性: class Tool(object): #属性(类属性)类对象(Tool) num = 0 #方法 def __init__(self,new_name): self.name = ...
- 史上最详细的C语言和Python的插入排序算法
史上最详细的C语言和Python的插入排序算法插入排序原理:所谓插入排序,就像我们在打牌(斗地主)时,整理我们自己手中自己的牌一样,就像是2,1,3,9,J,K,5,4,这四张牌.我们要把它其中的几张 ...