一些序言
似乎 malloc、calloc、realloc 和 free 都复制在 ld-linux.so
和 libc.so
中。据我了解,这是由动态加载程序完成的,用于在加载 libc.so
之前处理 ld-linux.so
中的内存管理并使其内存管理功能可行的。但是,我对那些重复的符号有一些疑问:
这是一个非常简单的 C 程序调用 malloc 并退出:
#include <stdlib.h>
int main()
{
void *p = malloc(8);
return 0;
}
我在 x86_64 linux box 中用 gcc 编译它并用 gdb 进行一些调试:
$ gcc -g -o main main.c
$ gdb ./main
(gdb) start
Temporary breakpoint 1 at 0x4004f8
Starting program: main
Temporary breakpoint 1, 0x00000000004004f8 in main ()
(gdb) info symbol malloc
malloc in section .text of /lib64/ld-linux-x86-64.so.2
(gdb) b malloc
Breakpoint 2 at 0x7ffff7df0930: malloc. (2 locations)
(gdb) info breakpoints
Num Type Disp Enb Address What
2 breakpoint keep y <MULTIPLE>
2.1 y 0x00007ffff7df0930 in malloc at dl-minimal.c:95
2.2 y 0x00007ffff7a9f9d0 in __GI___libc_malloc at malloc.c:2910
libc.so 和 ld.so 中的 nm 显示以下内容:
$ nm -D /lib/x86_64-linux-gnu/libc.so.6 | grep malloc
00000000000829d0 T __libc_malloc
00000000003b6700 V __malloc_hook
00000000003b8b00 V __malloc_initialize_hook
00000000000829d0 T malloc
0000000000082db0 W malloc_get_state
00000000000847c0 T malloc_info
0000000000082480 W malloc_set_state
00000000000844f0 W malloc_stats
0000000000084160 W malloc_trim
00000000000844b0 W malloc_usable_size
$ nm -D /lib64/ld-linux-x86-64.so.2 | grep malloc
0000000000016930 W malloc
问题
malloc
在libc.so
和ld-linux.so
中被复制,但是对于ld- linux.so
它是一个弱符号,所以它们应该都解析到同一个地址。此外,据我所知,动态加载器的符号解析表是全局的,每个符号只解析一个地址(如果我错了请纠正我)。但是,gdb 清楚地显示了其他情况(两个不同的地址)。为什么 是吗?
gdb 在键入
break malloc
时有效地在两个不同的地址中断,但在键入info symbol malloc
时仅显示 ld.so 中符号的信息。这是为什么?虽然我在 malloc 和
libc.so
定义了一个malloc
符号(如 nm 所示),但 gdb 在符号__GI___libc_malloc
。这是为什么?
最佳答案
- 我怀疑 GDB 只是将断点放在它能找到的所有
malloc
符号上,可以说是“以防万一”。 GDB 使用它的内部符号表,而不是动态加载器的。这样,如果您有调试符号,它可以在非导出符号上中断。命令反馈仅列出一个地址,可能是为了在匹配过多的情况下减少噪音。它仍然提到“2 个位置”,因此您可以使用info 断点
自行检查它。 - 我的猜测是
info symbol
实现者没有预见到这种情况,所以它只打印第一个匹配项 __GI___libc_malloc
是 libc.so 内部malloc
内部实际实现的名称。由于您还获得了源代码行信息"at malloc.c:2910"
,我猜它来自调试符号而不是来自 ELF 的符号表。同样,一个位置可以有多个名称(请参阅符号列表中的__libc_malloc
),因此 GDB 只选择一个。
顺便说一句,当加载 libc.so 时,ld.so 的 GOT 中的 malloc
指针确实被 libc 的 malloc
地址替换(最初它指向内部实现).因此,当到达进程入口点时,您确实会获得相同的地址,并且不再使用 ld.so 的 malloc
。
关于c - libc.so 和 ld-linux.so 中重复的内存管理符号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14867024/