gcc hello.c
再看我们的目录下,就多了目标文件a.out。
现在我们想做的是看看a.out里到底有什么,可能有童鞋回想到用vim文本查看,当时我也是这么天真的认为。但a.out是何等东西,怎能这么简单就暴露出来呢。是的,vim不行。“我们遇到的问题大多是前人就已经遇到并且已经解决的",对,其中有一个很强悍的工具叫做objdump。有了它,我们就能彻底的去了解目标文件的各种细节,当然还有一个叫做readelf也很有用,这个在后面介绍。
这两个工具一般Linux里面都会自带有有,可以自行google
注:这里的代码主要是在Linux下用GCC编译,查看目标文件用的是Objdump、readelf。但是我会把所有的运行结果都上图,所以之前没有接触过Linux的童鞋来看下面的内容也完全没问题哦。我用的是ubuntu,感觉挺好~
下面是a.out的组织结构:(每段的起始地址、、大小等等)
查看目标文件的命令是 objdump -h a.out
就和上文中描述的目标文件的格式一样,可以看出是分类存储的。目标文件被分为了6段。
从左到右,第一列(Idx Name)是段的名字,第二列(Size)是大小,VMA为虚拟地址,LMA为物理地址,File off是文件内的偏移。也就是这段相对于段中某一参考(一般是段起始)的距离。最后的Algn是对段属性的说明,暂时不用理会
“text”段:代码段。
“data”段:也就是上面说的数据段,保存了源代码中的数据,一般是以初始化的数据。
“bss”段:也是数据段,存放那些未初始化的数据,因为这些数据还未分配空间,所以单独存放。
“rodata”段:只读数据段,里面存放的数据是只读的。
“cmment”存放的是编译器版本信息。
剩下的两段对我们的讨论没有实际意义,就不再介绍。认为他们包含了一些链接、编译、装在的信息就可。
注:
这里的目标文件格式只是列出实际情况中主要部分。实际情况还有一些表未列出。如果你也在用Linux,可以用objdump -X列出更详细的段内容。
深入a.out
上面部分通过实例说了目标文件中的典型的段,主要是段的信息,如大小等相关的属性。
那么这些段里面究竟有些什么东西呢,“text”段里到底存了什么东西,还是用我们的objdump。
objdump -s a.out 通过-s选项就可以查看目标文件的十六进制格式。
查看结果如下:
如上图所示,列出了各段的十六进制表示形式。可以看出图中共分为两栏,左边的一栏是十六进制的表示, 右边则显示相应的信息。
比较明显的如“rodata”只读数据段中就有“hello world”。。汗,好像程序里的“hello”打错了,后面多加了一个“w”,截图麻烦,。原谅下哈。
你也可以查看“hellow world”的ASCII值,对应的十六进制就是里面的内容了。
“comment”上文中说的这个段包含了一些编译器的版本信息,这个段后面的内容就是了:GCC编译器,后面的是版本号。
a.out反汇编
编译的过程总是先把源文先变为汇编形式,再翻译为机器语言。(添加中间层嘛)看了这么多的a.out,再研究一下他的汇编形式是恨必要的
objdump -d a.out可以列出文件的汇编形式。不过这里只列出了主要部分,即main函数部分,其实在main函数执行的开始和main函数执行以后都还有多工作要做。
即初始化函数执行环境以及释放函数占用的空间等。
上面的图中,左边是代码的十六进制形式,左边是汇编形式。对汇编熟悉的童鞋应该能看懂大部分,这里就不在多述。
a.out头文件
在介绍目标文件格式的时候,提到过头文件这个概念,里面包含了这个目标文件的一些基本信息。如该文件的版本、目标机器型号、程序入口地址等等。
下图是文件头的形式:
可以用readelf -h来查看。(下图中查看的是hello.o,它是源文件hello.c编译但未链接的文件。 这个和查看a.out大部分是一样的)
图中分为两栏,左边一栏表示的是属性,右边是属性值。第一行常被称为魔数。后面是一连串的数字,其中的具体含义就不多说了,可以自己去google。
接下来的是一些和目标文件相关的信息。由于和我们要讨论的问题关系不大,这里就不展开讨论了。
上面是内容用具体的实例说了目标文件内部的组织形式,目标文件只是产生可执行文件过程中的一个中间过程,对于程序是如何运行的还没做讨论,目标文件是如何转变为可执行文件以及可执行文件是如何执行的将在下面的部分中讨论
对链接的简单认识
链接通俗的说就是把几个可执行文件。
如果程序A中引用了文件B中定义的函数,为了A中的函数能正常执行,就需要把B中的函数部分也放在A的源代码中,那么将A和B合并成一个文件的过程就是链接了。
有专门的过程用来链接程序,称为链接器。他将一些输入的目标文件加工后合成一个输出文件。这些目标文件中往往有相互的数据、函数引用。
上文中我们看过了hello world的反汇编形式,是一个还没有经过链接的文件,也就是说当引用外部函数的时候是不知道其地址的:
如下图:
本文来源:不详 作者:佚名