静态链接之符号解析

符号解析

符号解析的目的就是将各个模块(模块之中与模块之间)引用与定义联系起来

首先,什么是符号?符号包括

函数(static和非static)
全局变量
外部变量
静态局部变量
static属性

先简单说明一下static属性,对于全局变量和函数来说,使用static是将它们的“可见”范围限制在了本模块,即它们可以被合法引用的地方仅仅限与定义它们的这个模块(文件);
而对于函数体内部的过程变量来说,使用static修饰是延长了它的“生存周期”,即使在退出循环也不会被销毁。
具体到存放方式就是:符号都是存放在堆里面,而不是和局部变量一样放在栈里面

符号解析

在整个c语言程序之中,既有符号的定义又有符号的引用(使用)。那么,在链接过程之中,真正链接之前需要做的一件事就是将将这些引用与定义关联起来
进一步,试想如果C语言源程序中如果同一个符号名被定义了多次,链接又该如何进行呢?
首先,如果是局部符号(带static属性),由于作用范围限制在同一模块之中,所以它的引用解析是很是清晰的,只需要在同一模块之中不被重复定义即可。
麻烦的是全局符号(非static的全局变量和函数)的解析,如果发生同名的现象链接器又会做出什么样子的反应呢?

首先说明一下强弱符号,强弱符号的概念是针对全局符号的概念:
强符号:函数名、已初始化的全局变量
弱符号:未初始化的全局符号

由此在强弱符号概念的基础之上,链接器在链接时对于同名全局符号有以下规则:

  1. 链接器不允许多个同名的强符号
  2. 当强符号和弱符号同名时,选择强符号作符号解析
  3. 当弱符号之间同名时,随机选择其中一个作符号解析

接下来看一个强弱符号同名的例子

mismatch-main.c

long int x;  /* Weak symbol */

int main(int argc, char *argv[]) {
    printf("%ld\n", x);
    return 0;
}

mismatch-variable.c

/* Global strong symbol */
double x = 3.14;

编译
gcc -c mismatch-variable.c mismatch-main.c
静态链接
gcc -static -o prog mismatch-main.o mismatch-variable.o
运行
./prog
以下是机器操作过程与运行结果
静态链接之符号解析_第1张图片

分析:
在mismatch-variable.c定义了一个强符号浮点数x=3.14(8字节) 而在mismatch-main.c定义的是一个同名的未初始化的弱符号长整型数x; 根据上文所述的规则2,在两模块链接过程中,对于“x”选择的解析是mismatch-variable中的浮点数x

为此我们运行下面一段代码:

print-double.c

#include 

int main(){
	double x = 3.14;
	unsigned short *p=(unsigned short *)&x;
	for(int i = 0;i < 4; i++){
		printf(" [%d] %p :%x\n",i+1,p,*p);
		p++;
	}
	return 0;
}

结果:
静态链接之符号解析_第2张图片
我们把它转变成十进制数:
静态链接之符号解析_第3张图片

发现所得的数也正好与前面prog所得结果461,425,307,021,498,087相对应
所以prog中main函数是将浮点数x用作x的最终解释,并且将3.14的double型表示按照长整型输出了
对于prog中的错误在编译链接过程中都不会报错,所以一旦编程过程中出现这种错误是比较难以发现的,只有运行之后才会发现错误,但是在代码量巨大的情况下,定位错误依然有难度很大。因此作为程序员应该尽量细心避免这种错误。

在此的建议是:
1.尽量不用跨模块全局变量,给全局变量带上static属性
2.非得使用跨模块引用记得带上外部属性

你可能感兴趣的:(静态链接之符号解析)