汇编 rbp_new delete 以及 new[] delete [] 汇编层面分析

本文分析了C++中的new和delete操作符在汇编层面的工作原理,包括普通new、placement new以及new[]和delete[]的情况。讨论了如何分配内存、调用构造函数和析构函数,以及在数组操作中如何存储和获取数组长度。同时提到了operator-new和operator-delete的重载机制。
摘要由CSDN通过智能技术生成

fb2b71479047be09187365586eee3c9f.png

new delete

new:

方式一:string *p = new string("123");

  • - 编译器插入一行代码,调用operator-new函数,分配原始的,未命名的内存空间以便存储,
  • - 执行构造函数。返回指向该对象的指针

方式二:string *p = new (pold) string("123");

  • - 一个特殊的标准库函数operator new(size_t, void*)被调用,它什么也不做。
  • - 在pold所指地址上构造对象

new是一个操作符,无法被重载,它总是执行两步:

  • - 调用某个operator-new函数
  • - 构造对象

只是当它遇到方式二时,调用的是一个特殊的operator-new函数;从而跳过分配空间这一步。这种时候,new被称为placement new。

注:operator new(size_t, void*)无法被重载,否则placement new可能执行失败。

再次强调,new delete是操作符,placement new是指new以方式二的情况被调用。operator-new和operator-delete是函数。

当A *pa = new A(-1)的时候发生了什么

class A {
public:
    A(int ia):ia(ia){};
    int ia;
};
int main(int argc, char **argv)
{
    A *ps = new A(-1) ;
}

翻译成汇编:

0x0000000000401586  mov    $0x4,%ecx //sizeof(A) is 4
0x000000000040158b  callq  0x4b2980 <_Znwy> // _Znwy is operator new(unsigned long long, call ::opertor new(sizeof(A))
0x0000000000401590  mov    %rax,%rbx //为A分配的地址
0x0000000000401593  mov    $0xffffffff,%edx //-1
0x0000000000401598  mov    %rbx,%rcx
0x000000000040159b  callq  0x4210c0 <A::A(int)> //A::A(-1)
0x00000000004015a0  mov    %rbx,-0x58(%rbp) // ps = 为A分配的地址

当 new [] 和 delete []的时候发生了什么

当发生 A* pa = new A[num];的时候:

  • - 计算这个数组所需要的size,记为sz(这个size除了放得下数组,应该还放的下num)
  • - 调用operator new[](unsigned long long)。记::operator new [](sz)的返回值为p_new - *p_new = num;记录数组的长度,用于delete
  • - 令p_temp = p_new;用于初始化数组。p_temp += 0x8;这个长度用于存储数组长度。
  • - 循环在p_temp上调用构造函数
  • - pa = p_new + 8,即指向第一个A对象;

与effective c++中描写的一致:

03890f54d3b724d58b80040d90aaf8e6.png

当发生delete [] pa时:

  • - num = *(pa - 0x8) - p_temp = pa + offset;其中offset时编译器考虑对齐计算的一个值,使p_temp指向最后一个对象
  • - 循环在p_temp上调用析构函数
  • - 最后调用operator delete[](pa)释放内存。

例子

int main(int argc, char **argv)
{
    string *pa = new string[5];
    delete [] pa;
}

对应的new和delete代码为:

// 0xa8 = sizeof(array) + 放num的大小
0x000000000040157c  mov    $0xa8,%ecx
//operator new
0x0000000000401581  callq  0x4b2980 <_Znay>
//*p_new = 0x5
0x0000000000401586  mov    %rax,%rbx
0x0000000000401589  movq   $0x5,(%rbx)
// p_temp = p_new + 5
0x0000000000401590  lea    0x8(%rbx),%rax
//这部分是循环调用构造函数
0x0000000000401594  mov    $0x4,%esi
0x0000000000401599  mov    %rax,%rdi
0x000000000040159c  test   %rsi,%rsi
0x000000000040159f  js     0x4015b3 <main(int, char**)+83>
0x00000000004015a1  mov    %rdi,%rcx
0x00000000004015a4  callq  0x4a16a0 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1Ev>
0x00000000004015a9  add    $0x20,%rdi
0x00000000004015ad  sub    $0x1,%rsi
0x00000000004015b1  jmp    0x40159c <main(int, char**)+60>
//pa = p_new + 8;
0x00000000004015b3  lea    0x8(%rbx),%rax
0x00000000004015b7  mov    %rax,-0x58(%rbp)
//delete [] pa
0x00000000004015bb  cmpq   $0x0,-0x58(%rbp)
0x00000000004015c0  je     0x401600 <main(int, char**)+160>
0x00000000004015c2  mov    -0x58(%rbp),%rax
// num = *(pa - 0x8)
0x00000000004015c6  sub    $0x8,%rax
0x00000000004015ca  mov    (%rax),%rax
//p_temp = &pa[-1]
//然后循环析构
0x00000000004015cd  shl    $0x5,%rax
0x00000000004015d1  mov    %rax,%rdx
0x00000000004015d4  mov    -0x58(%rbp),%rax
0x00000000004015d8  lea    (%rdx,%rax,1),%rbx
0x00000000004015dc  cmp    -0x58(%rbp),%rbx
0x00000000004015e0  je     0x4015f0 <main(int, char**)+144>
0x00000000004015e2  sub    $0x20,%rbx
0x00000000004015e6  mov    %rbx,%rcx
0x00000000004015e9  callq  0x4a19f0 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev>
0x00000000004015ee  jmp    0x4015dc <main(int, char**)+124>
0x00000000004015f0  mov    -0x58(%rbp),%rax
//::operator delete [] ( pa )
0x00000000004015f4  sub    $0x8,%rax
0x00000000004015f8  mov    %rax,%rcx
0x00000000004015fb  callq  0x4b2950 <_ZdaPv>

delete

  • 执行析构函数
  • 调用operator-delete函数释放空间

其中operator-new和operator-delete可以被重载:

  • - 作为类的方法被重载
  • - 作为一个全局函数被重载

当编译器没有找到用户重载的operator-new和operator-delete时,调用标准库的::operator new和::operator delete

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值