Linker and Loader Sep 25 2006 Copyright Tsinghua

  • Slides: 41
Download presentation
链接器、加载器 Linker and Loader Sep. 25, 2006 Copyright @ Tsinghua University Page 1

链接器、加载器 Linker and Loader Sep. 25, 2006 Copyright @ Tsinghua University Page 1

Sep. 25, 2006 Copyright @ Tsinghua University Page 3

Sep. 25, 2006 Copyright @ Tsinghua University Page 3

编译器驱动程序 • 编译器驱动程序为用户根据需求调用预处理器、汇 编器和链接器。 • 以GCC为例,我们要用用GCC编译系统编译如下程 序: /* swap. c*/ /* main. c */

编译器驱动程序 • 编译器驱动程序为用户根据需求调用预处理器、汇 编器和链接器。 • 以GCC为例,我们要用用GCC编译系统编译如下程 序: /* swap. c*/ /* main. c */ void swap(); int buf[2] = {1. 2}; int main() { swap(); return 0; } Sep. 25, 2006 extern int buf[]; int *bufp 0 = &buf[0]; int *bufp 1; void swap() { int temp; bufp 1 = &buf[1]; temp = *bufp 0; *bufp 0 = *bufp 1; *bufp 1 = temp; } Copyright @ Tsinghua University Page 5

Sep. 25, 2006 Copyright @ Tsinghua University Page 11

Sep. 25, 2006 Copyright @ Tsinghua University Page 11

符号表示例 • 下面是main. o的符号表的最后3个表目: Sep. 25, 2006 Copyright @ Tsinghua University Page 15

符号表示例 • 下面是main. o的符号表的最后3个表目: Sep. 25, 2006 Copyright @ Tsinghua University Page 15

静态库使用示例 对于如下程序main 2. c,它调用了静态库libv. a中向量加法模块 addvec. o中的函数,因此编译和链接main 2. c时,需要在命令行 中输入如下的参数: /* main 2. c

静态库使用示例 对于如下程序main 2. c,它调用了静态库libv. a中向量加法模块 addvec. o中的函数,因此编译和链接main 2. c时,需要在命令行 中输入如下的参数: /* main 2. c */ #include <stdio. h> #include “vector. h” int x[2] = {1, 2}; int y[2] = {3, 4}; int z[2]; int main() { add. Vec(x, y, z, 2); printf(“z = [%d %d]n”, z[0], z[1]); return 0; } Sep. 25, 2006 unix> gcc –O 2 –c main 2. c unix> gcc –static –o p 2 main 2. o. /libv. a Copyright @ Tsinghua University Page 21

示例程序的静态链接示意图 main 2. c vector. h libc. a libv. a main 2. o addvec.

示例程序的静态链接示意图 main 2. c vector. h libc. a libv. a main 2. o addvec. o p 2 Sep. 25, 2006 printf. o以及被printf. o 调用的其他模块 完全链接的 可执行目标文件 Copyright @ Tsinghua University Page 22

Sep. 25, 2006 Copyright @ Tsinghua University Page 25

Sep. 25, 2006 Copyright @ Tsinghua University Page 25

重定位符号引用算法 foreach section s{ foreach relocation entry r{ refptr = s + r. offset;

重定位符号引用算法 foreach section s{ foreach relocation entry r{ refptr = s + r. offset; if ( r. type == R_386_PC 32 ) { refaddr = ADDR(s) + r. offset; *refptr = (unsigned) ( ADDR(r. symbol)+*refptr -refaddr); } if ( r. type == R_386_32 ) *refptr = (unsigned) ( ADDR(r. symbol)+*refptr); } } Sep. 25, 2006 Copyright @ Tsinghua University Page 29

重定位符号示例 在 7. 2所示的程序中,main. o调用了swap. o中定义的函数swap, call指令的反汇编结果如下: 6: e 8 fc ff ff ff

重定位符号示例 在 7. 2所示的程序中,main. o调用了swap. o中定义的函数swap, call指令的反汇编结果如下: 6: e 8 fc ff ff ff call 7<main+0 x 7> swap(); 7: R_386_PC 32 swap relocation entry 其中relocation entry含义为: r. offset = 0 x 7; r. symbol = swap; r. type = R_386_PC 32 假设链接器已经确定: ADDR(s) = ADDR(. text) =0 x 80483 b 4 ADDR(r. symbol) = ADDR(swap) = 0 x 80483 c 8 则重定位计算如下: refaddr = ADDR(s) + r. offset = 0 x 80483 bb refptr = (unsigned) (ADDR(r. symbol) +*refptr - refaddr) = (unsigned) (0 x 80483 c 8 + (-4) – 0 x 80483 bb) = 0 x 9 Sep. 25, 2006 Copyright @ Tsinghua University Page 30

Linux的运行时内存映像 Memory invisable to user code 0 xc 0000000 Stack pointer 0 x 40000000

Linux的运行时内存映像 Memory invisable to user code 0 xc 0000000 Stack pointer 0 x 40000000 brk load from the executable file 0 x 08048000 Sep. 25, 2006 Copyright @ Tsinghua University Page 34

应用程序中加载和链接共享库 除了在编译时、加载时完成对共享库的链接,有时候还需要在运 行时由动态链接器加载和链接共享库。 #inckude <dlfcn. h> void *dlopen(const char *filename, int flag) void *dlsym(void

应用程序中加载和链接共享库 除了在编译时、加载时完成对共享库的链接,有时候还需要在运 行时由动态链接器加载和链接共享库。 #inckude <dlfcn. h> void *dlopen(const char *filename, int flag) void *dlsym(void *handle, char *symbol) void *dlclose(void *handle) void *dlerror(void) Sep. 25, 2006 Copyright @ Tsinghua University Page 40