Upload
tidesq
View
8.101
Download
18
Embed Size (px)
DESCRIPTION
主要介绍编译,链接与装载的基本概念与原理静态链接常见错误分析,静态链接常用链接选项使用讲解dlopen/dlsym?常用链接选项讲解
Citation preview
五竹
一淘搜索与算法
Linux C++ 编程之链接与装载
—基础篇
课程大纲页
• 编译与链接的基本概念
• 常见链接错误分析
• 静态链接
• 动态库 与 动态链接基础
• 常用链接选项
• 工具介绍
编译与链接的基本概念
编译与链接的基本概念
//hello.c
#include <stdio.h>
int main()
{
printf("Hello World\n");
return 0;
}
编译:
gcc hello.c
编译与链接的基本概念
编译与链接的基本概念—预处理
• 预处理(Prepressing) : -E 表示只进行预处理, 即 : gcc –E hello.c –o
hello.i
展开所有 #define 定义的宏
处理所有条件预编译指令,如 #if, #ifdef
递归的将 #include 的文件插入到该预编译文件中
删除各类注释
添加行和文件标识,如 #2 "hello.c" 2 ,用于调试或编译出错报警
保留所有的 #pragma 编译指令,编译器要使用
• 对于C++ 来说,预处理后的文件扩展名是 .ii
编译与链接的基本概念—编译
• 编译(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
编译与链接的基本概念—汇编
• 汇编(Assembly) :
gcc –C hello.s –o hello.o
或 as hello.s -o hello.o
• 汇编器是将编译语言转换成机器可以执行的指令.
编译与链接的基本概念—链接
• 链接(Linking):解决一个程序被分割成多个模块后,
模块间最后如何组合成一个单一程序的问题.
• 链接的主要任务是把各个模块之间相互引用的部
分处理好,使各个模块之间能正确的衔接.
常见链接错误分析 calu.c
#include <math.h> #include <stdio.h> int main (void) {
double x = sqrt (2.0); printf ("The square root of 2.0 is %f\n", 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
常见链接错误分析
导致符号未定义的原因:
1. 链接时缺少某个库, 目标文件的路径不正确, 符号
的声明与定义不一样,父类声明的虚函数,父或子类
都没有实现等.
2. C与C++的库之间兼容问题
3. 链接时库的顺序问题
常见链接错误分析—C与C++之间兼容问题
--符号修饰与函数签名// plusplus_example.hint func(int);float func(float);class C {
int func(int);class C2 {
int func(int);};
};namespace N {
int func(int);class C {
int func(int);};
}
// cplusplus_example.cpp
#include "example.h"int func(int){};float func(float){};int C::func(int){};int C::C2::func(int){};namespace N {
int func(int){};int C::func(int){};
}
函数签名 修饰后名称(符号名)
int func(int) _Z4funcifloat func(float) _Z4funcfint C::func(int) _ZN1C4funcEiint C::C2::func(int) _ZN1C2C24funcEiint N::func(int) _ZN1N4funcEiint N::C::func(int) _ZN1N1C4funcEi
GCC的基本C++名称修饰方法:1. 所有的符号都以"_Z"开头,
2. 对于嵌套的名字(在名称空间或在类里面的),后面紧
跟"N",3. 然后是各个名称空间和类的名字,每个名字前是名字字
符串长度,再以"E"结尾。
4. 函数来说,它的参数列表紧跟在"E"后面
常见链接错误分析—C与C++之间兼容问题
--符号修饰与函数签名
常见链接错误分析—C与C++之间兼容问题
--符号修饰与函数签名
#ifdef __cplusplusextern "C" {#endif
void * memset(void *, int ,size_t);
#ifdef __cplusplus}#endif
extern "C" 关键字
条件宏 __cplusplus
链接时库的顺序问题--libtimeutil
链接时库的顺序问题--libtimeutil
链接时库的顺序问题--libdso
库的顺序问题—示例A(1)• case02:
• case03:
• Case04:
• Case05:
库的顺序问题—示例A(2)
• case02:
• case03:
• case04:
• case05:
库的顺序问题—示例B(1)
• Case06:
库的顺序问题—示例B(2)
• Case07:
• Case08:
• Case09:
库的顺序问题—示例B(3)• Case06:
• Case08:
• Case09:
• Case07:
库的顺序问题—示例C(1)
• libdso:
库的顺序问题—示例C(2)• Case10:
• Case14:
• Case11:
库的顺序问题—示例C(3)
• Case16:
• Case17:
• Case15:
库的顺序问题—示例C(4)• Case10:
• Case14:
• Case11:
库的顺序问题—示例C(5)• Case15:
• Case17:
• Case16:
库的顺序问题—示例D(1)• libaba:
库的顺序问题—示例D(2)• Makefile
库的顺序问题—示例D(3)• aba_main.cpp:
• Case20:
• Case21:
• Case22:
库的顺序问题—示例D(4)• Case20:
• Case22:
• Case21:
库的顺序问题—总结
• 在链接静态库时, 如果目标文件(.o) 与静态库之间存在依赖关系,
则有依赖关系的目标文件(.o)与静态库存在链接顺序问题。
• 在链接静态库时, 如果动态库 与静态库之间存在依赖关系,则有
依赖关系的动态库与静态库存在链接顺序问题。
• 在链接静态库时,如果多个静态库之间存在依赖关系,则有依
赖关系的静态库之间存在链接顺序问题。
• 静态库之间存在循环依赖的时候经常需要根据依赖关系,将静态
库列出多次.
• 遵守从左到右排序对象文件的惯例.
静态链接
静态链接过程
符号解析
重定位过程
静态链接—输入文件类型
• 重定位目标文件
• 归档库
• 共享库
静态链接--处理过程
• 链接的主要内容是把各个模块之间相互引用的部
分处理好,使各个模块之间能正确的衔接.
• 两步链接(Two-passing Linking)
地址与空间分配(Address and Storage Allocation)
符号解析(Symbol Resolution)和重定位(Relocation)
• 全局符号表:链接器会保存一个全局符号表,在任
何输入文件中被引用或者定义的符号都会有一个
表项
静态链接--地址与空间分配
静态链接—符号分类与符号解析
• 符号分类
• 符号解析(symbol resolution)概念
库的顺序问题—示例D
• Case22:
• Case24:
静态链接—符号处理示例—case22
静态链接—符号处理示例—case24
静态链接时重定位
• 重定位概念
• 重定位表
• 符号解析与重定位的关系
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))
重定位类型表
名字 值 计算
R_X86_64_32 1 S+A
R_X86_64_PC32 2 S+A-P
R_X86_64_GOT32 3 G + A
R_X86_64_PLT32 4 L + A - P
R_X86_64_COPY 5 none
R_X86_64_GLOB_DAT 6 S
R_X86_64_JUMP_SLOT 7 S
R_X86_64_RELATIVE 8 B + A
R_X86_64_GOTPCREL 9 S + A - GOT
静态链接时重定位示例
静态链接时重定位示例
动态库 与 动态链接基础
如何创建动态库
为什么要动态链接
动态链接的主要技术点
显式运行时加载(dlopen/dlsym/dlclose)
动态库连接与动态加载选项说明
如何创建动态库
为什么要动态链接
• 内存与磁盘空间
• 程序开发与发布
• 程序的可扩展性与兼容性
动态链接
• 基本思想:把程序按
照模块分拆成各个
相对独立部分,在程
序运行时才将它们
链接在一起形成一
个单独的可执行文
件.
动态链接的实现
• 方便程序开发,部属:
方法:程序的各模块独立,
装载时才链接(符号查找,
重定位).
• 节约内存:
方法: 地址无关代码(PIC)
技术实现:全局偏移量表
(GOT)
• 性能优化:
方法:延迟绑定(Lazy
Binding)
技术实现:函数链接表
(PLT)
• 程序的可扩展性与兼容性:
方法: 显式运行时加载
动态链接的实现—GOT,PLT
动态链接的实现—GOT,PLT
类型 2:模块内部的数据访问
类型 4:模块外部的数据访问
类型 1:模块内部的函数调用
类型 3:模块外部的函数调用
动态链接的实现—GOT,PLT
常用链接选项(1)
• -Wl:这个选项可以将指定的参数传递给链接器。
• -Bstatic : 将其后的库作为静态库链入.
• -Bdynamic: 将其后的库作为动态库链入.
• 示例: -Wl,-Bstatic -lanet -lalog -Wl,-Bdynamic –ldl
ld 链接选项
• -Xlinker –rpath:
示例: -Xlinker -rpath ../timeutil
• --enable-new-dtags
示例: -Xlinker -rpath ../timeutil -Xlinker --enable-new-
dtags
• -export-dynamic 或 -rdynamic:
• -Bsymbolic:
示例: -Wl, -Bsymbolic
动态链接过程—库的搜索路径
1. DT_RPATH: 在 .dynamic 节的 DT_RPATH的表项指定,
且没有 RUNPATH表项,是由分号分隔开的可以搜索库
的目录列表.
2. 环境变量 LD_LIBRARY_PATH
3. RUNPATH : 如果在 .dynamic 节有项,则DT_RPATH 项
失效.
4. 库缓冲文件/etc/ld.so.cache
5. 缺省目录: /usr/lib; /lib ; /usr/local/lib等
分析工具
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.
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.
参考资料
• <程序员的自我修养—链接、装载与库>
• <连接器和加载器>
谢 谢 !