使用静态链接重新定义malloc / free具有多个定义错误

时间:2011-04-07 05:25:34

标签: c++ c gcc malloc static-linking

最近,我的公司想要将编译器从gcc-3.4更新到gcc-4.5。但是,我们客户的机器可能没有最新的libstdc++.so,因此我们希望静态链接我们的二进制文件。

我们的计划需要定制malloc()/free()以满足极高的性能要求。

我修改了makefile,在链接时添加了-static,并收到以下错误消息:

/usr/lib64/libc.a(malloc.o)(.text+0x18c0): In function `free':
: multiple definition of `free'
../../ic/src/memmgr/libmemmgr_mt_thread.a(memmgr_mt_thread.o)(.text+0x3430): first defined here
/usr/bin/ld: Warning: size of symbol `free' changed from 271 in ../../ic/src/memmgr/libmemmgr_mt_thread.a(memmgr_mt_thread.o) to 255 in /usr/lib64/libc.a(malloc.o)
/usr/lib64/libc.a(malloc.o)(.text+0x3970): In function `malloc':
: multiple definition of `malloc'
../../ic/src/memmgr/libmemmgr_mt_thread.a(memmgr_mt_thread.o)(.text+0x29c0): first defined here
/usr/bin/ld: Warning: size of symbol `malloc' changed from 281 in ../../ic/src/memmgr/libmemmgr_mt_thread.a(memmgr_mt_thread.o) to 461 in /usr/lib64/libc.a(malloc.o)
/usr/lib64/libc.a(malloc.o)(.text+0x4050): In function `realloc':
: multiple definition of `realloc'
../../ic/src/memmgr/libmemmgr_mt_thread.a(memmgr_mt_thread.o)(.text+0x3e80): first defined here
/usr/bin/ld: Warning: size of symbol `realloc' changed from 335 in ../../ic/src/memmgr/libmemmgr_mt_thread.a(memmgr_mt_thread.o) to 927 in /usr/lib64/libc.a(malloc.o)

好的,这是合理的,因为libc.a已经有malloc()/free()

但令我困惑的是动态链接时没有错误的原因。我搜索过,发现了这个问题:How to redefine malloc() in Linux for use in C++ new。答案是链接器以不同方式处理库文件(.a)和目标文件(.o)。现在我知道静态链接发生错误的原因,而不是动态错误。

但是,我尝试了该答案中描述的解决方案,直接用目标文件替换了库文件,但没有区别。我仍然有多个定义链接错误。我也试过-static-libgcc(因为我不知道该怎么做,我只是尝试了我在gcc手册页中看到的所有内容),但它也无济于事。

我不必使用静态链接。我只想解决libstdc++.so版本问题。任何建议将不胜感激。

提前致谢。

编辑:对不起,我没有说清楚。使用#define malloc ...可能无济于事。因为我们的程序是C ++。 #define成语只能影响malloc()/free()函数。但我们的程序实际上使用new/delete来分配/释放内存。无论如何,谢谢:D

6 个答案:

答案 0 :(得分:5)

如果您主要关心的是libstdc ++的可用性,那么在目标系统中,为什么不简单地将新版本与您的应用程序一起分发呢?

我认为静态链接在任何情况下都不是一个好的解决方案,编译项目会变得更加困难,如果你自己使用共享对象(例如使用自己的插件时),那么静态链接就会停​​止工作,因为静态库的单独副本需要链接到二进制文件的每个,可执行文件等等。你能想象如果在加载时同一程序中有多个全局变量,锁等实例会发生什么?我告诉你:崩溃。

所以不要静态链接,复制libstdc ++。所以到私有目录(我不知道你的应用程序安装在哪里,但如果它有一个私有前缀,那很简单,使用$ prefix / lib)。 / p>

然后设置LD_LIBRARY_PATH,或使用-rpath将路径编码为二进制文件,以便链接器找到它。当然,这意味着您链接的所有库,也可能使用libstdc ++,也应该与您的应用程序一起分发。

但从大小来看,它大致相同,静态链接也会带有代码。

答案 1 :(得分:3)

您可以使用rpath进行动态链接。见“man ld”和“man ld.so”。

$ ORIGIN扩展可能很有用:捆绑每个.so你需要在与程序(或子目录)相同的目录中,并在链接时使用“-rpath $ ORIGIN”或“-rpath,'$ ORIGIN / lib”与ld。

许多程序使用这种方法捆绑自己的私有库。

另一种方法是使用.sh脚本设置LD_LIBRARY_PATH,然后调用真实程序(下载firefox二进制文件并查看run-mozilla.sh)。但是LD_LIBRARY_PATH将泄漏到子进程。所以它不是那么干净,但可能更容易移植到非GNU系统。

答案 2 :(得分:2)

您应该在项目中使用自己的free / alloc / realloc函数,但我强烈建议您使用与标准库相同的名称。

例如

void* myProject_malloc(...)
void myProject_free()

您可以将它与宏结合使用,将分配功能重定向到您的功能,但我真的不想让您这样做。您有义务检查所有源代码是否包含此头文件,并且编译器可以使您了解宏重定义(取决于编译器和您使用的选项)

#define malloc(x) myProject_malloc(x)
#define free() myProject_free()

如果您不想使用标准库,则应使用gcc选项:“ - nostdlib”。但是如果你这样做,你就不能使用标准库的任何其他功能。

答案 3 :(得分:1)

如果您使用的是GNU libc,则可以使用GNU malloc Hooks。我对这个API的设计不太满意所以我不建议使用它。

您可以尝试修补libc。删除malloc/中的所有代码,并将其替换为您的实现。

使用相同的想法,您可能会尝试删除libc.a,删除包含.o和朋友的所有malloc个文件(这应该是所有.o个文件对应malloc/*.c)并重新加载libc.a与您的实施。

答案 4 :(得分:0)

很可能您需要更改自定义分配例程的名称。之后,您应该使用答案中描述的方法来节省时间,这样您就不必更改所有对新名称的调用:

#define malloc myMalloc
#define free myFree

答案 5 :(得分:0)

如果您只需要为C ++执行此操作,则可以覆盖new,delete,new [],delete []运算符。请参见18.6.1“存储分配和释放”

  void* operator new(std::size_t size);
  [...]
  void operator delete(void* ptr);

“可替换:C ++程序可以使用此函数签名定义一个函数,取代C ++标准库定义的默认版本。”

我不知道它是否适用于静态链接(不知道它是如何实现的)。