【发布时间】:2022-01-03 07:35:33
【问题描述】:
一个共享对象,例如 glibc,如果编译得当,会定义很多符号,例如 main_arena,这些符号通常不会被其他程序使用(尽管它们可以在 objdump 和 gcc 中看到),但是用它们的地址定义为本地符号:
$ objdump -t ../.glibc/glibc_2.30_no-tcache/libc.so.6 | grep main_arena
00000000003b4b60 l O .data 0000000000000898 main_arena
然而,当我在 C 中引用其中一个(通过extern)并尝试链接时,链接器找不到它:
$ gcc -g -Og -no-pie -Wl,-rpath ../.glibc/glibc_2.30_no-tcache/ -Wl,--dynamic-linker=../.glibc/glibc_2.30_no-tcache/ld.so.2 s1.c -o s1
/usr/bin/ld: /tmp/ccjKyCNh.o: in function `printf':
/usr/include/x86_64-linux-gnu/bits/stdio2.h:112: undefined reference to `main_arena'
/usr/bin/ld: /usr/include/x86_64-linux-gnu/bits/stdio2.h:112: undefined reference to `main_arena'
collect2: error: ld returned 1 exit status
注意:我已经通过广泛的研究更新了这个问题:
这是设计使然:
-
c language, global symbol, local symbol clarification "local (static): 由模块 m 专门定义和引用的本地符号....这些符号在模块 m 内的任何地方都可见,但不能被其他模块引用。"
-
另请参阅“符号可见性 符号可以分为本地或全局。不能从包含符号定义的对象以外的对象引用局部符号。”https://docs.oracle.com/cd/E26505_01/html/E26506/chapter2-90421.html
-
和https://reverseengineering.stackexchange.com/questions/14895/why-are-symbols-with-local-binding-present-in-the-symbol-table-of-my-elf-files 和http://web.cse.ohio-state.edu/~reeves.92/CSE2421au12/SlidesDay52.pdf
尽管如此,为了调试、探索和逆向工程,有时需要引用在共享对象中定义的外部本地符号。所有信息都在那里,gdb 的显示能力证明了这一点;它只是一个标志,告诉 ld 不要将符号解析为它。
鉴于此,是否可以告诉 ld 忽略本地标志,并解析为符号?
例如:
$ objdump -t ../.glibc/glibc_2.30_no-tcache/libc.so.6 | grep -E ' malloc$| main_arena$'
00000000003b4b60 l O .data 0000000000000898 main_arena
0000000000083500 g F .text 0000000000000213 malloc
$ man objdump 2>/dev/null | grep -A10 'flag characters'
The flag characters are divided into 7 groups as follows:
"l"
"g"
"u"
"!" The symbol is a local (l), global (g), unique global (u), neither global nor local (a space) or both global and
local (!). ...
我希望能够编写用于调试和逆向工程的代码,无论如何都引用符号main_arena。我该怎么做?
更新
我已阅读Employed Russian关于相关主题的优秀帖子,并看到他对XY Problem 的引用。考虑到这一点,让我问我的问题 X:
出于探索目的,我希望能够查看 main_arena 和其他 malloc 内部结构的行为,因为我使用 malloc 和 free。我可以用 gdb 做到这一点。但我想在 C 中以编程方式执行此操作。执行此操作的一种方法可能是实际链接到这些符号(question Y),但没有理由认为这是最好的方法,唯一的方法,甚至是可行的方法。鉴于:
如何从不同的程序中检查共享库中本地符号的值,而不必放到 gdb 中?
【问题讨论】: