从C代码到elf文件(1)

从C代码到ELF文件格式(1) – 了解ELF

现在是互联网时代,编程语言更多考虑的是表达能力,而非单纯的指令级性能。所以,编程语言越来越向动态语言,脚本语言发展。但是,无论编程语言怎么发展,基本的逻辑还是不能变的,了解elf文件格式对提升水平还是很有用的。从小处说,学基础的东西可以以不变应万变;说得远一点,相信随着国家的发展,越来越多的基础研发工作会转移过来,相应的工作也许会多起来吧,加油!本系列文章,主要讨论C和elf格式的对应关系。主要涉及C的编译和链接的具体关键细节,看似偏了点,但其实本应该是专业程序员的常识。

上过高等工科课程的同学一般都学习过C程序设计语言,虽然不是所有人都会在工作中用到。开源的 Linux 操作系统主要是用C语言编写的(少量汇编)。linux上(以及其他unix系OS)的可执行程序,lib库(动态和静态库), 包括linux内核镜像本身都是使用的elf文件格式。虽然windows使用PE格式,但PE文件格式和elf文件格式有个共同祖先——COFF文件格式,所以它们的很多表示方式是一致的。

本文先简单分析下C的程序结构,elf文件格式的基本组成,C程序的编译链接过程,然后考虑C程序的汇编输出形式,目标文件格式,so文件格式,静态库,程序的加载和动态链接过程,以及他们和C程序的对应关系。所有讨论的概念和示例都是基于linux。

C程序的结构

C程序源码一般是由*.h *.c文件构成的。*.h文件是头文件,包含了需要导出和导入的函数,变量,类型定义,宏定义。*.c则是具体的变量定义,函数实现,和模块内部类型定义。一般来说,一个c文件会对应一个h文件,共同构成一个可单独编译的模块。编译器会一个一个c文件的编译,每个c文件会生成一个目标文件*.o, 然后根据连接脚本把多个*.o连接成可执行程序或者库文件(例如*.so)。

a.c + a.h -> a2.c -> a.o  
                      +  =  exe或动态库(*.so)或静态库(*.ar)
b.c + b.h -> b2.c -> b.o

C语言有个很奇怪的特性,叫做宏。宏本身也是一种语言,每行都以#开头,在被编译器处理之前,先由预处理器,处理宏语言来完成宏替换,代码块的选择,头文件的包含。预处理之后才是真正纯粹的C代码。最后编译器其实只用处理一个个单独的C文件即可。
预处理完之后的C文件有哪些内容呢?举个例子:
1. 需要导入的外部函数,全局变量。 extern
2. 需要导出的函数的声明和定义,变量的声明和定义。 extern
3. 内部使用的全局变量, 函数。static
4. 类型定义。编译完成后,这部分信息elf中不存在。

了解ELF文件

ELF(Executable and Linking Format),最初由UNIX实验室开发的,是应用程序接口(ABI)的一部分。它是Object文件格式,分为三种:

可重定位文件(relocatable file ): 包含代码和数据,可与其他对象文件连接成可执行文件或共享库。
可执行文件(executable file): 包含可以执行的代码。
共享对象文件(shared object file)首先,它可以和其他重定位文件和共享对象文件连接,产生新的对象文件。另外,可执行文件可以和它动态连接成可执行的镜像。
ELF文件格式

如下图,对象文件参与程序的连接和执行。Linking view显示了对连接(Relocatable)其有效的视图。Excution view则是最后可执行文件(loadable)的视图。

这里写图片描述

ELF header在文件最开头, 用来指明文件类型,指令集,编码格式(如大小端),文件的结构即:sectionheader和program header的位置和大小等。
Section Header Table指定了各个section的位置,大小,名称等信息,连接时需要。
Section 包含各种对象文件的信息,如:数据,指令,符号表,重定位信息等。
Program header Table是可执行文件用的,用于指明哥哥segment的位置等信息。重定位文件不需要。
这里写图片描述
这里我们重点了解下SectionSection Header Table64bit ELF格式可参考文件ELF64

除了ELF header,program header table,section header table, 其它信息都包含在section中。
section由Section Header Table来定位,它的每一个表项结构如下:

typedef struct
{
Elf64_Word sh_name; /* Section name *///实际是字符串表的偏移
Elf64_Word sh_type; /* Section type *///类型
Elf64_Xword sh_flags; /* Section attributes *///处理器相关
Elf64_Addr sh_addr; /* Virtual address in memory *///虚拟内存地址,在加载到内存前为0
Elf64_Off sh_offset; /* Offset in file *///从文件最开始计算的文件内部偏移
Elf64_Xword sh_size; /* Size of section *///在文件内占用的字节数
Elf64_Word sh_link; /* Link to other section *///具体含义依赖section的类型
Elf64_Word sh_info; /* Miscellaneous information *///具体含义依赖section的类型
Elf64_Xword sh_addralign; /* Address alignment boundary *///对齐边界,2的整数次方
Elf64_Xword sh_entsize; /* Size of entries, if section has table *///内部表(如重定位表)项数目,某些情况下有效,否则为0
} Elf64_Shdr;

下面是一些常见的section类型,其它信息详见[ELF64],不赘述:
这里写图片描述

可以看到,section包含字符串表,符号表,重定位表,Hash表,动态链接等。

字符串表,存储了各种字符串,每个字符串都是以0结尾,挨个排列。符号表中不直接存储字符串,而是通过字符串在字符串表中的偏移整数值来引用字符串,除此之外也指明了符号的类型,大小,值,位于的section的索引。符号分为SECTION(section name),FUNC(函数名),OBJECT(数据对象),FILE(对应的源文件名)等类型。

重定位表,表项如下:
这里写图片描述

只看Elf64_Rel:
r_offset指明了符号对应的变量在object文件的具体位置,一般对应变量或者函数地址在编译后的二进制指令的操作数的section内部偏移。通过他能够找到重定位符号在程序中的位置。
r_info则指明了重定位表对应的符号在符号表中的偏移。即指明是对哪个符号重定位。

Hash表,放在.hash section中。用来加速字符串的查找:
这里写图片描述
hash表的原理,其实是把字符串转换为整数hash值,使用这个hash值作为数组偏移(会根据捅的个数取模)来查找到对应的数组元素(这里成为hash bucket,hash桶),字符串集合的元素都通过hash值计算映射到了桶中。由于不同字符串的hash值会重复,所以会有多个不同的字符串在一个桶中(通过chain把这些字符串连接起来)。查找字符串时,先计算hash值,找到桶,再在桶中去匹配具体的字符串。桶的总数是可以自定义的,越大桶中重复元素就越少,查找就越快。chain数组的个数实际上等于字符串个数,符号S对应chain[S的符号表索引值], chain数组的元素值是桶中下一个符号的符号表索引。bucket数组的值也是符号表索引值。根据字符串获取字符串对应的符号表索引,伪码如下:

    sym_table_index = bucket[hash(str) % nbucket];
    while(sym_table_index != STN_UNDEF){
        temp_str = get_str_by_sym(sym_table_index); //根据符号表找字符串
        if ( 0 == strcmp(str, temp_str)){ //就是这个符号
            return sym_table_index;
        }
        sym_table_index = chain[sym_table_index];// 桶的下一个符号表索引
    }
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值