计算机系统篇之链接(4):符号解析
Author:stormQ
Wednesday, 15. April 2020 12:35PM
符号解析的整体过程
符号解析的目的是将每个符号引用与唯一的符号定义关联起来。符号解析的过程由编译器、汇编器和链接器协作完成。具体地处理行为如下:
符号 | 编译器如何处理 | 汇编器如何处理 | 链接器如何处理 |
---|---|---|---|
对于全局符号定义 | 如果同一个全局符号在同一个目标模块内有多个定义,那么编译器会报错,不会进行后面的汇编和链接过程。 | 只要编译器不报错,汇编器也不会报错。 | 如果同一个全局符号在不同的目标模块内都有定义,那么链接器会报错。 |
对于全局符号引用 | 只要编译器不报错,汇编器也不会报错。 | 如果一个全局符号引用在其他目标模块内都没有定义,那么链接器会报错。 | |
对于局部符号定义 | 如果同一个局部符号在同一个目标模块内有多个定义,那么编译器会报错,不会进行后面的汇编和链接过程。 | 只要编译器不报错,汇编器也不会报错。 | 链接器不会涉及局部符号定义的处理过程。 |
对于局部符号引用 | 只要编译器不报错,汇编器也不会报错。 | 链接器不会涉及局部符号引用的处理过程。 |
1)验证“如果同一个全局符号在同一个目标模块内有多个定义,那么编译器会报错,不会进行后面的汇编和链接过程。”
# 全局变量 g_val(int 类型的)和 g_val(double 类型的)对应的全局符号的名称相同,属于“同一个全局符号在同一个目标模块内有多个定义”的情况
# 函数 int func(int val) 和 void func(int val) 对应的全局符号的名称相同,属于“同一个全局符号在同一个目标模块内有多个定义”的情况
$ cat compile_error1.cpp
int g_val = 0;
double g_val = 0;
int func(int val)
{
return val;
}
void func(int val)
{
}
# 在生成汇编文件时报错,即编译器会报错
$ g++ -S compile_error1.cpp -o compile_error1.s
compile_error1.cpp:2:8: error: conflicting declaration ‘double g_val’
double g_val;
^~~~~
compile_error1.cpp:1:5: note: previous declaration as ‘int g_val’
int g_val;
^~~~~
compile_error1.cpp: In function ‘void func(int)’:
compile_error1.cpp:9:6: error: ambiguating new declaration of ‘void func(int)’
void func(int val)
^~~~
compile_error1.cpp:4:5: note: old declaration ‘int func(int)’
int func(int val)
^~~~
2)验证“如果同一个全局符号在不同的目标模块内都有定义,那么链接器会报错。”
# 在不同的目标模块中定义相同名称的全局符号
$ cat link_error1.cpp
int g_val = 1;
int func(int val)
{
return val;
}
$ cat main.cpp
int g_val = 100;
void func(int val)
{
}
int main()
{
return 0;
}
# 编译器和汇编器不会报错
$ g++ -c link_error1.cpp -o link_error1.o
$ g++ -c main.cpp -o main.o
# 在生成可执行目标文件时报错,即链接器会报错
$ g++ -o main main.o link_error1.o
link_erro