ELF 可重定位目标文件简析

本博客在 X86-64 系统上运行,实验用例为以下两个 C 语言程序

  main.c

#include<stdio.h>
int sum(int *a, int n);
int array[2] = {1, 2};
int main(){
    int val = sum(array, 2);
    return val;
}

  sum.c

int sum(int *a, int n){
    int i, s = 0;
    for(i = 0; i < n; i++){
        s += a[i];
    }
    return s;
}

一、下面是一个典型程序的转换处理过程:

   本博客主要讲解可重定位目标文件(.o 文件),所以前面的处理过程就不展开讲解了。

 二、使用链接的前提是利用符号表示跳转位置和变量的方法简化了问题(汇编)

  左侧全部使用 0 1 来表示程序, 0010 表示“跳转”指令,指令后接的就是跳转的地址,现在跳转的地址是 0101 (即 5),但是如果在 3 的位置插入一条指令的话,那么需要跳转的地址可能就不是 0101 了,从而导致程序的修改。  

  而右侧使用符号很好地为程序员解决了这个烦恼。在程序中,用助记符表示操作码,用符号表示位置,用助记符表示寄存器

  例如上例,先确定 L0 的地址,再在 jmp 指令中填入 L0 的地址。

三、ELF 可重定位目标文件格式

 四、 ELF 头

  我们重点了解 ELF 头 和 节头表 的信息。

  ELF 头位于 ELF 文件开始,包含文件结构的说明信息,分 32 位系统和 64 位系统,下面分别是 32 位系统和 64 位系统对应的 ELF 头的数据结构。

  在Linux 的 /usr/include/elf.h 文件中查看

   其中魔数( Magic number) :文件开头几个字节,用来确定文件的类型或格式。(加载或读取文件时,用魔数确认文件类型是否正确)

  a.out 的魔数:01H 07H

  PE 的魔数:4DH 5AH

  ELF 的魔数:7f 45 4c 46  (其中 45 4c 46 是 ELF 的 ASCII 码值)

  可重定位目标文件是二进制文件,在linux终端 输入以下命令,就可以看见 ELF头的信息。(不同设备运行结果可能是不一样的)

readelf -h main.o

  

   1. 入口点地址为 0x0 :这是 ELF 文件,所以给出的是链接视图,不是执行视图。

  2. 本头的大小为 64 字节,说明在 ELF文件中,下一个块(.text) 的起始位置很有可能为 0x40。

  3. 最后方框中的内容的意思是:节头表中每一个表项的大小为 64 个字节,一共有 12 个表项,所以字节表的大小为 64*12 = 768(即 0x300)

五、节头表(Section header)

  下面是 32 位系统和 64 位系统的节头表的数据结构

  输入以下命令可以查看节头表的信息

readelf -S main.o

  

   根据偏移量和大小,可以得到以下 可重定位目标文件 main.o 的结构‘

  

 其中 .bss 是不分配空间的。

猜你喜欢

转载自www.cnblogs.com/lyw-hunnu/p/11619512.html
今日推荐