链接器对符号的管理和解析
2015-09-17 16:59
162 查看
链接
符号和符号表
如下是示例代码,文件为swap.cextern int buf[]; int *bufp0 = &buf[0]; static int *bufp1; static void incr() { static int count; count++; } void swap() { int temp; incr(); bufp1 = &buf[1]; temp = *bufp0; *bufp0 = *bufp1; *bufp1 = temp; }
如下是经过预处理,编译后对应的ELF文件swap.o,它的符号表.symbol
Symbol table ‘.symtab’ contains 12 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS swap.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 3
4: 0000000000000000 0 SECTION LOCAL DEFAULT 5
5: 0000000000000000 0 SECTION LOCAL DEFAULT 7
6: 0000000000000000 0 SECTION LOCAL DEFAULT 8
7: 0000000000000000 0 SECTION LOCAL DEFAULT 6
8: 0000000000000000 38 FUNC GLOBAL DEFAULT 1 swap
9: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND buf
10: 0000000000000008 8 OBJECT GLOBAL DEFAULT COM bufp1
11: 0000000000000000 8 OBJECT GLOBAL DEFAULT 3 bufp0
以上列表的每一个条目的格式使用一个C结构表示,如下:
typedef struct { int name; /* String table offset */ char type:4, /* Function or data (4 bits) */ binding:4; /* Local or global (4 bits) */ char reserved; /* Unused */ short section; /* Section header index */ long value; /* Section offset or absolute address */ long size; /* Object size in bytes */ } Elf64_Symbol;
下面解释该结构各个成员描述了列表各个列,其中section成员对应Nxd列,说明每一个符号必须与某一个节是相关的,比如符号bufp0是在C文件swap.c里的一个初始化的全局变量,对应在节.data占用8字节大小,再比如符号bufp1是在C文件swap.c里的一个未初始化的全局变量,符号表里使用COM所引导节.bss。而swap 符号是在C文件swap.c里的一个函数,对应在节.text占用38字节大小。
符号解析
符号从链接的角度上来看分为3类,一类是模块内的带有static属性的函数或全局变量,这类符号不能被其他模块引用。第二类是模块内定义且被模块自身引用的全局符号。第三类是由其他模块定义但被自己模块引用的全局符号,这类符号叫做外部符号第一:编译器能识别出重定义并在编译时报告这种错误,一个模块的本地符号只允许有一个定义
第二:编译器能识别出未定义并在编译时报告这个错误,比如,第三类符号,如果编译器在其他任何输入模块都找不到它的定义的话,编译器就会报告符号未定义错误
第三:编译如何解析多处定义的全局符号,使用如下规则:
规则1,不允许有多个强符号
规则2,如果有一个强符号和多个弱符号,那么选择强符号
规则3,如果有多个弱符号,那么从这些弱符号中任意选择一个。
规则2的实验:
code.c
#include <stdio.h> void f(void); int x = 15213; int main() { f(); printf("x = %d\n", x); return 0; }
bar.c
int x; void f() { x = 15212; }
构建测试程序,gcc -O2 -o test code.c bar.c
运行测试,观察结果:# ./test
x = 15212。
发现链接器选择了强符号,而强符号的值被恶意修改了,这是危险的。
规则3的实验:
code.c
#include <stdio.h> void f(void); int x; int main() { x = 15123; f(); printf("x = %d\n", x); return 0; }
bar.c
int x; void f() { x = 15212; }
构建测试程序,gcc -O2 -o test code.c bar.c
运行测试,观察结果:# ./test
x = 15212
发现链接器选择了code.c文件里定义的弱符号,该弱符号的值在其他文件被错误的修改了,这是不符合我们预期的,是危险的。
以上是程序设计时,容易忽略的问题,应特别注意。
相关文章推荐
- openwrt: Makefile 框架分析
- C# 之 Excel 导入一列中既有汉字又有数字:数字可以正常导入,汉字导入为空
- Java实现的堆排序(最小堆)
- Redis 学习笔记八 NodeJs使用Redis
- Win10系统旗舰版ghost版系统镜像下载
- haproxy 配置缺省的webserver
- JDK 1.5 新特性
- POJ 3253 Fence Repair 哈夫曼树
- scala和java解压zip的文件,并上传到hdfs服务器
- Python 学习(3)---Python标准异常总结
- YAML文件的使用及参数服务器
- POJ 2485 Highways (最小生成树prim)
- Winform开发框架之介绍
- chrome打开清除浏览数据窗口快捷键
- DataGridView设置列标题
- C# winform 拖拽效果
- iOS9适配
- list请求参数作为springmvc方法参数
- request.getParameter() request.getAttribute()区别
- Ecshop wap