👹
Carlos's Tech Blog
  • 🧔ECUs
    • ZYNQ_Documents
      • [ZYNQ] 构建ZYNQ的BSP工程
      • [ZYNQ] 启动流程
      • [ZYNQ] Secure Boot Flow
      • [ZYNQ] Provisioning Guideline
      • [ZYNQ] Decrypting Partition by the Decrypt Agent Using PUF key
      • [ZYNQ] enabling the cryptsetup on ramdisk
      • [ZYNQ] Encrypt external files based on file system using PUF key
      • [ZYNQ] Loading an Encrypted Linux kernel at U-Boot with a KUP Key
      • [ZYNQ] cross-compile the cryptsetup on Xilinx ZYNQ aarch64 platform
      • [ZYNQ] Linux Linaro系统镜像制作SD卡启动
    • S32G_Documents
      • [S32G] Going through the s32g hard/soft platform
      • [S32G] S32g247's Secure Boot using HSE firmware
        • S32g2 HSE key config
        • How S32g verify secure boot image
        • S32g secure boot signature generation
        • How to download and build S32g Secure boot image
        • [S32G] OTA with Secure Boot
    • RT117x_Documents
      • [RT-117x]IMX RT1170 Provisioning Guideline
      • [RT-117x] Going through the MX-RT1170 hard/soft platform
      • [RT-117x] i.MX-RT1170's Secure Boot
        • [RT-117x]Signing image with the HSM (SignServer)
    • LS104x_Documents
      • [LS104x] bsp project
      • [LS104x] boot flow
      • [LS104x] secure boot
      • [LS104x] Application Note, Using the PKCS#11 in TCU platform
      • [LS104x] 使用ostree更新rootfs
      • [LS104x] ostree的移植
      • [LS104x] Starting with Yocto
      • [LS104x] 使用FIT的kernel格式和initramfs
    • IMX6/8_Documents
      • [IMX6] Defining A U-Boot Command
      • NXP IMX6 嵌入式板子一些笔记
      • NXP-imx6 initialization
    • Vehicle_Apps
      • [SecOC] Tree
        • [SecOC] SecOC Freshness and MAC Truncation
  • 😾TECH
    • Rust Arm OS
      • ARMv7m_Using_The_RUST_Cross_Compiler
    • ARM
      • ARM-v7-M
        • 01_ARMv7-M_处理器架构技术综述
        • 02_ARMv7-M_编程模型与模式
        • 03_ARMv7-M_存储系统结构
        • 04_ARMv7-M_异常处理及中断处理
      • ARM-v8-A
        • 02_ARMv8_基本概念
        • 03_ARMv8_指令集介绍_加载指令集和存储指令集
        • 04_ARMv8_指令集_运算指令集
        • 05_ARMv8_指令集_跳转_比较与返回指令
        • 06_ARMv8_指令集_一些重要的指令
        • 0X_ARMv8_指令集_基于汇编的UART驱动
        • 07_ARMv8_汇编器Using as
        • 08_ARMv8_链接器和链接脚本
        • 09_ARMv8_内嵌汇编(内联汇编)Inline assembly
        • 10_ARMv8_异常处理(一) - 入口与返回、栈选择、异常向量表
        • 11_ARMv8_异常处理(二)- Legacy 中断处理
        • 12_ARMv8_异常处理(三)- GICv1/v2中断处理
        • 13_ARMv8_内存管理(一)-内存管理要素
        • 14_ARMv8_内存管理(二)-ARM的MMU设计
        • 15_ARMv8_内存管理(三)-MMU恒等映射及Linux实现
        • 16_ARMv8_高速缓存(一)cache要素
        • 17_ARMv8_高速缓存(二)ARM cache设计
        • 18_ARMv8_高速缓存(三)多核与一致性要素
        • 19_ARMv8_TLB管理(Translation Lookaside buffer)
        • 20_ARMv8_barrier(一)流水线和一致性模型
        • 21_ARMv8_barrier(二)内存屏障案例
      • ARM Boot Flow
        • 01_Embedded_ARMv7/v8 non-secure Boot Flow
        • 02_Embedded_ARMv8 ATF Secure Boot Flow (BL1/BL2/BL31)
        • 03_Embedded_ARMv8 BL33 Uboot Booting Flow
      • ARM Compiler
        • Compiler optimization and the volatile keyword
      • ARM Development
        • 在MACBOOK上搭建ARMv8架构的ARM开发环境
        • Starting with JLink debugger or QEMU
    • Linux
      • Kernel
        • 0x01_LinuxKernel_内核的启动(一)之启动前准备
        • 0x02_LinuxKernel_内核的启动(二)SMP多核处理器启动过程分析
        • 0x21_LinuxKernel_内核活动(一)之系统调用
        • 0x22_LinuxKernel_内核活动(二)中断体系结构(中断上文)
        • 0x23_LinuxKernel_内核活动(三)中断体系结构(中断下文)
        • 0x24_LinuxKernel_进程(一)进程的管理(生命周期、进程表示)
        • 0x25_LinuxKernel_进程(二)进程的调度器的实现
        • 0x26_LinuxKernel_设备驱动(一)综述与文件系统关联
        • 0x27_LinuxKernel_设备驱动(二)字符设备操作
        • 0x28_LinuxKernel_设备驱动(三)块设备操作
        • 0x29_LinuxKernel_设备驱动(四)资源与总线系统
        • 0x30_LinuxKernel_设备驱动(五)模块
        • 0x31_LinuxKernel_内存管理(一)物理页面、伙伴系统和slab分配器
        • 0x32_LinuxKernel_内存管理(二)虚拟内存管理、缺页与调试工具
        • 0x33_LinuxKernel_同步管理_原子操作_内存屏障_锁机制等
        • 01_LinuxDebug_调试理论和基础综述
      • Userspace
        • Linux-用户空间-多线程与同步
        • Linux进程之间的通信-管道(上)
        • Linux进程之间的通信-管道(下)
        • Linux进程之间的通信-信号量(System V)
        • Linux进程之间的通信-内存共享(System V)
        • Linux进程之间的通信-消息队列(System V)
        • Linux应用调试(一)方法、技巧和工具 - 综述
        • Linux应用调试(二)工具之coredump
        • Linux应用调试(三)工具之Valgrind
        • Linux机制之内存池
        • Linux机制之对象管理和引用计数(kobject/ktype/kset)
        • Linux机制copy_{to, from}_user
        • Linux设备树 - DTS语法、节点、设备树解析等
        • Linux System : Managing Linux Services - inittab & init.d
        • Linux System : Managing Linux Services - initramfs
      • Kernel Examples
        • Linux Driver - GPIO键盘驱动开发记录_OMAPL138
        • 基于OMAPL138的Linux字符驱动_GPIO驱动AD9833(一)之miscdevice和ioctl
        • 基于OMAPL138的Linux字符驱动_GPIO驱动AD9833(二)之cdev与read、write
        • 基于OMAPL138的字符驱动_GPIO驱动AD9833(三)之中断申请IRQ
        • Linux内核调用SPI驱动_实现OLED显示功能
        • Linux内核调用I2C驱动_驱动嵌套驱动方法MPU6050
    • OPTEE
      • 01_OPTEE-OS_基础之(一)功能综述、简要介绍
      • 02_OPTEE-OS_基础之(二)TrustZone和ATF功能综述、简要介绍
      • 03_OPTEE-OS_系统集成之(一)编译、实例、在QEMU上执行
      • 05_OPTEE-OS_系统集成之(三)ATF启动过程
      • 06_OPTEE-OS_系统集成之(四)OPTEE镜像启动过程
      • 07_OPTEE-OS_系统集成之(五)REE侧上层软件
      • 08_OPTEE-OS_系统集成之(六)TEE的驱动
      • 09_OPTEE-OS_内核之(一)ARM核安全态和非安全态的切换
      • 10_OPTEE-OS_内核之(二)对安全监控模式的调用的处理
      • 11_OPTEE-OS_内核之(三)中断与异常的处理
      • 12_OPTEE-OS_内核之(四)对TA请求的处理
      • 13_OPTEE-OS_内核之(五)内存和cache管理
      • 14_OPTEE-OS_内核之(六)线程管理与并发
      • 15_OPTEE-OS_内核之(七)系统调用及IPC机制
      • 16_OPTEE-OS_应用之(一)TA镜像的签名和加载
      • 17_OPTEE-OS_应用之(二)密码学算法和安全存储
      • 18_OPTEE-OS_应用之(三)可信应用的开发
      • 19_OPTEE-OS_应用之(四)安全驱动开发
      • 20_OPTEE-OS_应用之(五)终端密钥在线下发系统
    • Binary
      • 01_ELF文件_目标文件格式
      • 02_ELF文件结构_浅析内部文件结构
      • 03_ELF文件_静态链接
      • 04_ELF文件_加载进程虚拟地址空间
      • 05_ELF文件_动态链接
      • 06_Linux的动态共享库
      • 07_ELF文件_堆和栈调用惯例以ARMv8为例
      • 08_ELF文件_运行库(入口、库、多线程)
      • 09_ELF文件_基于ARMv7的Linux系统调用原理
      • 10_ELF文件_ARM的镜像文件(.bin/.hex/.s19)
    • Build
      • 01_Script_makefile_summary
    • Rust
      • 02_SYS_RUST_文件IO
    • Security
      • Crypto
        • 1.0_Security_计算机安全概述及安全需求
        • 2.0_Security_随机数(伪随机数)
        • 3.0_Security_对称密钥算法加解密
        • 3.1_Security_对称密钥算法之AES
        • 3.2_Security_对称密钥算法之MAC(CMAC/HMAC)
        • 3.3_Security_对称密钥算法之AEAD
        • 8.0_Security_pkcs7(CMS)_embedded
        • 9.0_Security_pkcs11(HSM)_embedded
      • Tools
        • Openssl EVP to implement RSA and SM2 en/dec sign/verify
        • 基于Mac Silicon M1 的OpenSSL 编译
        • How to compile mbedtls library on Linux/Mac/Windows
    • Embedded
      • eMMC启动介质
  • 😃Design
    • Secure Boot
      • JY Secure Boot Desgin
    • FOTA
      • [FOTA] Module of ECUs' FOTA unit design
        • [FOTA] Tech key point: OSTree Deployment
        • [FOTA] Tech key point: repositories role for onboard
        • [FOTA] Tech key point: metadata management
        • [FOTA] Tech key point: ECU verifying and Decrpting
        • [FOTA] Tech key point: time server
      • [FOTA] Local-OTA for Embedded Linux System
    • Provisioning
      • [X-Shield] Module of the Embedded Boards initialization
    • Report
由 GitBook 提供支持
在本页
  • ELF文件结构
  • 1. 文件结构
  • 附录 I: 原始C文件
  1. TECH
  2. Binary

02_ELF文件结构_浅析内部文件结构

https://github.com/carloscn/blog/issues/6

ELF文件结构

1. 文件结构

1.1. Scope

通用的ELF文件,我们可以分为四大类:

  • Header: 描述基本属性的

  • Sections:各个段,包括.text .data .bss等

  • Section header tables:ELF中所有段的段名、段长度、文件偏移、读写权限等

  • Helper tables:辅助结构,字符串表、符号表。

----------------------------------------
       ELF Header(描述基本属性)               
----------------------------------------
       .text (段1)
----------------------------------------
       .data (段2)
----------------------------------------
       .bss  (段3)
----------------------------------------
       ...other 
          sections...
----------------------------------------
       Section header tables (段表)
----------------------------------------
       String Tables   (字符串表)
       Symbol Tables   (符号表)
----------------------------------------

1.2. Header

aarch64-none-linux-gnu-gcc main.c -o main

readelf -h main

➜ readelf -h main
ELF Header:
  // e_ident members
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 // ELF 魔数
  Class:                             ELF64                 // 有ELF32 / ELF64
  Data:                              2's complement, little endian 
  Version:                           1 (current)  // always 1
  OS/ABI:                            UNIX - System V  
  ABI Version:                       0
  
  // e_type members
  Type:                              EXEC (Executable file)
  // e_machine members
  Machine:                           AArch64
  // e_version members
  Version:                           0x1
  // e_entry members: 规定ELF程序的入口的虚拟地址,操作系统在加载完程序后从这个地址开始执行进程指令
  Entry point address:               0x4004c0
  // e_phoff members:ELF链接视图和执行视图相关
  Start of program headers:          64 (bytes into file)
  // e_shoff member:段表在文件中的偏移,从13521字节开始
  Start of section headers:          13520 (bytes into file)
  // e_word
  Flags:                             0x0
  // e_ehsize: ELF文件头的大小
  Size of this header:               64 (bytes)
  // e_phentsize: ELF链接视图和执行视图相关
  Size of program headers:           56 (bytes)
  // e_phnum: ELF链接视图和执行视图相关
  Number of program headers:         9
  // e_shentsize: 段表描述符的大小 一般为sizeof(Elf32_Shdr)
  Size of section headers:           64 (bytes)
  // e_shnum: 段表描述符的数量。
  Number of section headers:         38
  // e_shstrndx: 段表字符串表所在的段在段表中的下标
  Section header string table index: 37

ELF的类型可以参考:elf(5) - Linux manual page (man7.org)

1.3. Section Header Table(段表)

段表的作用是,在ELF中记录每个段的基本属性(段名、段的长度、在文件中的偏移、读写权限及段的其他属性)。编译器和链接器还有装载器都需要依靠段表来定位和访问各个段的属性。在elf文件头中e_shoff 决定段表的存储位置。

readelf -S main

➜  work-temp readelf -S main
There are 38 section headers, starting at offset 0x34d0:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .interp           PROGBITS         0000000000400238  00000238
       000000000000001b  0000000000000000   A       0     0     1
  [ 2] .note.ABI-tag     NOTE             0000000000400254  00000254
       0000000000000020  0000000000000000   A       0     0     4
  [ 3] .hash             HASH             0000000000400278  00000278
       0000000000000028  0000000000000004   A       5     0     8
  [ 4] .gnu.hash         GNU_HASH         00000000004002a0  000002a0
       000000000000001c  0000000000000000   A       5     0     8
  [ 5] .dynsym           DYNSYM           00000000004002c0  000002c0
       0000000000000078  0000000000000018   A       6     1     8
  [ 6] .dynstr           STRTAB           0000000000400338  00000338
       0000000000000044  0000000000000000   A       0     0     1
  [ 7] .gnu.version      VERSYM           000000000040037c  0000037c
       000000000000000a  0000000000000002   A       5     0     2
  [ 8] .gnu.version_r    VERNEED          0000000000400388  00000388
       0000000000000020  0000000000000000   A       6     1     8
  [ 9] .rela.dyn         RELA             00000000004003a8  000003a8
       0000000000000018  0000000000000018   A       5     0     8
  [10] .rela.plt         RELA             00000000004003c0  000003c0
       0000000000000060  0000000000000018  AI       5    23     8
  [11] .init             PROGBITS         0000000000400420  00000420
       0000000000000018  0000000000000000  AX       0     0     4
  [12] .plt              PROGBITS         0000000000400440  00000440
       0000000000000060  0000000000000000  AX       0     0     16
  [13] .text             PROGBITS         00000000004004c0  000004c0
       0000000000000214  0000000000000000  AX       0     0     64
  [14] CARLOS_FUNC       PROGBITS         00000000004006d4  000006d4
       0000000000000030  0000000000000000  AX       0     0     4
  [15] .fini             PROGBITS         0000000000400704  00000704
       0000000000000014  0000000000000000  AX       0     0     4
  [16] .rodata           PROGBITS         0000000000400718  00000718
       000000000000002f  0000000000000000   A       0     0     8
  [17] .eh_frame_hdr     PROGBITS         0000000000400748  00000748
       000000000000005c  0000000000000000   A       0     0     4
  [18] .eh_frame         PROGBITS         00000000004007a8  000007a8
       000000000000012c  0000000000000000   A       0     0     8
  [19] .init_array       INIT_ARRAY       0000000000410de8  00000de8
       0000000000000008  0000000000000008  WA       0     0     8
  [20] .fini_array       FINI_ARRAY       0000000000410df0  00000df0
       0000000000000008  0000000000000008  WA       0     0     8
  [21] .dynamic          DYNAMIC          0000000000410df8  00000df8
       00000000000001e0  0000000000000010  WA       6     0     8
  [22] .got              PROGBITS         0000000000410fd8  00000fd8
       0000000000000010  0000000000000008  WA       0     0     8
  [23] .got.plt          PROGBITS         0000000000410fe8  00000fe8
       0000000000000038  0000000000000008  WA       0     0     8
  [24] .data             PROGBITS         0000000000411020  00001020
       0000000000000018  0000000000000000  WA       0     0     8
  [25] CARLOS_DATA       PROGBITS         0000000000411038  00001038
       0000000000000004  0000000000000000  WA       0     0     4
  [26] .bss              NOBITS           000000000041103c  0000103c
       000000000000000c  0000000000000000  WA       0     0     4
  [27] .comment          PROGBITS         0000000000000000  0000103c
       000000000000005d  0000000000000001  MS       0     0     1
  [28] .debug_aranges    PROGBITS         0000000000000000  000010a0
       0000000000000130  0000000000000000           0     0     16
  [29] .debug_info       PROGBITS         0000000000000000  000011d0
       0000000000000715  0000000000000000           0     0     1
  [30] .debug_abbrev     PROGBITS         0000000000000000  000018e5
       00000000000002a1  0000000000000000           0     0     1
  [31] .debug_line       PROGBITS         0000000000000000  00001b86
       000000000000037d  0000000000000000           0     0     1
  [32] .debug_str        PROGBITS         0000000000000000  00001f03
       00000000000004ea  0000000000000001  MS       0     0     1
  [33] .debug_loc        PROGBITS         0000000000000000  000023ed
       0000000000000182  0000000000000000           0     0     1
  [34] .debug_ranges     PROGBITS         0000000000000000  00002570
       0000000000000090  0000000000000000           0     0     16
  [35] .symtab           SYMTAB           0000000000000000  00002600
       0000000000000b10  0000000000000018          36    90     8
  [36] .strtab           STRTAB           0000000000000000  00003110
       0000000000000258  0000000000000000           0     0     1
  [37] .shstrtab         STRTAB           0000000000000000  00003368
       0000000000000161  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  p (processor specific)

以上表为下列结构体的数组

typedef struct
{
  Elf64_Word	sh_name;		/* Section name (string tbl index) */
  Elf64_Word	sh_type;		/* Section type */
  Elf64_Xword	sh_flags;		/* Section flags */
  Elf64_Addr	sh_addr;		/* Section virtual addr at execution 如果该段可以被加载,显示为进程空间的虚拟地址,否则为0 */
  Elf64_Off		sh_offset;		/* Section file offset 这段对.bbs没有意义 */
  Elf64_Xword	sh_size;		/* Section size in bytes */
  Elf64_Word	sh_link;		/* Link to another section */
  Elf64_Word	sh_info;		/* Additional section information */
  Elf64_Xword	sh_addralign;	/* Section alignment 有的段有对齐要求,0/1表示没有对其要求 */
  Elf64_Xword	sh_entsize;		/* Entry size if section holds table */
} Elf64_Shdr;

重定位表 Relocation Table

在其他段里面引用了一些段的地址,这些地址单独存成一个重定位表,例如printf("hello world"), 里面的字符串就要被重定位到一个单独的区域。

字符串表 String Table

段名、变量名长度不固定,单独放在一个连续的区域里面,使用偏移来索引字符串。.strtab,.shstrtab字符串表, 在header里面 e_shstrndx: 段表字符串表所在的段在段表中的下标 表示

附录 I: 原始C文件

// main.c
#include <stdio.h>

int a = 84;
int b;
const int g = 0xAA;
void func(int i)
{
    printf("helloworld!%d\n", i);
}

__attribute((section("CARLOS_DATA"))) int name = 4;
__attribute((section("CARLOS_FUNC"))) int func2 (void){
    int m = 9, n = 10;
    int q;
    q = m+n;
    return q;
}

int main(void)
{
    static int var_1 = 85;
    static int var_2;
    int c = 6;
    int d;
    func(var_1 + var_2 + c + d);
    return c;
}
上一页01_ELF文件_目标文件格式下一页03_ELF文件_静态链接

最后更新于1年前

😾