我们知道,.c文件是不能直接执行的,必须经过编译和链接阶段成为可执行文件才能够执行
那么从.c文件到可执行文件需要那些过程呢?????????????????????
首先我们来看编译阶段
其实编译阶段可以分为这几个阶段
预编译阶段:编译阶段主要是做着几件事情: 删除注释,处理以#开头的一些预编译指令
此阶段结束后生成:.i文件。
编译阶段 :编译阶段主要做这几件事情:语法语义的分析,代码的优化,汇总所有的符号
此阶段结束后生成:.s文件
汇编:汇编阶段主要做这几件事情:它会根据指令(mov,lea,add等)和机器平台的结合->把
把.s文件转化成机器码,构建.o/.obj文件的格式 ,此阶段完成后生成.o/.obj文件(二进制可重定位文件)
此后,生成符号表:每一个数据生成一个符号,一个函数只生成一个符号(函数名),此阶段完成后
文件是不可执行的,因为数据在使用的时候分配的是0内存(也就是说数据没有分配内存),所以就
有了下面的阶段
链接:
(1)合并所有obj文件的段:所有相同属性的段进行合并,组织在一个页面上(比如所有的.text(只读),所有
的.bss,.data(可读可写))
(2)调整段偏移和段长度:因为段进行了合并,所以必须调整偏移量和长度
(3)合并符号表,进行符号解析,分配内存地址:所有obj符号表中对符号引用的地方都要找到该符号的定义的地方,比如你在
文件a中定义了一个全局变量,在b文件中想去引用它,(链接过程所有的文件是一起链接了),而合并符号表就
实现了这一功能;分配内存地址(数据分配绝对地址,而函数分配下一行指令地址的偏移量)
(4)符号的重定位:把之前没有正确的符号地址改正成正确的地址,只对所有obj文件的globle符号进行处理,Local文件不做处理
——————————————————————————————————————————————————————————
这最终才是我们的可执行文件
接下来我们来看一下.o文件内容的布局:
main.o
我们会发现在文件上的布局少了在虚拟用户地址空间里的.bss,这是因为什么呢,这是因为在.bss存储的数据都属未初始化或初始化为
0的数据,完全没有必要现在占用我问文件的存储量,从这里也可以看出,.bss不占用文件的内存,那么,我们的.bss里面的数据到底在
哪里呢,大家有没有注意到最后一个名字:section table:在ELFHeader中存放着它的地址,它就是段表:保存文件所有段的详细信息,
读文件头时就可知道,所以也知道.bss里面的信息了
————————————————————————————————————————————————————————————-
我们再来看一下可执行文件的组成格式
其中program headers中存放这两个load;知名当前可执行文件哪些段可放在一个页面上
而这两个load 存放在磁盘上
————————————————————————————————————————————————————————————
程序的运行 进程
1:创建虚拟地址空间到物理内存的映射(创建内核地址映射结构体,创建页目录和页表)
2:加载代码段和数据段
3:把可执行文件的入口地址(main的地址)写到cpu的pc寄存器里面