您的位置:首页 > 理论基础

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

2013-11-23 21:10 363 查看
/**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);//返回字符串,描述调用前述函数时的产生的错误
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: