Linux ELF可重定向文件格式解析

本文详细解析了Linux系统的ELF可重定向文件格式,包括ELF文件头、段表Section Header Table、段Section(如.text、.data、.bss等)以及符号表、调试信息等内容。通过实例展示了如何使用binutils工具如objdump、readelf、nm等分析ELF文件的结构,还探讨了弱符号、强符号、弱引用等链接概念。
摘要由CSDN通过智能技术生成

可重定向文件生成

文件的格式与操作系统和编译器密切相关,linux的可执行文件是基于COFF的ELF格式,可重定向文件(也叫做目标文件.o)与可执行文件格式很接近,只是没有经过链接调整符号和地址。

源代码:

/*
 * SimpleSection.c
 *
 * Linux:
 *      gcc -c SimpleSection.c
 *
 * Windows:
 *      cl SimpleSection.c /c /Za
 */

int printf(const char* format, ...);

int global_init_var = 84;  //存储在.data section
int global_uninit_var;  //.bss section 实际上先放在COMM符号表中,在链接时确定地址后放入.bss

void func1(int i) //.text section
{
        printf("%d\n", i);
}

int main(void) //.text section
{
        static int static_var = 85; //.data section
        static int static_var2;  //.bss section
        int a = 1;
        int b;

        func1(static_var + static_var2 + a + b);

        return a;
}

 

gcc  -c Simplesection.c //生成可重定位文件,如果加上-o选项,会生成可共享文件

使用file查看文件类型

可重定向文件类型

liyumin@liyumin-B250M-D3H:~/compile_link_exec/elf_file$ file SimpleSection.o

SimpleSection.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

共享文件类型

SimpleSection.o: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=13352fe3ae9e92467df387aaf04926d89f599792, not stripped

本文解析可重定位文件

程序的编译链接过程解析参考另一篇文章:https://blog.csdn.net/starcraft501/article/details/100823506

 

ELF目标文件总体结构

ELF目标文件除了有编译后的机器指令码,数据,还有一些辅助信息,比如符号表,调试信息,字符串表等。这些信息分布在不同的section中存储。节section的概念用在链接视图中,另外一个段segment的概念用在装载视图中。

| ELF Header

| .text  //代码段 code section

| .data //数据段,保存初始化后的全局变量和局部静态变量 data section

| .bss //数据段,保存未初始化的局部静态变量,预留位置,不占ELF文件空间 data section

| ... other sections

| Section Header Table 段表

| String Tables  字符串表

| Symbol Tables 符号表

| ...

 

解析elf文件使用的工具:binutils

binutils的工具objdump用于查看目标文件的内部结构

-h 打印段的基本信息,忽略了复杂性的段,比如符号表,字符串表,段名字符串表,重定位表等

-x 打印段的详细信息

$objdump -s -d SimpleSection.o //-s 按16进制打印段的内容 -d 将包含指令的段反汇编(从机器指令转换为汇编指令)

objdump -t SimpleSection.o //查看符号表详情

c++filt _ZN1N1C4funcEi  //c++filt用于解析被修饰过的名称

size命令查看ELF文件的代码段,数据段,bss段的长度

liyumin@liyumin-B250M-D3H:~/compile_link_exec/elf_file$ size SimpleSection.o
   text       data        bss        dec        hex    filename
    179          8          4        191         bf    SimpleSection.o

readelf查看ELF文件

readelf -h SimpleSection.o //查看ELF文件头

readelf -S SimpleSection.o //查看ELF完整的段表结构

readelf -s SimpleSection.o //查看符号表

readelf -a //查看所有信息

nm查看ELF文件符号表

nm SimpleSection.o

strip去掉可执行文件中的调试信息

strip xxx

 

ELF文件头

描述文件属性信息

  • 文件类型,是否可执行,静态链接,动态链接;
  • 可执行文件类型的入口地址;
  • 目标硬件;
  • 目标操作系统;

使用$readelf -h SimpleSection.o读取文件头,文件头后就是各个段seciton的内容

ELF文件的详细定义查看ELF标准文档,由编译器厂商,CPU厂商,操作系统厂商供共同完成

ELF 头:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 //e_ident ELF魔数, 包含类别,数据,版本,OS/ABI,ABI版本这5项数据
  类别:                              ELF64  //7f 45 4c 46 , DEL控制符,E,L,F  对应的ASCII码表,是ELF文件的标识,用于操作系统检查文件类型
  数据:                              2 补码,01 小端序 (little endian) //00无效文件 01 32位 02 64位ELF文件  01 代表小端,02代表大端,00是无效的
  版本:                              1 (current) //01 第7个字节
  OS/ABI:                            UNIX - System V //00
  ABI 版本:                          0  //00
  类型:                           REL (可重定位文件)  //e_type ELF文件类型,REL:.o目标文件, EXEC:可执行文件, DYN:共享目标文件
  系统架构:                          Advanced Micro Devices X86-64 //e_machine, CPU平台属性,表明该文件只能在X86-64上运行
不同平台下的ELF文件都遵循同一标准,但是文件不是通用的。需要gcc和binutils工具根据不同平台适配。

liyumin@liyumin-B250M-D3H:~/compile_link_exec/elf_file$ objdump -x SimpleSection.o

SimpleSection.o:     文件格式 elf64-x86-64
SimpleSection.o
体系结构:i386:x86-64, 标志 0x00000011:
HAS_RELOC, HAS_SYMS
起始地址 0x0000000000000000


  版本:                              0x1 //ELF版本,通常为1
  入口点地址:          0x0 //入口虚拟地址,操作系统在加载该ELF文件后从这个地址开始执行指令,可重定位文件没有入口地址,为0
  程序头起点:          0 (bytes into file)//start of program headers
  Start of section headers:          1104 (bytes into file) //e_shoff 段表位置,在ELF文件中的偏移为0x450,
  标志:             0x0 //标识平台相关属性,格式为EF_machine_flag, machine为平台,flag为标志
  本头的大小:       64 (字节) //文件头大小
  程序头大小:       0 (字节) //Size of program headers
  Number of program headers:         0
  节头大小:         64 (字节) //Size of section headers == sizeof(Elf64_Shdr), 段表描述符大小,每个段一个
  节头数量:         13 //Number of section headers,段表描述符数量,即段数量
  字符串表索引节头: 12 //Section header string table index 段表字符串表所在段,在段表中的下标

64位文件头Elf64_Ehdr的结构定义在/usr/include/elf.h,另外还有32位的版本Elf32_Ehdr。两个版本的文件头内容一样,但成员占用的字节不一样。使用typedef定义特定的变量类型,规定在不同编译环境下都使用相同的字段长度。

/* Type for a 16-bit quantity.  */
typedef uint16_t Elf32_Half;  //无符号短整型 2字节
typedef uint16_t Elf64_Half;

/* Types for signed and unsigned 32-bit quantities.  */
typedef uint32_t Elf32_Word; //4字节
typedef int32_t  Elf32_Sword;
typedef uint32_t Elf64_Word;
typedef int32_t  Elf64_Sword;

/* Types for signed and unsigned 64-bit quantities.  */
typedef uint64_t Elf32_Xword; //8字节
typedef int64_t  Elf32_Sxword;
typedef uint64_t Elf64_Xword;
typedef int64_t  Elf64_Sxword;

/* Type of addresses.  */
typedef uint32_t Elf32_Addr;
typedef uint64_t Elf64_Addr;

/* Type of file offsets.  */
typedef uint32_t Elf32_Off;
typedef uint64_t Elf64_Off;

/* Type for section indices, which are 16-bit quantities.  */
typedef uint16_t Elf32_Section;
typedef uint16_t Elf64_Section;

/* Type for version symbol information.  */
typedef Elf32_Half Elf32_Versym;
typedef Elf64_Half Elf64_Versym;

 

typedef struct
{
  unsigned char e_ident[EI_NIDENT];     /* Magic number and other info, EI_NIDENT = 16, 16个字符*/
  Elf64_Half    e_type;                 /* Object file type, typedef uint16_t Elf64_Half;  2*/ 
  Elf64_Half    e_machine;              /* Architecture ,typedef uint16_t Elf64_Half; 2*/
  Elf64_Word    e_version;              /* Object file version, typedef uint32_t Elf64_Word; 4*/
  Elf64_Addr    e_entry;                /* Entry point virtual address, typedef uint64_t Elf64_Addr; 8*/
  Elf64_Off     e_phoff;                /* Program header table file offset,typedef uint64_t Elf64_Off; 8*/
  Elf64_Off     e_shoff;                /* Section header table file offset,typedef uint64_t Elf64_Off; 8*/
  Elf64_Word    e_flags;                /* Processor-specific flags, typedef uint32_t Elf64_Word; 4*/
  Elf64_Half    e_ehsize;               /* ELF header size in bytes,typedef uint16_t Elf64_Half; 2*/
  Elf64_Half    e_phentsize;            /* Program header table entry

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值