· 把文件A和运行A需要的文件B(如库函数)链接起来,形成文件A+
· 把文件A+装载进入内存,运行文件
(其实如果是看参考书或者其他资料的话可能不止这几步,只是这里为了简化我把它归纳为3步)
“any problem in computer science can be sloved by another layer of indirecition”
“计算机科学领域的任何问题都可以通过增加一个中间层来解决”
现在来看一下上面说的目标文件是如何组织的(也就是存放结构)。
想象一下如果是你来设计会如何组织这些二进制代码?就像书桌上的物品要分类放置才整洁一样,为了便于管理翻译出来的二进制代码也分类存放,把表示代码的放在一起,表示数据的放在一起。这样,二进制代码就分为了不同的块来存放。这样的一个区域就是被称为段(segment)的东西。
和计算机科学中的很多东西一样,为了方便人们的交流、程序的兼容等问题。也为这种二进制的存放方式制订了标准,于是COFF(common object file format)就诞生了。现在的windows、Linux、等主流操作系统下的目标文件格式和COFF大同小异,都可以认为是它的变种。
a.out是目标文件的默认名字。也就是说,当编译一个文件的时候,如果不对编译后的目标文件重命名,编译后就会产生一个名字为a.out的文件。
/*hello.c*/ #include int main() { int a=5; printf("hellow world \n"); }
gcc hello.c
编译的过程总是先把源文先变为汇编形式,再翻译为机器语言。(添加中间层嘛)看了这么多的a.out,再研究一下汇编形式是有必要的。
在介绍目标文件格式的时候,提到过头文件这个概念,里面包含了这个目标文件的一些基本信息。如该文件的版本、目标机器型号、程序入口地址等等。
可以用readelf -h 来查看。(下图中查看的是 hello.o,它是源文件hello.c编译但未链接的文件。 这个和查看a.out 大部分是一样的)