0

以下のように、プログラムに独自の 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 のシンボルが再配置されることがわかりました。これが別のプログラムで dlopen によってロードされると、私の環境では、新しい & 削除が別のプログラムの新しい & 削除にマップされます...

詳細情報は以下の通りです...

  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 サブ $0x24,%esp
    80484b3: 83 e4 f0 および $0xffffffff0 ,%esp
    80484b6: b8 00 00 00 00 mov $0x0,%eax
    80484bb: 83 c0 0f add $0xf,%eax
    80484be: 83 c0 0f add $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 call 80483f4 <_Znwj> --> 新規: 期待!!
    80484d5: 89 c3 mov %eax,%ebx
    80484d7: 89 1c 24 mov %ebx,(%esp)
    80484da: e8 35 00 00 00 call 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 <_ZN6Object
    : 84D5 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 サブ $0x24,%esp
    6db: 83 e4 f0 および $0xffffffff0 ,%esp
    6de: b8 00 00 00 00 mov $0x0,%eax
    6e3: 83 c0 0f add $0xf,%eax
    6e6: 83 c0 0f add $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 call 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 呼び出し 723 ---> 削除: 再配置される、予期しない :(
    727: 8b 45 e8 mov -0x18(%ebp),%eax
    72a: 89 04 24 mov %eax,(%esp)
    72d: e8 fc ff ff ff コール 72e

4

1 に答える 1

0

ただし、共有オブジェクトの場合、new&deleteのシンボルは再配置されます

これは設計どおりです(UNIX共有ライブラリはその点でWindows共有ライブラリとは大きく異なります)。

理由:シンボルの介在。たとえば、UNIXでは、代替のmalloc実装(tcmallocなど)をメインの実行可能ファイルにリンクでき、独自のmallocを提供するものを含むすべての共有ライブラリがmallocを呼び出しますlibc.so

UNIXでWindowsのようなシンボルバインディングを実現したい場合は、-Bsymbolicリンカーフラグが希望どおりに機能する可能性があります(man ldプラットフォームで読み取ります)。

LinuxまたはSolarisを使用gcc -shared -Wl,-Bsymbolic ...している場合は、必要な処理を実行する必要があります。注意:「システムに逆らって」行くことには多くの落とし穴があります。あなたはそれをこのようにしようとしたことを後悔するようになるかもしれません。

于 2012-05-26T15:25:42.073 に答える