开发一定要搞懂的符号与符号表 您所在的位置:网站首页 快压护眼精灵怎么卸载 开发一定要搞懂的符号与符号表

开发一定要搞懂的符号与符号表

2023-01-08 06:22| 来源: 网络整理| 查看: 265

符号

符号(Symbol)常用来表示一个地址,这个地址可能是一端程序的起始地址,也可能是一个变量的起始地址,简而言之,将它当做是标记或名称即可。 上一节聊到的链接 过程,实质上就是将不同的目标文件汇集在一起。链接构成中,目标文件的相互拼合汇集,实际上是目标文件之间对地址的引用。链接过程中,我们将函数 和 变量 统一称作为符号 ,函数名与变量名称就是符号名 ,其记录的地址信息就是其符号值 。

符号分类

符号是有分类的,根据其特点,可分为内部符号和外部符号。

内部符号:内部函数或方法、变量名称(当前Mach-O) 如:AppDelegate,编译期就知道其地址,分为: 全局符号 :全局作用域的函数、符号,整个项目可见 本地符号 :当前文件内的符号,当前文件可见 外部符号:外部函数或方法、变量名称(非当前Mach-O) 如:NSLog,这类符号又分为: 导入符号:对于当前 mach-O文件,导入了 NSLog 符号,称为:导入符号 导出符号:对于Foundation 来说,导出了 NSLog 符号,称为:导出符号 导出符号,一定是全局符号,可推理出,全局符号不能被脱去 编译链接时不知道其地址,在动态链接的时候才能确定它的内存地址 统一位于重定位符号表又叫**间接符号表**中 特殊符号:链接器生成可执行文件时生成的特殊符号等 __executable_start, 程序的起始地址,非入口地址 _end 或 end, 程序结束地址

🤔 为什么外部符号需要在动态链接时才能确定它的内存地址?

本地符号通过地址偏移可以得到,但是由于Mach-O 还没被加载,程序虚拟内存空间还没有被分配,导入的外部符号还没有内存地址。

全局符号

为了说明全局符号,在上述hello.c文件中添加如下代码

#include #define MAX_AGE 120 int globalVal = 99; int globalUndefineVal; int main() { printf("%s\n", "hello world~"); printf("%d\n", MAX_AGE); // 简单输出 return 0; } 复制代码

执行编译输出a.out 查看,可见

_globalVal 和 _globalUndefinedVal 符号签名都是 g 说明是全局符号 _globalVal 和 _globalUndefinedVal 符号都在_DATA 段,但是一个在 __data 一个在 __common

image.png

本地符号

本地符号又叫静态符号,它和全局符号的区别是在可见性方面。为了对比本地符号,在上述hello.c文件中添加如下代码

int globalUndefineVal; static int staticVal = 88; # 静态变量 static int staticUndefineVal; # 未初始化的静态变量 int main() { printf("%d %d\n", staticVal, staticUndefineVal); // 简单输出 ... } 复制代码

注意:如果静态变量没有进行引用的话,会变成调试符号,无法输出 image.png

导入导出符号

导入与导出是相对的,一方的导出符号,可以作为另一方的导入符号,查看一下 a.out 的导出符号

objdump --macho --exports-trie a 复制代码

image.png 可见,导出符号就是前面见到的 全局符号 ,全局符号默认是导出符号 ,当然也可以隐藏全局符号 ,如下示例

int globalVal2 __attribute__((visibility("hidden"))) = 99; 复制代码

通常,用到的外部符号会被放入到间接符号表 中,查看一下 a.out 的间接符号表

objdump --macho --indirect-symbols a.out 复制代码

image.png

符号表

链接过程中,我们需要对各种符号 进行管理,每一个目标文件 都会有一个对应的 符号表 Symbol Table ,用来记录目标文件中所有用到的符号,在静态链接时候,会进行相同性质段的合并。 符号表分类

Symbol Table: 所有符号表 存储所有的符号信息,包含动态链接符号表内的符号 Dynamic Symbol Table:动态链接符号表,间接符号表(Indirect Symbol) 存储着所有使用到的位于其他外部动态库中的符号信息,动态链接时进行绑定 String Table:符号的名称

image.png image.png

常用命令 ----------------------------------------- # -a输出全部符号表,-p 不用排序 $ nm -pa hello.o 0000000000000000 T _main U _printf $ nm -pa a 0000000100008008 d __dyld_private 0000000100000000 T __mh_execute_header 0000000100003f30 T _main U _printf U dyld_stub_binder ----------------------------------------- # 查看 Mach-Header 内容 $ otool -h a a: Mach header magic cputype cpusubtype caps filetype ncmds sizeofcmds flags 0xfeedfacf 16777223 3 0x00 2 16 1368 0x00200085 $ objdump --macho --private-header a Mach header magic cputype cpusubtype caps filetype ncmds sizeofcmds flags MH_MAGIC_64 X86_64 ALL 0x00 EXECUTE 16 1368 NOUNDEFS DYLDLINK TWOLEVEL PIE ----------------------------------------- # 查看 __TEXT 代码段 内容 $ objdump --macho -d a a: (__TEXT,__text) section _main: 100003f30: 55 pushq %rbp 100003f31: 48 89 e5 movq %rsp, %rbp 100003f38: c7 45 fc 00 00 00 00 movl $0, -4(%rbp) ... 100003f75: 5d popq %rbp 100003f76: c3 retq ----------------------------------------- # 查看符号 objdump --macho -syms hello.o hello.o: SYMBOL TABLE: 0000000000000048 g O __DATA,__data _globalVal 0000000000000000 g F __TEXT,__text _main 0000000000000004 *COM* 0000000000000004 _globalUndefineVal 0000000000000000 *UND* _printf ----------------------------------------- # 查看导出符号 $ objdump --macho --exports-trie a a: Exports trie: 0x100000000 __mh_execute_header 0x100003F30 _main 0x100008010 _globalVal 0x100008014 _globalUndefineVal ----------------------------------------- # 查看间接符号 $ objdump --macho --indirect-symbols a a: Indirect symbols for (__TEXT,__stubs) 1 entries address index name 0x0000000100003f78 5 _printf Indirect symbols for (__DATA_CONST,__got) 1 entries address index name 0x0000000100004000 6 dyld_stub_binder Indirect symbols for (__DATA,__la_symbol_ptr) 1 entries address index name 0x0000000100008000 5 _printf 复制代码


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有