c++ - 为什么符号 malloc、__malloc 和 __libc_malloc 指向相同的代码地址?

标签 c++ c linux gcc symbols

当我从符号表中 grep malloc 时,使用以下命令

readelf -s bin | grep malloc

我可以看到符号 malloc、__malloc 和 __libc_malloc 共享相同的代码地址。我可以得到PC地址,想知道用户程序什么时候调用了malloc,但是__malloc和__libc_malloc给了我嘈杂的信息,有什么好的方法来区分malloc吗?因为我使用 -static 编译二进制文件,所以 dlsym 在这种情况下不起作用。

最佳答案

除非使用动态链接,否则您无法区分它们,因为它们是同一事物,而静态链接的行为会将名称引用替换为例程的地址。

举个例子:

#include <stdlib.h>

extern void *__malloc(size_t);
extern void *__libc_malloc(size_t);

int
main(int argc, char **argv)
{
    void *v = malloc(200);
    free(v);
    v = __malloc(200);
    free(v);
    v = __libc_malloc(200);
    free(v);
    return 0;
}

编译时使用:gcc -static -o example example.c,然后反汇编我们看到的主例程:

  40103e:       55                      push   %rbp
  40103f:       48 89 e5                mov    %rsp,%rbp
  401042:       48 83 ec 20             sub    $0x20,%rsp
  401046:       89 7d ec                mov    %edi,-0x14(%rbp)
  401049:       48 89 75 e0             mov    %rsi,-0x20(%rbp)
  40104d:       bf c8 00 00 00          mov    $0xc8,%edi
  401052:       e8 19 52 00 00          callq  406270 <__libc_malloc>
  401057:       48 89 45 f8             mov    %rax,-0x8(%rbp)
  40105b:       48 8b 45 f8             mov    -0x8(%rbp),%rax
  40105f:       48 89 c7                mov    %rax,%rdi
  401062:       e8 09 56 00 00          callq  406670 <__cfree>
  401067:       bf c8 00 00 00          mov    $0xc8,%edi
  40106c:       e8 ff 51 00 00          callq  406270 <__libc_malloc>
  401071:       48 89 45 f8             mov    %rax,-0x8(%rbp)
  401075:       48 8b 45 f8             mov    -0x8(%rbp),%rax
  401079:       48 89 c7                mov    %rax,%rdi
  40107c:       e8 ef 55 00 00          callq  406670 <__cfree>
  401081:       bf c8 00 00 00          mov    $0xc8,%edi
  401086:       e8 e5 51 00 00          callq  406270 <__libc_malloc>
  40108b:       48 89 45 f8             mov    %rax,-0x8(%rbp)
  40108f:       48 8b 45 f8             mov    -0x8(%rbp),%rax
  401093:       48 89 c7                mov    %rax,%rdi
  401096:       e8 d5 55 00 00          callq  406670 <__cfree>
  40109b:       b8 00 00 00 00          mov    $0x0,%eax
  4010a0:       c9                      leaveq 
  4010a1:       c3                      retq   
  4010a2:       66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  4010a9:       00 00 00 
  4010ac:       0f 1f 40 00             nopl   0x0(%rax)

即代码不区分条目。

现在,如果你使用动态链接;你会得到不同的结果。一方面,__malloc 在生成的二进制文件中不可用 - 这是因为 __malloc 名称是静态链接的副作用(有一种方法可以防止它从被生产出来,但机制现在让我逃脱了)。所以当我们编译二进制文件时(删除 __malloc 调用),main 看起来像:

  40058d:       55                      push   %rbp
  40058e:       48 89 e5                mov    %rsp,%rbp
  400591:       48 83 ec 20             sub    $0x20,%rsp
  400595:       89 7d ec                mov    %edi,-0x14(%rbp)
  400598:       48 89 75 e0             mov    %rsi,-0x20(%rbp)
  40059c:       bf c8 00 00 00          mov    $0xc8,%edi
  4005a1:       e8 ea fe ff ff          callq  400490 <malloc@plt>
  4005a6:       48 89 45 f8             mov    %rax,-0x8(%rbp)
  4005aa:       48 8b 45 f8             mov    -0x8(%rbp),%rax
  4005ae:       48 89 c7                mov    %rax,%rdi
  4005b1:       e8 9a fe ff ff          callq  400450 <free@plt>
  4005b6:       bf c8 00 00 00          mov    $0xc8,%edi
  4005bb:       e8 c0 fe ff ff          callq  400480 <__libc_malloc@plt>
  4005c0:       48 89 45 f8             mov    %rax,-0x8(%rbp)
  4005c4:       48 8b 45 f8             mov    -0x8(%rbp),%rax
  4005c8:       48 89 c7                mov    %rax,%rdi
  4005cb:       e8 80 fe ff ff          callq  400450 <free@plt>
  4005d0:       b8 00 00 00 00          mov    $0x0,%eax
  4005d5:       c9                      leaveq 
  4005d6:       c3                      retq   
  4005d7:       66 0f 1f 84 00 00 00    nopw   0x0(%rax,%rax,1)
  4005de:       00 00

因此,要确定使用 __libc_malloc 还是 malloc,您可以检查对例程的 plt 条目的调用。

当然,这一切都假设您实际上正在对二进制文件执行某种类型的静态分析。如果您在运行时执行此操作,通常的方法是使用 LD_PRELOAD 进行库拦截,这是一个完全不同的问题。

关于c++ - 为什么符号 malloc、__malloc 和 __libc_malloc 指向相同的代码地址?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22155237/

相关文章:

c - 初始化指针到指针而不丢失保留内存

linux - 如何在整个目录上运行 dos2unix?

c++ - 使用函数传递的最大元素初始化数组

c++ - 集合比较器的前向声明

c - 反转二进制数中偶数位置的位

更改固定的二维数组以获取运行时给定的大小

c++ - 如何使用D-Bus获取设备名称?

linux - 如何检查软链接(soft link)的最终目标文件是否实际存在?

c# - 将带有字符串的 C# 结构传递给 C++ 应用程序

c++ - 在 cmake 中使用 boost::json 静态库