Linux c++ 编程之链接与装载 -基础篇--v0.3--20120509

8,725 views

Published on

主要介绍编译,链接与装载的基本概念与原理
静态链接常见错误分析,
静态链接常用链接选项使用讲解
dlopen/dlsym?常用链接选项讲解

Linux c++ 编程之链接与装载 -基础篇--v0.3--20120509

  1. 1. Linux C++ 编程之链接与装载 —基础篇 五竹 一淘搜索与算法
  2. 2. 课程大纲页• 编译与链接的基本概念• 常见链接错误分析• 静态链接• 动态库 与 动态链接基础• 常用链接选项• 工具介绍
  3. 3. 编译与链接的基本概念
  4. 4. 编译与链接的基本概念//hello.c#include <stdio.h>int main(){ printf("Hello Worldn"); return 0;}编译:gcc hello.c
  5. 5. 编译与链接的基本概念
  6. 6. 编译与链接的基本概念—预处理• 预处理(Prepressing) : -E 表示只进行预处理, 即 : gcc –E hello.c –o hello.i  展开所有 #define 定义的宏  处理所有条件预编译指令,如 #if, #ifdef  递归的将 #include 的文件插入到该预编译文件中  删除各类注释  添加行和文件标识,如 #2 "hello.c" 2 ,用于调试或编译出错报警  保留所有的 #pragma 编译指令,编译器要使用• 对于C++ 来说,预处理后的文件扩展名是 .ii
  7. 7. 编译与链接的基本概念—编译• 编译(Compilation): gcc –S hello.i –o hello.s 编译过程就是把预处理完的文件进行一系列词法分析, 语法分析,语义分析及优化后生成相应的汇编代码文件.• 现在的gcc 把预处理和编译两个步骤合成一个步骤,C语言 使用一个叫做 cc1 的程序来完成,C++则是 cc1plus ,位于 /usr/libexec/gcc/x86_64-redhat-linux/4.1.2/• gcc 实际上是这些后台程序的包装,它会根据参数要求去调 用 cc1(cclplus), 汇编器 as 和链接器 ld
  8. 8. 编译与链接的基本概念—汇编• 汇编(Assembly) : gcc –C hello.s –o hello.o 或 as hello.s -o hello.o• 汇编器是将编译语言转换成机器可以执行的指令.
  9. 9. 编译与链接的基本概念—链接• 链接(Linking):解决 一个程序被分割成多个模块后, 模块间最后如何组合成一个单一程序的问题.• 链接的主要任务是把各个模块之间相互引用的部 分处理好,使各个模块之间能正确的衔接.
  10. 10. 常见链接错误分析 calu.c #include <math.h> #include <stdio.h> int main (void) { double x = sqrt (2.0); printf ("The square root of 2.0 is %fn", x); return 0; } gcc -Wall calu.c -o calc -fno-builtin /tmp/ccKPlcED.o: In function `main: calu.c:(.text+0x1c): undefined reference to `sqrt collect2: ld 返回 1
  11. 11. 常见链接错误分析导致符号未定义的原因: 1. 链接时缺少某个库, 目标文件的路径不正确, 符号 的声明与定义不一样,父类声明的虚函数,父或子类 都没有实现等. 2. C与C++的库之间兼容问题 3. 链接时库的顺序问题
  12. 12. 常见链接错误分析—C与C++之间兼容问题// plusplus_example.h --符号修饰与函数签名int func(int);float func(float); // cplusplus_example.cppclass C{ #include "example.h" int func(int); class C2 int func(int){}; { float func(float){}; int func(int); int C::func(int){}; }; int C::C2::func(int){};}; namespace Nnamespace N {{ int func(int){}; int func(int); class C int C::func(int){}; { } int func(int); };}
  13. 13. 常见链接错误分析—C与C++之间兼容问题 --符号修饰与函数签名函数签名 修饰后名称(符号名)int func(int) _Z4funcifloat func(float) _Z4funcfint C::func(int) _ZN1C4funcEiint C::C2::func(int) _ZN1C2C24funcEiint N::func(int) _ZN1N4funcEiint N::C::func(int) _ZN1N1C4funcEiGCC的基本C++名称修饰方法:1. 所有的符号都以"_Z"开头,2. 对于嵌套的名字(在名称空间或在类里面的),后面紧 跟"N",3. 然后是各个名称空间和类的名字,每个名字前是名字字 符串长度,再以"E"结尾。4. 函数来说,它的参数列表紧跟在"E"后面
  14. 14. 常见链接错误分析—C与C++之间兼容问题 --符号修饰与函数签名#ifdef __cplusplusextern "C" {#endif void * memset(void *, int ,size_t);#ifdef __cplusplus}#endif extern "C" 关键字 条件宏 __cplusplus
  15. 15. 链接时库的顺序问题--libtimeutil
  16. 16. 链接时库的顺序问题--libtimeutil
  17. 17. 链接时库的顺序问题--libdso
  18. 18. 库的顺序问题—示例A(1)• case02:• case03:• Case04:• Case05:
  19. 19. 库的顺序问题—示例A(2)• case02:• case03:• case04:• case05:
  20. 20. 库的顺序问题—示例B(1)• Case06:
  21. 21. 库的顺序问题—示例B(2)• Case07:• Case08: • Case09:
  22. 22. 库的顺序问题—示例B(3)• Case06:• Case07:• Case08:• Case09:
  23. 23. 库的顺序问题—示例C(1)• libdso:
  24. 24. 库的顺序问题—示例C(2)• Case10: • Case11: • Case14:
  25. 25. 库的顺序问题—示例C(3)• Case15:• Case16:• Case17:
  26. 26. 库的顺序问题—示例C(4)• Case10:• Case11:• Case14:
  27. 27. 库的顺序问题—示例C(5)• Case15:• Case16:• Case17:
  28. 28. 库的顺序问题—示例D(1)• libaba:
  29. 29. 库的顺序问题—示例D(2)• Makefile
  30. 30. 库的顺序问题—示例D(3)• aba_main.cpp:• Case20:• Case21:• Case22:
  31. 31. 库的顺序问题—示例D(4)• Case20:• Case21:• Case22:
  32. 32. 库的顺序问题—总结• 在链接静态库时, 如果目标文件(.o) 与静态库之间存在依赖关系, 则有依赖关系的目标文件(.o)与静态库存在链接顺序问题。• 在链接静态库时, 如果动态库 与静态库之间存在依赖关系,则有 依赖关系的动态库与静态库存在链接顺序问题。• 在链接静态库时,如果多个静态库之间存在依赖关系,则有依 赖关系的静态库之间存在链接顺序问题。• 静态库之间存在循环依赖的时候经常需要根据依赖关系,将静态 库列出多次.• 遵守从左到右排序对象文件的惯例.
  33. 33. 静态链接 静态链接过程 符号解析 重定位过程
  34. 34. 静态链接—输入文件类型• 重定位目标文件• 归档库• 共享库
  35. 35. 静态链接--处理过程• 链接的主要内容是把各个模块之间相互引用的部 分处理好,使各个模块之间能正确的衔接.• 两步链接(Two-passing Linking)  地址与空间分配(Address and Storage Allocation)  符号解析(Symbol Resolution)和重定位(Relocation)• 全局符号表:链接器会保存一个全局符号表,在任 何输入文件中被引用或者定义的符号都会有一个 表项
  36. 36. 静态链接--地址与空间分配
  37. 37. 静态链接—符号分类与符号解析• 符号分类• 符号解析(symbol resolution)概念
  38. 38. 库的顺序问题—示例D• Case22:• Case24:
  39. 39. 静态链接—符号处理示例—case22
  40. 40. 静态链接—符号处理示例—case24
  41. 41. 静态链接时重定位• 重定位概念• 重定位表• 符号解析与重定位的关系
  42. 42. Elf64_Rela// Relocation table entry with addend (in section of type SHT_RELA).typedef struct{ Elf64_Addr r_offset; /* Address of need relocation*/ Elf64_Xword r_info; /* Relocation type and symbol index */ Elf64_Sxword r_addend; /* Addend */} Elf64_Rela;#define ELF64_R_SYM(i) ((i) >> 32) // 符号表中的下标#define ELF64_R_TYPE(i) ((i) & 0xffffffff) // 重定位入口的类型#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type))
  43. 43. 重定位类型表名字 值 计算R_X86_64_32 1 S+AR_X86_64_PC32 2 S+A-PR_X86_64_GOT32 3 G+AR_X86_64_PLT32 4 L+A- PR_X86_64_COPY 5 noneR_X86_64_GLOB_DAT 6 SR_X86_64_JUMP_SLOT 7 SR_X86_64_RELATIVE 8 B+AR_X86_64_GOTPCREL 9 S + A - GOT
  44. 44. 静态链接时重定位示例
  45. 45. 静态链接时重定位示例
  46. 46. 动态库 与 动态链接基础 如何创建动态库 为什么要动态链接 动态链接的主要技术点 显式运行时加载(dlopen/dlsym/dlclose) 动态库连接与动态加载选项说明
  47. 47. 如何创建动态库
  48. 48. 为什么要动态链接• 内存与磁盘空间• 程序开发与发布• 程序的可扩展性与兼容性
  49. 49. 动态链接• 基本思想:把程序按 照模块分拆成各个 相对独立部分,在程 序运行时才将它们 链接在一起形成一 个单独的可执行文 件.
  50. 50. 动态链接的实现• 方便程序开发,部属: • 性能优化:  方法:程序的各模块独立, 方法:延迟绑定(Lazy 装载时才链接(符号查找, Binding) 重定位). 技术实现:函数链接表• 节约内存: (PLT)  方法: 地址无关代码(PIC) • 程序的可扩展性与兼容性:  技术实现:全局偏移量表 方法: 显式运行时加载 (GOT)
  51. 51. 动态链接的实现—GOT,PLT
  52. 52. 动态链接的实现—GOT,PLT 类型 2:模块内部的数据访问 类型 4:模块外部的数据访问 类型 1:模块内部的函数调用 类型 3:模块外部的函数调用
  53. 53. 动态链接的实现—GOT,PLT
  54. 54. 常用链接选项(1)• -Wl:这个选项可以将指定的参数传递给链接器。• -Bstatic : 将其后的库作为静态库链入.• -Bdynamic: 将其后的库作为动态库链入.• 示例: -Wl,-Bstatic -lanet -lalog -Wl,-Bdynamic –ldl
  55. 55. ld 链接选项• -Xlinker –rpath: 示例: -Xlinker -rpath ../timeutil• --enable-new-dtags 示例: -Xlinker -rpath ../timeutil -Xlinker --enable-new- dtags• -export-dynamic 或 -rdynamic:• -Bsymbolic: 示例: -Wl, -Bsymbolic
  56. 56. 动态链接过程—库的搜索路径1. DT_RPATH: 在 .dynamic 节的 DT_RPATH的表项指定, 且没有 RUNPATH表项,是由分号分隔开的可以搜索库 的目录列表.2. 环境变量 LD_LIBRARY_PATH3. RUNPATH : 如果在 .dynamic 节有项,则DT_RPATH 项 失效.4. 库缓冲文件/etc/ld.so.cache5. 缺省目录: /usr/lib; /lib ; /usr/local/lib等
  57. 57. 分析工具
  58. 58. binutls工具集 ld - the GNU linker. as - the GNU assembler. addr2line - Converts addresses into filenames and line numbers. ar - A utility for creating, modifying and extracting from archives. c++filt - Filter to demangle encoded C++ symbols. gprof - Displays profiling information.
  59. 59. binutls工具集 nm - Lists symbols from object files. objcopy - Copys and translates object files. objdump - Displays information from object files. ranlib - Generates an index to the contents of an archive. readelf - Displays information from any ELF format object file. size - Lists the section sizes of an object or archive file. strings - Lists printable strings from files. strip - Discards symbols.
  60. 60. 参考资料• <程序员的自我修养—链接、装载与库>• <连接器和加载器>
  61. 61. 谢 谢 !

×