如何从C程序访问共享对象(.so)中的全局变量?解决调用设置函数后变量未更新问题
问题分析与解决方案
嘿,我一眼就瞅出问题出在哪了——你头文件里的全局变量声明方式错了,导致test可执行文件和preload.so里各有一个独立的var,自然看不到修改效果!
为啥原来的代码不生效?
你在preload.h里写的int var;不是单纯的“告诉编译器有这个变量”,而是直接让编译器在每个包含这个头文件的编译单元里都创建一个var的实例。这就导致:
test.c包含头文件后,最终生成的test可执行文件里有自己的var;preload.so里也有一个自己的var(不然你编译so的时候会报错);- 这俩
var完全是两个不同的内存地址!setting()改的是so里的那个,而main用的是test自己的,当然看不到变化。
修复步骤
只需要调整声明和定义的位置,让test里的var指向so里的实例:
修正头文件的变量声明
把preload.h里的int var;改成extern声明,只做“告知存在”的作用,不创建变量:// preload.h extern int var; void setting(int x);在so的实现文件里定义变量
到preload.c里真正定义这个全局变量,让so加载时分配内存:// preload.c #include "preload.h" // 这里才是var的真正定义,只会在so里生成一个实例 int var; void setting(int x) { var = x; }简化test.c的代码
因为头文件已经做了extern声明,test.c里不需要再重复写extern int var;了,直接用就行:// test.c #include "preload.h" #include <stdio.h> // 别忘了加这个,不然printf没法用 int main(){ int x = 42; // 随便设个测试值 setting(x); printf("var的值是:%d\n", var); // 现在就能拿到so修改后的结果了 return 0; }重新编译执行
还是用你原来的编译和执行命令:gcc test.c -o test gcc -shared -fPIC preload.c -o preload.so -ldl LD_PRELOAD=$PWD/preload.so ./test
额外提醒
这种LD_PRELOAD动态注入的场景下,符号隔离是很容易踩的坑。如果多个模块(可执行/so)里有同名全局变量,默认情况下它们是独立的,除非你用extern明确声明要引用其他模块的变量。另外,头文件里永远不要定义变量,只做声明——这是C语言的基本规范,能避免很多类似的隐蔽问题。
内容的提问来源于stack exchange,提问作者Steven
相关产品推荐
相关产品推荐

