可执行文件的生成和进程的运行

Computer System 专栏收录该内容
4 篇文章 0 订阅

关于这篇文章

博客所涉及的基础知识来自于机械工业出版社的《计算机系统基础》、《编译原理》和《操作系统教程》和其他博友的相关总结。这篇文章旨在初步了解在IDE开发中编写完毕的高级语言源程序从点击编译按钮到控制台响应的一系列转换过程,并以实例来探究可重定位目标文件和可执行目标文件的相互关系。

研究背景

体系结构:IA-32(X86-32)    操作系统:Ubuntu16.4    汇编代码格式:AT&T    高级语言:C语言

第一部分 从点击编译按钮到链接结束——可执行文件的生成

一、预处理

    命令:$gcc -E hello.c -o hello.i
    操作:通过处理源文件中以"#"开头的预编译指令进行宏替换。
    结果:得到一个可读但不包含任何宏定义的文本文件,称为预处理文件。
具体如下:


 图片不见了。。。

二、编译

    命令:$gcc -S hello.i -o hello.s
    操作:通过编译程序将预处理文件进行词法分析、语法分析、语义分析、中间代码生成、代码优化和代码生成。
    结果:得到一个汇编语言源文件。
具体如下:


I.词法分析

词法分析器会根据高级语言源程序的字符流,将每一个字符构建成为一个结构体——词法单元,从而获得一连串的词法单元序列,为下一步语法分析做准备。

 图片不见了。。。
II.语法分析

语法分析器通过一种树形的中间表示如"语法树"来表示词法单元序列的语法结构,从而判断是否是一个符合语法规范的表达式,如检查语法树发现某表达式中存在二元操作符却只有一个操作数,则不符合语法,编译器报错。

 图片不见了。。。
III.语义分析

语义分析器会根据语法树和符号表中的信息来检查高级语言源程序是否和语言定义的语义一致,并对语法树和符号表进行更新,主要涉及类型检查和自动类型转换等部分,如某表达式的语义是70+30,但不小心把70写成浮点数类型,30写成整数类型,那么在经过例行的类型检查后,需要自动类型转换将二者操作数类型加以转化,在这儿是把30拓展成浮点数类型。

 图片不见了。。。
IV.中间代码生成

根据更新后的语法树生成一个源程序的明确的低级的中间表示,作为从高级语言格式到汇编语言格式的过渡形式。

 图片不见了。。。
V.代码优化

通过尽可能消除中间表示的冗余部分,使其更加精简、高效。

 图片不见了。。。
VI.代码生成

代码生成器通过为每一个变量分配寄存器或内存单元的手段来将中间表示映射成最终的汇编语言格式。

 图片不见了。。。
(注:这儿只给出对应的汇编伪代码,非IA-32指令集)

三、汇编

    命令:$gcc -c hello.s -o hello.o
    操作:通过汇编程序将汇编语言源文件转换成机器指令序列,并将源文件中具有相同特征的最小可处理单位在目标文件中统一划分成对应节。
    结果:得到一个不可读的二级制代码文件,称为可重定位目标文件。
具体如下:


 图片不见了。。。
ELF头包含链接过程所用的目标代码信息,如二进制表示方式、排序方式,ELF头本身大小、节头表大小和操作系统类型等
.text节编译后的目标代码部分
.rodata节只读数据,如printf格式串
.data节已初始化的全局变量
.bss节未初始化全局变量,不占磁盘空间。区分初始化和非初始化节是为了空间效率
.symtab节存放函数和全局变量信息,也就是符号表所在的节。注意不包含局部变量
.rel.text节.text节的重定位信息,用于链接过程的.text节中的符号引用处地址的修改
.rel.data节.data节的重定位信息,用于链接过程的.data节中的符号引用处地址的修改
.debug节调试用符号表
.strab节包含.symtab和.debug节中符号及节名
.line节包含调试信息,包括哪些调试符号的行号,为程序指令码与源文件的行号建立联系
节头表除ELF头外,是可重定位目标文件最重要的部分,用于描述每个节的节名、在文件中偏移、大小和对齐方式等

四、链接

    命令:$gcc -static -o myproc main.o test.o
    操作:将多个可重定位目标文件进行符号解析、合并和重定位操作。
    结果:仍然得到一个不可读的二级制代码文件,称为可执行目标文件。
具体如下:


I.符号解析

将每个符号引用都与一个确定的符号定义建立关联,因为是根据引用来逐一寻找定义,因此允许存在符号定义的数量大于符号引用的数量的情况。

 图片不见了。。。
II.合并

将多个可重定位目标文件的相同的节合并成一个单独的可执行目标文件的同名节,如多个文件中的.text节共同合并成一个单独的.text节。

 图片不见了。。。
III.重定位

计算每个符号定义在虚拟地址空间中的绝对地址,再根据该绝对地址去修改符号引用处的地址信息。


第二部分 从作业请求到控制台响应——进程的运行

当编译器生成可执行目标文件后,便向CPU请求加载文件以期望运行,直到控制台响应,看似直截了当,实际上从作业请求到控制台响应整个过程却有着诸多检测策略在路上充当检查站的作用。

一、基础知识

在我们具体分析整个检测过程前,我们需要先了解当前流行的操作系统的基本特性和IA-32计算机的组成结构。

分时操作系统
处理机调度时间片轮转算法RR,即处于就绪态的进程只允许一次性执行一个固定的时间片的时间,在当前进程运行完时间片后,便将CPU分配给就绪队列中的下一个进程
进程同步机制信号量机制,即使用PV操作实现多个进程之间的同步和互斥关系
死锁避免银行家算法,即进程每次请求资源,CPU会根据"分配对应资源后系统不会产生死锁"的原则来为进程分配资源,否则将拒绝请求,进程等待
死锁检测资源分配图,每隔一段时间便会自动执行检测当前系统是否存在死锁
内存分配与回收基于虚拟存储技术的请求分页存储管理机制,即将进程虚拟存储空间分成各个页面,物理内存空间也分成和页面相同大小的各个页框,将组成进程的页面分散存放在相应页框之中,避免了进程运行时需要一大块连续空间的窘境
页面置换最近最久未使用置换算法LRU,即若进程所拥有的页框都存放了对应页面,当需要访问新的页面时,按照最近最久未访问的策略来与特定页面发生置换,获取对应页框的使用权
Cache行和主存块的映射方式组相联映射,即将Cache分成若干行,主存分成若干主存块,存储数据的主存块分别映射到Cache固定组中的任一行
Cache中主存块替换最近最少用算法LRU,将最近最少用的存储块淘汰掉,将其对应的行置空,等待新的存储块存放
磁盘调度C-LOOK算法,即只会响应磁头移动方向上的磁道请求,当磁头移动方向上不再有请求,就立即让磁头放回至起点,重新扫描
设备分配动态分配方式,即进程运行过程中动态申请设备资源,而非在加载时便给它分配需要的所有资源
内部异常在CPU内部发生的意外事件,如指令所引起的意外事件,如缺页
外部中断在CPU外部发生的意外事件,如I/O设备所引起的意外事件,如设备数据已经准备完毕
I/O控制方式DMA方式,即CPU发出I/O命令,启动DMA控制器来处理数据传输的事宜,而此时CPU可以进行其它事情,当DMA控制器处理完毕再发送中断请求至CPU以期望其完成善后工作
IA-32计算机组成
CPU中央处理器作为计算机系统的运算和控制核心,是信息处理、程序运行的最终执行单元
Cache高速缓冲存储器主要由SRAM存储器组成,具有易失性,存放的内容是主存储器的部分备份,用于减少访问主存储器次数,从而增加程序执行效率
TLB相联高速缓冲存储器是Cache的变种,存放的内容是虚拟存储技术下的页表的部分备份
主存储器主要由DRAM存储器组成,采用双译码结构,主要用来存放指令和数据等信息,读取速度相比Cache慢
磁盘一种磁表面存储器,由磁记录介质、磁盘驱动器和磁盘控制器组成,主要用来存放大量指令和数据等信息,读取速度相比主存储器慢许多

二、从作业请求到CPU分配

在经过上述术语的简要介绍和策略算法的规定,已经可以在具体的环境下讲解从作业请求到控制台响应整个过程中操作系统扮演的角色。

在经过第一部分的操作成功生成可执行目标文件生成后,IDE将自动向操作系统发送作业请求来说明自身想要运行某程序的愿望,此时操作系统并非直接接纳该愿望,而是先通过查找系统资源表检测是否有足够的页框资源分配给该程序的进程,若资源不够则先进入后备队列等待,待其它进程释放资源后再考虑将作业加载进内存并进行进程初始化等操作,最后根据处理机调度算法RR与其他就绪队列的进程平分CPU时间,这时CPU通过将可执行目标文件中的ELF头中的程序虚拟起始地址字段作为EIP值,开始执行程序第一条指令。

 图片不见了。。。

三、控制台响应——进程的运行

即使在具体的策略条件下,在实际操作仍存在诸多变化,因此在这篇文章中选择性地按最槽糕的情况进行分析,期望用最少的内容来覆盖更多的变化,同时我也根据"功能的不同"将实际程序的汇编代码划分成以下五种可能情景。

I.含有形式地址的RM取数操作

当CPU执行RM取数指令时,会根据指令的寻址地址字段和形式地址字段计算出操作数的有效地址(虚拟地址),并尝试将有效地址转换为主存物理地址,为此CPU会优先访问TLB快表查找是否已存在二者的映射关系,如果不存在,则会根据当前进程的对应寄存器所保存的页表的主存物理地址读取页表内容至CPU,CPU再次在页表中查找。此时一定可以找到二者的映射关系,但在着手转化成主存物理地址之前,会先根据页表对应表项判断包含有效地址的相应页面是否已加载至主存空间,

如果不在则发生缺页内部异常将页面从磁盘加载到主存的页框中,具体为将断点(当前指令的地址,即RM取数指令地址)和程序状态字保存到相应寄存器中,根据专门的硬件查询电路识别异常,并获取中断类型号,在根据类型号到中断向量表中读取对应的中断服务程序的入口地址,通过执行中断服务程序来调用磁盘的驱动程序,在驱动程序中通过IO控制方式-DMA方式来启动磁盘工作(通过磁盘调用-CLOOK算法读取由磁盘地址确认的扇区信息并送至磁盘控制器的数据缓冲寄存器),此时CPU得到解放可以执行其他进程,此后由DMA控制器来控制相应页面的信息从磁盘到主存的传递过程,待信息全部传递完毕后DMA控制器发送中断请求至CPU以告知传输完成,

CPU在每一个指令周期末会检测是否有中断请求,若发现存在则进入中断响应,CPU状态为禁止中断,再将断点(当前指令的下一条指令地址,即其他进程的指令地址)和程序状态字保存到相应寄存器中,根据专门的硬件查询电路识别异常,并获取中断类型号,在根据类型号到中断向量表中读取对应的中断服务程序的入口地址,在中断服务程序中完成数据传输任务的善后工作,恢复断点和程序状态字并开中断,返回断点处继续执行其他进程。

此时已经把页面加载至主存的页框,若分配给进程的页框已经都存放了页面,则发生页面置换-LRU算法,将新页面成功存放至对应页框后,再进一步更新TLB和页表相应字段的信息,最后便是恢复异常时保存的断点和程序状态字,返回发生异常时的断点处继续执行。此时将重复最开始的操作,即访问TLB快表,此时由于TLB内容已经更新,此时可以找到RM取数指令中操作数的虚拟地址和物理地址的映射关系,故此时虚拟地址转化为物理地址。

在根据物理地址优先访问Cache的各行,如果不存在包含目标页面的主存块的行,再根据物理地址访问主存中的主存块,最后送至CPU和Cache,如果目标主存块在Cache中位置不够,则发生Cache主存块替换-LRU算法,完成取数操作。

 图片不见了。。。
II.进程同步操作

当就绪队列中存在多个进程共同使用信号量机制-PV操作实现对同一资源的互斥时,如果资源已经耗尽,那么剩余竞争进程会因此进入阻塞态,直到资源满足后才会被分配到就绪队列,重新分配CPU时间,若长时间未满足且内存空间不足则可能将进程从内存存放至磁盘,腾出内存空间,直到满足资源后再考虑重新运行。

III.过程调用操作

在整个过程调用操作中存在两个研究对象——调用者P和被调用者Q。当P开始调用Q时,首先会陆续将调用者保存寄存器的内容、入口参数(实参)和返回地址入栈,随后将CPU控制权移交至Q(实际上是将Q的第一条指令地址存到EIP中),Q得到控制权后开始保存P的栈帧信息,同时将被调用保存寄存器的内容送入栈,再进一步在栈中开辟自身的局部变量存放空间,开始执行,待Q执行完毕后恢复P的栈帧和释放自身局部变量空间,取出P存放在栈中的返回地址,将CPU控制权返还给P。

 图片不见了。。。
IV.系统调用操作

系统调用封装函数的汇编代码中存在陷阱指令,当CPU执行到陷阱指令后,会根据EAX寄存器中的系统调用号,选择执行一个相应的系统调用处理程序,并在系统调用处理程序中再次调用系统调用服务例程,最终在服务例程中实现系统函数功能。

 图片不见了。。。
V.进程切换操作

当进程占据CPU超过一个时间片后,就需要进行进程切换到另外一个进程,此时需要将当前处理器的寄存器上下文保存到当前进程的系统级上下文的现场信息中,将新进程系统级上下文中的现场信息作为新的寄存器上下文恢复到处理器的各个寄存器中,最后将CPU控制权转移到新进程中。
可执行目标文件加载时,只会将其部分节加载至主存,并和其余部分共同构建起一个进程的虚拟存储映像,在映像中存在这系统级上下文和用户级上下文两部分,其中系统级上下文又分为进程标识信息、进程现场信息、进程控制信息和系统内核栈,用户级上下文则分为用户堆栈、用户数据块、用户程序块和共享地址空间。

 图片不见了。。。

第三部分 实例演示——重定位目标文件与可执行目标文件的关系

I.初始材料
  1. sum.c
int sum(int a,int b)
{
    return a+b;
}
  1. main.c
int sum(int a,int b);
int main(void)
{
    int a=12;
    int res=sum(a,13);
    return 0;
}
II.可重定位文件的具体内容
1. main.o的主要内容
 图片不见了。。。
字段含义值的解释
Magic俗称魔数,确定文件的类型7f 为固定格式,剩余45、4c和46分别代表着’E’、‘L’、'F’字符的ASCII码的十六进制
入口点地址程序第一条指令的虚拟地址由于main.o非可执行目标文件,故这儿默认为0
程序头起点程序头在文件的起始偏移量由于非可执行目标文件,不含有程序头,故默认为0
Start of section headers节头表在文件的起始偏移量节头表的第一个字节位于距重定位目标文件开头516B处
本头的大小ELF头本身所占空间大小一般固定为52B大小,开辟了同样空间,区别仅在于有没有存值
程序头大小- -由于非可执行目标文件,不含有程序头,故默认为0
Number of program headers程序头表中表项的个数由于非可执行目标文件,不含有程序头,故默认为0
节头大小节头表中每一表项所占空间每一表项分别占用固定大小空间40B
节头数量节头表中表项的数量节头表中一共有12个表项,对应main.o文件中存在12个节
 图片不见了。。。
字段含义值的解释
Value符号定义的虚拟地址因为非可执行目标文件,故默认为0
Size符号定义的大小一般只有符号定义才会分配空间,故函数名和变量名,否则默认为0
Type符号的类型一般分有’NOTYPE’未定义、'SECTION’节、'FILE’文件、'FUNC’函数和’OBJECT’变量
Bind符号的绑定属性一般分有’LOCAL’本地变量、'GLOBAL’全局变量、'WEAK’弱符号
Ndx存储符号定义的节号- -
Name符号具体名称比如main函数所定义的main函数名和调用的sum函数名
 图片不见了。。。
字段含义值的解释
偏移量符号引用在可重定位目标文件的偏移量比如在main.o中sum函数的调用的指令位于距文件21H处
类型重定位类型有符号引用处的有效地址就是重定位后的值’R_386_PC32’ 和 有效地址是重定位的值加上当前PC的值’R_386_32 '两种
符号名称符号引用的符号名比如main.o所调用的sum函数名
 图片不见了。。。
字段含义值的解释
Name可重定位目标文件的节名- -
Addr节的第一个字节在虚拟地址空间的虚拟地址由于非可执行目标文件,故默认为0
Off节的第一个字节在可重定位目标文件的偏移量比如.text节位于main.o文件开头后34H处
Size节所占的空间大小比如.text节存储需要38B的空间
Al节存放时所按照的对齐方式比如.rel.text节是按照4B的对齐方式

根据ELF头中的本头的大小、Start of section headers、节头大小和节头数量字段,我们可以得出ELF头大小和节头表偏移量和大小,再结合节头表各节的Name、Off和Size字段,我们可以得出可重定位目标文件main.o的具体格式。

 图片不见了。。。

2. sum.o的主要内容
 图片不见了。。。
 图片不见了。。。
 图片不见了。。。
 图片不见了。。。

同理,也可以绘制出同样为可重定位目标文件的sum.o格式。

 图片不见了。。。

III.可执行目标文件的具体内容
 图片不见了。。。
字段含义值的解释
入口点地址程序第一条指令的虚拟地址程序加载后,CPU在虚拟地址8048074H处取得第一条指令开始执行
程序头起点程序头在文件的起始偏移量程序头表的第一个字节在可执行目标文件的距开头52B处
Start of section headers节头表在文件的起始偏移量节头表的第一个字节位于距重定位目标文件开头632B处
本头的大小ELF头本身所占空间大小一般固定为52B大小,开辟了同样空间,区别仅在于有没有存值
程序头大小- -程序头表占用空间为32B
Number of program headers程序头表中表项的个数由于程序加载后会有两个段,故在程序头表中存在2个表项
 图片不见了。。。
 图片不见了。。。

在可执行目标文件的生成中需要重定位,因此可重定位目标文件中存放可重定位信息,因此待可执行文件成功生成后便无需再保存相关信息。

 图片不见了。。。
字段含义值的解释
Name可执行目标文件的节名- -
Addr节的第一个字节在虚拟地址空间的虚拟地址比如程序加载后可执行目标文件的.text节位于虚拟地址8048074H处
 图片不见了。。。
字段含义值的解释
Type描述存储段的类型或特殊节的类型一般有可装入段LOAD、特殊的动态节DYNAMIC和异常调试用的GUN_STACK等
Offset本段在可执行目标文件的偏移量比如LOAD段,即只读区域和可读写数据区域所包含的节,的第一个字节在文件的偏移量为0H
VirAddr本段的第一个字节的虚拟地址比如LOAD段的第一个字节的虚拟地址为8048000H
PhysAddr本段的第一个字节的主存地址- -
FileSiz本段所包含的节在文件中所占的总大小- -
MemSiz本段所包含的节在磁盘所占的总大小- -
Flg描述存取权限- -
Align本段在存储时的对齐方式比如LOAD段存储时的对齐方式为2的12次方

在绘制可重定位目标的基础上,再根据程序头表中的偏移量52H可以进一步勾勒出该可执行目标文件的格式。

 图片不见了。。。
IV 可重定位目标文件与可执行目标文件的相互关系
 图片不见了。。。
 图片不见了。。。
  • 3
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值