嚴華 发表于 2024-8-18 14:51:30

程序人生大作业







计算机系统
大作业


题     目  程序人生-Hello’s P2P   
专       业    计算机科学与技术                  
学     号     2021110541               
班     级     2103101               
学       生     刘奥           
指 导 教 师     刘雄伟            






计算机科学与技术学院
2022年5月
摘  要

在本大实验中,我们以一个hello.c源程序为例,深入跟踪一个程序,明白它从出生到闭幕的一生:预处理,编译,汇编,链接生成可实行文件hello, 同时明白计算机系统是如何和hello程序举行历程管理,存储管理,I/O管理的,通过探索程序的一生和它与计算机系统之间的工作配合,来深化对计算机系统的明白。                  
关键词:预处理、编译、汇编、链接、可实行文件、历程管理、存储管理、I/O管         理










目  录

第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简介

根据Hello的自白,利用计算机系统的术语,简述Hello的P2P,020的整个过程。
一、Hello的P2P:预处理器(cpp)将源程序文本hello.c根据以#开头的命令,转换成修改了的源程序(仍为文本文件)hello.i,接着编译器(ccl)将文本文件hello.i翻译成一个包罗汇编语言程序的文本文件hello.s,接下来汇编器(as)将hello.s翻译成机器语言指令,指令打包成可重定位目标程序格式并生存在目标文件hello.o中(二进制文本),末了由链接器将多个可重定位目标程序(比方printf.o)与hello.o合成一个可实行文件hello,并存放在磁盘上。
然后为了在Unix系统上运行,将文件名输入到shall命令行表明器中,fork一个子历程,并用execve运行程序,终极生成一个历程。(过程如图1.1)
https://i-blog.csdnimg.cn/blog_migrate/0845e6eb5e46e96c8d3c8e2e5b3d71e7.png
 

                                  图1.1由源程序生成历程的过程

      二、Hello的020:shell对其子历程调用execve函数,然后映射出虚拟内存(为每个历程提供一致的地点空间并掩护其不被其他历程破坏的功能),并在程序开始运行时载入物理内存,运行中CPU为程序分配时间片实行逻辑控制流,程序结束时,父历程回收并开释子历程的程序数据与空间占用,终极实现程序实行的全过程。
1.2 情况与工具

列出你为编写本论文,折腾Hello的整个过程中,使用的软硬件情况,以及开辟与调试工具。

硬件情况:X64 CPU;16CPUs;3.2GHz;16384MB RAM;BIOS J6CN40WW
软件情况:Windows11 64位;Codeblocks;Ubantu 16.04 LTS 64位
开辟与测试工具:gcc,vim,edb/gdb,readelf等
1.3 中间结果

列出你为编写本论文,生成的中间结果文件的名字,文件的作用等。
      hello.c:程序源代码
      hello.i:预处理之后得到的修改了的文本文件
      hello.s:编译器编译后得到的汇编语言文本文件
      hello.o:汇编器生成的可重定位目标文件(二进制文件)
      hello:  链接得到的可实行目标文件(二进制文件)
      hello_elf1:可重定位文件生成的elf格式文件
      hello_elf2:可实行文件生成的elf格式文件
      asm1.txt: 可重定位文件反汇编生成的汇编语言文本文件
      asm2.txt: 可实行文件反汇编生成的汇编语言文本文件


1.4 本章小结

本末节是整个大作业的目录部分,简要先容了hello程序的生成与实行过程,并先容本次实验的实验情况以及过程中生成的文件,详细的讲解将在下方完成。



第2章 预处理

2.1 预处理的概念与作用

预处理的概念:预处理是在程序编译前举行的基于宏定义命令、文件包罗命令、条件编译命令等命令的处理,是对程序的简单加工,不举行语法错误检查,是举行编译前的程序预备阶段。
预处理的作用:本讲解主要基于C语言讨论,C中定义了三种预处理功能:1、宏定义。2、文件包罗。3、条件编译。
一、宏定义(带参数的宏定义和不带参数的宏定义)
      不带参数的宏定义就是在作用区间内简单的字符串更换,而带参数的宏定             义还要在此基础上举行参数的更换。
      不带参数的宏定义:# define 标识符 字符串;
      带参数的宏定义:# define 宏名(参数表) 字符串;
   宏定义可以在肯定水平上使代码简便,提高程序运行效率。
二、文件包罗(一个源文件将另一个源文件的全部内容包罗进来)
     一般有两种格式:#include "file" 和 #include <file>
     使用双引号:起首到当前目录下查找被包罗的文件,再到系统指定的包罗         文件目录;使用尖括号:直接到系统指定的包罗文件目录查找。文件包罗            的目标是利用复制功能,来制止后续重复工作。
三、条件编译(根据宏定义举行部分代码的静态编译)
     其由一些伪指令构成,如:#ifdef、#ifndef,其目标是淘汰下一步代码    编译的数量,从而节流空间占用,并且提高了C语言通用性,差别计算机     能兼容实行代码程序。








2.2在Ubuntu下预处理的命令

Linux下,在命令行中输入gcc -E -o hello.i hello.c实现预处理,如下图2.2.1    所示
https://i-blog.csdnimg.cn/blog_migrate/126e5bdbfc8169a83d30ddc9de832dba.png
 

                    图2.2.1 Linux下对源程序举行预处理过程
2.3 Hello的预处理结果解析

根据下图2.3.1我们不难看出,程序的文本文件变得繁多复杂,缘故原由是预处理过程中生成的文本文件将头文件的代码添加进去,宏定义举行代换处理,包罗的文件也举行写入,末了还去掉了解释

https://i-blog.csdnimg.cn/blog_migrate/28262acdc77a525e6fdafb90c2a01ddf.png
 

图2.3.1 预处理文件的生成结果
宏定义展开:图2.3.2
https://i-blog.csdnimg.cn/blog_migrate/3dbbe4bbfac0f461dd72f8e298cf4f75.png
 

              图2.3.2宏定义展开成extern FILE *()形式
文件包罗:图2.3.3
https://i-blog.csdnimg.cn/blog_migrate/7a035ffd0141c910c1bc8b08149a943d.png
 

      图2.3.3将声明内容到场到源文件
2.4 本章小结

本末节简单先容了可实行文件生成的第一步:预处理。在这个过程中我们看似将代码变得繁杂,实在本质上是有利于后续操作(尤其是编译过程),预处理过程将多个程序,文件整合在一起能提高效率、节省空间、提高兼容性。

第3章 编译

3.1 编译的概念与作用

       编译的概念: 编译是将代码转化为汇编指令的过程,汇编指令只与CPU相干,其可以将逻辑一致的代码转化为同一形式。在这个转化过程中,编译举行语法的检查、中间代码的生成、源程序的优化等过程。
       一、语法检查:以C语言程序为例,编译过程可以分析出正确的C语言指令以错误的次序排列造成的编译错误,或者C语言符号使用不当造成的错误,这里语法检测的实现是基于C语言特定的语法树的,但是编译过程不能分析得出动态的语义错误,由于其没有违反C语言的规则。
       二、中间代码的生成:中间代码的生成能使编译结构在逻辑上更加简单明白,而且可以举行对于中间代码的优化工作,使得后续优化变得简单,因此除了少部分简单计算,大部分复杂语句都会举行中间代码的生成。
       三、源程序的优化:编译过程可以基于中间代码(或不生成中间代码)的条件下举行程序优化,比方乘除变为移位、直接寻址与间接寻址的选择、复杂指令化简等操作。
       

3.2 在Ubuntu下编译的命令

在Linux下,输入指令gcc -S hello.i -o hello.s来实现编译过程,如下图3.2.1所示
https://i-blog.csdnimg.cn/blog_migrate/391a3b2c4a9491fe985c939be80ad8b6.png
 

                  图3.2.1编译的过程与汇编语言文本文件的生成
3.3 Hello的编译结果解析

3.3.1汇编指令开头声明:如下图3.3.1图
https://i-blog.csdnimg.cn/blog_migrate/dbe62f2efda30f398528f3f12f8e9b85.png
 

      图3.3.1汇编指示部分
.file:声明对应源文件
.text: 代码段,只读和可实行的
.section:定义内存段,将代码划分为多个段,在操作系统加载时差别段加载到
差别的地点中,赋予差别的操作权限。
.align:数据/地点的对其方式
.string:字符串声明
.globl :声明全局变量
.type:声明一个字符的范例是函数/数据
3.3.2数据:
(1)常量
立刻数常量表示形式为$+数字(十进制)。如图3.3.2.1
https://i-blog.csdnimg.cn/blog_migrate/29862880345a5e089cbf8a796e0fb2bd.png
https://i-blog.csdnimg.cn/blog_migrate/0706883d7399b93eeea8928451d4c8b1.png 
 
 
图3.3.2.1 立刻数
字符串常量可在.string声明中看到,其存储形式为十进制数(依照ASCII码转换生成)
https://i-blog.csdnimg.cn/blog_migrate/005b9da40b660f6173079bc6f15bb0ef.png
 

图3.3.2.2 字符串常量
(2)变量:
1.全局变量:全局变量存储在内存中,在汇编代码阶段,可在.globl处查看,如图3.3.2.3main为全局变量
https://i-blog.csdnimg.cn/blog_migrate/8a90d44de7bc5549933ca3db5375b2dc.png
 
图3.3.2.3全局变量
2.局部变量:局部变量存储在寄存器中,当局部变量不敷被寄存器存放时将其存放在栈中。固然对于数组和拥有&的局部变量也需要将其存放在内存(栈)中。
https://i-blog.csdnimg.cn/blog_migrate/881ece5a2a95a79d3fc6ff00e122afcb.png
 
图3.3.2.4存放在栈中局部变量
3.静态变量:一般通过static定义,仅使用在文本文件中的变量,其也被编译器存放在栈中。
(3)表达式:编译器将它举行处理结果放入寄存器或者内存中
(4)宏定义:在预处理阶段已经展开,编译阶段仅需译码即可
3.3.3 赋值
赋值在汇编语言中就是将一个值赋给寄存器,这个值可以来自立刻数、寄存器或者内存中,一般来说在汇编语言中通过movX(b、w、l、q)及其相干变形指令(movsXX、movzXX)来实现。
对于movX指令,根据操作数据大小的差别将其分为1、2、4、8字节(对应b、w、l、q)如图3.3.3.1
https://i-blog.csdnimg.cn/blog_migrate/e33df88518d1148f5d1f4c617ad3a41a.png
 

       如图3.3.3.1简单数据传输MovX指令
movsXX:符号扩展数据传输指令,与简单类似不外高位通过符号位扩展
movzXX:零扩展数据传输指令,高位通过0位扩展
https://i-blog.csdnimg.cn/blog_migrate/e717929879f75759511ca189388f3602.png  
 
 图3.3.3.2 数据传输指令
如图3.3.3.2第一行和第四行是将内存中的值赋给(返回值)寄存器中,第七行是寄存器向寄存器赋值。
3.3.4 范例转换(显示或者隐式)
显树模例转换是程序员用强制转换符()对程序操作举行的数据范例转换,隐式范例转换是编译器内部将数据范例举行的转换。
我们常见的整形与整型、字符型的转换都是依据按位操作通过截断和扩展实现的;当整形转化为浮点型时,是根据数据的值举行的,可能存在舍入操作。
本程序中的转换为字符转化为整形,运用atoi函数按位操作转换的,如下图
https://i-blog.csdnimg.cn/blog_migrate/3d5a2cfe7cd40f2d77a7041c42c6829e.png
 

图3.3.4.1 范例转换(显示)
3.3.5 sizeof
sizeof()是一个内存容量度量函数,以字节为单位返回变量大小,如下图
https://i-blog.csdnimg.cn/blog_migrate/52f8703cfb2deee943dfc65f3450fa9b.png
 

图3.3.5.1 间接寻址中的偏移计算
指针大小为八,其为返回值开辟了四个相应的内存空间。
3.3.6算术操作以及逻辑/位操作
下方列举出整形相干的算术操作,除了加载有效地点(leaq)外其余的指令都  是更加尺度的一元或二元操作,》A表示算术右移,》L表示逻辑右移。
https://i-blog.csdnimg.cn/blog_migrate/f2307256437b4519647abe32c23acd50.png
 

             图3.3.6.1算术操作与位移操作
https://i-blog.csdnimg.cn/blog_migrate/4ee89d8402f7171e0798a0cbc72287d3.png
 

图3.3.6.2加法操作
上图将立刻数加到寄存器%rax存储的值上
https://i-blog.csdnimg.cn/blog_migrate/3ac1fff7aeaed97f6a8c85d31f70d4dd.png
 

图3.3.6.3加载地点
上图将%rip中存储的数加上.LC1的值所对应地点中的内容加载到寄存器%rdi中
3.3.7关系操作和跳转
在条件码寄存器中存在控制实行条件分支的指令:
CF:进位标志,最近操作使最高位产生进位。
ZF: 零标志,最近操作结果为零。
SF:符号标志,最近操作结果为负。
OF:溢出标志,最近操作补码溢出。
对应的我们列举如下比力和测试指令:
https://i-blog.csdnimg.cn/blog_migrate/46a3853d53fb36fe18ce2e723fc9e41f.png
 

图3.3.7.1比力和测试指令
以下是针对大作业中的详细实例:
https://i-blog.csdnimg.cn/blog_migrate/257cab6920f62b4f77173b8717e71d13.png
 

图3.3.7.2比力双字
将%rbp-20地点中内容与4举行比力,并实行后续相同则跳转的指令。
控制转移部分用到jump指令,如下
https://i-blog.csdnimg.cn/blog_migrate/cb65b45a0d803f4f3cff8265a9df5d36.png
 

图3.3.7.3 jump指令
详细例子:
https://i-blog.csdnimg.cn/blog_migrate/f24736d65ad3faab79f56551a924cbc5.png
https://i-blog.csdnimg.cn/blog_migrate/894efc0e5d2a9b05bd454803309fe1d0.png 
https://i-blog.csdnimg.cn/blog_migrate/743e0420a32412e8078ed5874399ef9b.png 
 


图3.3.7.4 详细跳转指令
上面三个跳转指令分别对应,直接无判定跳转、有符号小于便是跳转、相等/零时跳转。
3.3.8数组/指针/结构操作
对于数组/指针/结构的操作是通过基址地点偏移寻址的方式存取的,其偏移量的大小基于对应变量的字节大小。
其内存访问形式有如下几种,对于引用数组和结构元素时,比力复杂的寻址常常应用:
https://i-blog.csdnimg.cn/blog_migrate/7f029b9d4fdffabaac32cc00c7ac1046.png
 

图3.3.8.1内存访问形式
详细实例:
https://i-blog.csdnimg.cn/blog_migrate/c7909c8b94aa1e6e076196c1ffafb81e.png
 

图3.3.8.2 参数数组的访问
上图实现了对参数数组的访问,基于(基址+偏移量)寻址来实现的。
3.3.9函数操作
函数操作时基于call指令对指定函数调用的操作,当控制从函数p转移到函数q时需要把PC设置为Q的代码起始位置并将p当前地点的下一个地点压栈用于返回时继承实行函数p的操作。
函数通报需要有参数,因此对寄存器%rdi、%rsi、%rdx、%rcx、%r8、%r9分别存放六个参数,多余的参数将在栈中存储。
当调用过程中出现了局部变量,需要为其分配内存空间,并在结束返回时开释。
https://i-blog.csdnimg.cn/blog_migrate/eee2f244f41ebab8d5cad47594272dee.png
 

图3.3.9.1 运行时的栈
https://i-blog.csdnimg.cn/blog_migrate/8c22e0f7d24c26b1b2ecca08991c0a63.png
 


图3.3.9.2 调用指令
详细在大作业中的实现:
https://i-blog.csdnimg.cn/blog_migrate/960bb003459cd007e97e51af4acf9e09.png
 

%dei中存放sleep的秒数。
https://i-blog.csdnimg.cn/blog_migrate/21b671a0138a628f7be725065fab50ee.png
 

%dei中存放退出的状态。
https://i-blog.csdnimg.cn/blog_migrate/fe579ae11eeee2e5275c1951763352ad.png
 

这里的ret是主函数的返回
图3.3.9.3 函数的调用实现
3.4 本章小结

简述了编译的定义及作用,用gcc实现了编译的过程,通过观察源文件,分析了九个方面:数据、赋值、范例转换、sizeof、算术和逻辑/位操作、关系操作和跳转、数组/指针/结构操作、函数操作的详细实现过程。

第4章 汇编

4.1 汇编的概念与作用

汇编的概念:把汇编语言翻译成机器语言的过程(生成机器能识别的二进制文件),
汇编的过程中把机器语言指令打包生成可重定位目标程序的格式,生存在hello.o中。
汇编的作用:生成机器能看懂的二进制机器语言,用于后续生成可实行文件。


4.2 在Ubuntu下汇编的命令

在Linux下,汇编过程的命令为gcc -c hello.s -o hello.o,如下图:
https://i-blog.csdnimg.cn/blog_migrate/db8b4c6640a09332323b01190087b41d.png
 


4.3 可重定位目标elf格式

       下图为经典可重定位目标文件的格式:
https://i-blog.csdnimg.cn/blog_migrate/0a4ec265ed7a5223ee81f6091e9a8e1d.png
 

图4.3.1典型的ELF可重定位目标文件
为了便于分析观察我们通过指令readelf -a hello.o > ./hello_elf1.txt将elf格式文本导入到hello_elf1.txt文本文件当中,截图如下:
https://i-blog.csdnimg.cn/blog_migrate/5eac9540f8a290dd8fe2e2591738d01e.png
 

图4.3.2 生成可读文本文件hello_elf1.txt
https://i-blog.csdnimg.cn/blog_migrate/1589567f9564c06237de26c0e6138cce.png
 

图4.3.3 hello_elf1.txt中的内容
一、ELF头
   ELF头是以一个16字节的序列开始的,这个序列形貌了生成该文件的系统的字的大小和字节次序。头以下的部分是帮助链接器语法分析和表明目标文件信息的(ELF头的大小、目标文件的范例、机器范例、节头部表的文件偏移以及节头部表中条目标大小和数量。
https://i-blog.csdnimg.cn/blog_migrate/fc163c76d41d62dff706de37edfa0637.png
 

图4.3.4ELF头
二、节头部表
差别节的位置和大小是由节头部表形貌的,其中目标文件中每个节都有一个固定大小的条目。
https://i-blog.csdnimg.cn/blog_migrate/998a382b85ea8d21df81b63b7eeb22e1.png
 

图4.3.5节头部表
我们可以从中读出节的名称,范例,地点、偏移量以及对齐信息等,以.rodata为例范例为PROGBITS,地点为Ox0,偏移量为0xd8,对其要求为8字节。
三、重定位节
重定位的节记录引用外部变量的信息,便于后续基于表中信息与相应的内存空间毗连起来,也就是基于基址和偏移地点计算正确的地点:
https://i-blog.csdnimg.cn/blog_migrate/d808ee511c9db1a0a093f91169bb9f7b.png
 

图4.3.6重定位节
我们可以从图中分析得出偏移地点、基址信息、链接器识别修改范例、重定位到目标的名称等。
四、符号表
每个可重定位目标模块m都有一个符号表,它包罗m定义和引用的符号信息,符号表中的符号包括:由模块m定义并能被其他模块引用的全局符号、外部符号、
只被模块m定义和引用的局部符号。
需要注意的是.symtab中的符号表对应于本地非静态程序变量的任何符号,这些符号是被栈管理的。
https://i-blog.csdnimg.cn/blog_migrate/7bb9cfac87b1db443ba6d2a09f2e25c7.png
 

图4.3.7符号表
通过上图,我们可以分析得到符号名称、定义的节以及对于定义节起始位置的偏移大小、范例,符号是全局还是本地等相干信息。
4.4 Hello.o的结果解析

https://i-blog.csdnimg.cn/blog_migrate/1f1cde66628c235960eab9a16a2da66e.png
 

图4.4.1 生成反汇编文本文件
https://i-blog.csdnimg.cn/blog_migrate/92a4b515ac65f82c83b2879cf291eb87.png
 

图4.4.2反汇编文件内容
经过对比发现,反汇编文件中不仅有汇编语言还有机器语言,我们可以发现一条汇编语言的实现对应这相应的机器语言,这是一个双射,表明两者可以相互转化,下面就差别点举行分析。
一、分支转移
https://i-blog.csdnimg.cn/blog_migrate/331345b53efcc42812ebddca233217d0.png
https://i-blog.csdnimg.cn/blog_migrate/0fb57d5de4be410d060592d86e9e4ab8.png 
 


图4.4.3 跳转的对比
在hello.s文件中跳转指令是以段名称(.L3)作为目标的,而在反汇编文件中跳转地点是用下一条指令的相对地点偏移量给出的。
二、函数调用
https://i-blog.csdnimg.cn/blog_migrate/6fa5289e1e3e85a3c30ffa35ff52cf1f.png
https://i-blog.csdnimg.cn/blog_migrate/38faf32397abe595cc4cfb3c5835822c.png 
 


图4.4.4函数调用的对比
在hello.s文件中函数调用是以函数名称作为目标的,而在反汇编文件中函数调用是用下一条指令的相对地点偏移量给出的,这是由于机器无法识别函数名称,需要将其转化为地点给出。注意:特殊情况下可能需要等到链接,动态链接外部函数后才能确定地点。
三、操作数
https://i-blog.csdnimg.cn/blog_migrate/b409c53928e0920ece9fc20aefb7f912.png
https://i-blog.csdnimg.cn/blog_migrate/b59f2721d428ba915a77969ab35d2e04.png 
 


图4.4.5操作数对比
在hello.s文件中操作数都是十进制,而反汇编文件中立刻数以十六进制存储。
4.5 本章小结

简述了汇编这一过程的概念与作用,举行汇编操作后对程序ELF格式文件举行分析,然后反汇编生成文本文件与hello.s文本文件比力异同,加深对汇编过程的明白。

第5章 链接

5.1 链接的概念与作用

链接的概念:链接是将各种代码和数据片段收集并组合成为一个单一文件的过程,这个文件可以被加载到内存并实行。广义上的链接可以实行于编译时(源代码被翻译成机器代码时)、加载时(程序被加载器加载到内存并实行时)和运行时(应用程序实行)。
链接的作用:大作业中链接作用是将hello.o与其他可重定位文件(比方printf.o)组合共同生成可实行文件hello,并让其加载到内存运行。
5.2 在Ubuntu下链接的命令

在Linux下输入命令:gcc -m64 -Og -no-pie -fno-stack-protector -fno-PIC hello.c -o hello
https://i-blog.csdnimg.cn/blog_migrate/403a2b37ae9920001355f8d1e9ac5e92.png
 

图5.2.1 在shall命令行中输入链接命令并生成可实行文件

5.3 可实行目标文件hello的格式

与生成重定位目标文件的ELF格式类似,输入到命令行指令readelf -a hello > hello_elf2.txt生成可实行文件的ELF格式,如图:
https://i-blog.csdnimg.cn/blog_migrate/bbead3dde7a6685ea9481434b2d9db52.png
 

图5.3.1 hello的ELF格式
一、ELF头
https://i-blog.csdnimg.cn/blog_migrate/f984f35436f0974ef0ff7dc8c115e681.png
 

图5.3.2 ELF头
与可重定位文件的格式类似,ELF头形貌文件的总体格式,还包括程序的入口点,也就是当程序运行时要实行的第一条地点(如图第11行)。
二、节头部表
https://i-blog.csdnimg.cn/blog_migrate/ea7c976f94157445245eb4f0a79f0209.png
 
 
图5.3.3 节头部表
其与hello.o 的节头部表对于节信息的形貌范围一致,包括:节的名称,范例,地点、偏移量以及对齐信息等
三、程序头部表
https://i-blog.csdnimg.cn/blog_migrate/20083d554493752ad24762737a7fea25.png
 

图5.3.4程序头部表
程序头部表用于形貌一种映射关系,可实行文件的连续片被映射到连续的内存段。
从程序头部表我们会看到根据可实行目标文件的内容初始化为四个内存段,以第一个段为例(第五第六行)有读/实行访问权限,地点开始于0x400000。
四、动态链接段表
https://i-blog.csdnimg.cn/blog_migrate/b0970fda99a562742d397962364de2aa.png
 

图5.3.5动态链接段表
存放着动态链接的信息,比方名称、范例等。
五、重定位的节
https://i-blog.csdnimg.cn/blog_migrate/199ac73f76d5f9c9d771343d215062c6.png
 

图5.3.6重定位的节
我们可以从图中分析得出偏移地点、基址信息、链接器识别修改范例、重定位到目标的名称等。
六、符号表
https://i-blog.csdnimg.cn/blog_migrate/60ddbac5f1d4c8beb0bdfa5ddd7f79e1.png
 

图5.3.7符号表
5.4 hello的虚拟地点空间

https://i-blog.csdnimg.cn/blog_migrate/2c36759873b2512830e6eb294191332f.png
 

图5.4.1edb加载hello
从0x00400000开始载入,节的排布与地点中相同
对照程序头分析:


程序头表中记录了运行时加载的内容,提供出各段的虚拟空间和物理内存的大小,读写权限、对其方式(之前已经分析)
以下是对程序头表中的各个范例举行分析
INTERP:表示动态链接器等
LOAD:从二进制文件映射到虚拟空间的段,生存了常量数据与代码等相干内容。
DYNAMIC:动态链接器的实用信息
NOTE:辅助信息
GNU_STACK:栈实行允许标志
GNU_RELRO:重定位后的内存只读地域。
5.5 链接的重定位过程分析

https://i-blog.csdnimg.cn/blog_migrate/57f9676c91452ca9ff2a82a928271bde.png
 

图5.5.1在shall 下生成可实行文件hello的反汇编文件
hello与hello.o的差别:
1.hello中多了.init 和.plt节
https://i-blog.csdnimg.cn/blog_migrate/9d0652b35f94cf34e52f1907f8f6c7fa.png
 

图5.5.2 新增的.init和.plt节
.init节定义了一个小函数,叫做_init,程序的初始化代码会用到它。而.plt节表示过程链接表,每一个plt条目都是一小段可实行代码。
2.hello中多了许多新函数
https://i-blog.csdnimg.cn/blog_migrate/a5fdf82852a8dd94cf2e17e466fa97ae.png
 

图5.5.3 新增的函数
这是新增的节中出现的函数
3.函数调用及一些跳转指令后接的是虚拟地点
https://i-blog.csdnimg.cn/blog_migrate/9dd78ae8f581df17cc1456c9c1c49293.png
 

图5.5.4跳转后接虚拟地点
因此分析得出,链接重定位的过程为:
一旦链接器完成了符号解析这一步,就把代码中的每个符号的引用和正好一个符号的定义关联起来,此时由于知道代码节数据节简直切的大小,因此链接器开始将所有相同范例的节合并为同一范例的新的聚合节,再把代码节和数据节中对每个符号的引用修改,使得他们指向正确的运行地点,这一过程依靠于重定位条目,而重定位条目是基于汇编器遇到的终极位置未知的目标引用时生成的。

5.6 hello的实行流程

实行过程为:从_start、_libc _start_main开始,接着实行主函数中的过程:_main、_printf、_exit、_sleep、_getchar;末了退出。
https://i-blog.csdnimg.cn/blog_migrate/34763a6cae9fd0a6320a7473449b9700.png
 

图5.6.1
根据上图并对照之前图片分析得到
子程序名以及地点:
_start    0x4010f0
_libc_start_main     0x2f12271d
_main        0x401125
_printf        0x401040
_exit     0x401070
_sleep       0x401080
_getchar  0x401050
5.7 Hello的动态链接分析

动态链接: 共享库是一个目标模块,在运行或加载中,可以加载到恣意的内存地点,并且和内存中的程序链接起来的过程。动态库不需要像静态库一样,需要定期维护与更新,而且也不需要消耗大量的内存。
当程序调用一个由共享定义的函数时,编译器无法猜测地点,我们可以通过延迟绑定的方式,将过程地点的绑定推迟到第一次调用该过程时。
延迟绑定通过GOT和PLT实现,GOT是数据段的一,PLT是代码短的一部分。接下来我们团结详细例子分许动态链接:
https://i-blog.csdnimg.cn/blog_migrate/f48b84f9649dfd27278aede6204f95c7.png
 

图5.7.1
由上图分析,GOT起始位置为0x404000
https://i-blog.csdnimg.cn/blog_migrate/d13a3169eeff088c14facb7b0e2cc09a.png
 

图5.7.2
然后在_start函数前设置断点,再次查看,发现0x404008和0x404010处的两个8字节的数据发生改变,分析得出0x7f445f3cf190和0x7f445f3b8ae0,这就是GOT和GOT的地点。
5.8 本章小结

详细分析了链接的概念以及作用,分析白shall命令行下的链接指令,并对hello的ELF格式各个部分举行了分析,还使用edb加载hello,查看本了历程的虚拟地点空间各段信息,并通过反汇编hello文件,将其与hello.o反汇编文件举行了对比,详细了解了重定位过程;此外,还遍历了整个hello的实行过程,在末了对hello举行了动态链接分析。


第6章 hello历程管理

6.1 历程的概念与作用

       历程的概念:历程是操作系统对正在运行的程序的一种抽象,历程的定义是具有独立功能的一个程序关于某个数据集合的一次运行活动。历程会提供一种系统上似乎只有某一个程序在运行,而且该程序看上去是独占地使用处理器、主存、I/O设备,该程序的代码和数据是系统内存中唯一的对象的假象。
       历程的作用:给应用程序提供两个抽象:1. 一个独立的逻辑控制流2.一个私有地点
6.2 简述壳Shell-bash的作用与处理流程

作用:读取用户命令行,串联用户与内核,也就是说shall是用户与操作系统之间        交互的窗口。
处理流程:1.用户对shall输入的命令举行解析
                 2.shall切分命令,判定范例并且据此得到参数
                 3.判定其是否为内置命令,是则实行
                 4.如果不是,fork一个子历程实行命令
                 5.子历程完毕后由父历程回收

6.3 Hello的fork历程创建过程

       在终端输入./+可实行文件名,shell将会对此内容举行分析解读。判定出其为可实行文件后,shell将会调用fork创建一个新的子历程,然后在这个子历程中调用execve函数装入要实行的程序。产生的父历程和子历程是相互独立的,但是同时实行的。当子历程先于父历程结束,父历程负责子历程空间的回收工作并开释;如果晚于父历程结束,子历程变成孤儿历程,系统将自身负责回收孤儿历程。
6.4 Hello的execve过程

子历程创建成功之后,子历程调用execve函数在当前的上下文空间运行hello程序,详细步调如下:
1.删除当前用户虚拟地点中的已存在地域结构
2. 为代码、数据、.bss和栈地域映射创建私有地域,并在写时举行复制。其中.bss地域和堆栈地域请求二进制零。
3.当存在与hello程序由共享对象链接的,如尺度库libc.so,将其动态链接并虚拟共享到用户虚拟地点空间
4.设置程序计数器,使得下次运行时能从代码地域入口点举行。

6.5 Hello的历程实行

       shell接收到可实行文件的实行命令,fork创建出一个子历程。此子历程将调用execve函数在当前历程的上下文中加载并运行刚才的可实行文件。加载器删除子历程现有的虚拟内存,并创建一块新的空间并初始化为0。然后,通过将虚拟地点空间中的页映射到可实行文件的页,代码段和数据段都会被设置为可实行文件的内容。
       当hello调用getchar的时候,实际实行输入流是stdin的系统调用read函数,hello之前运行在用户模式,在举行read调用之后进入内核,内核中的陷阱处理程序请求来自键盘缓冲区的DMA传输,并且安排在完成从键盘缓冲区到内存的数据传输后,中断处理器。此时进入内核模式,内核实行上下文切换,切换到其他历程。当完成键盘缓冲区到内存的数据传输时,引发一个中断信号,此时内核从其他历程举行上下文切换回到hello历程。
6.6 hello的异常与信号处理

程序中可能出现的异常如下:1. 外部I/O设备引起的中断异常2.函数调用相干3.缺页故障 4.缓存器破坏造成的奇偶错误
 1.正常停止:
https://i-blog.csdnimg.cn/blog_migrate/1d6f7926b30f164ef48af454afb29f39.png
 

图6.6.1历程以回车结束
2.不停乱按
https://i-blog.csdnimg.cn/blog_migrate/8b18f62cf5c4aef69ae34c3ab71cd8e5.png
 

图6.6.2
键盘中的输入进入缓冲区stdin,当getchar()的时候读出一个’\n’结尾的字串,当hello结束后stdin中的字符会被shall看成命令行输出,因此乱输入会出如今每次历程的内容之前输出,不会影响内容输出。
3.疯狂按回车
https://i-blog.csdnimg.cn/blog_migrate/25a48a4773e1186ebb38b68758634e79.png
 

图6.6.3
每次键入一个回车键就会多空出一行并且会引起当前子历程结束,增加一次回到shell请求用户输入命令的历程
4.输入Ctrl C
https://i-blog.csdnimg.cn/blog_migrate/068a2d46b39b63aceb9133de6bb091f6.png
 

图6.6.4
输入Ctrl C会让程序终止,通过ps观察得出结论
5. 输入Ctrl Z
https://i-blog.csdnimg.cn/blog_migrate/fc0f254e6c13c6d4aa1864ddd88e37f6.png
 

图6.6.5
输入Ctrl Z程序不会终止仅是停止,也就是说hello程序被挂起,此时可以输入各种命令查看工作信息/杀死历程,程序仍可规复运行。
https://i-blog.csdnimg.cn/blog_migrate/9ff3b003a01c398b63facb2215ff6e12.png
https://i-blog.csdnimg.cn/blog_migrate/09e43b34c03b9f5e9d1b86a9b53cadaf.png https://i-blog.csdnimg.cn/blog_migrate/c8537e6d2b7ccdb1e8283879e0099d4a.png
 
 



图6.6.6
6.7本章小结

本阶段先容了历程的概念和作用,先容了shell的功能和工作机制,末了通过hello程序加强对信号处理的了解。

第7章 hello的存储管理

7.1 hello的存储器地点空间

团结hello分析逻辑地点、线性地点、虚拟地点、物理地点的概念。
7.2 Intel逻辑地点到线性地点的变更-段式管理

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

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

7.5 三级Cache支持下的物理内存访问

7.6 hello历程fork时的内存映射

7.7 hello历程execve时的内存映射

7.8 缺页故障与缺页中断处理

7.9动态存储分配管理

Printf会调用malloc,请简述动态内存管理的根本方法与战略。
7.10本章小结


第8章 hello的IO管理

8.1 Linux的IO设备管理方法

设备的模型化:文件
设备管理:unix io接口
8.2 简述Unix IO接口及其函数

8.3 printf的实现分析

从vsprintf生成显示信息,到write系统函数,到陷阱-系统调用 int 0x80或syscall等.
字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。
显示芯片按照革新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。
8.4 getchar的实现分析

异步异常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,生存到系统的键盘缓冲区。
getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回。
8.5本章小结






结论

hello的经历了代码撰写、预处理、编译、汇编、链接、运行、创建子历程、加载、实行指令、访问内存、动态内存分配、发送信号、终止的过程。
(1)   预处理:将.c文件生成.i文件,将.c中调用的外部库展开合并到.i中
(2)   编译:由.i生成.s汇编文件
(3)   汇编:将.s文件翻译为机器语言指令,并打包成可重定位目标程序.o
(4)   链接:将.o可重定位目标文件和动态链接库链接成可实行目标程序hello
(5)   运行:在shell中输入命令
(6)   创建子历程:shell用fork为程序创建子历程
(7)   加载:shell调用execve函数,将hello加载到子历程,映射出虚拟内存
(8)   实行指令:CPU为历程分配时间片,加载器将计数器预置在程序入口点,               则hello可以次序实行自己的逻辑控制流
(9)   访问内存:MMU将虚拟内存地点映射成物理内存地点,CPU通过其来           访问
(10) 动态内存分配:根据需要申请动态内存
(11) 信号:shell的信号处理函数可以接受程序的异常和用户的请求
(12) 终止:实行完成后父历程回收子历程,内核删除为历程创建的数据结                         构
附件

列出所有的中间产物的文件名,并予以分析起作用。
      hello.c:程序源代码
      hello.i:预处理之后得到的修改了的文本文件
      hello.s:编译器编译后得到的汇编语言文本文件
      hello.o:汇编器生成的可重定位目标文件(二进制文件)
      hello:  链接得到的可实行目标文件(二进制文件)
      hello_elf1:可重定位文件生成的elf格式文件
      hello_elf2:可实行文件生成的elf格式文件
      asm1.txt: 可重定位文件反汇编生成的汇编语言文本文件
      asm2.txt: 可实行文件反汇编生成的汇编语言文本文件



参考文献

  林来兴. 空间控制技术. 北京:中国宇航出版社,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.


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