linux的目标文件格式是,【进程的内存布局一】Linux 目标文件

1 基础知识参考:;程序员的自我修养:(1)目标文件。

1.1 百度百科目标文件:

目标文件(objectfile)即存放目标代码的计算机文件,它常被“称作”二进制文件(binaries)。目标文件包含着机器代码(可直接被计算机中央处理器执行)以及代码在运行时使用的数据,如重定位信息,如用于链接或调试的程序符号表(变量和函数的名字),此外还包括其他调试信息。

1.2 Linux下有3种目标文件形式:

可执行目标文件,可重定位目标文件和共享目标文件。也有对应的称为可执行文件,目标文件,共享库,只是说法不同,指的都是同样的东西。

可执行目标文件:包含二进制代码和数据,可以在存储器中直接执行。

可重定位目标文件:包含二进制代码和数据,可以在编译时与其他可重定位目标文件合并起来的,创建一个可执行目标文件。

共享目标文件:是一种特殊的可重定位目标文件,可以在加载或者运行时被动态加载到存储器并链接。

事实上,编译器和汇编器生成可重定位目标文件(包含共享目标文件)。链接器生成可执行目标文件。

1.3 Linux下目标文件文件格式:

由于编译后的中间文件(Windows下的.obj和Linux下的.o),动态链接库和静态链接库(Windows下的.lib.dll和Linux下的.a.so),跟可执行文件的内容和结构相似,所以一般跟可执行文件一起采用同一种文件格式存储。

1.4Linux下有3种主要的可执行目标文件格式:

a.out(assembler and link editor output 汇编器和链接编辑器的输出)、COFF(Common Object File Format 通用对象文件格式)、ELF(Executable and Linking Format 可执行和链接格式)。老的可执行文件格式缺乏可扩展性,如不能包含“现代”可执行文件中常见的调试信息,所以基本上已被ELF格式取代。现代Linux使用的可执行目标文件格式都是ELF。

1.5Linux下ELF格式的目标文件有4种主要类型:

可重定位文件:可以被用来链接成可执行目标文件或共享目标文件的文件。扩展名.o或.a。

可执行文件:可以直接执行的程序。ELF可执行文件一般没有扩展名。

共享目标文件:可以在两种情况下使用:1 链接器(Linux系统中为ld)可以将它与其他可重定向目标文件、共享目标文件链接,形成新的目标文件;2 动态加载器(Linux系统中为/lib/ld-linux.so.2)(注:dynamic loader,在很多文章中将之称之为动态链接器,但我认为称为动态加载器比较好,这样不容易和链接器相混淆)(注:动态加载器所在的路径在可执行文件可以查到:readelf -l xxx | grep interpreter)可以将它与可执行目标文件结合,作为进程映像的一部分。扩展名.so。

core dump文件:。

d4158ff1f4597424b99b6fd8dc7e1ff0.png

图片选自:进程中的地址是从何而来

1.6 Linux下ELF文件文件格式:

ELF文件格式提供了两种视图,分别是链接视图和执行视图。

链接视图是以节(section)为单位,执行视图是以段(segment)为单位。链接视图就是在链接时用到的视图,而执行视图则是在执行时用到的视图。上图左侧的视角是从链接来看的,右侧的视角是执行来看的。总个文件可以分为四个部分:

e17dfda699f1508dc30124d8debdeb66.png

点击(此处)折叠或打开

-ELF header:描述整个文件的组织。

-Program Header Table:描述文件中的各种segment,用来告诉系统如何创建进程映像的。

-sections 或者 segments:segments是从运行的角度来描述elf文件,sections是从链接的角度来描述elf文件,也就是说,在链接阶段,我们可以忽略program header table来处理此文件,在运行阶段可以忽略section header table来处理此程序(所以很多加固手段删除了section header table)。从图中我们也可以看出,segments与sections是包含的关系,一个segment包含若干个section。

-Section Header Table:包含了文件各个section的属性信息,section名字、section大小、section在elf文件中的偏移等。

9b0f419fd0eee223d0ced6d557a4bb73.png

选自:ELF文件格式解析

1.7 Linux下ELF文件中各个section的含义:

ELF文件中各个section的含义如下图所示:

870cf0b0cf822783691ef661318b05fa.png

选自:进程中的地址是从何而来

2 常见问题

2.1Linux下ELF文件和.BIN文件的区别(注:通过如上对ELF的描述,ELF有两种视角:可执行、可链接,而通常讲的、也是这里讲的是ELF可执行的视角):

.BIN文件:是raw binary文件,这种文件只包含机器码。

执行时,只需要将程序加载到其起始地址,一般为0x00地址,就可以执行。

ELF文件:除了机器码外,还包含其它额外的信息,如段的加载地址,运行地址,重定位表,符号表等。

执行时,需要一个ELF Loader。正因为uboot和Linux kernel启动的时候是没有ELF Loader的,所以烧在flash上的文件只能是raw binary格式的,即镜像文件image。

一般情况下,通过gcc编译出来的是elf文件,而通过objcpy可以把elf文件转换为bin文件。

小结:ELF文件包含了一些调试信息;.BIN文件是将ELF文件中的代码段、数据段,还有一些自定义段,抽取出来做成的一个内存镜像文件。

参考:ELF文件和BIN文件。

2.2Linux下.ko文件和.o文件的区别(注:这里.o狭义的指用于内核使用的动态链接文件):

.o文件:是object文件。

.ko文件:是kernel object文件。是Linux 2.6内核使用的动态链接文件,用于在Linux系统启动时动态的加载卸载内核模块。

小结:.ko是linux 2.6内核编译之后生成的,相比linux 2.4内核编译生成的.o,其多了一些module信息,如author,license之类的。

2.3Linux下ELF文件和.out文件的区别:

历史由来:a.out是"assembler output"的缩写格式,代表汇编程序输出。在较早版本的类unix系统中,a.out是一种输出格式,用于可执行文件,目标文件和共享库。早期的 PDP-7系统上没有链接器,程序的创建过程是先把所有源文件连接成一个文件,然后进行汇编,产生的汇编程序保存在a.out中。这样a.out是名副其实的汇编输出。

但到PDP-11之后,人们为其编写了链接器,程序的创建是先编译然后链接输出保存到a.out中,这时a.out其实已经是链接输出了,但输出的可执行文件仍然延续这个命名习惯。

后来,因为构建a.out的复杂性,a.out格式被现在普遍使用的ELF格式所替代,但输出文件名仍旧是a.out。现在我们看到的a.out只是一个可执行文件,而不再是文件格式。

实际操作:当编译程序时,如果不加-o参数,生成的binary代码的名字都是默认的a.out。如:gcc helloworld.c

当然,也可以使用-o选项给生成的文件起一个别的名字。如:gcc helloworld.c -o helloword.out,或者gcc helloworld.c -o helloword

事实上,如上两种生成的a.out、helloworld.out、helloworld其实都是ELF文件格式的可执行目标文件。

参考:linux c/c++ a.out的由来。

2.4Linux下ELF结构文件的确定:

ELF的可执行文件:第一个字节是八进制177也就是16进制的7F,紧跟其后的2,3,4字节是ELF三个字母。你可以输入od -c a.out | head查看一下。如:a.out、helloworld.out、helloworld

ELF的其他目标文件,除.a文件:第一个字节是八进制177也就是16进制的7F,紧跟其后的2,3,4字节是ELF三个字母。如:helloworld.o、helloworld.so

ELF的.a文件:包含八进制177也就是16进制的7F,紧跟其后的2,3,4字节是ELF三个字母。如:helloworld.a

参考:linux c/c++ a.out的由来。

2.5 Linux下ELF文件的段和段表的区别关系:

ELF文件最重要的一个概念就是“段”(segment or section),例如:.text段、.data段、.bss段等等。

而,描述ELF文件中各个“段”的是“段表”(Section Header Table),包含了描述每个段的属性信息,比如段的名字、段的大小、段在elf文件中的偏移等。

另外,可以通过readlef -S a.out或objdump -h a.out来查看ELF文件的段表;通过readelf -s a.out或objdump -t a.out来查看ELF文件的符号表。如下是,常用的查看命令:

查看ELF文件

查看所有内容

readelf -a (-a=–all相当于-e -r

-s)

查看header

all header

objdump -x (-x=–all-headers包括file、section header以及符号表和重定位表)

readelf -e (-e=–headers包括file、program、section header)

file header

objdump -f (-f=–file-headers)

readelf -h (-h=–file-header)

program header

readelf -l (-l=–program-header)

section header

objdump -h (-h=–section-headers)

readelf -S (-S=–section-headers)

readelf -t (-t=–section-details)

查看section

查看数据

objdump -s (-s=–full-contents包括.text、.data、.rodata、.comment的二进制和ASCII码)

查看代码

objdump -d -z -r -l (-d=–disassemble, -z=–disassemble-zeroes, -r=–reloc, -l=–line-numbers只反汇编.text段)

objdump -D (-D=–disassemble-all不只反汇编.text段,也把.data、.bss、.rodata、.comment当成代码反汇编)

在objdump后加上|

grep -A15“” 可以查看某个函数的15行反汇编代码

查看符号表

objdump -t (-t=–syms)

readelf -s (-s=–syms)

查看重定位表

objdump -r (-r=–reloc)

readelf -r (-r=–relocs)

查看某section内容

objdump -j .text -s/-d (根据section是数据还是代码)

选自:程序员的自我修养:(1)目标文件

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值