马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
计算机科学与技术学院
2022年5月
摘 要
本文通过对hello程序在linux体系中的一生的研究,探讨预处置处罚编译,汇编,链接,进程,储存的过程,深入理解hello.c程序,联合《深入理解计算机体系》内容,对本学期所学的知识举行梳理总结,加深对计算机体系的理解
关键词:计算机体系;预处置处罚;编译;汇编;链接;进程;储存
目 录
第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简介
P2P即Program to Process,是指将hello.c从可实行文件变为进程的过程,先后经过预处置处罚、编译、汇编、链接得到可实行文件,末了在shell中创建进程。
020即From 0 to 0,详细理解为:初始时内存中并没有hello.c的相关内容,在shell中调用execve函数,hello.c的内容将载入内存中,并实行相关代码。在程序运行完毕后,进程被回收。
1.2 环境与工具
1.2.1 硬件环境
ThinkBook 14+
AMD Ryzen 7 6800H with Radeon Graphics 3.20 GHz
AMD Radeon Graphics 680m
16.0GB (13.7GB可用)
512GB固态硬盘
1.2.2 软件环境
Windows 11 家庭中文版 22H2
Visual Studio Community 2022
VMware Workstation Pro 17
Ubuntu 22.04.2 LTS
1.2.3 开发工具
Visual Studio Community 2022
Code::Blocks IDE
EDB
1.3 中间效果
hello.i
| 预处置处罚后得到的文本文件
| hello.s
| 编译后得到的汇编语言文件
| hello.o
| 汇编后得到的可重定位目标文件
| hello.elf
| 用readelf读取hello.o得到的ELF格式信息
| hello
| hello.c的可实行文件
|
1.4 本章小结
先容了P2P和020的过程,并给出了实验环境,以及期中生成的文件
第2章 预处置处罚
2.1 预处置处罚的概念与作用
预处置处罚是在编译之前的操纵,指在程序开始运行时,预处置处罚器根据以#起始的命令,修改原始的C语言,并生成一个XXX.i的文件的过程。
2.2在Ubuntu下预处置处罚的命令
gcc -E hello.c -o hello.i
图1 预处置处罚hello.c
2.3 Hello的预处置处罚效果解析
发现很短的hello.c变成了3091行的文本文件,因为预处置处罚过程中将stdio.h 、unistd.h、 stdlib.h展开,而原hello.c的main函数在末端
图2 预处置处罚效果(部分)
图3 main函数在hello.i的部分
2.4 本章小结
本章对预处置处罚举行的分析,论述了预处置处罚过程的概念和作用,并在linux下实行了hello.c的预处置处罚过程,生成了hello.i文件,并对hello.i文件举行了开端的分析。
第3章 编译
3.1 编译的概念与作用
编译为通过分析(词法分析、语法分析),将合法的指令翻译成汇编代码的过程。具体概念为cll将合法的.i文件翻译为.s文件
3.2 在Ubuntu下编译的命令
gcc -S hello.i -o hello.s
3.3 Hello的编译效果解析
3.3.1 数据:
常量:
函数中的if语句的4生存在.text中, for中的0、9、1、2、3也生存在.text中。
printf()字符串将会生存在.rodata中
变量:有局部变量i被生存在栈上
3.3.2 赋值:
赋值操纵有for语句中的=,为给i赋值0
3.3.3 算术操纵:
算数操纵有for循环中的i++;给i+1,由add指令来实现,
3.3.4 关系操纵:
关系操纵有两个,分别是if语句中的!= 和for语句中的<
3.3.5 数组/指针/结构操纵:
数组/指针/结构操纵有main函数中吸收的指针数组char *argv[]
3.3.6 控制转移:
控制转移有三个,一个是if语句,一个是无条件跳转,一个是for语句中的判断身分
3.3.7 函数操纵:
函数操纵通过call指令调用过程
3.4 本章小结
本章论述了编译的概念、作用和过程。先容了汇编代码对应的各种数据、操纵。
第4章 汇编
4.1 汇编的概念与作用
汇编是将汇编语言转化为呆板语言指令,并把这些指令打包成一个可重定位目标文件的格式,生成目标文件.o文件
4.2 在Ubuntu下汇编的命令
gcc -c hello.s -o hello.o
!
图5 生成hello.o
4.3 可重定位目标elf格式
典范的ELF格式的可重定位目标文件的结构如下:
图6 elf结构
生成hello.o文件elf格式的命令:readelf -a hello.o
图7 表现elf格式
通过如上图可知:hello.o中共有13个节,8个重定位条目,7个全局符号
4.4 Hello.o的效果解析
输入objdump -d -r hello.o得到了hello.o中实行代码的反汇编效果
图8 反汇编效果
经过对比发现hello.o反汇编代码和hello.s文件基本一样,只有部分不同。
- 分支转移不同,.s文件是通过指令jmp,je等直接跳转到对应的代码。而反汇编代码中,转移时通过地点举行跳转的。
- 函数调用不同, .s文件中是通过call+函数名称举行调用函数。而在反汇编代码中,call后跟的是下一条指令。因为这些函数都是共享库函数,地点是不确定的,所以call指令后面还会有为链接专门空出的空间,等待链接器的下一步的重定位、链接。
- 全局变量不同, .s文件中,利用段地点+%rip访问rodata完成的,而在反汇编代码中,则是:0+%rip举行访问,因为.rodata节中的数据是在运行时确定的,也必要重定位,将操纵数设为0并给.rela.text添加重定位条目。
4.5 本章小结
本章论述了汇编的概念和作用,并通过生成的elf文件对eld格式结构举行了研究,比对了.asm和.s的雷同和不同之处。
第5章 链接
5.1 链接的概念与作用
链接是指通过链接器将不同文件的数据和代码综合到一起,并生成一个可以在程序中加载和运行的单一的可实行目标文件的过程
5.2 在Ubuntu下链接的命令
命令:ld -o hello.o -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 /usr/lib/gcc/x86_64-linux-gnu/9/crtbegin.o hello.o -lc /usr/lib/gcc/x86_64-linux-gnu/9/crtend.o /usr/lib/x86_64-linux-gnu/crtn.o -z relro -o hello
图9 生成可实行文件
5.3 可实行目标文件hello的格式
命令:readelf -a hello
ELF头:hello的ELF头和hello.o的ELF头基本雷同,不同之处:hello为可实行文件,节头有27个,type为EXEC
图10 elf头
.节头:包罗了对所有节的声明。
图11 节头
程序头表:
图12 程序头表
动态节:
图13 动态节
可重定位条目:
图14 可重定位条目
符号表
图15 符号表
版本信息
图16 版本信息
5.4 hello的虚拟地点空间
从程序头可以看出客家在的地点为0x400000,
图17 程序头
利用edb打开hello,从Data Dump找到0x400000:
图18 Data Dump
也可以根据5.3中的信息,在edb中找到各段的信息
如.text节的信息:
图19 .text对应的Data Dump表
5.5 链接的重定位过程分析
objdump -d -r hello
图20 反汇编效果
不同:可实行文件的反汇编效果的内容中多了很多函数代码,这些函数是链接器把共享库中hello.c用到的函数也加入到文件中;另一个不同是地点不同,因为重定位后把相对地点替换为了虚拟地点(重定位后)或绝对地点(call指令跳转)。
重定位分析:
- 重定位节和符号定位:链接器将所有雷同类型的节归并为同一类型的聚合节,然后链接器将内存地点给新的聚合节、输入模块定义的每个节和符号。
- 重定位节中的符号引用:链接器修改代码节和数据节中对每个符号的引用,让他们指向精确的运行时地点。
5.6 hello的实行流程
记载如下:
401000 <_init>
401020 <.plt>
401030 <puts@plt>
401040 <printf@plt>
401050 <getchar@plt>
401060 <atoi@plt>
401070 <exit@plt>
401080 <sleep@plt>
401090 <_start>
4010c0 <_dl_relocate_static_pie>
4010c1 <main>
401150 <__libc_csu_init>
4011b0 <__libc_csu_fini>
4011b4 <_fini>
图21 edb运行程序
5.7 Hello的动态链接分析
动态链接为把程序拆分成各个相对独立的部分,在程序运行的时间将其链接起来。在调用共享库函数的时间编译器为其生成一条重定位记载,在程序加载的时间链接器再解析它。
由图可知got起始表位置在0x404000
调用之前:
图22 调用之前
调用之后:
图23 调用之后
5.8 本章小结
本章论述了链接的概念和作用,通过edb检察,和hello和hello.o的反汇编代码的区别,探讨了链接中重定位的过程。
第6章 hello进程管理
6.1 进程的概念与作用
进程是指一个实行中的程序的实例,大概可以定义为一个具有一定独立功能的程序关于某个数据聚集的一次运行活动。进程是体系举行资源分配和调理的基本单元,是操纵体系结构的底子。
6.2 简述壳Shell-bash的作用与处置处罚流程
- 终端输入./hello
- Shell解释器构造argv和envp
- 调用fork()创建子进程
- 调用execve()再当进步程的上下文加载并运行hello程序
- 调用hello中的main函数。
6.3 Hello的fork进程创建过程
获取实行命令之后,父进程判断是否是内部指令,如果是就立即实行,如若不是就通过fork函数创建子进程,子进程地点空间与父进程完全雷同。Fork函数只被调用一次,但是会返回两次,父进程返回子进程的UID,子进程中,返回0。子进程运行结束后,如果父进程还存在,就对子进程回收,否则就由init进程回收子进程。
6.4 Hello的execve过程
Execve函数在当进步程的上下文中加载并运行一个新程序。execve函数加载并运行可实行目标文件filename,且带参数列表argv和环境变量列表envp。与fork一次调用返回两次不同,execve调用一次,不返回。
6.5 Hello的进程实行
联合进程上下文信息、进程时间片,论述进程调理的过程,用户态与焦点态转换等等。
进程上下文:一样平常在进程切换中提到,进程控制块PCB,生存着进程的诸多详细信息,当进程要切换时当进步程的寄存器内容以及内存页表的详细信息等等内容,也就是关于形貌进程的信息。
进程时间片:即CPU分配给各个程序的时间,每个线程被分配一个时间段,称作它的时间片,即该进程答应运行的时间,使各个程序从表面上看是同时举行的。如果在时间片结束时进程还在运行,则CPU将被剥夺并分配给另一个进程。如果进程在时间片结束前阻塞或结束,则CPU立即举行切换。
进程调理:当内核选择一个新的进程运行时,则内核调理了这个进程。在内核调理了一个新的进程运行后,它就抢占当进步程,并利用上下文切换机制将控制转移到新的进程。
用户态与焦点态:进程hello初始运行在用户模式中,知道它通过实行体系调用exit,sleep和getchar时便陷入内核。内核中的陷阱处置处罚程序完成对体系函数的调用。7之后,内核实行上下文切换,将控制返回给hello紧随体系调用之后的那条语句。
6.6 hello的非常与信号处置处罚
正常运行效果:
图24 正常运行效果
不绝乱按:不影响进程实行
图25 乱按效果
按回车:
图26 按回车效果
按Ctrl+C:收到SIGTSTP,进程中断。
图27 按Ctrl+C效果
按Ctrl+Z:进程暂停
图28 按Ctrl+Z效果
之后运行ps:获取所有进程的状态
图29 运行ps效果
运行jobs:打印所有作业
图30 运行jobs效果
运行Fg:使暂停的进程继续作为前台作业运行,
图31 运行fg效果
运行Kill:停止处于暂停的hello作业。
图32 运行kill效果
6.7本章小结
本章论述了进程的概念和作用和shell的作用和过程,同时了解到非常与信号机制。
第7章 hello的存储管理
7.1 hello的存储器地点空间
逻辑地点:逻辑地点指的是呆板语言指令中,用来指定一个操纵数大概是一条指令的地点
线性地点:跟逻辑地点类似,它也是一个不真实的地点,如果逻辑地点是对应的硬件平台段式管理转换前地点的话,那么线性地点则对应了硬件页式内存的转换前地点
虚拟地点:这是对整个内存的抽像形貌。它是相对于物理内存来讲的,可以直接理解成“不直实的”,“假的”内存,
物理地点:用于内存芯片级的单元寻址,与处置处罚器和CPU连接的地点总线相对应
7.2 Intel逻辑地点到线性地点的变动-段式管理
逻辑地点为段选择符+偏移量,每个段选择符为16为大小,段形貌符为8字节,CPU会通过段选择定位到GDT/LDT中的段形貌符,通过这个段形貌符得到的段的基址,和段内偏移地点加起来就是线性地点。
7.3 Hello的线性地点到物理地点的变动-页式管理
虚拟内存被分为多少页,CPU取一个线性地点的高多少位,通过他们在页表里查询对应的页表条目,得到对应的物理页起始地点,然后和线性地点的低位相加就是物理地点。
7.4 TLB与四级页表支持下的VA到PA的变动
以Intel i7为例,i7为四级页表。
CPU产生VA(虚拟地点),传给MMU(内存管理单元),MMU向TLB寻找,如果命中就返回PA(物理地点),如果没有命中,MMU查询页表,CR3确定第一级页表的起始地点,VPN1确定在第一级页表中的偏移量,查询出PTE,同理,末了在第四级页表找到PPN,PPN和VPO组合成PA,
7.5 三级Cache支持下的物理内存访问
CPU为了快速访问内存,利用三级Cache缓存,将之前访问过的内存块存在缓存中,当CPU对一个物理地点访问时,先去L1检察是否有对应的内存块,如果有就直接访问L1,如果没有就依次L2,L3访问,如果都没有就去内存访问,并将块加载到L3L2L1缓存上。
7.6 hello进程fork时的内存映射
Fork函数被调用时,将会创建子进程,并为子进程提供各种数据结构,分配这个子进程一个PID,为了给这个新进程创建虚拟内存,它创建了当进步程的 mm_struct、区域结构和页表的原样副本。它将两个进程中的每个页面都标记为只读,并将两个进程中的每个区域结构都标记为私有写时复制。
当 fork 在新进程中返回时,新进程现在的虚拟内存刚好和调用 fork 时存在的虚拟内存雷同。当这两个进程中的任一个厥后举行写操纵时,写时复制机制就会创建新页面,因此,也就为每个进程保持了私有地点空间的抽象概念。
7.7 hello进程execve时的内存映射
execve函数加载并运行hello必要以下几个步调:
- 在bash中的进程中实行execve调用
- execve函数在当进步程中加载并运行包罗在可实行文件hello中的程序,用hello替换了当前bash中的程序。
3. 删除已存在的用户区域
4. 映射私有区域
5. 映射共享区域
6. 设置程序计数器
7.8 缺页故障与缺页中断处置处罚
缺页故障指的是当软件试图访问已映射在虚拟地点空间中,但是现在并未被加载在物理内存中的一个分页时,由中心处置处罚器的内存管理单元所发出的中断。
缺页中断处置处罚:
(1) 保存进程上下文
(2)判断内存是否有空闲可用帧,若有,则获取一个帧号No,转(4) 启动I/O过程。若无,继续(3)
(3)腾出一个空闲帧,即:
(3)-1调用置换算法,选择一个镌汰页PTj。
(3)-2 PTj(S)=0 ; //驻留位置0
(3)-3 No= PTj (F); //取该页帧号
(3)-4 若该页曾修改过,则
(3)-4-1 请求外存交换区上一个空闲块B ;
(3)-4-2 PTj(D)=B ; //记载外存地点
(3)-4-3启动I/O管理程序,将该页写到外存上。
(4)按页表中提供的缺页外存位置,启动I/O,将缺页装入空闲帧No中。
(5)修改页表中该页的驻留位和内存地点。PTi(S)=1 ; PTi(F) =No。
(6)结束。
7.9动态存储分配管理
有些操纵对象只有在程序运行时才能确定,这样编译器在编译时就无法为他们预定存储空间,只能在程序运行时,体系根据实行的必要,部分地震态装入。同时,在装入主存的程序不实行时,体系可以收回该程序所占据的主存空间。这种方法称为动态内存分配。所有动态存储分配都在堆区中举行。
再者,用户程序装入主存后的位置,在运行期间可根据体系必要而发生改变。别的,用户程序在运行期间也可动态地申请存储空间以满足程序需求。由此可见,动态存储分配方式在存储空间的分配和释放上,表现得十分灵活,今世的操纵体系常采用这种存储方式。
7.10本章小结
本章论述了存储的机制,形貌了四种地点的定义,给出了fork函数和execve函数的内存映射,诠释了动态存储分配管理
结论
通过大作业对这7部分的分析,我们可以用以下这一系列步调来论述hello所经历的一切:
- 预处置处罚:对hello.c文件举行预处置处罚(cpp),得到hello.i文件
- 编译:通过分析(词法分析、语法分析)将合法指令翻译成汇编代码,得到hello.s文件
- 汇编:将hello.s文件翻译成一个可重定位目标文件hello.o
- 链接:把hello.o文件和可重定位目标文件和动态库链接起来,生成可实行文件hello
- 运行:在shell中运行 ./hello
- 进程:利用fork函数创建子进程
- 加载:利用execve函数为新进程把代码和数据载入虚拟内存空间,开始实行程序
- 实行指令:CPU分配时间片,hello享有CPU资源,次序实行自己的控制逻辑流
- 访问内存:通过MMU将逻辑地点映射成物理地点,
- 动态内存:printf会调用malloc函数向动态内存分配器申请堆中的内存
- 信号处置处罚:键入ctrl+c或ctrl+z对进程举行操纵,+c是停止,+z是挂起
- 结束:父进程等待并回收子进程,内核删除为进程创建的数据结构
感悟:通过这次实验,我深刻的感受到计算机的功能强大和结构操纵精细,运行一个小小的hello.c也必要背后大量的机制操纵来支撑。驻足回望,从接触计算机的第一个hello world到现在的hello.c,变化的是年岁,见地,知识,不变的是对计算机科学的一片激情密切!
附件
hello.i
| 预处置处罚后得到的文本文件
| hello.s
| 编译后得到的汇编语言文件
| hello.o
| 汇编后得到的可重定位目标文件
| hello.elf
| 用readelf读取hello.o得到的ELF格式信息
| hello
| hello.c的可实行文件
|
参考文献
[1] 《深入理解计算机体系》 Randal E.Bryant David R.O’Hallaron 机器工业出版社
[2] https://blog.csdn.net/qq_43101637/article/details/106646554
[3] https://blog.csdn.net/TYUTyansheng/article/details/108148566
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |