前言
还是前面所说的项目:
公司项目有个比较偏门的需求,需要在java进程里找到并修改libjvm.so里定义的一个类的static + private的成员变量,但是通过代码一直没有找到该变量的符号和地址。
之前的测试已经完成,但是在c++的demo里,可以找到 static + private 的变量的符号和地址,问题到底在哪呢?
分析
没啥其他方法,先通过nm来查看一下变量在对应的so里到底是什么性质的.
libjvm.so里的变量:
0000000000e27d00 b _ZN14AttachListener12_initializedE
libb.so里的变量:
0000000000201068 D _ZN6BClass18static_private_varE
b和D分别是什么意思呢?
B/b The symbol is in the uninitialized data section (known as BSS). 非初始化符号
D/d The symbol is in the initialized data section. 初始化符号
我后续把我的demo代码修改了一下,也改成非初始化的,但显示是B,那么大小写又有什么区别呢?
查了一下发现是GLOBAL和LOCAL的区别,那这里有区别么?
测试
参考了该链接:
GCC的符号可见性——解决多个库同名符号冲突问题
修改代码后,也把我的demo里的变量的性质改为LOCAL:
通过readelf -s也可以看到:
PS:
为啥nm和readelf看到的符号名称是不同的?
然后用同样的代码进行测试,的确就找不到了;
但是gdb依然是可以找到该变量的:
结论
某些ELF文件里,通过编译选项,可以把一些符号给“隐藏”起来,防止外部进行链接的时候出现各种问题,以及避免外部的一些可能的错误的调用;这样的话,通过简单的ptrace attach 然后遍历符号表的方式,就找不到这些被“隐藏”的符号了;
GDB之所以能够找到该符号,很可能是编译时通过 -g 选项,额外添加了很多调试信息,而这些调试信息就包括这些被隐藏的符号的,因此GDB可以找到并设置该变量——猜测,不保证准确性!
后续:
参考链接:
https://blog.csdn.net/ld11690/article/details/81027578