普通函数调用和虚函数调用
1.普通函数调用
源文件.cpp经过编译变成目标文件,函数保存在目标文件的代码段,符号表保存在只读数据段,这时代码段和数据段中的函数调用的地址都是临时地址,链接时目标文件合并,函数地址固定下来,重定位修改临时地址为新地址,普通函数的调用就是最终编译成 call 函数地址 的指令,也就是说普通函数的调用在编译链接后就确定好了
2.虚函数的调用
源文件.cpp经过编译变成目标文件,子类虚函数表是拷贝父类虚表,存在只读数据段,虚函数在代码段,重写虚函数会覆盖原来子类虚函数表里的指针,链接合并目标文件,虚函数的调用编译器会编译成去虚函数表中找对应虚函数地址然后调用,虚函数的调用在运行时才确定好
1. 符号表(Symbol Table)
作用:
符号表记录了目标文件中定义的符号(如函数、全局变量)以及引用的外部符号信息,用于链接阶段的符号解析和地址绑定。
主要内容:
-
符号名称:函数或变量的名称(如
printf
、main
)。 -
符号类型:区分是函数(
FUNC
)、变量(OBJECT
)还是未定义符号(UND
)。 -
作用域:全局(可被其他文件访问)或局部(仅当前文件可见)。
-
地址/大小:符号在内存或目标文件中的相对地址及大小(未定义的符号地址为0)。
用途:
-
链接阶段:
链接器通过符号表解析跨文件的符号引用。例如,文件A调用文件B的函数,链接器需找到该函数的定义并绑定地址。 -
调试信息:
符号表可包含调试符号(如函数名、变量名),帮助调试工具(如GDB)定位问题。 -
动态链接:
动态库的符号表在运行时由动态链接器(如ld-linux.so
)加载,解析未定义符号。
示例(使用 readelf -s
查看):
Symbol table '.symtab' contains 10 entries:Num: Value Size Type Bind Vis Ndx Name0: 00000000 0 NOTYPE LOCAL DEFAULT UND 1: 00000000 0 FUNC GLOBAL DEFAULT UND printf2: 00001129 42 FUNC GLOBAL DEFAULT 14 main
2. 重定位表(Relocation Table)
作用:
重定位表记录了目标文件中需要修改的地址(如函数调用、变量引用),指导链接器或加载器在链接或运行时修正这些地址。
主要内容:
-
重定位位置:需要修改的指令或数据的偏移地址。
-
重定位类型:指示如何计算新地址(如相对跳转、绝对地址)。
-
依赖的符号:需要绑定的符号(如
printf
的地址)。
用途:
-
静态链接:
链接器合并多个目标文件时,根据重定位表修改指令中的地址,使其指向最终的内存位置。 -
动态链接:
动态库加载时,动态链接器根据重定位表修正指令中的地址(如PLT/GOT条目)。 -
地址无关代码(PIC):
共享库通过重定位表实现代码段共享,数据段每进程独立。
示例(使用 objdump -r
查看):
RELOCATION RECORDS FOR [.text]: OFFSET TYPE VALUE 0000001c R_X86_64_PC32 printf 00000025 R_X86_64_32 global_var