2017-2018-1 20179202《Linux内核原理与分析》第五周作业
一、系统调用实验:
1.知识准备:
(1)系统调用的三层皮:xyz()(API)、system_call(所有系统调用的入口) 、 sys_xyz()(中断服务程序)
(2)API是程序员在用户空间下可以直接使用的函数接口,它提供了一套封装例程,将系统调用在用户空间包装后供用户编程使用。涉及到与内核空间进行交互的API会封装系统调用,而不涉及与内核进行交互的API不会封装系统调用。
(3)系统调用是用户进入内核的接口,并非内核函数。用户程序通过某个系统调用进入内核后,会接着去执行这个系统调用对应的内核函数。这个内核函数 sys_xyz() 称为系统调用的服务例程。
(4)系统调用号将 xyz() 与 sys_xyz() 关联起,系统调用号由 eax 寄存器传递。
2.系统调用的两种实现方法:
本实验我选择的是系统调用号为 38 的 sys_rename(),功能实现设计为将hello.c 文件重新命名 newhello.c

(1)库函数API实现:

运行结果如下:

(2)嵌入汇编代码实现:

运行结果如下:

3.实验分析:
(1)库函数API实现:
在 /include/linux/syscalls.h 中找到 sys_rename 函数原型:
asmlinkage long sys_rename(const char __user *oldname,const char __user *newname);
可以看出需要传递两个参数,一个是旧文件名,一个是新文件名。由于是指针类型,所以此时的文件名也代表该文件,也就是说,先找到叫 oldname 的文件,然后把其名改为 newname。rename() 是 glibc 对sys_rename 的封装,用户在用户态调用 rename(),将 oldname和newname 参数传入,系统会产生中断陷入内核态执行sys_rename。当重命名成功时,函数返回0。
(2)嵌入汇编代码实现:
asm volatile("movl %2,%%ecx\n\t" //newname存入ecx
"movl %1,%%ebx\n\t" //oldname存入ebx
"movl $0x26,%%eax\n\t" //系统调用号存入eax
"int $0x80" //执行系统调用
:"=a"(ret)
:"b"(oldname),"c"(newname)
);
把系统调用号38(16进制是0x26)存入 eax,将 oldname 存入 ebx,将 newname 存入 ecx,通过执行 int $0x80 来执行系统调用,使应用程序陷入内核态,system_call 根据传入的系统调用号在系统调用列表中查找对应的内核函数,根据 ebx 和 ecx 中保存的参数调用内核函数 sys_rename,执行完后将执行结果存放到 eax 中,最后返回 eax 中的值。
4.问题及解决:
(1)起初不太会写汇编,老师给的例子没有参数,将 ebx 清零,而 sys_rename 有两个参数,该往哪里放呢?通过搜索我知道了参数按顺序赋值给ebx、ecx、edx、esi、edi、ebp,如果超过6个则通过指针变量指向另一片堆栈区,如果无参数传入则赋值为0。于是,oldname 是第一个参数传给 ebx,newname 是第二个参数传给 ecx。
(2)在学习C语言嵌入汇编时,我看到了“m”代表内存变量,于是我想可不可以把“=a”变成“=m”,结果如下:

可看出 hello.c 确实变成了 newhello.c,但却显示没有修改成功,即 ret 不等于0。既然确实执行了 sys_rename,返回值0就应该保存在 eax中,返回采用的是“=m”,是不是返回值0并没有在内存中?于是我将代码改为:

也就是把 eax 中的值0放入内存,但编译后又出错了:

这个问题困扰了我很久,我看了很多简单的嵌入汇编代码,发现在输出的上一行才会出现不加 \n\t 的情况,其他语句最后都有\n\t,搜索后我知道语句之间需使用"\n"或"\n\r"或"\n\t"分开,我猜测不加\n\t说明已经执行结束,再在其后补充一条代码肯定会出错,所以将代码改为:

执行成功:

此外,movl允许寄存器到寄存器,立即数到寄存器等,但是不允许内存到内存的操作。因此操作数不能同时使用"m"作为限定字符。
(3)API方法实现系统调用实现非常便捷,只需知道函数原型即可,有很好的移植性。但是,如果 glibc 没有封装某个内核提供的系统调用时,就没办法通过此方法来调用内核函数。我想,如果内核增加了一个新的系统调用,没来得及为其编写API,那我该如何进行系统调用呢?
参考Linux 下系统调用的三种方法,可以利用 glibc 提供的syscall 函数直接调用。函数原型为long int syscall (long int sysno, ...)sysno 是系统调用号,在 sys/syscall.h 中有所有可能的系统调用号的宏定义。代码改为(SYS_rename换成38也正确):

执行成功:

(4)如果本身就存在 newhello.c,我认为肯定会报错,重命名不成功。实践后发现并不是这样:

可以看出修改成功,且只有一个 newhello.c,那这个 newhello.c 到底是 hello.c的重命名,还是以前的 newhello.c 呢?我在 hello.c 中写入 hello.c,在 newhello.c 中写入 newhello.c,发现执行完 rename 后的 newhello.c 中内容是 hello.c,即是 hello.c的重命名:

所以,如果newname指定的文件存在,则会被删除。
5.小结:
如果用户态要涉及内核态的操作,就需要通过系统调用来实现,可以屏蔽平台相关操作,降低了软件开发难度,增强了系统安全性,使程序具有更好的移植性。系统调用过程为:应用程序在用户态调用 API 函数,系统调用号和参数保存到 eax,ebx 等寄存器中,通过 0x80 中断向量触发中断陷入内核态,中断服务程序根据系统调用号调用并执行对应的内核函数,执行完毕后将结果存放的 eax 中并返回给程序,程序返回用户态。
二、课本笔记:
处理器的速度跟外围硬件设备的速度往往不在一个数量级,所以提供中断机制,让硬件需要的时候再向内核发出信号,使得处理器和外部设备可以协同工作。硬件发出的中断是为了通知内核有新的东西等待处理,内核响应中断时会执行中断处理程序,运行于中断上下文。
中断处理可切为上半部和下半部。重要、紧迫而又与硬件相关的工作必须放在上半部,下半部的实现主要是通过软中断、tasklet、工作队列来实现。上半部的功能是响应中断。上半部完全屏蔽中断,如果它没有执行完,其他中断就不能及时地处理,只能等到这个中断处理程序执行完毕以后。下半部是可中断的,如果其它设备产生了中断,这个下半部可以暂时中断,等到那个设备的上半部运行完了,再运行自己的下半部。request_irq() 注册中断处理程序,free_irq() 释放中断处理程序。上半部将下半部排到它们所负责的设备中断的处理队列中去,不再做其他处理,而下半部几乎完成了中断处理程序所有的事情。
软中断一般是“可延迟函数”的总称,可延迟函数上可以执行四种操作:初始化、激活、执行、屏蔽。软中断产生后并不是马上执行,必须要等待内核的调度才能执行。软中断不能被自己打断,只能被中断打断(上半部)。软中断可以并发运行在多个CPU上(即使同一类型的也可以)。软中断必须设计为可重入的函数(允许多个CPU同时操作),因此也需要使用自旋锁来保护其数据结构。
tasklet建立在软中断上。某一段tasklet代码在某个时刻只能在一个CPU上运行,不同的tasklet代码在同一时刻可以在多个CPU上并发地执行。用DECLARE_TASKLET(name,func, data)和DECLARE_TASKLET_DISABLED(name,func, data)静态地创建一个tasklet_struct结构。当该tasklet被调度以后,给定的函数func(处理程序)会被执行,它的参数由data给出,此外还可动态地创建tasklet。tasklet不能睡眠,但可以响应中断。
软中断不能睡眠、不能阻塞。由于中断上下文出于内核态,没有进程切换,所以如果软中断一旦睡眠或者阻塞,将无法退出这种状态,导致内核会整个僵死,因此要使用工作队列。工作队列可以在进程上下文中执行,工作队列允许被重新调度甚至是睡眠。推后执行的任务叫做工作(work),数据结构为work_struct,这些工作以队列结构组织成工作队列(workqueue),数据结构为workqueue_struct,而工作线程就是负责执行工作队列中的工作。当一个工作者线程被唤醒时,它会执行它的链表上的所有工作。工作被执行完毕,它就将相应的work_struct对象从链表上移去。当链表上不再有对象的时候,它就会继续休眠。
思考:中断上下文为什么不能睡眠?
睡眠是为了进程调度存在的。进程有进程号,但是中断没有。中断处理程序一旦睡眠,不仅没有其他的东西会获得处理器而且无法调度,所以中断处理程序永远不会被唤醒,系统就会瘫痪。
2017-2018-1 20179202《Linux内核原理与分析》第五周作业的更多相关文章
- 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 20199329《Linux内核原理与分析》第九周作业
<Linux内核原理与分析>第九周作业 一.本周内容概述: 阐释linux操作系统的整体构架 理解linux系统的一般执行过程和进程调度的时机 理解linux系统的中断和进程上下文切换 二 ...
- 2019-2020-1 20199329《Linux内核原理与分析》第二周作业
<Linux内核原理与分析>第二周作业 一.上周问题总结: 未能及时整理笔记 Linux还需要多用 markdown格式不熟练 发布博客时间超过规定期限 二.本周学习内容: <庖丁解 ...
- 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语言程序并分析其汇编指令执行过程 因 ...
随机推荐
- (转)select、poll、epoll之间的区别
本文来自:https://www.cnblogs.com/aspirant/p/9166944.html (1)select==>时间复杂度O(n) 它仅仅知道了,有I/O事件发生了,却并不知道 ...
- at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:142) :json转化“$ref 循环引用”的问题
原因: entity实体中存在@OneToMany,@ManyToOne注解,在转化json是产生了循环引用 报的错误 解决方法: springmvc @ResponseBody 默认的json转化用 ...
- bootstrap下laydate样式错乱问题
查看发现bs使用了 * {box-sizing:border-box;}重置了盒子模型 那么我们再把它重置回来,在样式中加入以下代码 .laydate_box, .laydate_box * { bo ...
- [php]手动搭建php开发环境(排错)
前提:针对自己的系统下载相应的php.apache.mysql,安装完毕后按照以下去配置httpd.conf和php.ini 本人用的是php5.6.4和apache2.4.4 一.Apache : ...
- 【NOIP】普及组2010 三国游戏
[算法]贪心 [题解]如果看重一对,先选择其中一个点,该点相邻最大的肯定被选走.所以答案就是最大的[所有点的次大连边点]啦. #include<cstdio> #include<al ...
- MSSQL 详解SQL Server连接(内连接、外连接、交叉连接)
在查询多个表时,我们经常会用“连接查询”.连接是关系数据库模型的主要特点,也是它区别于其它类型数据库管理系统的一个标志. 什么是连接查询呢? 概念:根据两个表或多个表的列之间的关系,从这些表中查询数据 ...
- [Leetcode] N-Queens 系列
N-Queens 系列题解 题目来源: N-Queens N-Queens II N-Queens The n-queens puzzle is the problem of placing n qu ...
- 75.VS2013和opencv3.1.0开发环境配置
首先要做的就是 开发环境配置,具体过程如下: Step 1:OpenCV环境变量配置 我的电脑--->属性--->高级系统设置--->高级--->环境变量--->系统变量 ...
- 【swupdate文档 三】SWUpdate: 嵌入式系统的软件升级
SWUpdate: 嵌入式系统的软件升级 概述 本项目被认为有助于从存储媒体或网络更新嵌入式系统.但是,它应该主要作为一个框架来考虑,在这个框架中可以方便地向应用程序添加更多的协议或安装程序(在SWU ...
- Linux 用户态与内核态的交互【转载】
Linux 用户态与内核态的交互 在 Linux 2.4 版以后版本的内核中,几乎全部的中断过程与用户态进程的通信都是使用 netlink 套接字实现的,例如iprote2网络管理工具,它与内核的交 ...