【问题标题】:Why new&delete operator symbols in shared-obj is to be relocated even if they are implemented in that shared-obj?为什么 shared-obj 中的 new&delete 运算符符号即使在该 shared-obj 中实现也要重新定位?
【发布时间】:2012-06-01 17:07:17
【问题描述】:

我正在尝试在我的程序中实现我自己的 c++ new & delete 运算符,如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <new>

using namespace std;

void *operator new(std::size_t size) throw(std::bad_alloc)
{
    printf("My new is called!\n");
    return malloc(size);
}

void operator delete(void *ptr) throw ()
{
    printf("My delete is called!\n");
    free(ptr);
}

void *operator new(std::size_t size, const std::nothrow_t&) throw()
{
    return malloc(size);
}

void operator delete(void *ptr, const std::nothrow_t&) throw()
{
    free(ptr);
}

void *operator new[](std::size_t size) throw(std::bad_alloc)
{
    return malloc(size);
}

void operator delete[](void *ptr) throw () 
{
    free(ptr);
}

void *operator new[](std::size_t size,
                     const std::nothrow_t&) throw()
{
    return malloc(size);
}

void operator delete[](void *ptr,
                       const std::nothrow_t&) throw()
{
    free(ptr);
}

class Object
{
public:
    Object() {}
    ~Object() {}

private:
    int a;
};

int main()
{
    Object* obj = new Object();
    if (obj)
        delete obj;

    return 0;
}

然后我发现,如果程序构建为: -- 一个 exe,然后按预期调用我的 new/delete -- 但是,一个共享对象,然后 new & delete 的符号将被重新定位,所以在我的环境中,当这个 so 由 dlopen 在另一个程序中加载时,new & delete 将映射到另一个程序的 new & delete。 ..

详细信息如下...

  1. 构建一个 exe:

    gcc -m32 -c main.cpp gcc -m32 main.o -o main.exe

    $ ./main.exe 我的新叫! 我的删除被调用了!

    $ objdump -d main.exe 080484ac :
    80484ac:55 推 %ebp
    80484ad: 89 e5 mov %esp,%ebp
    80484af: 53 推送 %ebx
    80484b0: 83 ec 24 sub $0x24,%esp
    80484b3: 83 e4 f0 和 $0xfffffff0,%esp
    80484b6: b8 00 00 00 00 移动 $0x0,%eax
    80484bb: 83 c0 0f 添加 $0xf,%eax
    80484be: 83 c0 0f 添加 $0xf,%eax
    80484c1: c1 e8 04 shr $0x4,%eax
    80484c4: c1 e0 04 shl $0x4,%eax
    80484c7: 29 c4 子 %eax,%esp
    80484c9: c7 04 24 04 00 00 00 movl $0x4,(%esp)
    80484d0: e8 1f ff ff ff 调用 80483f4 <_znwj> --> 新:预期!!
    80484d5: 89 c3 mov %eax,%ebx
    80484d7: 89 1c 24 mov %ebx,(%esp)
    80484da: e8 35 00 00 00 调用 8048514 <_zn6objectc1ev>
    80484df: 89 5d f8 mov %ebx,-0x8(%ebp)
    80484e2: 83 7d f8 00 cmpl $0x0,-0x8(%ebp)
    80484e6:74 22 je 804850a
    80484e8: 8b 45 f8 mov -0x8(%ebp),%eax
    80484eb: 89 45 e8 mov %eax,-0x18(%ebp)
    80484ee: 83 7d e8 00 cmpl $0x0,-0x18(%ebp)
    80484f2:74 16 je 804850a
    80484f4: 8b 45 e8 mov -0x18(%ebp),%eax
    80484f7: 89 04 24 mov %eax,(%esp)
    80484fa: e8 1b 00 00 00 调用 804851a <_zn6objectd1ev>
    80484ff: 8b 45 e8 mov -0x18(%ebp),%eax
    8048502: 89 04 24 mov %eax,(%esp)
    8048505: e8 0a ff ff ff call 8048414 <_zdlpv> --> 删除:预期

  2. 构建一个共享对象:

    gcc -m32 -c main.cpp gcc --shared -m32 main.o -o main.so

    $ objdump -d main.so 000006d4 :
    6d4: 55 推动 %ebp
    6d5: 89 e5 mov %esp,%ebp
    6d7: 53 推 %ebx
    6d8: 83 ec 24 sub $0x24,%esp
    6db: 83 e4 f0 和 $0xfffffff0,%esp
    6de: b8 00 00 00 00 移动 $0x0,%eax
    6e3: 83 c0 0f 添加 $0xf,%eax
    6e6: 83 c0 0f 添加 $0xf,%eax
    6e9: c1 e8 04 shr $0x4,%eax
    6ec: c1 e0 04 shl $0x4,%eax
    6ef: 29 c4 sub %eax,%esp
    6f1: c7 04 24 04 00 00 00 movl $0x4,(%esp)
    6f8: e8 fc ff ff ff call 6f9 ---> 新:要重新定位,意外:( 6fd: 89 c3 mov %eax,%ebx
    6ff: 89 1c 24 mov %ebx,(%esp)
    702:e8 fc ff ff ff 呼叫 703
    707: 89 5d f8 mov %ebx,-0x8(%ebp)
    70a: 83 7d f8 00 cmpl $0x0,-0x8(%ebp)
    70e: 74 22 je 732
    710: 8b 45 f8 mov -0x8(%ebp),%eax
    713: 89 45 e8 mov %eax,-0x18(%ebp)
    716: 83 7d e8 00 cmpl $0x0,-0x18(%ebp)
    71a:74 16 je 732
    71c: 8b 45 e8 mov -0x18(%ebp),%eax
    71f: 89 04 24 mov %eax,(%esp)
    722: e8 fc ff ff ff call 723 ---> 删除:要重新定位,意外:(
    727: 8b 45 e8 mov -0x18(%ebp),%eax
    72a: 89 04 24 mov %eax,(%esp)
    72d: e8 fc ff ff ff 调用 72e

【问题讨论】:

  • 你的 GCC 版本是什么?我记得过去的一个版本未能为默认分配函数提供足够“弱”的链接,因此它们可以被替换(我的问题是当我使用 -fwhole-program 时)。
  • gcc 4.0.4。仅供参考:我还使用其他函数进行测试,例如:void foo(),以便共享对象中的 foo 也将被重新定位到加载此共享对象的程序......有人可以分享如何防止它吗?因为共享对象已经有这个 foo 的实现,在上面的情况下也是 new & delete ...
  • 那很老了。用 GCC 4.6.3 试试吧。
  • @KerrekSB 在这个问题中,GCC 的版本与 anything 有什么关系?你认为新的 GCC 会有什么不同吗? (不会的。)
  • @EmployedRussian:至少有一个与我报告的默认分配函数的链接有关的错误,该错误在 4.5 之后已修复。不知道它是否与 this 问题有关,但它非常相似,因此值得尝试使用更新的版本。

标签: c++ linker relocation


【解决方案1】:

但是,一个共享对象,那么 new 和 delete 的符号将被重新定位

这与设计完全一致(UNIX 共享库在这方面与 Windows 共享库的工作方式非常不同)。

原因:符号插入。例如,在 UNIX 上,您可以将替代 malloc 实现(例如 tcmalloc)链接到主可执行文件,并且每个共享库,包括提供自己的 malloc 的 libc.so,将调用 您的 malloc。

如果您想在 UNIX 上实现类似于 Windows 的符号绑定,-Bsymbolic 链接器标志可能会满足您的需求(在您的平台上阅读 man ld)。

如果您使用的是 Linux 或 Solaris,gcc -shared -Wl,-Bsymbolic ... 应该可以满足您的需求。当心:“反对系统”有很多陷阱。你可能会后悔尝试这样做。

【讨论】:

  • Bsymbolic 不完全是一个“默认”选项,例如索拉里斯。基本上它禁用了 solaris 链接器的命名空间支持
猜你喜欢
  • 2010-11-14
  • 2017-01-12
  • 1970-01-01
  • 1970-01-01
  • 2014-04-12
  • 1970-01-01
  • 1970-01-01
  • 2018-01-15
  • 1970-01-01
相关资源
最近更新 更多