最近在学习elf格式,那遍介绍elf格式的文档分两部分介绍elf格式,第一部分是目标文件,第二部分是程序加载和动态链接。文档我会上传的我的资源里,有兴趣的可以下载,不用资源分的。这里是我学习第一部分时记的一些笔记
一、简介
三种主要类型的目标文件:
1、可重定位文件:保存着代码和数据,这些代码和数据适合和其他目标文件链接在一起,生成一个可执行文件或共享目标文件。
2、可执行文件:保存着适合执行的程序;这个文件告诉exec(BA_OS)怎样创建一个程序的进程映像。
3、共享目标文件:保存着适合在两个上下文中链接的代码和数据。
1)、链接编辑器可能把它和其他的可重定位和共享目标文件一起处理,生成另外一个目标文件。
2)、动态链接器把它与一个可执行文件和其他的共享目标组合在一起,生成一个进程映像。
二、文件格式
目标文件参与程序的链接和执行,为了方便和有效,目标文件格式提供了一个文件内容的并行视图,反映这些活动的不同需求。
elf头在文件的开始部分,并保存着描述此文件组织的路线图。section保存着大量的用于链接的目标文件信息:指令、数据、符号表、重定位信息等。
program header table告诉系统怎样创建一个进程映像。创建一个进程映像,即执行一个程序,必须有一个program header table. section header table包含描述文件section的信息。每个section在这个表中有一个入口;每个入口给出了一些信息,如section name、section size等。在链接时使用到的文件必须有一个section header table。
注意:除了elf header位置固定在文件的开始,其他部分位置任意。
三、ELF Header
# d e f i n e E I _ N I D E N T 1 6
t y p e d e f s t r u c t {
u n s i g n e d c h a r e _ i d e n t [ E I _ N I D E N T ] ;
E l f 3 2 _ H a l f e _ t y p e ;
E l f 3 2 _ H a l f e _ m a c h i n e ;
E l f 3 2 _ W o r d e _ v e r s i o n ;
E l f 3 2 _ A d d r e _ e n t r y ;
E l f 3 2 _ O f f e _ p h o f f ;
E l f 3 2 _ O f f e _ s h o f f ;
E l f 3 2 _ W o r d e _ f l a g s ;
E l f 3 2 _ H a l f e _ e h s i z e ;
E l f 3 2 _ H a l f e _ p h e n t s i z e ;
E l f 3 2 _ H a l f e _ p h n u m ;
E l f 3 2 _ H a l f e _ s h e n t s i z e ;
E l f 3 2 _ H a l f e _ s h n u m ;
E l f 3 2 _ H a l f e _ s h s t r n d x ;
} E l f 3 2 _ E h d r ;
e_ident 把文件标记为一个目标文件,并提供机器独立的数据,用于解码和解释这个文件内容
e_type 标识目标文件类型,如可重定位文件、可执行文件、共享目标文件等
e_machine 指出一个文件要运行在哪种体系结构上
e_version 标出目标文件版本
e_entry 虚拟地址,文件开始执行的入口
e_phoff program header table在文件中的偏移量
e_shoff section header table在文件中的偏移量
e_flags 处理器相关标记
e_ehsize elf header大小
e_phentsize program header table 中一个入口的大小,即一个program header的大小
e_phnum program header table 中入口的数量
e_shentsize section header table 中一个入口的大小,即一个section header的大小
e_shnum section header table中入口的数量
e_shstrndx section header table中section name string table的入口索引
四、sections
section header table 是一个Elf32_Shdr结构数组。section包含一个目标文件的除elf header、program header table和section header table之外的所有信息。此外,目标文件的section要满足几个条件:
1、 一个目标文件中每个section都只有一个section heard 描述它
2、 一个文件中每个section占用一个相邻的字节序
3、 一个文件中的各section不能重叠。
4、 一个目标文件可以有不活动的空间,各种headers 和sections可能没有覆盖一个目标文件的所有字节。
section header
t y p e d e f s t r u c t {
E l f 3 2 _ W o r d s h _ n a m e ;
E l f 3 2 _ W o r d s h _ t y p e ;
E l f 3 2 _ W o r d s h _ f l a g s ;
E l f 3 2 _ A d d r s h _ a d d r ;
E l f 3 2 _ O f f s h _ o f f s e t ;
E l f 3 2 _ W o r d s h _ s i z e ;
E l f 3 2 _ W o r d s h _ l i n k ;
E l f 3 2 _ W o r d s h _ i n f o ;
E l f 3 2 _ W o r d s h _ a d d r a l i g n ;
E l f 3 2 _ W o r d s h _ e n t s i z e ;
} E l f 3 2 _ S h d r ;
sh_name section名称
sh_type section类型
sh_flags section标志,描述各种section属性
sh_addr section在进程映像中的地址
sh_offset section在文件中的偏移量
sh_size section的大小
sh_link section header table索引连接
sh_info 辅助信息
sh_addralign 地址对齐方式
sh_entsize 入口大小
五、字符串表
字符串表section保存着一些字符串。目标文件用这些字符串表示符号和section名称。section header的sh_name保存着一个索引,用这个索引可在“section header字符串表”中找到对应的名称。这个表是由ELF header中e_shstrndx成员指定。
六、符号表
目标文件的符号表保存着一些信息,用于定位和重定位一个程序的符号定义和引用。符号表是一个Elf32_Sym结构数组。数组中的每一个元素称为一个符号表入口。
symbol table entry
t y p e d e f s t r u c t {
E l f 3 2 _ W o r d s t _ n a m e ;
E l f 3 2 _ A d d r s t _ v a l u e ;
E l f 3 2 _ W o r d s t _ s i z e ;
u n s i g n e d c h a r s t _ i n f o ;
u n s i g n e d c h a r s t _ o t h e r ;
E l f 3 2 _ H a l f s t _ s h n d x ;
} E l f 3 2 _ S y m ;
st_name 符号名,保存着一个索引,用于在目标文件的符号字符串表中查找符号名
注意:外部C符号在C文件和目标文件的符号表中名称是一样的
st_size 很多符号有相关的大小,如:一个数据对像的大小就是这个对像所包含的字节数。
如果这个符号没有大小或大小未知,则此成员为0。
st_info 符号信息,指定符号的类型和属性
st_other 为0,暂未定义
st_shndx 每一个被定义的符号表入口涉及到一些section。这个成员保存着相关section
header table的索引。
在共享目标文件中的函数符号有特殊的意义。当另一个目标文件从一个共享目标文件中引用一个函数时,链接编辑器自动为被引用的符号创建一个plt表入口。
符号值:
不同目标文件类型的符号表对st_value的解释略有不同。
1、可重定位文件:st_value保存着st_shndx为SHN_COMMON的符号的对齐限制。
2、可重定位文件: st_value保存着一个已定义符号的section偏移量,即st_value是从st_shndx标识的section开始处的一个偏移值。如这个文件中有个函数的定义
int max(a,b)
{
if(a>b)
return a;
return b;
}
这个值就是指这个max函数的定义在其section中从section开始处的偏移量.
3、可执行文件和共享目标文件:st_value保存着一个虚拟地址。如在可执行文件中有一个函数调用printf();则这个值是指printf这个符号的定义所在的虚拟地址。
七、重定位
重定位是联接符号引用和符号定义的过程。例如,当一个程序调用一个函数,相关的调用指令在执行时必须把控制权传递到正确的目的地址。换句话说,就是可重定位文件必须有些信息,描述怎样修改它们的section内容,因而允许可执行文件和共享目标文件掌握正确的信息用于进程的程序映像。
重定位入口
relocateon entries
t y p e d e f s t r u c t {
E l f 3 2 _ A d d r r _ o f f s e t ;
E l f 3 2 _ W o r d r _ i n f o ;
} E l f 3 2 _ R e l ;
t y p e d e f s t r u c t {
E l f 3 2 _ A d d r r _ o f f s e t ;
E l f 3 2 _ W o r d r _ i n f o ;
E l f 3 2 _ S w o r d r _ a d d e n d ;
} E l f 3 2 _ R e l a ;
r_offset 指出在哪里进行重定位操作,对于可重定位文件,它的值是从section的开始处到
受重定位影响的存储单元的偏移量。对于可执行文件或共享目标文件,它的值是受
重定位影响的存储单元的虚拟地址
r_info 指出必须进行重定位的符号在符号表中的索引和使用的重定位类型
r_addend 指定一个常量加数,用于计算被存储到可加载处的值
一个重定位section涉及到另外两个section:符号表和一个要修改的section。不同的目标文件对重定位入口的解释略有不同。
1、 在可重定位文件中,r_offset包含了一个section偏移量。也就是说,重定位section(重定位表所占的section,类似符号表也占了一个section)自己描述了在这个文件中如何修改另一个section. 重定位偏移量指明了在第二个section中的一个存储单元。
2、 在可执行文件和共享目标文件中,r_offset包含了一个虚拟地址(这个虚拟地址应该是那个引用语句所在的地址,然后通过r_info指定的符号表索引在符号表中找到对应的符号,根据对应符号st_value指定的地址,找到符号的定义),为了使这些文件的重定位入口对动态链接器更有用,section偏移量(文件中的解释)让位于一个虚拟地址(内存中的解释)。
重定位类型
重定位入口描述了怎样改变下面的指令和数据域
从概念上来讲,链接编辑器合并一个或多个可重定位文件形成一个输出文件。它首先决定怎样组合加载输入的文件,然后更新符号值(st_value的值),最终实现了重定位。对于可执行文件或共享目标文件,重定位的应用是相似的,并且达到了相同的效果。后面的叙述使用了下面的符号:
A 表示用于计算重定们域的值的加数(addend)
B 表示在执行期间,一个共享目标文件被加载到内存的基地址
G 表示got表中的一个偏移量,重定位入口符号的地址在执行期间会驻留在这个表中
GOT got表的地址
L plt(procedure linkage table)入口位置,它对应着一个符号。plt入口把一个函数调用改
到正确的目的地址上。链接编辑器创建并初始化plt表,而动态链接器在执行期间修改
了它的入口
P 被重定位存储单元的位置(用r_offset计算的)
S 符号值,这个符号的索引在重定位入口中
重定位入口的r_offset值指定了受影响存储单元首字节的偏移量或虚地址。重定位类型指定了要改变哪些位以及怎样计算它们的值。system v 体系结构只使用了Elf32_Rel重定位入口,要被重定位的域保存了加数(addend)。在所有情况下,加数和计算结果使用相同的字节序。
重定位类型(relocation types)
___N__a_m_e_ ___V_a_l_u_e_ ___F_i_e_ld____C_a_l_c_u_la_t_i_o_n__
R_386_NONE 0 none none
R_386_32 1 word32 S + A
R_386_PC32 2 word32 S + A - P
R_386_GOT32 3 word32 G + A - P
R_386_PLT32 4 word32 L + A - P
R_386_COPY 5 none none
R_386_GLOB_DAT 6 word32 S
R_386_JMP_SLOT 7 word32 S
R_386_RELATIVE 8 word32 B + A
R_386_GOTOFF 9 word32 S + A - GOT
R_386_GOTPC 10 word32 GOT + A - P _ __________________________________________________
有些重定位类型的语义超越的简单的计算
R_386_GOT32 计算从got表的基址到符号的got入口的距离。另外它指示链接编辑器建立 got表
R_386_PLT32 这个重定位类型计算符号的plt表入口地址并且指示链接编辑器构建一个plt表
R_386_COPY 链接编辑器为动态链接创建了重定位类型。它的偏移量对应于一个可写segment中的一个位置。符号表索引指定了一个符号,这个符号在当前目标文件和共享目标文件中都存在。在执行期间,动态链接器拷贝与共享目标的符号相关的数据到由偏移量指定的位置。
R_386_GLOB_DAT 这个重定位类型被用于给指定符号的地址设置一个got表入口。
R_386_JMP_SLOT 链接编辑器为动态链接创建的重定位类型,它的偏移量给出了plt表入 口的位置,动态链接器修改plt入口把控制权传给指定的符号地址处。
R_386_RELATIVE 链接编辑器为动态链接创建的重定位类型。它的偏移量给出了共享目标中的一个位置,这个位置包含了一个代表相对地址的值。动态链接器通过把共享目标被加载的虚地址与相对地址相加,计算出对应的虚地址。这个重定位类型的重定位入口必须把符号表索引置‘ 0 ’ 。
R_386_GOTOFF 这个重定位类型计算符号值和got表地址的不同。另外,它指示链接编辑器构建got表
R_386_GOTPC 除了在计算中使用got表的地址,这个类型类似于R_386_PC32。