【问题标题】:Override libc functions without LD_PRELOAD在没有 LD_PRELOAD 的情况下覆盖 libc 函数
【发布时间】:2016-12-01 16:35:06
【问题描述】:

我计划实现自己的 malloc/free,但在尝试将共享库与可执行文件链接时遇到了一些问题。

现在,我可以让它与 LD_PRELOAD 一起使用,但不能通过将 .so 链接到可执行文件,尽管我可以通过将它们链接到我的可执行文件来让类似的库(如 tcmalloc)正常工作,并且想要做同样的事情。

我正在使用 cmake 构建所有内容,这是我的共享库的 CMakeLists:

cmake_minimum_required(VERSION 2.8)
project(allocator)

add_library(allocator SHARED exports.cpp)
target_link_libraries(allocator dl)

target_compile_features(allocator PRIVATE cxx_range_for)

这是exports.cpp:

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include <stdio.h>
#include <dlfcn.h>

typedef void * (*MallocType)(size_t);
typedef void (*FreeType)(void *);

static bool g_initialized = false;

static MallocType real_malloc = nullptr;
static FreeType   real_free   = nullptr;

static void alloc_init(void)
{
    real_malloc = (MallocType) dlsym(RTLD_NEXT, "malloc");

    if (!real_malloc)
    {
        fprintf(stderr, "Error in `dlsym`: %s\n", dlerror());
    }

    real_free = (FreeType) dlsym(RTLD_NEXT, "free");

    if (!real_free)
    {
        fprintf(stderr, "Error in `dlsym`: %s\n", dlerror());
    }

    g_initialized = true;
}

extern "C" void * malloc(size_t size)
{
    if (!g_initialized)
    {
        alloc_init();
    }

    printf("Allocate %u.\n", size);
    return real_malloc(size);
}

extern "C" void free(void *ptr)
{
    if (!g_initialized)
    {
        alloc_init();
    }

    printf("Free %p.\n", ptr);
    real_free(ptr);
}

正如我所说,尝试将生成的 .so 链接到可执行文件并不能真正链接库(ldd 中没有条目,并且调用了 libc malloc)。我想知道我做错了什么。

编辑: 我也试过用

编译
g++ -o liballocator.so -shared exports.cpp -std=c++11 -fPIC -ldl
g++ -o test launcher.cpp memusage.cpp app.cpp -ldl -L. -lallocator -std=c++11

【问题讨论】:

  • 这显然不是 C,而是用 C++ 编译器编译的。将 C 编译为 C 并使用相应的标头链接到您的 C++ 代码。标准库的名称是保留的。使用它们(至少你在这里做的方式)会调用未定义的行为。
  • 启用 make 的详细输出并检查实际执行的链接命令可能很有启发性。
  • 我尝试编译纯 C 但结果是一样的,而且我认为我也应该能够链接 C++ 代码,特别是因为 LD_PRELOAD 确实有效。
  • 无法在 Ubuntu 14.04 上复制,库链接得很好,并在运行时成功插入 Glibc 分配器...
  • 我不知道为什么,但是现在可以了,从昨天开始我没有改变任何东西,无论如何。

标签: c++ linux cmake dynamic-linking


【解决方案1】:

CMake 不是您在这里选择的工具。 CMake 为 C 源代码创建 makefile 或 IDE 项目文件,并且有一种工作假设,即所有代码都以常规方式执行常规操作。如果您已承诺提供自己的 malloc,那就不再适用了。

大多数 C 编译器可以被哄骗链接用户提供的 malloc 版本,通常是通过调整链接标志的顺序。但这是一个容易出错的过程,因为可能会提前绑定间接调用或子模块。您可以通过重命名 malloc() mymalloc() 立即解决所有这些问题,但是当然您必须重写客户端代码。

【讨论】:

  • 这看起来更像是评论而不是答案。
  • C++ 也是如此:它不是解决方案的一部分,而是问题的一部分。
猜你喜欢
  • 2019-06-29
  • 2021-11-28
  • 1970-01-01
  • 2014-01-31
  • 2014-01-20
  • 1970-01-01
  • 2014-05-05
  • 1970-01-01
  • 2013-05-18
相关资源
最近更新 更多