zoukankan      html  css  js  c++  java
  • 软件构件基础-->目标文件分析

    目标文件格式

    目标文件是已经编译但还没有链接的文件,其格式与可执行文件格式很类似。

    在Windows中目标文件格式为PE(Portable Executable),文件以".obj"为后缀。

    在Linux中目标文件格式为ELF(Executable Linkable Format),文件名称没有明确规定一般以".o"结尾。

    目标文件内容

          目标文件内容是已经经过整理的内容,将代码、数据、符号表、调试信息、字符串等以"节"(Section)或"段"(Segment)的形式存储,

    节和段都表示一个固定长度的区域,在ELF的链接和装载时有区别。段之间存储可能因为字节对齐的原因,会有间隔。

    段名称:

    目标文件默认段的名称以"."作为前缀,如下定义:

    .code 或 .text       代码段

    .data                            初始化的数据段

    .bss                             未初始化数据段,编译器默认赋值0,所以此段只表明未初始化数据空间大小,但并不实际占用目标文件存储空间。

                 但在实际运行时,是会占用内存空间的。

    .rodata                         只读数据

    .comment                     编译器版本信息

    .debug                         调试信息

    .dynamic                      动态链接信息

    .hash                           符号哈希表

    .line                             调试时的行号表

    .note                            额外的编译信息

    .strtab                          字符串表

    .symtab                        符号表

    .shstrtab                       段名表

    .plt和.got                      动态链接跳转表和全局入口表

    .init和.fini                     程序初始化与终结代码段

    当然也可以自定义段名,为了不与系统默认段名冲突,所以不使用前缀。

    在gcc编译器下,使用格式 "__attribute__((section("name")))" 定义。

    __attribute__((section("Global")))  int global=42;
    #指定变量global位于Global段中,可以通过链接脚本指定变量位置
    
    __attribute__((section("Foo"))) void foo(void)
    {
     
    }
    
    #指定函数foo位于Foo段中,可以通过链接脚本指定函数位置

    简易的ELF文件结构

    ELF文件头
    代码段(.text)
    数据段(.text)
    未初始化段(.bss)
    其他段
    段表
    符号表

    文件头:

    ELF文件头包含了魔数、数据存储方式、运行平台、版本、入口地址、段表地址等等。

    读取这些数据,是按照一个结构体Elf32_Ehdr或Elf64_Ehdr(位于/usr/include/elf.h)来一一对应的。

    可用“readelf -h *.o ”查看文件头。

    段表:

    整个段表在文件的起始位置由文件头的"e_shoff"决定,段表用于保存段的基本属性,包括段名、段长度、在文件中的偏移等等。

    和文件头一样,这些数据也是按照结构体Elf32_Shdr(位于/usr/include/elf.h)来一一对应的。

    可用“readelf -S *.o ”查看段表。

    重定位表(.rel.text  real.data):

    重定位表存储了外部引用的数据或函数,在最后的链接过程中,需要为它们重新制定运行地址。

    字符串表(.strtab .shstrtab):

    将文件中使用的段名、变量名等集中存储于此,其他段仅仅存储它在字符串表中的偏移量,便能推出字符串内容。

    符号表(.symtab):

    符号表记录了目标文件中所用到的所有符号,每个符号都有一个符号值。

    符号表也是由结构体Elf32_Sym来解析。

    可用“readelf -s *.o ”查看符号表。

    特殊符号:

    有些符号并不存在工程的源文件中,而是链接脚本可以定义一些特殊值(一般是地址),但是源文件可以引用这些值。

    在最后链接过程中,连接器会自动为这些符号指定正确的值。

    常用的符号有:

    __executable_start:程序起始地址

    __etext或_etext或etext:代码段结束地址

    _edata或edata:数据段结束地址

    _end或end:程序结束地址

    使用这些值:

    extern char __executable_start[];
    extern char __etext[],_etext[],etext[];
    extern char _end[],end[];
  • 相关阅读:
    电子书《数字化转型领导者的技术修养》免费下载
    数字签名
    C:条件编译
    轻量级日志收集方案Loki
    安装Kubernetes(k8s)保姆级教程---无坑版
    设计模式七大原则-迪米特法则
    设计模式七大原则-开闭原则
    设计模式七大原则-里氏替换原则
    deepin-terminal改造风云再起
    deepin-terminal再改造
  • 原文地址:https://www.cnblogs.com/KcMeterCEC/p/5407407.html
Copyright © 2011-2022 走看看