I am try to implement my own c++ new & delete operators in my program as bellow:
#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;
}
Then I find that, if the program is built out as: -- an exe, then my new/delete is called as expected -- but,, a shared-object, then symbols of new & delete is to be relocated, so in my env when this so is loaded by dlopen in another program then the new & delete will be mapped to another program's new & delete...
The detailed information is as bellow...
build out an exe:
gcc -m32 -c main.cpp gcc -m32 main.o -o main.exe
$ ./main.exe My new is called! My delete is called!
$ objdump -d main.exe 080484ac :
80484ac: 55 push %ebp
80484ad: 89 e5 mov %esp,%ebp
80484af: 53 push %ebx
80484b0: 83 ec 24 sub $0x24,%esp
80484b3: 83 e4 f0 and $0xfffffff0,%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 sub %eax,%esp
80484c9: c7 04 24 04 00 00 00 movl $0x4,(%esp)
80484d0: e8 1f ff ff ff call 80483f4 <_Znwj> --> new: expected!!
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 call 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> --> delete: expectedbuild out a shared object:
gcc -m32 -c main.cpp gcc --shared -m32 main.o -o main.so
$ objdump -d main.so 000006d4 :
6d4: 55 push %ebp
6d5: 89 e5 mov %esp,%ebp
6d7: 53 push %ebx
6d8: 83 ec 24 sub $0x24,%esp
6db: 83 e4 f0 and $0xfffffff0,%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 ---> new: to be relocated, unexpected :(
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 call 723 ---> delete: to be relocated, unexpected :(
727: 8b 45 e8 mov -0x18(%ebp),%eax
72a: 89 04 24 mov %eax,(%esp)
72d: e8 fc ff ff ff call 72e
This is exactly as designed (UNIX shared libraries work very differently from Windows shared libraries in that respect).
The reason: symbol interpositioning. For example, on UNIX you can link in an alternative malloc implementation (e.g. tcmalloc) into the main executable, and every shared library, including
libc.so
which provides its own malloc, will call your malloc.If you want to achieve Windows-like symbol binding on UNIX, the
-Bsymbolic
linker flag might do what you want (readman ld
on your platform).If you are on Linux or Solaris,
gcc -shared -Wl,-Bsymbolic ...
should do what you want. Beware: there are many gotcha's in going "against the system". You may come to regret trying to do it this way.