20189220 余超《Linux内核原理与分析》第五周作业
扒开系统调用的三层皮?(上)
第4章的基础知识
- Linux系统调用的三层机制:xyz()(API函数)、system_call(系统调用处理入口) 、 sys_xyz()(系统调用内核处理函数)。
- 32位的X86机器上在用户态的时候只能访问0x00000000—0xbfffffff的地址空间,而在内核态下可以访问所有的地址空间。
- 中断,系统调用是最常用的两种方式,从用户态切换到内核态。
- int指令触发中断机制会在堆栈上保存一些寄存器的值,会保存用户态栈顶地址,当时的状态字,当时的CS:EIP的值。
- 中断发生后的第一件事就是保存现场,中断结束的最后一件事就是恢复现场。
- 系统调用的意义可以把用户从底层的硬件编程中解放出来,极大的提高了系统的安全性,使用户程序具有可移植性。
- API(应用程序编程接口)是函数定义,一个API可以对应多个系统调用,他们之间是多对多的关系。
- 使用EAX寄存器传递一个名为系统调用号的参数。
- Linux操作系统中采用了0和3两个特权级别,分别对应内核态和用户态。
- 在Linux中,系统调用是用户空间访问内核的惟一手段;除异常和中断外,它们是内核惟一的合法入口。 而kernel留给用户层的接口其实就只有一个:软中断(int 0x80)。用户态通过它来陷入内核态,完成系统调用。为了方便使用,kernel与用户层之间又增加了API与一些库(例如libc库)来封装这一过程。因此,目前的资料里大部分都写,调用一个系统调用有三种方法:
(1)通过 glibc 提供的库函数
(2)使用 syscall 函数直接调用
(3)通过 int 0x80指令陷入 - API/libc与系统调用的关系:既然API与libc对软中断进行了封装,那我们先一起看看它们之间的具体关系。一般情况下,应用程序通过应用编程接口(API)而不是直接通过系统调用来编程。这点很重要,因为应用程序使用的这种编程接口实际上并不需要和内核提供的系统调用一一对应。一个API定义了一组应用程序使用的编程接口。从程序员的角度看,系统调用无关紧要,他们只需要跟API打交道就可以了。相反,内核只跟系统调用打交道;库函数及应用程序是怎么使用系统调用不是内核所关心的。
系统调用实现机制
与调用函数一样,系统调用也需要输入输出参数。每个系统调用至少有一个参数,即系统调用号(由eax传递),其他参数依次由ebx、ecx、edx、esi、edi、ebp传入。 由于使用寄存器传递参数,因此对参数的长度做了限制:
(1)每个参数的长度不能超过寄存器的长度,即32位
(2)在系统调用号(eax)之外,参数的个数不能超过6个(ebx、ecx、edx、esi、edi、ebp)如果超过六个,可以传入一个地址,地址所在地存放多个参数
系统调用的三个层次依次是:xyz函数(API)、system_ call(中断向量)和 sys_ xyz(中断服务程序)。

触发一个系统调用的三种方式
1.API函数的方式
首先我选取的是20号的getpid系统调用

编译的结果如下:

2.嵌入式汇编方式

编译运行完的结果

3.调用库函数syscall

编译完运行的结果

4.用gdb进行调试看API的调用是否就是像我们之前分析的对系统调用的封装那样执行的
在getpid处设置断点,运行到断点处。

使用ni命令,对汇编指令逐条运行,前面的清理寄存器的值此处先不讨论,直接一直ni运行到传递系统调用号处(箭头所指的为下一条将要运行的指令, 利用info r命令来查看当前寄存器的值,系统调用号还未传入,eax还为0)。

ni一下,再次查看,发现系统调用号已经传入,确实是利用eax的。

再ni一下,此时该系统调用的实际工作已经完成了,结果(也就是pid)保存在eax中。

实验分析
- getpid是一种函数,功能是取得进程识别码。
- 函数原型:旧的原型为pid_t getpid(void);,推荐使用int _getpid( void );这种形式。注意,函数名第一个字符是下划线。
- 函数说明:getpid函数用来取得目前进程的进程ID,许多程序利用取到的此值来建立临时文件,以避免临时文件相同带来的问题。
- 返回值:目前进程的进程ID。
- 在Linux系统中是通过激活0x80中断来触发系统调用的,需要调用的系统调用号实现赋值给eax存储器,如果有传入参数可赋值给ebx寄存器,如果多于1个则按顺序赋值给ebx、ecx、edx、esi、edi、ebp,如果超过6个则通过指针变量指向另一片堆栈区,如果无参数传入则赋值为0。
汇编代码的分析
#include <stdio.h>
#include<unistd.h>
int main()
{
pid_t pid;
asm volatile(
"movl $0,%%ebx\n\t"//将ebx寄存器清零,系统调用传递第一个参数使用ebx,这里是null
"movl $0x14,%%eax\n\t"//将0xd放入eax中,0x14为20,传递系统调用号20
"int $0x80\n\t"
"movl %%eax,$0\n\t"//通过eax这个寄存器返回系统调用值,和普通函数一样
:"=m"(pid)
);
printf("this process's pid is : %u\n",pid);
return 0;
}
遇到的问题
1.我最开始在做书上给的38号系统调用的例子的时候,出现了下面的问题

后面再网上搜索资料可以得知是因为在64位系统下去编译32位的目标文件,这样是非法的。必须用”-m32”强制用32位ABI去编译,即可编译通过。
2.我在改写syscall函数的的时候,出现了下面的问题

最后发现是因为缺少必要的头文件,添加上 1 #include <unistd.h>2 #include <sys/syscall.h>3 #include <sys/types.h>即可
本章总结
- 在Linux中我们可以通过三种方式也进行系统的调用分为:API方式,C代码中嵌入式汇编语言,和库函数syscall。API方法实现系统调用实现非常便捷,只需知道函数原型即可。
- 经过这次实验,我们可以看到:
(1)要查看系统资源(如pid等),只有处于内核态(0级)的时候才可以。
(2)用户要从用户态(3级)切换到内核态(0级),就要通过软中断(int 0x80)来进行系统调用。
(3)通过eax传递系统调用号,然后由system_call交给system_service完成工作。
(4)system_service完成工作后,结果又由eax传递给用户态堆栈。
我对API系统调用的理解:

- 总之用户调用API函数,系统调用号和参数保存到 eax,ebx ,等寄存器中,通过 0x80 中断向量触发中断陷入内核态,中断服务程序根据系统调用号调用并执行对应的系统调用函数,执行完毕后将结果存放的 eax 中并返回给程序,程序返回用户态。
20189220 余超《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语言程序并分析其汇编指令执行过程 因 ...
随机推荐
- 【开发笔记】- 在Windows环境下后台启动redis
1. 进入 DOS窗口 2. 在进入Redis的安装目录 3. 输入:redis-server --service-install redis.windows.conf --loglevel verb ...
- 【转载】 C#中使用float.Parse方法将字符串转换为Float类型
在C#编程过程中,很多时候涉及到数据类型的转换,例如将字符串类型的变量转换为单精度Float类型就是一个常见的类型转换操作,float.Parse方法是C#中专门用来将字符串转换为float类型的,f ...
- CRC-CCITT CRC-16
CRC分为以下几种标准: CRC-12码 CRC-16码 CRC-CCITT码 CRC-32码 在线CRC计算器 https://www.lammertbies.nl/comm/info/crc-ca ...
- Web前端之【 iframe 】
iframe基本用法 1.最基本的用法 iframe 标签指定 src <iframe src="demo_iframe_sandbox.htm"></ifram ...
- [JavaScript] js中全局标识正则表达式的lastIndex属性
在JavaScript中使用正则表达式时,遇到一个坑:第一次匹配是true,第二次匹配是false. 因为在带全局标识"g"的正则表达式对象中,才有“lastIndex” 属性,该 ...
- MySQL高可用架构应该考虑什么? 你认为应该如何设计?
一.MySQL高可用架构应该考虑什么? 对业务的了解,需要考虑业务对数据库一致性要求的敏感程度,切换过程中是否有事务会丢失 对于基础设施的了解,需要了解基础设施的高可用的架构.例如 单网线,单电源等情 ...
- Replication Controller 和 Replica Set
使用Replication Controller . Replica Set管理Pod Replication Controller (RC) 简写为RC,可以使用rc作为kubectl工具的快速管理 ...
- Python入门篇-解析式、生成器
Python入门篇-解析式.生成器 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.列表解析式(List Comprehension) 1>.列表解析式语法 语法 [ 返回 ...
- An exception has occurred, use %tb to see the full traceback.----parser.parse_args()报错
一.报错: 原因: 由于在jupyter notebook中,args不为空. 二.问题解决 改成args = parser.parse_args(args=[])
- python代码规范 自动优化工具Black
自动优化工具Black 在众多代码格式化工具中,Black算是比较新的一个,它***的特点是可配置项比较少,个人认为这对于新手来说是件好事,因为我们不必过多考虑如何设置Black,让 Black 自己 ...