现在的位置: 首页 > 综合 > 正文

深入理解计算机系统第七章读书笔记

2019年07月18日 ⁄ 综合 ⁄ 共 5390字 ⁄ 字号 评论关闭

/**1.可重定位目标文件  */
ELF可重定位目标文件主要包括一下部分:
(1)ELF头:
  生成文件的系统的字的大小和字节序列
  链接器语法分析和目标文件的信息
    (2).text      已编译程序的机器代码
    (3).rodata    只读数据
    (4).data      已初始化的全局变量C变量
    (5).bss       未初始化的全局C变量
    (6).symtab    符号表
    (7).rel.text  任何调用外部函数或者使用全局变量的指令都需要修改
    (8).rel.data  被模块引用或定义的全局变量的重定位信息
    (9).debug     调试符号表,程序中定义的局部变量和类型定义,程序中定义和引用的全局变量,以及原始的C源文件  -g选项
    (10).line     原始C源程序行号和.text节中的机器指令间的映射
    (11).strtab   字符串表,包含.symtab和.bss中的符号表以及节头部的节名称,以null结尾
(12)节头部表

/**2.symtab的格式(符号标)  */
基本条目格式(.symtab是该条目的数组)
typedef struct{
    int name;       .strtab的中的字节偏移
    int value;      表示距离定义目标的节的起始位置的偏移量
    int size;       目标的大小(以字节为单位)
    char type:4,    类型
        binding 4;  符号是本地的还是全局的  
     char reserved;   
    char section;   每个符号关联对应的一个节,section用于指定对应的节。对应到节头部的索引(ELF或者.o文件中Ndx),
                    /特殊的三类伪节:(1)ABS不该被重定位的符号(2)UNDEF为定义的符号,本目标模块中引用,其他地方定义
                    /(3)COMMON未被分配的未初始化的数据目标。此三类伪节在节头部表中无条目
} Elf_Symbol;

ELF 头:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2's complement(二补数), little endian(小端模式)
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (可执行文件)
  Machine:                           Intel 80386
  Version:                           0x1
  入口点地址:               0x8048094
  程序头起点:          52 (bytes into file)
  Start of section headers:          432 (bytes into file)
  标志:             0x0
  本头的大小:       52 (字节)
  程序头大小:       32 (字节)
  Number of program headers:         3
  节头大小:         40 (字节)
  节头数量:         9
  字符串表索引节头: 6

节头:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        08048094 000094 000049 00  AX  0   0  4
  [ 2] .eh_frame         PROGBITS        080480e0 0000e0 000058 00   A  0   0  4
  [ 3] .data             PROGBITS        08049138 000138 00000c 00  WA  0   0  4
  [ 4] .bss              NOBITS          08049144 000144 000004 00  WA  0   0  4
  [ 5] .comment          PROGBITS        00000000 000144 00002a 01  MS  0   0  1
  [ 6] .shstrtab         STRTAB          00000000 00016e 00003f 00      0   0  1
  [ 7] .symtab           SYMTAB          00000000 000318 000120 10      8   9  4
  [ 8] .strtab           STRTAB          00000000 000438 000048 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

There are no section groups in this file.

程序头:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x08048000 0x08048000 0x00138 0x00138 R E 0x1000
  LOAD           0x000138 0x08049138 0x08049138 0x0000c 0x00010 RW  0x1000
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x4

 Section to Segment mapping:
  段节...
   00     .text .eh_frame
   01     .data .bss
   02     

There is no dynamic section in this file.

该文件中没有重定位信息。

The decoding of unwind sections for machine type Intel 80386 is not currently supported.

Symbol table '.symtab' contains 18 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 08048094     0 SECTION LOCAL  DEFAULT    1
     2: 080480e0     0 SECTION LOCAL  DEFAULT    2
     3: 08049138     0 SECTION LOCAL  DEFAULT    3
     4: 08049144     0 SECTION LOCAL  DEFAULT    4
     5: 00000000     0 SECTION LOCAL  DEFAULT    5
     6: 00000000     0 FILE    LOCAL  DEFAULT  ABS main.c
     7: 00000000     0 FILE    LOCAL  DEFAULT  ABS swap.c
     8: 00000000     0 FILE    LOCAL  DEFAULT  ABS
     9: 08049140     4 OBJECT  GLOBAL DEFAULT    3 bufp0
    10: 080480a8    53 FUNC    GLOBAL DEFAULT    1 swap
    11: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND _start
    12: 08049144     0 NOTYPE  GLOBAL DEFAULT    4 __bss_start
    13: 08048094    18 FUNC    GLOBAL DEFAULT    1 main
    14: 08049138     8 OBJECT  GLOBAL DEFAULT    3 buf
    15: 08049144     0 NOTYPE  GLOBAL DEFAULT    3 _edata
    16: 08049148     0 NOTYPE  GLOBAL DEFAULT    4 _end
    17: 08049144     4 OBJECT  GLOBAL DEFAULT    4 bufp1

/**3.符号解析  */
/** 解析多重定义的全局符号  */
函数和已经初始化的全局变量是强符号,为初始化的全局变量是弱符号。
规则1:不允许出现多个强符号
规则2:如果一个强符号和多个弱符号,则选择强符号
规则3:如果有多个弱符号,则任意选择一个弱符号
(这种情形下会发生很多不易察觉的问题,所以要尽量避免多重定义的全局符号)

/**4.链接器使用静态库解析引用  */
符号解析阶段,链接器从左到右按照它在编译器驱动程序命令行上出现的相同顺序来扫描可重定位目标文件和存档文件(编译器自动将.c文件转换成.o文件)。
扫描过程中,链接器维持三个集合:
(1).o可重定位目标文件集合E
(2)未解析符号集合U(引用但未定义)
(3)在之前的输入文件已经定义的符号集合D
a)输入文件f是目标文件,将f添加到集合E,修改U和D
b)输入文件f是存档文件,尝试匹配U中未解析的符号和存档文件成员定义的符号。存档文件存在多个文件成员,所以需要一次进行匹配。匹配成功则修改U和D,并将存档文件中该文件成员归类到集合E中。
c)链接器完成对命令行上输入文件的扫描后,U非空,则链接器报错。否则合并E中的目标文件产生可执行目标文件。

上面a)、b)、c)描述的过程和编译器驱动程序命令行中的顺序有很大的关系。因此要求
1)库文件一般放置在命令行的结尾
2)库文件相互独立的话,相互位置可以随意放置;库文件不独立时,被依赖的库文件放置在最后。
总的原则是,被依赖越严重的放置在命令行的最后面。

/**5.重定位  */
重定位是在前一步符号解析的基础上合并输入模块,并为每个符号分配运行时的地址。
(1)重定义节和符号定义
    将所有相同类型的节合并成同一类型的新的聚合节
    将运行时的存储器地址赋给新的聚合节,赋给输入模块定义的每个节和每个符号
(2)重定位节中的符号引用
    链接器修改代码节和数据节中对于每个符号的引用,使得它们指向正确的运行时的地址。依据重定位条目进行。
重定位条目:
    代码的重定位条目放在.rel.text
    数据的重定位条目放在.rel.data
    typedef struct{
        int offset;
        int symbol:24,
            type:8;
    }Elf32_Rel;

/**6.动态链接共享库 */
    共享库是一个目标模块,在运行时,可以加载在任意的存储器地址,并和一个在存储器中的程序链接起来。这个过程成为动态链接,是由动态链接器的程序来实现的。
    在unix中动态链接共享库通常用.so后缀来表示,windows以.dll表示。
    共享的方式:
    (1)所有引用该库的可执行目标文件共享这个.so文件中的代码和数据
    (2)在存储器中,一个共享文件的库.txt副本可以被不同的正在执行的进程共享
    动态链接器通过执行:
    (1)重定位共享库的文本和数据到某个存储器段
    (2)重定位部分链接的可执行目标文件中所有对于动态链接库文件中定义的符号的引用。
    完成上面的重定位后动态链接器将控制权转交给应用程序。
    Linux为动态链接器提供的接口
    #include<dlfcn>
    void *dlopen(const char *filename,int flag);//以flag选项打开filename指向的动态链接库文件,成功则返回只想句柄的指针
    void *dlsym(void *handle,char *symbol);//若句柄handle指向的符号存在,则返回symbol指针指向符号地址
    int *dlclose(void *handle);//关闭句柄handle对应的共享库
    const char *dlerror(void);//返回字符串,描述调用前述函数时的产生的错误
   

抱歉!评论已关闭.