简图记录-C语言 强符号与弱符号

本文介绍C语言中符号的管理方式,包括符号定义、强弱符号的区别及其编译规则,并提供了查看符号的方法及实用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简图记录学习~

    C语言在编译过程函数和变量都按符号的方式记录,常在编译链接时发生符号重复定义、符号无定义等错误,一不小心还会出现强弱符号覆盖这类不易察觉的隐含问题。以下部分内容来自《程序员的自我修改》,非常好的一本关于编译链接和库的书籍。

一、概念

    符号:编译器在链接不同目标文件时,需要处理各个文件之间的定义、调用和访问关系,编译器将函数和变量等都统称为符号,每个elf文件都有一个符号段.symtab存放所有符号,其实就是一个ELF32_Sym结构体类型的数组。

typedef struct{
Elf32_Word st_name;//符号名,实为字符串表下标。对应函数和变量一般为函数名和变量名
Elf32_Addr st_value;//符号值,函数或者变量为其所在地址
Elf32_Word st_size;//符号长度,变量为类型长度如int为4
unsigned char st_info;//符号信息,包括符号类型(局部/全局/弱引用)、绑定信息(未知/数据/函数/段名/文件名)
unsigned char st_other;//未使用
Elf32_Half st_shndx;//符号所在段
}ELF32_Sym; 

    强弱符号:函数或者已初始化全局变量为强符号,未初始化全局变量为弱符号(有命令可以转化强符号为弱符号)

    常见弱符号转换命令:

__attrible__((week)) void fun();
//或者:
extern void fun();
#pragma weak fun

    强弱符号编译规则:1、强符号不能重复定义,但强弱可共存 2、强弱共存时,强符号覆盖弱符号 3、都是弱符号时,选择第一个size最大的弱符号定义(默认值为0)

//举例:
//a.c文件:
int i=2;
//b.c文件:
int i;
int main()
{
   printf("i=%d\n",i);
   return 0;
}
/*当链接a.c b.c后打印i=2,b文件被覆盖*/

    强弱引用:对强符号访问为强引用,若链接完发现未定义编译失败;对弱符号访问为弱引用,链接完成是发现未定义不会编译失败,但直调用弱符号函数会导致运行时报错(可以先判断函数地址是否非0再调用)

//a.c内容
__attrible__((week)) void fun();
int main()
{
    if (fun)fun();
    return 0;
}
/*a.c单独编译能成功,运行时也不会出错,如果链接一个定义了fun的文件,则可调用过去*/

  二、查看符号方法

     查看符号表方法:readelf -S xxx.o   --->num序号也是所在字符串表下标;value符号值;size符号大小;Type符号类型;bind符号绑定信息;Vis无用;Ndx所在段;Name符号名;

    查看目标文件符号方法:nm -n(按地址排序默认按函数名)L(打印文件位置) xxx.o --->地址(如0x12345678) 类型(A绝对 地址/B bss段/C 未初始化符号/D 数据段/R 只读段/T 代码段/U 未定义,小写表示内部符号 大写外部符号) 符号名(如main)

三、常用技巧及注意事项

    1、如何防止多个全局变量强弱覆盖问题?

        (1)最优方案:优化掉全局变量 (2)一般方案:定义为static,就无强弱符号概念,外部无法访问 (3)最差方案:要求全部全局变量必须初始化,只要有人未初始化该变量就有被覆盖风险;

        GCC提供编译命令:-fno-common识别覆盖问题

    2、弱符号使用技巧,在以下场景可以很好解决问题

        (1)希望有编译时可带可不带的扩展功能模块时,扩展功能访问都用弱引用方式;(2)希望支持如多线程和单线程多个版本时,可按弱引用调用线程库接口,判断为0时走单线程流程。通过编译时是否带-lpthread控制;(3)避免开源组件开源传染,开源组件要求发布时能单独编译且保持功能正常,如果你在SDK下适配了开源组件,必须以弱引用访问SDK,否则SDK会被要求开源;


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值