飞不高 发表于 2024-9-29 00:05:17

步伐人生-Hello’s P2P



https://i-blog.csdnimg.cn/blog_migrate/483ac36addde562561eff10729c8600c.jpeg

计算机系统

大作业


题     目  步伐人生-Hello’s P2P 
专       业       信息安全                
学     号        2022111759               
班     级       2203202                
学       生      李达鹏               
指 导 教 师        史先俊               






计算机科学与技术学院
2024年5月
摘  要
本文通过先容 hello 步伐的 P2P 和 O20 过程,深入分析了步伐的整个生命周期,使我们对计算机系统有了更深入的理解。

首先,hello.c 步伐编写完成后,颠末 C 预处置惩罚器预处置惩罚生成 hello.i 文件;随后 C 编译器将其翻译为汇编语言文件 hello.s;接着汇编器将其转换为可重定位目标文件 hello.o;然后毗连器将刚生成的 hello.o 文件与系统目标文件结合,生成可实验目标文件 hello,这就是 P2P 过程。

接下来,shell 创建子进程运行 hello 步伐,涉及进程管理、内存管理和 I/O 管理,最后 hello 进程被采取,这就是 O20 过程。
关键词:hello;P2P;020;计算机系统                          

(择要0分,缺失-1分,根据内容精彩称都酌情加分0-1分)









目  录

第1章 概述................................................................................... - 4 -
1.1 Hello简介............................................................................ - 4 -
1.2 情况与工具........................................................................... - 4 -
1.3 中心结果............................................................................... - 4 -
1.4 本章小结............................................................................... - 4 -
第2章 预处置惩罚............................................................................... - 5 -
2.1 预处置惩罚的概念与作用........................................................... - 5 -
2.2在Ubuntu下预处置惩罚的命令................................................ - 5 -
2.3 Hello的预处置惩罚结果解析.................................................... - 5 -
2.4 本章小结............................................................................... - 5 -
第3章 编译................................................................................... - 6 -
3.1 编译的概念与作用............................................................... - 6 -
3.2 在Ubuntu下编译的命令.................................................... - 6 -
3.3 Hello的编译结果解析........................................................ - 6 -
3.4 本章小结............................................................................... - 6 -
第4章 汇编................................................................................... - 7 -
4.1 汇编的概念与作用............................................................... - 7 -
4.2 在Ubuntu下汇编的命令.................................................... - 7 -
4.3 可重定位目标elf格式........................................................ - 7 -
4.4 Hello.o的结果解析............................................................. - 7 -
4.5 本章小结............................................................................... - 7 -
第5章 链接................................................................................... - 8 -
5.1 链接的概念与作用............................................................... - 8 -
5.2 在Ubuntu下链接的命令.................................................... - 8 -
5.3 可实验目标文件hello的格式........................................... - 8 -
5.4 hello的虚拟地点空间......................................................... - 8 -
5.5 链接的重定位过程分析....................................................... - 8 -
5.6 hello的实验流程................................................................. - 8 -
5.7 Hello的动态链接分析........................................................ - 8 -
5.8 本章小结............................................................................... - 9 -
第6章 hello进程管理.......................................................... - 10 -
6.1 进程的概念与作用............................................................. - 10 -
6.2 简述壳Shell-bash的作用与处置惩罚流程........................... - 10 -
6.3 Hello的fork进程创建过程............................................ - 10 -
6.4 Hello的execve过程........................................................ - 10 -
6.5 Hello的进程实验.............................................................. - 10 -
6.6 hello的非常与信号处置惩罚................................................... - 10 -
6.7本章小结.............................................................................. - 10 -
第7章 hello的存储管理...................................................... - 11 -
7.1 hello的存储器地点空间................................................... - 11 -
7.2 Intel逻辑地点到线性地点的变更-段式管理................... - 11 -
7.3 Hello的线性地点到物理地点的变更-页式管理............. - 11 -
7.4 TLB与四级页表支持下的VA到PA的变更.................... - 11 -
7.5 三级Cache支持下的物理内存访问................................ - 11 -
7.6 hello进程fork时的内存映射......................................... - 11 -
7.7 hello进程execve时的内存映射..................................... - 11 -
7.8 缺页故障与缺页中断处置惩罚................................................. - 11 -
7.9动态存储分配管理.............................................................. - 11 -
7.10本章小结............................................................................ - 12 -
第8章 hello的IO管理....................................................... - 13 -
8.1 Linux的IO设备管理方法................................................. - 13 -
8.2 简述Unix IO接口及其函数.............................................. - 13 -
8.3 printf的实现分析.............................................................. - 13 -
8.4 getchar的实现分析.......................................................... - 13 -
8.5本章小结.............................................................................. - 13 -
结论............................................................................................... - 14 -
附件............................................................................................... - 15 -
参考文献....................................................................................... - 16 -



第1章 概述

1.1 Hello简介

1) 步伐的生命周期始于一个高级 C 语言步伐 hello.c,由步伐员用 C 语言编写。
2) 预处置惩罚器(cpp)根据以字符 # 开头的命令,对原始步伐举行预处置惩罚生成 hello.i 文件。
3) 编译器(ccl)将 hello.i 翻译生成汇编语言文件 hello.s 文件。
4) 接着,汇编器(as)将 hello.s 翻译成可重定位目标文件 hello.o。
5) 链接器(ld)负责处置惩罚 hello.o 和系统目标文件的合并,生成一个可实验目标文件(或简称为可实验文件) hello。
(参考自《深入理解计算机系统》)

P2P流程如下图所示:
https://i-blog.csdnimg.cn/blog_migrate/c49c9eac7f35282afc704bcc91b9be0e.png
6) 在 shell 中输入实验 hello 的命令后,shell 解析命令行,通过 fork 新建一个子进程来实验 hello,此时 hello 从步伐转换为进程。
7) 步伐开始时,一切为 0,初始为 zero。shell 为新建的子进程调用 execve,举行虚拟内存映射,进入步伐入口后开始将步伐载入物理内存,接着进入 main 函数实验目标代码,CPU 以流水线情势读取并实验指令,实验逻辑控制流。操作系统负责进程调理,为进程分配时间片。在实验过程中,通过 L1、L2、L3 高速缓存、TLB、多级页表等举行存储管理,使用 I/O 系统举行输入输出。当步伐运行结束后,shell 父进程负责采取 hello 进程,内核删除相干数据布局,一切重新归零,这就是 O20 过程。
1.2 情况与工具

列出你为编写本论文,折腾Hello的整个过程中,使用的软硬件情况,以及开发与调试工具。
硬件情况:X64 CPU;2.6GHz;16G RAM;256GHD Disk
软件情况:Windows10 64位;Vmware 16;Ubuntu 16.04 LTS 64位
开发与调试工具:gcc,gdb,edb,readelf,HexEdit
1.3 中心结果

列出你为编写本论文,生成的中心结果文件的名字,文件的作用等。
列出你为编写本论文,生成的中心结果文件的名字,文件的作用等。
hello.c 源步伐
hello.i 预处置惩罚后文件,由C预处置惩罚器产生,用于分析预处置惩罚过程。
hello.s 编译后的汇编文件,由C编译器产生,用于分析编译过程。
hello.o 汇编后的可重定位目标实验文件,由汇编器产生,用于分析汇编过程。
hello 链接后的可实验文件,由链接器产生,用于分析链接过程。
hello_elf.txt  hello.o的ELF格式,用于分析可重定位目标文件hello.o。
hello_elf2.txt  hello的ELF格式,用于分析可实验目标文件hello。
1.4 本章小结

本章使用计算机系统的术语形貌了一个hello步伐P2P、020的整个过程,给出了实验所用的情况和工具的根本信息,列出了编写论文过程中生成的所有文件和其对应作用
(第1章0.5分)



第2章 预处置惩罚

2.1 预处置惩罚的概念与作用

2.1.1 概念:预处置惩罚器(cpp)根据以字符 # 开头的命令,修改原始的 C 步伐。

2.1.2 作用:根据源代码中的预处置惩罚指令修改源代码,预处置惩罚将系统头文件中的源码插入目标文件中,同时将宏和常量标识符替换为相应的代码和值,生成扩展名为 .i 的预处置惩罚后文件。例如,在 hello.c 中,第一行的 `#include <stdio.h>` 命令告诉预处置惩罚器读取系统头文件 `stdio.h` 的内容,并直接插入到步伐文本中。
https://i-blog.csdnimg.cn/blog_migrate/1e51ab3b85daa6fd902b5ca570614ce8.png
图2-1 C语言预处置惩罚指令表
2.2在Ubuntu下预处置惩罚的命令

Ubuntu下预处置惩罚命令为:gcc -E hello.c -o hello.i

https://i-blog.csdnimg.cn/blog_migrate/11f7b8a098bafe49ac34c6d040373e48.png
图2-2 预处置惩罚
预处置惩罚后得到hello.i文件。
2.3 Hello的预处置惩罚结果解析

https://i-blog.csdnimg.cn/blog_migrate/36f05906d67da48aeb4933c0249c60a8.png
图2-3预处置惩罚文本
打开预处置惩罚后文件,发现hello.i文件为纯文本文件,并且有3060行,说明原.c文件中的宏举行了宏展开,头文件中的内容被包含进该文件中,例如声明函数、定义布局体、定义变量、定义宏等内容。
2.4 本章小结

本章先容了预处置惩罚的概念和作用,在虚拟机的ubuntu系统下动手举行了预处置惩罚操作,并且分析了得到的预处置惩罚文件

(第2章0.5分)

第3章 编译

3.1 编译的概念与作用

 1 概念:编译器(ccl)将文本文件 hello.i 翻译为文本文件 hello.s,此中包含一个汇编语言步伐。

 2 作用:编译器将高级语言转换为计算机可识别的二进制语言。计算机只能理解0和1,编译器将人们熟悉的语言转换为二进制情势。编译过程包罗五个阶段:词法分析、语法分析、语义查抄和中心代码生成、代码优化以及目标代码生成。此中,词法分析和语法分析是最紧张的阶段,也称为源步伐分析,检测语法错误并提供相应提示信息。



-词法分析:处置惩罚由字符组成的单词,逐个字符地扫描源步伐,生成单词符号串,将源步伐表现为单词符号串的中心情势。

- 语法分析:以单词符号为输入,查抄单词符号串是否形成符合语法规则的语义单元,例如表达式、赋值、循环等。终极查抄是否形成符合要求的步伐,按照语言的语法规则对每条语句举行分析和查抄。语法规则可用上下文无关文法来形貌。

- 代码优化:对步伐举行等价转换,以生成更有效的目标代码。转换后的步伐不改变运行结果,但可以使步伐的运行时间减少、占用存储空间更小。

 

在编译过程中,如果发现源步伐中有错误,编译器会报告错误的性质和位置。通常情况下,编译器仅举行语法查抄和最根本的语义查抄,而不查抄步伐的逻辑。3.2 在Ubuntu下编译的命令

在Ubuntu下编译的命令:gcc -S hello.i -o hello.s
https://i-blog.csdnimg.cn/blog_migrate/46f20bfafd6f7fe532d6a7ded0979cc9.png
图3-1 编译处置惩罚
生成了汇编文件hello.s 。
3.3 Hello的编译结果解析


https://i-blog.csdnimg.cn/blog_migrate/f1360f53833a7a4b405dffb8fceccb0a.png
https://i-blog.csdnimg.cn/blog_migrate/dda53098db4b94e91b1c366e7fe7747f.png
https://i-blog.csdnimg.cn/blog_migrate/e45c55fd78aafea047c0e70752982cfb.png
图3-2 编译结果
此部门是重点,说明编译器是怎么处置惩罚C语言的各个数据范例以及各类操作的。应分3.3.1~ 3.3.x等按照范例和操作举行分析,只要hello.s中出现的属于大作业PPT中P4给出的参考C数据与操作,都应解析。
3.3.0编译指令:
指令
内容
.file
声明源文件
.text
声明代码段
.data
声明数据段
.rodata
只读数据
.globl
全局变量
.size
声明巨细
.type
指定范例
.align
声明对指令或数据的存放地点举行对齐的方式
3.3.1数据

[*]常量https://i-blog.csdnimg.cn/blog_migrate/3b719dc889895e7ba05f694efe1acd31.png
图3-3 常量
两个printf的参数是字符串常量,存储在下图所示 .string 中。
https://i-blog.csdnimg.cn/blog_migrate/7eedbe341b4d3ab0af6a2830ee67fc71.png

图3-4 常量

[*]变量https://i-blog.csdnimg.cn/blog_migrate/02d0b5274a15252723bf887651b7cc5a.png
步伐中设置了i作为循环条件,i是一个变量,编译器编译时用movl指令将这个局部变量放在堆栈中。如下面,i被放在栈上%rbp-4的位置,初始值为0;
https://i-blog.csdnimg.cn/blog_migrate/a8480a848cfdbe254487d70116a39d22.png
图3-5变量
3.3.2赋值
https://i-blog.csdnimg.cn/blog_migrate/1eafcefeb55d8a22a5811b7a27fd1448.png
图3-6变量
对于循环计数变量i,编译器在设置i时就设置其初始值为0。
https://i-blog.csdnimg.cn/blog_migrate/90298ced4b08a4c9177e9f30487addb6.png
图3-7变量
3.3.3范例转换

https://i-blog.csdnimg.cn/blog_migrate/2f5cbb0906f2e2bd16484534965ba2e2.png
图3-8范例转换
atoi函数将字符型argv转换为整型数,如下。
https://i-blog.csdnimg.cn/blog_migrate/b3d4a991e6a6d01ab7bd2a0873bfe3cd.png
图3-9范例转换
3.3.4算术操作

https://i-blog.csdnimg.cn/blog_migrate/0707182464fe4d823aae8840e9dd9441.png
https://i-blog.csdnimg.cn/blog_migrate/11e79ce31d00d13c0f1c9005e578d146.png
​编辑​
图3-10算术操作
hello.c源步伐中只包含一次算术操作,出如今循环变量i每次增加1的时候。算术操作为++。
算术操作++代表自增1的运算,编译时转化成add类的加法指令,使用立刻数1来实现每次增加1(由前面分析可知,%rbp-4处为变量i),如下。
https://i-blog.csdnimg.cn/blog_migrate/7344b818d90b6ccca0d2ebfddf961d2a.png
图3-11 算术操作
3.3.5关系操作

[*]在if中判断argc的取值是否不即是5
https://i-blog.csdnimg.cn/blog_migrate/efa07c37b0dbb45d215a05f2847d127c.png
图3-12 关系操作
编译时使用cmpl指令将argc和3举行比较,并设置条件码。跳转指令je根据条件码决定是否跳转。
    
https://i-blog.csdnimg.cn/blog_migrate/e6b730483c7d72c61927f4fed37b3433.png
图3-13 关系操作

[*]
https://i-blog.csdnimg.cn/blog_migrate/f471176c8124642114cecb45a3fc70a4.png
                            图3-14关系操作
在for循环中判断结束条件,即判断i是否小于8。编译器编译时使用cmpl指令,将i和7举行比较并设置条件码。跳转指令jle代表小于即是7时跳转,与小于8时跳转等效。这里举行比较的值是7而不是8,与编译的过程中举行了优化有关。
     
https://i-blog.csdnimg.cn/blog_migrate/a4137e0d0a4419d12748522f7094d054.png
3.3.6数组/指针/布局操作

https://i-blog.csdnimg.cn/blog_migrate/3e66ca3ac82ad7da19938a07bb773124.png
图3-15指针操作
argv数组是传入的参数,储存在栈上。初始地点位于%rbp-32,使用argv的地点加i*8,就能得到argv。
https://i-blog.csdnimg.cn/blog_migrate/ac3c3be5313637c6b6fce39c56aadeff.png
https://i-blog.csdnimg.cn/blog_migrate/0781ffa3869a7921ec15bc9396dfe0bc.png
https://i-blog.csdnimg.cn/blog_migrate/f648d8759fbc5ffff0fcc8b380a179dc.png
图3-16指针操作

3.3.7控制转移

[*]https://i-blog.csdnimg.cn/blog_migrate/836a3dce7502c9c02d1c1e8dff31ca9c.png
图3-17 控制转移操作
根据汇编器的汇编指令判断argc即是4时,跳转到 .L2 处
https://i-blog.csdnimg.cn/blog_migrate/8acdac439cc5aed3f18dcaf4df2f9f91.png
图3-17 控制转移操作
2)循环内的转移被编译为,循环变量小于即是7时,跳转到.L4指令处。
   
https://i-blog.csdnimg.cn/blog_migrate/fa7dce8db6a9014ba8827cb028018c8b.png
图3-17 控制转移操作
3.3.8函数操作
1)函数调用
调用printf函数
   
https://i-blog.csdnimg.cn/blog_migrate/12047e89810dca91d9a35606a0425be7.png
图3-18函数操作
调用sleep函数和atoi函数
    
https://i-blog.csdnimg.cn/blog_migrate/4f0e4db54bcd03a6a664eac6811638a0.png
图3-19 函数操作
调用getchar函数
    
https://i-blog.csdnimg.cn/blog_migrate/f2adf4487d4fa9e74913b6ff94a6cd82.png
函数调用会被翻译为call
https://i-blog.csdnimg.cn/blog_migrate/deeeced7349cb2ec6648e9089f24d6e6.png
https://i-blog.csdnimg.cn/blog_migrate/7c783edc6964cd3fe8a618e17dfe94f3.png
https://i-blog.csdnimg.cn/blog_migrate/1b0dc1efe3affd23e57b267d34ca8c5d.png
https://i-blog.csdnimg.cn/blog_migrate/548de4e068b2bf449847c0d988488bb0.png
图3-20函数操作
2)函数参数转达
参数的转达:大部门的参数转达通过寄存器实现,通过寄存器最多转达6个参数,按照顺序依次为%rdi、%rsi、%rdx、%rcx、%r8、%r9。多余的参数通过栈来转达。对于函数printf第一次出现,只有一个参数,通过寄存其%edi转达:
   
https://i-blog.csdnimg.cn/blog_migrate/e9087c5358b6eed36f319150e3554273.png
图3-21函数操作转达
对于函数printf第二次出现,分别通过寄存器%rdi、%rsi、%rdx转达。
    
https://i-blog.csdnimg.cn/blog_migrate/d82a7e00893603bda3005e79f5af9aad.png
图3-22 函数参数转达
对于函数sleep,只有一个参数,通过寄存器%edi转达。
     
https://i-blog.csdnimg.cn/blog_migrate/1920a84d247183612aa9055baac475c5.png
图3-23函数参数转达
对于函数getchar没有参数,无需转达.

3.4 本章小结

本章先容了编译的概念、作用和对应指令,在Ubuntu下汇编得到了hello.s文件。然后对该文件举行了分析,先容了C语言中赋值操作、范例转换、关系操作、数组/指针操作、控制转移和函数操作等对应的汇编语言的指令。

(第3章2分)

第4章 汇编

4.1 汇编的概念与作用

4.1.1 概念:汇编器(as)将 hello.s 翻译成呆板语言指令,并将这些指令打包成一种可重定位目标步伐格式,结果保存在目标文件 hello.o 中。

4.1.2 作用:目标文件 hello.o 是一个二进制文件,包含指令对应的二进制呆板语言,这种二进制代码能够被计算机理解和实验。汇编器的作用是将汇编语言转换为最底层的、计算机可理解的呆板语言,从而实现步伐的实验。4.2 在Ubuntu下汇编的命令

gcc hello.s -c -o hello.o
 
https://i-blog.csdnimg.cn/blog_migrate/9f84d19b9ccd1af282ea71db5168547d.png

图4-1汇编操作
4.3 可重定位目标elf格式

分析hello.o的ELF格式,用readelf等列出其各节的根本信息,特殊是重定位项目分析。
1)在Ubuntu中使用readelf命令来查看ELF,并将其重定位为文本文件。

readelf -a hello.o > hello_elf.txt
   
https://i-blog.csdnimg.cn/blog_migrate/10020bf2622a727b299df0a45dc8a441.png
图4-2汇编的重定位
2)一个ELF可重定位目标文件可包含如下内容:
https://i-blog.csdnimg.cn/blog_migrate/d2bf21ab1ca184ef1e16fa67163edc27.png
图4-3 重定位目标文件包含内容

[*]文件内容
https://i-blog.csdnimg.cn/blog_migrate/30d40ff393064ee4d356af82b2a41147.png
ELF头起始于一个16字节的目标序列,如图中所示,此中的 Magic 字段形貌了生成该文件的系统的字巨细和字节顺序。对于 hello.o 文件,这个16字节序列为 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00,表现系统的字巨细为 8 字节,字节顺序为小端序。
https://i-blog.csdnimg.cn/blog_migrate/4e16f7e5409a66c31b0664faaa7e3ab2.png
ELF头的其余部门包罗用于辅助链接器语法分析和解释目标文件的信息。此中包罗 ELF 头的巨细、目标文件范例、呆板范例、节头部表的文件偏移,以及节头部表中条目标巨细和数量。以 hello.o 为例,ELF头中包含了以下信息:ELF 头巨细为 64 字节;目标文件范例为 REL(可重定位文件);呆板范例为 Advanced Micro Devices X86-64;节头部表的文件偏移为 1240 字节;节头部表中条目数量为 14。

4.4 Hello.o的结果解析

objdump -d -r hello.o  分析hello.o的反汇编,并请与第3章的 hello.s举行对照分析。
说明呆板语言的构成,与汇编语言的映射关系。特殊是呆板语言中的操作数与汇编语言不同等,特殊是分支转移函数调用等。


https://i-blog.csdnimg.cn/blog_migrate/443db669e5db7eeb89c7f82209e492bd.png

图4-5反汇编内容

在将hello.s中的汇编语言转换为呆板语言时,汇编指令被映射到差别的二进制功能码,操作数也被映射到二进制的情势,以使呆板能够识别。每条汇编语句都有对应的呆板语言情势,反之亦然,从而实现相互转换。然而,这两种表现方式存在一些差别之处:



1) 操作数表现

在hello.s中,立刻数使用十进制表现,而在呆板语言中,立刻数以十六进制表现。



2) 分支转移:

在hello.s中,分支转移(跳转指令)直接使用助记符(如.LC0,.LC1)来举行跳转,在呆板语言中,跳转使用确定的地点,而不再使用助记符来标识跳转位置。



3) 函数调用:

在hello.s中,函数调用通过在call指令后面加上函数名来实现,而在呆板语言中,call指令后面是被调用函数的PC相对地点。观察到call指令后跟着一串0的情况,这是因为调用的是库函数,需要颠末动态链接以确定函数地点,因此在重定位节中要添加相应的重定位条目,在链接时才气确定终极调用函数的相对地点。4.5 本章小结

本章先容了汇编的概念与作用,在ubuntu下现实举行了汇编操作,生成了hello.o文件,进而分析汇编过程。然后还用readelf命令查看了hello.o文件的ELF格式,将两个文件对比分析了汇编语言和呆板代码的差异。
(第4章1分)

第5章 链接

5.1 链接的概念与作用

概念:链接是将各种代码和数据片断收集并组合成单个文件的过程,这个文件可以被加载到内存并实验。

作用:链接在软件开发中饰演偏紧张角色,使得分离编译成为可能。通过模块化设计和编程,软件开发可以更高效地举行分组工作。当需要修改或调试时,只需修改特定模块,重新编译并重新链接即可,而不需要重新编译整个步伐。即使对于像 hello 如许简单的小步伐,链接的作用也是非常紧张的。

5.2 在Ubuntu下链接的命令

Linux下使用链接器 (ld) 链接的命令为:
ld -o hello -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o hello.o /usr/lib/x86_64-linux-gnu/libc.so /usr/lib/x86_64-linux-gnu/crtn.o
https://i-blog.csdnimg.cn/blog_migrate/d0a156f6b487287367b4ca29349bf29e.png
图 5-1 链接命令
5.3 可实验目标文件hello的格式

分析hello的ELF格式,用readelf等列出其各段的根本信息,包罗各段的起始地点,巨细等信息。
在可实验目标文件中,其各类信息与在可重定位目标文件中其实是差不多的,故我们这里一些根本概念就不多叙述。

5.3.1 ELF头
      查看hello的ELF头:readelf -a hello
https://i-blog.csdnimg.cn/blog_migrate/1e11e0815585ca0982f997251f852f11.png
图 5-2 ELF头
我们可以看到可文件的范例为可实验文件,入口点地点为0x4010f0,以及其他的根本信息。比如节头部表的偏移量,ELF头的巨细等

       5.3.2 节头部表
              以下是部门的节头部表
https://i-blog.csdnimg.cn/blog_migrate/7a4de042bd479e3803a667e3eb58811b.png
图 5-3 部门节头部表
       可以看到,其根本内容和之前还是很相似的,但链接器将各个文件对应的段都合并了,并且重新分配并计算了相应节的范例、位置和巨细等信息。通过节头部表我们就可以知道各个节的地点和巨细了。而这些我们都可以到其反汇编文件中得到验证。
       5.3.3 符号表
              以下是部门符号表
https://i-blog.csdnimg.cn/blog_migrate/53d93cce0aad27b8d9e5c8e6c5e587b5.png
图 5-4 符号表
5.3.4 段节
https://i-blog.csdnimg.cn/blog_migrate/9486676a5fc9c7c590200533d505480f.png
图 5-5 段节
5.3.5 Dynamic section
https://i-blog.csdnimg.cn/blog_migrate/88dcbdd17e157327cdf92de3f38b9599.png
图 5-6 动态节

5.4 hello的虚拟地点空间

使用edb加载hello,查看本进程的虚拟地点空间各段信息,并与5.3对照分析说明。  
https://i-blog.csdnimg.cn/blog_migrate/700155e311b7c11dd9763531fcd50e19.png
图 5-7 edb内存空间截图
该图展示了edb中data dump的默认显示地点范围,是从0x401000到0x402000.然厥后看一下hello的步伐头表确认它所对应的段
https://i-blog.csdnimg.cn/blog_migrate/3b5b2945016ad0b84400c57f74673d8a.png
图 5-8 步伐头表
步伐头表形貌了每个段在文件中的位置、巨细以及它被放进内存后所在的位置和巨细。步伐头表有一列是type范例,该范例用来精确的形貌各段。PHDR保存步伐头表,INTERP指定步伐从可实验文件映射到内存之后,必须调用的解释器(就像java需要java虚拟机解释一样)。这个解释器可以通过链接其他步伐库,来办理符号引用。LOAD表现一个需要从二进制文件映射到虚拟地点空间的段,此中保存了常量数据(字符串等)、步伐目标代码。DYNAMIC保存了动态链接器(前面interp指定的解释器)使用的信息。GNU_STACK:权限标记,用于标记栈是否是可实验。GNU_RELRO:指定在重定位结束之后哪些内存区域是需要设置只读。
而每一段的Filesiz关键字和Memsiz关键字给出了每一段的文件巨细和占用内存的巨细,PhysAddr关键字给出的是每个段的物理地点,offset是偏移值,剩下的flags,align给出的是别的的信息,如许我们就知道了一个可实验步伐每个段在内存中的位置和其所占空间的巨细。
而通过分析,我们可以知道第二个LOAD段是代码段,有读和实验权限,开始于内存地点0x401000处,总共的内存巨细为0x27d字节,并且被初始化为可实验目标文件的头也是0x27d字节,此中包罗ELF头,步伐头部表以及.init、.text和.rodata节。
第四个LOAD段是数据段,有读和写权限,开始于内存地点0x403e50处,总共的内存巨细为0x1fc字节,并用从目标文件中偏移0x2e10处开始的.data节中的0x1fc字节初始化。
这是我们再根据反汇编的代码和内存空间去比较发现是相同的。
              我们这里也来对比一下第四个LOAD段的内存空间来看看
https://i-blog.csdnimg.cn/blog_migrate/f6df3b0abafbf650b917708af3ec4143.png
图 5-10 edb内存查看
       可以看到在0x403e50以前存储的都是0,而在之后存储了一些内容,当然我们这里也很难知道存储的是什么,但能说明简直是从这一段开始的,这验证了我们的想法。
5.5 链接的重定位过程分析

objdump -d -r hello 分析hello与hello.o的差别,说明链接的过程。

[*]hello新增了很多的函数相干的代码
https://i-blog.csdnimg.cn/blog_migrate/40f534ab229fa4da07ce7d89bb5e3fe5.png
图5-11 hello反汇编文件
这是通过重定位实现的。

[*] 新增了节
我们可以看到hello显着多了很多其他的节,比如.init .plt等。
https://i-blog.csdnimg.cn/blog_migrate/35ec5de2653edadf22b4c462f0a8b319.png
图 5-12 反汇编新增节
       init是为了初始化步伐,而plt是由于共享库链接时生成的。

[*] 函数跳转转移
在函数调用时,由于hello是重定位后的可实验步伐,因此其调用函数时,所调用的地点就是函数所在简直切地点,而hello.o则是调用一些相对的地点。

[*] 常量,全局变量的调用
在将字符串常量作为参数转达时,我们可以看到它直接使用了其地点来读取,而在hello.o则是要通过重定位来实现。

结合hello.o的重定位项目,分析hello中对其怎么重定位的。
我们主要拿书上提到的两种主要重定位范例举行分析。
第一种是重定位的绝对引用,这种相对简单。
https://i-blog.csdnimg.cn/blog_migrate/71172b3cf3940557e09d1d035e58d165.png
图 5-13 可重定位条目分析
这是在hello.o中转达字符串常量时出现的重定位条目(第一个),我们可以看到mov指令开始于节偏移0x19的位置,包罗1字节的操作码0xbf,后面跟着对该字符串常量地点的32位绝对引用的占用符。通过重定位条目我们可以知道,它的引用符号为.rodata,addend为0。下面我们去看.rodata中的地点。
https://i-blog.csdnimg.cn/blog_migrate/5f12632217157200f9039aa90046ee13.png
图 5-14 .rodata验证
       上图的信息量很大,我们首先通过readelf -x .rodata hello去查看hello的.rodata段的十六进制情势,可以看到是从0x402000开始的,但为什么不是下面的结果不是0x402000呢?这一点我也不太确定,但我们可以看到从0x402008开始有大量的信息存储,比如e794a8e6我们去查hello.s中看到的赋值序列,上网查询得知,这是汉字的八进制转义序列,每三个作为一个编码,转换为十六进制可以发现二者恰好对应,说明从0x402008开始存储的正是该字符串常量。
5.6 hello的实验流程

使用edb实验hello,说明从加载hello到_start,到call main,以及步伐终止的所有过程。请列出其调用与跳转的各个子步伐名或步伐地点。
由于对edb操作不是很熟悉,我采用的是gdb的方式,我们首先通过前面说到的入口点,即_start处的地点0x4010f0,在此处设置断点
https://i-blog.csdnimg.cn/blog_migrate/7954b773877278b3d0a4eb99954476fd.png
图 5-16 gdb设置断点
之后我们单步开始运行,然后看它跳转的函数及其地点。
步伐名
步伐地点
_start
0x4010f0
_libc_start_main_impl
0x7ffff7c29dc0
__GI___cxa_atexit
0x7ffff7c458c0
__new_exitfn
0x7ffff7c456d0
_init
0x401000
_dl_audit_preinit@plt
0x7ffff7c286d0
(跳至一个空的,没名字的地方)
0x7ffff7c28350
同上
0x7ffff7c28000
_dl_runtime_resolve_xsavec
0x7ffff7fd8d30
_dl_fixup
0x7ffff7fd5e70
_dl_lookup_symbol_x
0x7ffff7fcf0d4
do_lookup_x
0x7ffff7fce3f0
check_match
0x7ffff7fce24x
strcmp
0x7ffff7fea224
之后开始不断返回直到_dl_audit_preinit

__libc_start_call_main
0x7ffff7c29d10
_setjmp
0x7ffff7c421e0
_sigsetjmp
0x7ffff7c42110
__sigjmp_save
0x7ffff7c42190
main
0x401125
printf
0x4010a0
atoi
0x401191
sleep
0x4010e0
getchar
0x4010b0
返回至__libc_start_call_main

__GI_exit
0x7ffff7c455f0
__run_exit_handlers
0x7ffff7c45390
__GI___call_tls_dtors
0x7ffff7c45d60
_dl_fini
0x7ffff7fc9040
___pthread_mutex_lock
0x7ffff7c97ef0
_dl_audit_activity_nsid
0x7ffff7fde250
_dl_sort_maps
0x7ffff7fd6730
_fini
0x4011b4
_dl_audit_objclose
0x7ffff7fde570
终极跳至__GI_exit退出步伐


整个过程其实调用了很多未知的函数,但总结来说过程是
_start -> __libc_start_main ->  init -> main -> exit.
5.7 Hello的动态链接分析

分析hello步伐的动态链接项目,通过edb调试,分析在dl_init前后,这些项目标内容变化。要截图标识说明。
动态链接是一项风趣的技术。让我们思量一个简单的究竟,printf,getchar如许的函数实在使用的太过频繁,因此如果每个步伐链接时都要将这些代码链接进去的话,一份可实验目标文件就会有一份printf的代码,这是对内存的极大浪费。为了遏制这种浪费,对于这些使用频繁的代码,系统会在可重定位目标文件链接时仅仅创建两个辅助用的数据布局,而直到步伐被加载到内存中实验的时候,才会通过这些辅助的数据布局动态的将printf的代码重定位给步伐实验。即是说,直到步伐加载到内存中运行时,它才知晓所要实验的代码被放在了内存中的哪个位置。
这种风趣的技术被称为延迟绑定,将过程地点的绑定推迟到第一次调用该过程时。而那两个辅助的数据布局分别是过程链接表(PLT)和全局偏移量表(GOT),前者存放在代码段,后者存放在数据段。
https://i-blog.csdnimg.cn/blog_migrate/d9243b1be312eff65f6753b11629c343.png
图 5-17 节头部表查看.got节
       我们首先通过前面的节头部表获得got的地点,
       可以看到.got的位置是0x403ff0,我们去查相应的内存空间。
https://i-blog.csdnimg.cn/blog_migrate/7ef5e564f0c1f67fd773ef708a6e13aa.png
图 5-18 运行前got内存空间
       可以看到在运行之前是没什么内容的,而当我们运行之后,我们来看看它的变化:
https://i-blog.csdnimg.cn/blog_migrate/84bb7a5a45d75822afdff9de4a171d52.png
图 5-19 运行后got内存空间
       通过前后对比:在实验_dl_init之前,.got是全0的;在实验_dl_init之后,.got变成了相应的值。因此推测_dl_init作用是:初始化步伐,给其赋上调用的函数的地点,使这些被调用的函数链接到了动态库。
5.8 本章小结

本章先容了链接的概念与内容,分析了hello的elf格式,查看了hello的虚拟地点空间,对链接的重定位过程举行了分析,并验证了其重定位条目标引用等,并使用gdb和edb分析了hello的实验流程和动态链接分析。
在本章中呢,链接器ld通过可重定位目标文件中的数据布局,解析每个文件中的符号,仔细比对了符号的定义和引用,终极为每个符号的引用都找到了正确的符号定义的位置。而重定位的过程更加需要小心谨慎,链接器需要在特定的位置修改值,使得步伐在运行时能够指哪打哪而不会偏差。毕竟在cpu中哪怕是一个字节的偏差,失之毫厘,差之千里。因此可以说,链接的过程同样是充满着各种困难困苦的。
(第5章1分)


第6章 hello进程管理

6.1 进程的概念与作用

6.1.1概念:进程的经典定义就是一个实验中步伐的实例。系统中的每个步伐都运行在某个进程的上下文(context)中。上下文是由步伐正确运行所需的状态组成的。这个状态包罗存放在内存中的步伐的代码和数据,它的栈、通用目标寄存器的内容、步伐计数器、情况变量以及打开文件形貌符的集合。
6.1.2作用:进程提供给应用步伐两个关键抽象:
·1)一个独立的逻辑控制流,它提供一个假象,似乎我们的步伐独占地使用处置惩罚器。
2)一个私有的地点空间,它提供一个假象,似乎我们的步伐独占地使用内存系统。
6.2 简述壳Shell-bash的作用与处置惩罚流程

6.2.1作用:shell是一个交互型应用级步伐,为使用者提供操作界面。Shell担当用户命令,然后调用相应的应用步伐。Shell作为系统得用户界面,提供了用户与内核举行交互操作的接口
6.2.2处置惩罚流程
Shell主要功能是解释命令。
1)首先对用户输入的命令举行解析,判断命令是否为内置命令
2)如果为内置命令,调用内置命令处置惩罚函数;如果不是内置命令,就创建一个子进程,将步伐在该子进程的上下文中运行。
3)判断为前台步伐还是后台步伐,如果是前台步伐则直接实验并等待实验结束,如果是后台步伐则将其放入后台并返回。
4)同时Shell对键盘输入的信号和其他信号有特定的处置惩罚。
6.3 Hello的fork进程创建过程

在ubuntu终端输入对应的命令 ./hello 120L02041 接下来shell会读入输入的命令,然后首先判断hello不是一个内置的shell命令。以是下一步要找到当前所在目录下是否有可实验文件hello。找到hello后,shell主动调用fork( )函数让父进程创建一个新的运行的子进程。新创建的子进程得到与父进程用户级虚拟地点空间相同但是独立的一份副本,包罗代码和数据段、堆、共享库以及用户栈。子进程还获得与父进程任何打开文件形貌符相同的副本,这就意味着当父进程调用fork时,子进程可以读写父进程中打开的任何文件。
父进程和新创建的子进程之间最大的区别在于他们有差别的PID。
6.4 Hello的execve过程

1)子进程通过execve系统调用启动加载器。
2)加载器删除子进程现有的虚拟内存段,并创建一组新的代码、数据、堆和栈段。新的栈和堆段被初始化为零。
3)通过将虚拟地点空间中的页映射到可实验文件的页巨细的片(chunk),新的代码和数据段被初始化为可实验文件的内容。
4)最后,加载器跳转到_start地点,它终极会调用应用步伐的main函数。
除了一些头部信息,在加载过程中没有任何从磁盘到内存的数据复制。直到 CPU引用一个被映射的虚拟页时才会举行复制,此时,操作系统使用它的页面调理机制主动将页面从磁盘传送到内存。
6.5 Hello的进程实验

结合进程上下文信息、进程时间片,阐述进程调理的过程,用户态与核心态转换等等。
上下文:系统中的每个步伐都运行在某个进程的上下文(context)中。上下文是由步伐正确运行所需的状态组成的。这个状态包罗存放在内存中的步伐的代码和数据,它的栈、通用目标寄存器的内容、步伐计数器、情况变量以及打开文件形貌符的集合。
时间片:一个进程实验它的控制流的一部门的每一时间段叫做时间片。
并发流:一个逻辑流的实验在时间上与另一个流重叠。
用户模式和内核模式:为了使操作系统内核提供一个无懈可击的进程抽象,处置惩罚器必须提供一种机制,限制一个应用可以实验的指令以及它可以访问的地点空间范围。一个运行在内核模式的进程可以实验指令集中的任何命令,并且可以访问系统中的任何内存位置。用户模式中的进程不答应实验特权指令,也不答应直接引用地点空间中内核区内的代码和数据。

在进程实验的某些时刻,内核可以决定抢占当进步程,并重新开始一个先前被抢占了的进程。这种决策就叫做调理(scheduling),是由内核中称为调理器(scheduler)的代码处置惩罚的。当内核选择一个新的进程运行时,我们说内核调理了这个进程。
在内核调理了一个新的进程运行后,它就抢占当进步程,并使用一种称为上下文切换的机制来将控制转移到新的进程,上下文切换包罗三步

[*]保存当进步程的上下文
[*]规复某个先前被抢占的进程被保存的上下文
[*]将控制转达给这个新规复的进程。
以hello的进程实举动例。fork()函数生成子进程,在进程调用execve函数之后,进程已经为hello步伐分配了新的虚拟的地点空间,最初hello运行在用户模式下。
当hello进程调用sleep时,进程变为内核模式。这时hello进程被挂起,内核会选择调理sleep进程,通过上下文切换保存hello进程的上下文,将控制转达给sleep。sleep函数中定时器的时间到了后会发送中断信号,hello进程又变成运行状态,这时hello进程就可以等待内核调理它。
当内核再次调理hello进程时,规复保存的hello进程的上下文,就可以从刚才停止的地方继续实验了。
当hello调用getchar的时候同样会陷入内核模式,由于getchar需要来自键盘的DMA传输,时间很长,因此内核不会等待DMA完成,而是去调理其他进程。当DMA完成后,会向处置惩罚器发送中断信号,进入内核模式,内核知道DMA完成了,就可以再次调理hello进程了。
6.6 hello的非常与信号处置惩罚

hello实验过程中会出现哪几类非常,会产生哪些信号,又怎么处置惩罚的。
 步伐运行过程中可以按键盘,如不停乱按,包罗回车,Ctrl-Z,Ctrl-C等,Ctrl-z后可以运行ps  jobs  pstree  fg  kill 等命令,请分别给出各命令及运行结截屏,说明非常与信号的处置惩罚。

[*]非常先容
中断    来自I/O设备的信号     异步       总是返回到下一条指令
陷阱    有意的非常             同步       总是返回到下一条指令
故障    潜在可规复的错误       同步       可能返回到当前指令或终止
终止    不可规复的错误         同步       不会返回

[*]各命令结果

[*]不停乱按
不停乱按,没有输入回车的情况下,输入的字符串被缓存到缓冲区,没有任何反应;输入回车,回车前的字符被认为是输入的命令,返回未找到命令。
https://i-blog.csdnimg.cn/blog_migrate/2a573fc5a03d3bd2cfc249f1bad0797f.png

[*]回车
“回车”显示为空行,由后面命令输入提示符多出来好几行可以推断,回车被存储到缓冲区,输出完成后shell再对其反应
https://i-blog.csdnimg.cn/blog_migrate/6e35e1a4e8e72b8cfc0def21a6b52e88.png

[*]Ctrl-C
发送SIGINT信号给前台进程组的每个进程,终止了前台进程,即终止hello进程。
https://i-blog.csdnimg.cn/blog_migrate/e85c37610191f3c62d415d9210ca06ee.png

[*]Ctrl-Z等,Ctrl-z后可以运行ps  jobs  pstree  fg  kill
Ctrl-Z会发送SIGTSTP信号给前台进程组的每个进程,结果也是停止前台作业
https://i-blog.csdnimg.cn/blog_migrate/f666fd21c0c1aed515f82f3ea60b0f1b.png
https://i-blog.csdnimg.cn/blog_migrate/6931e4a9d70ecd3ca4948b8ade081561.png
https://i-blog.csdnimg.cn/blog_migrate/f38dab3ea12987fffaf9aae3aa107e06.png
6.7本章小结

本章了解了hello进程的实验过程。在hello运行过程中,内核对其调理,非常处置惩罚步伐为其将处置惩罚各种非常。每种信号都有差别的处置惩罚机制,对差别的shell命令,hello也有差别的响应结果。可以说,进程管理就是为了约束步伐的运行而存在的。
(第6章1分)

第7章 hello的存储管理

7.1 hello的存储器地点空间

(1)逻辑地点:指由步伐产生的段内偏移地点。

(2)线性地点:指虚拟地点到物理地点变更的中心层,是处置惩罚器可寻址的内存空间(称为线性地点空间)中的地点。步伐代码产生的逻辑地点加上相应段基址就成了一个线性地点。如果启用了分页机制,那么线性地点可以再颠末变更产生物理地点。如果没有采用分页机制,那么线性地点就是物理地点。

(3)虚拟地点:是由步伐产生的由段选择符和段内偏移地点组成的地点。

(4)物理地点:指内存中物理单元的集合。
7.2 Intel逻辑地点到线性地点的变更-段式管理

逻辑地点=段选择符+偏移量

每个段选择符巨细为16位,段形貌符为8字节。每个段的首地点都存放在自己的段形貌符中,而所有的段形貌符都存放在一个形貌符表中。而要想找到某个段的形貌符必须通过段选择符才气找到。

通过段选择符我们就可以找到我们想要的段形貌符,从而获取某个段的首地点,然后再将从段形貌符中获取到的首地点与逻辑地点的偏移量相加就得到了线性地点。                

7.3 Hello的线性地点到物理地点的变更-页式管理

分页机制把线性地点空间和物理地点空间分别划分为巨细相同的块。如许的块称之为页。通过在线性地点空间的页与物理地点空间的页之间创建的映射,分页机制实现线性地点到物理地点的转换。

https://i-blog.csdnimg.cn/blog_migrate/11eedfb559d784cf4292089e37f05222.png
虚拟内存被构造为一个由存放在磁盘上的N个连续的字节巨细的单元组成的数组。使用页表来管理虚拟页,页表就是一个页表条目(PTE)的数组,每个PTE由一个有效位和一个n位地点字段组成。

Cpu首先会生成一个虚拟地点,转达给MMU,MMU使用VPN获取PPN与保持和VPO不变的PPO组成物理地点

7.4 TLB与四级页表支持下的VA到PA的变更

https://i-blog.csdnimg.cn/blog_migrate/9b388cc99bca264ca387092f93ae361f.png

https://i-blog.csdnimg.cn/blog_migrate/2e5c3933c0163206b3dfd4ca210a6461.png
https://i-blog.csdnimg.cn/blog_migrate/f54e769a449e2e1528091d70794712a4.png
每个条目引用一个 4KB子页表:

P: 子页表在物理内存中 (1)不在 (0).

R/W: 对于所有可访问页,只读或者读写访问权限.

U/S: 对于所有可访问页,用户或超级用户 (内核)模式访问权限.

WT: 子页表的直写或写回缓存战略.

A: 引用位 (由MMU 在读或写时设置,由软件扫除).

PS: 页巨细为4 KB 或 4 MB (只对第一层PTE定义).

D:修改位,告知是否写回

Page table physical base address: 子页表的物理基地点的最高40位 (强制页表

4KB 对齐)

XD: 能/不能从这个PTE可访问的所有页中取指令.

虚拟地点的VPN被划分为VPN1,VPN2,VPN3,VPN4。CR3寄存器中有L1页表的地点,根据VPN1能够在L1页表找到相应PTE,得到L2页表的基地点,一次类推,终极我们得到物理地点的PPN。
7.5 三级Cache支持下的物理内存访问

https://i-blog.csdnimg.cn/blog_migrate/57b05010e553fc354f26c28012352f1a.png
  物理地点PA被分成3块,CT(标记)、CI(索引)、CO(偏移),之后在L1中寻找,若命中,则返回对应块偏移的数据。否则,L1不命中,我们需要前往L2,L3甚至是主存中得到对应的数据
7.6 hello进程fork时的内存映射

Fork函数为新进程创建虚拟内存,他会创建当进步程的的mm_struct, vm_area_struct和页表的原样副本。将两个进程中的每个页面都标记为只读,两个进程中的每个区域布局(vm_area_struct)都标记为私有的写时复制(COW),在新进程中返回时,新进程拥有与调用fork进程相同的虚拟内存,随后的写操作通过写时复制机制创建新页面。

7.7 hello进程execve时的内存映射

https://i-blog.csdnimg.cn/blog_migrate/027ca359e819c4ccd35b9356ade864a2.png
它首先删除已存在的用户区域,之后创建新的区域布局,此中的代码和初始化数据映射到.text和.data区(目标文件提供),.bss和栈映射到匿名文件。hello步伐与共享对象链接,这些对象动态链接到hello步伐,然后映射到用户虚拟地点空间。再设置PC,指向代码区域的入口点
7.8 缺页故障与缺页中断处置惩罚

有三种情况:
(1)段错误: 访问一个不存在的页面,此时会中断步伐实验。
(2)正常缺页,会选择牺牲页,换入新的页面并举行页表更新,完成缺页处置惩罚。
(3)保护非常: 例如,违反许可,写一个只读的 页面(Linux 报告 Segmentation fault
7.9动态存储分配管理

Printf会调用malloc,下面简述动态内存管理的根本方法与战略。

当步伐运行时,如果需要额外的虚拟内存时,可以用动态内存分配器来申请内存。动态内存分配器维护着一个进程的虚拟内存区域,称为堆(heap),假设堆是一个请求二进制零的区域,它紧接在未初始化的数据区域后开始,并向上生长(向更高的地点)。
对于每个进程,内核维护着一个变量 brk,它指向堆的顶部。分配器将堆视为一组差别巨细的块(block)的集合来维护。每个块就是一个连续的虚拟内存片(chunk),要么是已分配的,要么是空闲的。已分配的块显式地保留为供应用步伐使用。空闲块可用来分配。空闲块保持空闲,直到它显式地被应用所分配。一个已分配的块保持已分配状态,直到它被释放,这种释放要么是应用步伐显式实验的,要么是内存分配器自身隐式实验的。

隐式空闲链表分配中,内存块的根本布局如下:
https://i-blog.csdnimg.cn/blog_migrate/22e9cac5827f47b18cbcc5a203a15b8c.png
而对于显式空间链表,真实的操作系统现实上使用的是显示空闲链表管理。它的思路是维护多个空闲链表,每个链表中的块有大致相等的巨细,分配器维护着一个空闲链表数组,每个巨细类一个空闲链表,当需要分配块时只需要在对应的空闲链表中搜索就好了。
其一种实现的根本布局如下:
https://i-blog.csdnimg.cn/blog_migrate/c206bedec00b985fcd44a231e1e640e9.png
7.10本章小结

       本章先容了现代操作系统的魂魄:存储器地点空间、段式管理、页式管理,VA 到 PA 的变更、物理内存访问, hello 进程 fork 时和 execve 时的内存映射、缺页故障与缺页中断处置惩罚、包罗隐式空闲链表和显式空闲链表的动态存储分配管理。这些巧妙的设计使得我们的 hello 终极得以运行。



第8章 hello的IO管理

8.1 Linux的IO设备管理方法

(以下格式自行编排,编辑时删除)                     
设备的模子化:文件
设备管理:unix io接口
  一个Linux 文件就是一个m个字节的序列:B,B1, …,B。 , …,Bm-1。所有的I/O设备(例如网络、磁盘和终端)都被模子化为文件,而所有的输人和输出都被看成对相应文件的读和写来实验。这种将设备优雅地映射为文件的方式,答应Linux内核引出一个简单、低级的应用接口,称为Unix I/O,这使得所有的输入和输出都能以一种统一且同等的方式来实验:
   1)打开文件。一个应用步伐通过要求内核打开相应的文件,来宣告它想要访问一个I/О设备。内核返回一个小的非负整数,叫做形貌符,它在后续对此文件的所有操作中标识这个文件。内核记录有关这个打开文件的所有信息。应用步伐只需记住这个形貌符。Linux shell 创建的每个进程开始时都有三个打开的文件:标准输入(形貌符为0)、标准输出(形貌符为1)和标准错误(形貌符为2)。头文件< unistd.h>定义了常量sTDINFILENO、STDOUT_FILENO和 STDERR_FILENO,它们可用来代替显式的形貌符值。

[*]改变当前的文件位置。对于每个打开的文件,内核保持着一个文件位置k,初始为0。这个文件位置是从文件开头起始的字节偏移量。应用步伐能够通过实验seek 操作,显式地设置文件的当前位置为k。
[*]读写文件。一个读操作就是从文件复制n>0个字节到内存,从当前文件位置é开始,然后将é增加到k十n。给定一个巨细为m字节的文件,当k≥m时实验读操作会触发一个称为end-of-file(EOF)的条件,应用步伐能检测到这个条件。在文件末端处并没有明确的“EOF符号”。类似地,写操作就是从内存复制n>0个字节到一个文件,从当前文件位置k开始,然后更新k。
[*]关闭文件。当应用完成了对文件的访问之后,它就关照内核关闭这个文件。作为响应,内核释放文件打开时创建的数据布局,并将这个形貌符规复到可用的形貌符池中。无论一个进程因为何种原因终止时,内核都会关闭所有打开的文件并释放它们的内存资源。
8.2 简述Unix IO接口及其函数

1)打开文件用open函数
int open(char *filename , int flags ,mode_t mode )
open函将filename转换为一个文件形貌符,并且返回形貌符数字。返回的形貌符总是在进程中当前没有打开的最小形貌符。flags参数指明了进程打算怎样访问这个文件:
O_RDONLY 只读
O_WRONLY 只写
O_RDWR 可读只写

[*]关闭文件用close函数
int close(int fd)
[*]读和写文件
ssize_t read (int fd ,void *buf ,size_t n)
ssize_t write(int fd ,const void *buf ,size_t n)
    应用步伐分别调用read和write函数来实验输入和输出。
    Read函数从形貌符为fd的当前文件位置复制最多n个字节到内存位置buf。返回-1表现一个错误,而返回值0表现EOF。否则,返回值表现的是现实传送的字节数量。
    write函数从内存位置buf复制至多n个字节到形貌符fd的当前位置。下面是一个使用read和write调用一次一个字节地从标准输入复制到标准输出地步伐:https://i-blog.csdnimg.cn/blog_migrate/e05bd1271b45c4ef6f3ce4773aba4ab5.png
图8-1输入输出步伐示例
8.3 printf的实现分析

从vsprintf生成显示信息,到write系统函数,到陷阱-系统调用 int 0x80或syscall等.
字符显示驱动子步伐:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。
显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。
printf函数的函数体如下:
int printf(const char *fmt, ...)
{
int i;
char buf;
  
     va_list arg = (va_list)((char*)(&fmt) + 4);
     i = vsprintf(buf, fmt, arg);
     write(buf, i);
  
     return i;
    }
vsprintf函数根据格式串fmt,并结合args参数产生格式化之后的字符串结果保存在buf中,并返回结果字符串的长度。
write函数将buf中的i个字符写到终端,由于i保存的是结果字符串的长度,因此write将格式化后的字符串结果写到终端。
8.4 getchar的实现分析

异步非常-键盘中断的处置惩罚:键盘中断处置惩罚子步伐。担当按键扫描码转成ascii码,保存到系统的键盘缓冲区。
第一次调用getchar时,需要从键盘输入,但如果输入了多个字符,之后的getchar会直接从缓冲区中读取字符。getchar等调用read系统函数,通过系统调用读取按键ascii码,直到担当到回车键才返回。
getchar函数的函数体如下:
int getchar(void) 

static char buf; 
static char *bb = buf; 
static int n = 0; 
if(n == 0) 

n = read(0, buf, BUFSIZ); 
bb = buf; 

    return(--n >= 0)?(unsigned char) *bb++ : EOF; 
}
8.5本章小结

本章首先叙述了Linux的IO设备管理方法和Unix IO接口及其函数的有关知识,并分析了printf和getchar函数的实现。
结论

至此,hello 终于走完了它的一生,让我们为它的一生做个小结:
Hello步伐的生命周期开始于步伐员把其内容输入到文本编辑器中:字符数据颠末总线终极被传输到寄存器,并在文件被关闭后保存到磁盘。
接下来将源文件通过gcc编译器预处置惩罚,编译,汇编,链接,终极完成一个可以加载到内存实验的可实验目标文件。一系列操作,为hello.c一个空壳注入了活的魂魄。
接下来通过shell输入文件名,shell通过fork创建一个新的进程,然后在子进程里通过execve函数将hello步伐加载到内存。虚拟内存机制通过mmap为hello规划了一片空间,调理器为hello规划进程实验的时间片,使其能够与其他进程合理使用cpu与内存的资源。此时的它,才真正成为系统中独立的个体,往回看,逻辑控制流、虚拟地点、malloc的高效管理、非常与信号管理,这些都为它的驰骋拥有更加广阔的天地。
然后,cpu一条一条的从hello的.text取指令实验,不断从.data段去除数据。非常处置惩罚步伐监视着键盘的输入。hello内里的一条syscall系统调用语句使进程触发陷阱,内核接手了进程,然后实验write函数,将一串字符转达给屏幕io的映射文件。文件对传入数据举行分析,读取vram,然后在屏幕上将字符显示出来。可以说,Unix I/O 打开它与步伐使用者交流的窗口。
直至最后hello“垂老迈矣”,运行至最后一刻,步伐运行结束,__libc_start_main 将控制转移给内核,Shell 采取子进程,内核删除与它相干的所有数据布局,它在这个世界的所有陈迹至此被抹去。
从键盘上敲出hello.c的源代码步伐不外几分钟,从编译到运行,从敲下gcc到终端打印出hello信息,可能甚至不需要1秒钟。
但回首这短短的1秒,却惊心动魄,千难万险,此中的每一阶段无不汇集凝聚了人类几十年的聪明与心血!
高低电平转达着信息,这些信息被复杂而严谨的呆板逻辑捕捉。cpu不知疲倦的取指与实验。对于hello的实现细节,哪怕把这篇论文再扩充一倍仍讲不清楚。


(结论0分,缺失 -1分,根据内容酌情加分)

附件


列出所有的中心产物的文件名,并予以说明起作用。
hello.c 源步伐
hello.i 预处置惩罚后文件,由C预处置惩罚器产生,用于分析预处置惩罚过程。
hello.s 编译后的汇编文件,由C编译器产生,用于分析编译过程。
hello.o 汇编后的可重定位目标实验文件,由汇编器产生,用于分析汇编过程。
hello 链接后的可实验文件,由链接器产生,用于分析链接过程。
hello_elf.txt  hello.o的ELF格式,用于分析可重定位目标文件hello.o。
Hello_elf2.txt  hello的ELF格式,用于分析可实验目标文件hello。
(附件0分,缺失 -1分)

参考文献

为完成本次大作业你翻阅的书籍与网站等
  林来兴. 空间控制技术. 北京:中国宇航出书社,1992:25-42.
  辛希孟. 信息技术与信息服务国际研讨会论文集:A集. 北京:中国科学出书社,1999.
  赵耀东. 新期间的工业工程师. 台北:天下文化出书社,1998 . http://www.ie.nthu.edu.tw/info/ie.newie.htm(Big5).
  谌颖. 空间交会控制理论与方法研究. 哈尔滨:哈尔滨工业大学,1992:8-13.
  KANAMORI H. Shaking Without Quaking. Science,1998,279(5359):2063-2064.
  CHRISTINE M. Plant Physiology: Plant Biology in the Genome Era. Science,1998,281:331-332. http://www.sciencemag.org/cgi/ collection/anatmorp.
(参考文献0分,缺失 -1分)



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 步伐人生-Hello’s P2P