c - libc.so 和 ld-linux.so 中重复的内存管理符号

标签 c linux linker gdb glibc

一些序言

似乎 malloc、calloc、realloc 和 free 都复制在 ld-linux.solibc.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

问题

  1. malloclibc.sold-linux.so 中被复制,但是对于 ld- linux.so 它是一个弱符号,所以它们应该都解析到同一个地址。此外,据我所知,动态加载器的符号解析表是全局的,每个符号只解析一个地址(如果我错了请纠正我)。

    但是,gdb 清楚地显示了其他情况(两个不同的地址)。为什么 是吗?

  2. gdb 在键入 break malloc 时有效地在两个不同的地址中断,但在键入 info symbol malloc 时仅显示 ld.so 中符号的信息。这是为什么?

  3. 虽然我在 malloc 和 libc.so 定义了一个 malloc 符号(如 nm 所示),但 gdb 在符号 __GI___libc_malloc 。这是为什么?

最佳答案

  1. 我怀疑 GDB 只是将断点放在它能找到的所有 malloc 符号上,可以说是“以防万一”。 GDB 使用它的内部符号表,而不是动态加载器的。这样,如果您有调试符号,它可以在非导出符号上中断。命令反馈仅列出一个地址,可能是为了在匹配过多的情况下减少噪音。它仍然提到“2 个位置”,因此您可以使用 info 断点 自行检查它。
  2. 我的猜测是 info symbol 实现者没有预见到这种情况,所以它只打印第一个匹配项
  3. __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/

相关文章:

linux - 查找文件并以特定格式显示结果到txt文件

linux - 如何使用 sed 按指定顺序提取行?

c++ - mingw32 g++ 和 stdcall @suffix

linker - ld 检查共享库中未解析的符号不是多余的吗?

c - 如何避免重写不变的文本片段

c - 没有堆栈的 Linux 线程

c - 如何解释反三角函数(和 sqrt)函数(在 C 中)的浮点运算中的舍入误差?

linux - linux内核中usb鼠标使用了哪些驱动?

c++ - 为内联函数定义多次,怎么可能?

c - 忽略子进程中的 SIGINT 信号