new/delete操作符的汇编级粗略过程

new/delete操作符的汇编级粗略过程
MSVC6.0 DEBUG ASM

默认情况下(没有重载new运算符) new int 结果上完全等价于 (int *)malloc(sizeof(int))。new int[n]完全等价于(int *)malloc(sizeof(int) * n)
这个可以推广到所有非类类型。

对于类,假设ClassA,new ClassA; 相当于(ClassA *)malloc(sizeof(ClassA))之后用返回的指针调用ClassA的默认构造函数,再返回那个指针

new ClassA(参数表) 基本上和上面一样,只是会调用参数表对应的构造方法
new ClassA[n]比较复杂,一般会进行类似 int *t = (int *)malloc(sizeof(ClassA) * n + sizeof(int)); *t = n; ClassA *r = (ClassA *)(t + 1); for (int i = 0; i < n; i++, (r++)->ClassA::ClassA()); return (ClassA *)(t + 1);的操作。简单说就是申请内存,保存个数,然后对每个对象调用构造函数

对于非类类型 delete p和delete[] p相同,等价于free(p)
对于类,假设还是ClassA,delete p等价于 p->ClassA::~ClassA(); free(p); 先调用析构函数,然后释放内存
对于delete[] p,并且p用new []申请。对应上面的new []实现,delete[] p会进行 int *t = (int *)p - 1; for (int i = 0; i < *t; i++, (p++)->ClassA::~ClassA()); free(t);的操作。
注:以上这段摘自百度知道http://zhidao.baidu.com/question/200118329.html中的其他答案。。。​

(一)内置类型。
Ⅰ.new 内置类型:(如int *a=new int;或int *b=new int[5])
1.将operator new函数的参数nSize压栈,通常等于待分配空间长度(Eg: 1或5)。
2.调用void* __cdecl operator new(size_t nSize),寄存器传递分配成功后的指针,主调函数用临时变量接收。(注1:函数调用方式__cdecl表明参数压栈顺序为由右及左,调用完毕后由主调函数清除入栈参数恢复栈顶。注2:operator new函数执行过程中有机制用于记录分配的长度。该函数具体过程也不简单,参见其他网页)
3.将返回值传给目标指针。

Ⅱ.delete 内置类型:(如delete a;或delete[] a;;delete b;或delete[] b;,效果均相同)(注:若类类型无析构函数,则其delete操作符与内置类型完全相同!)
1.将待处理指针p压栈。
2.调用 void __cdecl operator delete(void* p) 。(注:调用方式也是__cdecl。因operator new函数执行过程中有用于记录分配的长度的外部数据结构,故在delete过程中可获取该指针对应分配的空间长度,从而正确释放。调用方式加不加中括号都是同样效果!)


(二)类类型。
分两种类别讨论:有无自定义构造函数和有无析构函数。以下条目是有构造函数和析构函数时的过程。
若去掉析构函数,与有析构函数相比:new单个对象的过程相同;但new对象数组则不同,虽过程相近,但分配区直接是类对象数组,而没有记录元素个数的单元。
若去掉析构函数,则new等于operator new直接按所需空间分配,然后初始化;而delete与内置类型完全相同,无需析构,delete操作符可混用!
若去掉构造函数但有析构函数,则调用operator new后无需初始化,但new对象数组时分配空间时仍多用一个内存单元记录个数。
若构造析构均无,则退化为内置类型。

(注:对于在函数中定义的局部变量,其过程相对以下条目,只是少了operator new/delete函数的调用)

Ⅲ. new 类类型的单个对象:(如int *c=new CString;)
1.将operator new函数的参数nSize压栈,即该类的sizeof值(Eg: 4)。
2.调用void* __cdecl operator new(size_t nSize),寄存器传递分配成功后的指针,主调函数用临时变量接收。
3.将构造函参进栈,将分配所得对象的指针传入ECX(类成员函数的调用方式默认为thiscall方式),调用适当的类构造函数。(若无构造函数,则无此步骤。)
3.将对象指针传给目标指针。

Ⅳ. new 类类型的数组:(如int *d=new CString[5];)
1.将operator new函数的参数nSize压栈,即该数组的sizeof值+4(Eg: 5*4+4=0x18h)。
2.调用void* __cdecl operator new(size_t nSize),寄存器传递分配成功后的指针,主调函数用临时变量接收。将已分配区的首个单元填上元素个数。(注:分配区的首个内存单元将存储数组元素个数,其后的内存单元才是类对象数组的实际空间,故nSize要大4字节)。
3.将eh vector constructor iterator函数的参数压栈,从左往右分别是首个对象的this指针,sizeof类类型,数组元素个数,类默认构造函数,类析构函数。 调用eh vector constructor iterator全局函数,即矢量构造函数,将每个对象均初始化。(注:析构函数可能是用于对象初始化过程失败后的回滚,即将已构造的对象再析构使之无效。)(若无析构函数,则调用vector constructor iterator全局函数,它有4个参数,不含类析构函数。若无构造函数,则无此步骤。)
4.将首个对象的指针,即已分配区指针的下一单元,传给目标指针。

. delete 类类型的单个变量:(如delete c;)
1.将立即数1压栈,将待处理指针p(new操作符返回的对象指针)传给ECX。(注:1代表delete操作符类别delete ;,不含方括号)
2.调用类的 scalar deleting destructor函数 其具体过程为:
(1)将对象指针传入ECX,调用类析构函数。
(2)测试之前入栈的立即数,若为奇数则进行(3),否则跳过并结束。
(3)将对象指针压栈,调用void __cdecl operator delete(void* p)。

Ⅵ.delete 类类型的数组:(如delete[] d;)
1.将立即数3压栈,将待处理指针p(new[]操作符返回的首对象指针)传给ECX。(注:3代表delete操作符 类别 delete[];
2.调用类的 vector deleting destructor 其具体过程为:
(1)将对象指针传入ECX,调用类析构函数。
(2)测试之前入栈的立即数,若为2或3则从(3)顺序执行;若不满足则不进行逐个析构,只对首个对象调用类析构函数,并跳到(4)。
(3)将eh vector destructor iterator全局函数的参数压栈,从左往右分别是首个对象的this指针,sizeof类类型,数组元素个数(从首对象地址的上一内存单元中读出),类析构函数。然后调用该函数。
(4)测试之前入栈的立即数,若为奇数则将首对象地址的上一单元地址入栈(因这是实际由operator new所分配空间的首地址),调用void __cdecl operator delete(void* p);若不满足则跳过operator delete的调用。最后EAX均传递operator new函数所分配的空间首地址。

测试代码:
class	Two
{
	int		a;
public:
	Two( int b =0)	{	a = 5;	};
	~Two( void )	{	a= 0;	};
};

int main(int argc, char* argv[])
{
	char *p0 = new char;
	char *p1= new char[10];
	delete p0;
	delete p1;
	Two a;
	Two b[3];
	Two *p2 = new Two;
	Two *p3 = new Two(10);
	Two *p4 = new Two[7];
	
	p1[0] = *p0;
	
	delete p2;
	delete p3;//delete[] p3;
	delete[] p4;//delete p4;
	return 0;
}

生成汇编:
PUBLIC	??0Two@@QAE@H@Z					; Two::Two
PUBLIC	??1Two@@QAE@XZ					; Two::~Two
PUBLIC	??_FTwo@@QAEXXZ					; Two::`default constructor closure'
PUBLIC	??_GTwo@@QAEPAXI@Z				; Two::`scalar deleting destructor'
PUBLIC	??_ETwo@@QAEPAXI@Z				; Two::`vector deleting destructor'
PUBLIC	_main
EXTRN	??_L@YGXPAXIHP6EX0@Z1@Z:NEAR			; `eh vector constructor iterator'
EXTRN	??_M@YGXPAXIHP6EX0@Z@Z:NEAR			; `eh vector destructor iterator'
EXTRN	??2@YAPAXI@Z:NEAR				; operator new
EXTRN	??3@YAXPAX@Z:NEAR				; operator delete
EXTRN	__except_list:DWORD
EXTRN	__chkesp:NEAR
EXTRN	___CxxFrameHandler:NEAR

_main	PROC NEAR					; COMDAT

; 40   : {

	push	ebp
	mov	ebp, esp
	push	-1
	push	__ehhandler$_main
	mov	eax, DWORD PTR fs:__except_list
	push	eax
	mov	DWORD PTR fs:__except_list, esp
	sub	esp, 192				; 000000c0H
	push	ebx
	push	esi
	push	edi
	lea	edi, DWORD PTR [ebp-204]
	mov	ecx, 48					; 00000030H
	mov	eax, -858993460				; ccccccccH
	rep stosd

; 41   : 	char *p0 = new char;

	push	1
	call	??2@YAPAXI@Z				; operator new
	add	esp, 4
	mov	DWORD PTR $T297[ebp], eax
	mov	eax, DWORD PTR $T297[ebp]
	mov	DWORD PTR _p0$[ebp], eax

; 42   : 	char *p1= new char[10];

	push	10					; 0000000aH
	call	??2@YAPAXI@Z				; operator new
	add	esp, 4
	mov	DWORD PTR $T298[ebp], eax
	mov	ecx, DWORD PTR $T298[ebp]
	mov	DWORD PTR _p1$[ebp], ecx

; 43   : 	delete p0;

	mov	edx, DWORD PTR _p0$[ebp]
	mov	DWORD PTR $T299[ebp], edx
	mov	eax, DWORD PTR $T299[ebp]
	push	eax
	call	??3@YAXPAX@Z				; operator delete
	add	esp, 4

; 44   : 	delete p1;

	mov	ecx, DWORD PTR _p1$[ebp]
	mov	DWORD PTR $T300[ebp], ecx
	mov	edx, DWORD PTR $T300[ebp]
	push	edx
	call	??3@YAXPAX@Z				; operator delete
	add	esp, 4

; 45   : 	Two a;

	push	0
	lea	ecx, DWORD PTR _a$[ebp]
	call	??0Two@@QAE@H@Z				; Two::Two
	mov	DWORD PTR __$EHRec$[ebp+8], 0

; 46   : 	Two b[3];

	push	OFFSET FLAT:??1Two@@QAE@XZ		; Two::~Two
	push	OFFSET FLAT:??_FTwo@@QAEXXZ		; Two::`default constructor closure'
	push	3
	push	4
	lea	eax, DWORD PTR _b$[ebp]
	push	eax
	call	??_L@YGXPAXIHP6EX0@Z1@Z			; `eh vector constructor iterator'
	mov	BYTE PTR __$EHRec$[ebp+8], 1

; 47   : 	Two *p2 = new Two;

	push	4
	call	??2@YAPAXI@Z				; operator new
	add	esp, 4
	mov	DWORD PTR $T302[ebp], eax
	mov	BYTE PTR __$EHRec$[ebp+8], 2
	cmp	DWORD PTR $T302[ebp], 0
	je	SHORT $L303
	push	0
	mov	ecx, DWORD PTR $T302[ebp]
	call	??0Two@@QAE@H@Z				; Two::Two
	mov	DWORD PTR -120+[ebp], eax
	jmp	SHORT $L304
$L303:
	mov	DWORD PTR -120+[ebp], 0
$L304:
	mov	ecx, DWORD PTR -120+[ebp]
	mov	DWORD PTR $T301[ebp], ecx
	mov	BYTE PTR __$EHRec$[ebp+8], 1
	mov	edx, DWORD PTR $T301[ebp]
	mov	DWORD PTR _p2$[ebp], edx

; 48   : 	Two *p3 = new Two(10);

	push	4
	call	??2@YAPAXI@Z				; operator new
	add	esp, 4
	mov	DWORD PTR $T306[ebp], eax
	mov	BYTE PTR __$EHRec$[ebp+8], 3
	cmp	DWORD PTR $T306[ebp], 0
	je	SHORT $L307
	push	10					; 0000000aH
	mov	ecx, DWORD PTR $T306[ebp]
	call	??0Two@@QAE@H@Z				; Two::Two
	mov	DWORD PTR -124+[ebp], eax
	jmp	SHORT $L308
$L307:
	mov	DWORD PTR -124+[ebp], 0
$L308:
	mov	eax, DWORD PTR -124+[ebp]
	mov	DWORD PTR $T305[ebp], eax
	mov	BYTE PTR __$EHRec$[ebp+8], 1
	mov	ecx, DWORD PTR $T305[ebp]
	mov	DWORD PTR _p3$[ebp], ecx

; 49   : 	Two *p4 = new Two[7];

	push	32					; 00000020H
	call	??2@YAPAXI@Z				; operator new
	add	esp, 4
	mov	DWORD PTR $T310[ebp], eax
	mov	BYTE PTR __$EHRec$[ebp+8], 4
	cmp	DWORD PTR $T310[ebp], 0
	je	SHORT $L311
	push	OFFSET FLAT:??1Two@@QAE@XZ		; Two::~Two
	push	OFFSET FLAT:??_FTwo@@QAEXXZ		; Two::`default constructor closure'
	mov	edx, DWORD PTR $T310[ebp]
	mov	DWORD PTR [edx], 7
	push	7
	push	4
	mov	eax, DWORD PTR $T310[ebp]
	add	eax, 4
	push	eax
	call	??_L@YGXPAXIHP6EX0@Z1@Z			; `eh vector constructor iterator'
	mov	ecx, DWORD PTR $T310[ebp]
	add	ecx, 4
	mov	DWORD PTR -128+[ebp], ecx
	jmp	SHORT $L312
$L311:
	mov	DWORD PTR -128+[ebp], 0
$L312:
	mov	edx, DWORD PTR -128+[ebp]
	mov	DWORD PTR $T309[ebp], edx
	mov	BYTE PTR __$EHRec$[ebp+8], 1
	mov	eax, DWORD PTR $T309[ebp]
	mov	DWORD PTR _p4$[ebp], eax

; 50   : 	
; 51   : 	p1[0] = *p0;

	mov	ecx, DWORD PTR _p1$[ebp]
	mov	edx, DWORD PTR _p0$[ebp]
	mov	al, BYTE PTR [edx]
	mov	BYTE PTR [ecx], al

; 52   : 	
; 53   : 	delete p2;

	mov	ecx, DWORD PTR _p2$[ebp]
	mov	DWORD PTR $T314[ebp], ecx
	mov	edx, DWORD PTR $T314[ebp]
	mov	DWORD PTR $T313[ebp], edx
	cmp	DWORD PTR $T313[ebp], 0
	je	SHORT $L315
	push	1
	mov	ecx, DWORD PTR $T313[ebp]
	call	??_GTwo@@QAEPAXI@Z			; Two::`scalar deleting destructor'
	mov	DWORD PTR -132+[ebp], eax
	jmp	SHORT $L316
$L315:
	mov	DWORD PTR -132+[ebp], 0
$L316:

; 54   : 	delete p3;//delete[] p3;

	mov	eax, DWORD PTR _p3$[ebp]
	mov	DWORD PTR $T318[ebp], eax
	mov	ecx, DWORD PTR $T318[ebp]
	mov	DWORD PTR $T317[ebp], ecx
	cmp	DWORD PTR $T317[ebp], 0
	je	SHORT $L319
	push	1
	mov	ecx, DWORD PTR $T317[ebp]
	call	??_GTwo@@QAEPAXI@Z			; Two::`scalar deleting destructor'
	mov	DWORD PTR -136+[ebp], eax
	jmp	SHORT $L320
$L319:
	mov	DWORD PTR -136+[ebp], 0
$L320:

; 55   : 	delete[] p4;//delete p4;

	mov	edx, DWORD PTR _p4$[ebp]
	mov	DWORD PTR $T322[ebp], edx
	mov	eax, DWORD PTR $T322[ebp]
	mov	DWORD PTR $T321[ebp], eax
	cmp	DWORD PTR $T321[ebp], 0
	je	SHORT $L323
	push	3
	mov	ecx, DWORD PTR $T321[ebp]
	call	??_ETwo@@QAEPAXI@Z			; Two::`vector deleting destructor'
	mov	DWORD PTR -140+[ebp], eax
	jmp	SHORT $L324
$L323:
	mov	DWORD PTR -140+[ebp], 0
$L324:

; 56   : 	return 0;

	mov	DWORD PTR $T325[ebp], 0
	mov	BYTE PTR __$EHRec$[ebp+8], 0
	push	OFFSET FLAT:??1Two@@QAE@XZ		; Two::~Two
	push	3
	push	4
	lea	ecx, DWORD PTR _b$[ebp]
	push	ecx
	call	??_M@YGXPAXIHP6EX0@Z@Z			; `eh vector destructor iterator'
	mov	DWORD PTR __$EHRec$[ebp+8], -1
	lea	ecx, DWORD PTR _a$[ebp]
	call	??1Two@@QAE@XZ				; Two::~Two
	mov	eax, DWORD PTR $T325[ebp]

; 57   : }

	mov	ecx, DWORD PTR __$EHRec$[ebp]
	mov	DWORD PTR fs:__except_list, ecx
	pop	edi
	pop	esi
	pop	ebx
	add	esp, 204				; 000000ccH
	cmp	ebp, esp
	call	__chkesp
	mov	esp, ebp
	pop	ebp
	ret	0
_TEXT	ENDS

;	COMDAT ??0Two@@QAE@H@Z
_TEXT	SEGMENT
_this$ = -4
??0Two@@QAE@H@Z PROC NEAR				; Two::Two, COMDAT

; 35   : 	Two( int b =0)	{	a = 5;	};

	push	ebp
	mov	ebp, esp
	sub	esp, 68					; 00000044H
	push	ebx
	push	esi
	push	edi
	push	ecx
	lea	edi, DWORD PTR [ebp-68]
	mov	ecx, 17					; 00000011H
	mov	eax, -858993460				; ccccccccH
	rep stosd
	pop	ecx
	mov	DWORD PTR _this$[ebp], ecx
	mov	eax, DWORD PTR _this$[ebp]
	mov	DWORD PTR [eax], 5
	mov	eax, DWORD PTR _this$[ebp]
	pop	edi
	pop	esi
	pop	ebx
	mov	esp, ebp
	pop	ebp
	ret	4
??0Two@@QAE@H@Z ENDP					; Two::Two
_TEXT	ENDS
;	COMDAT ??1Two@@QAE@XZ
_TEXT	SEGMENT
_this$ = -4
??1Two@@QAE@XZ PROC NEAR				; Two::~Two, COMDAT

; 36   : 	~Two( void )	{	a= 0;	};

	push	ebp
	mov	ebp, esp
	sub	esp, 68					; 00000044H
	push	ebx
	push	esi
	push	edi
	push	ecx
	lea	edi, DWORD PTR [ebp-68]
	mov	ecx, 17					; 00000011H
	mov	eax, -858993460				; ccccccccH
	rep stosd
	pop	ecx
	mov	DWORD PTR _this$[ebp], ecx
	mov	eax, DWORD PTR _this$[ebp]
	mov	DWORD PTR [eax], 0
	pop	edi
	pop	esi
	pop	ebx
	mov	esp, ebp
	pop	ebp
	ret	0
??1Two@@QAE@XZ ENDP					; Two::~Two
_TEXT	ENDS
;	COMDAT ??_FTwo@@QAEXXZ
_TEXT	SEGMENT
_this$ = -4
??_FTwo@@QAEXXZ PROC NEAR				; Two::`default constructor closure', COMDAT
	push	ebp
	mov	ebp, esp
	sub	esp, 68					; 00000044H
	push	ebx
	push	esi
	push	edi
	push	ecx
	lea	edi, DWORD PTR [ebp-68]
	mov	ecx, 17					; 00000011H
	mov	eax, -858993460				; ccccccccH
	rep stosd
	pop	ecx
	mov	DWORD PTR _this$[ebp], ecx
	push	0
	mov	ecx, DWORD PTR _this$[ebp]
	call	??0Two@@QAE@H@Z				; Two::Two
	pop	edi
	pop	esi
	pop	ebx
	add	esp, 68					; 00000044H
	cmp	ebp, esp
	call	__chkesp
	mov	esp, ebp
	pop	ebp
	ret	0
??_FTwo@@QAEXXZ ENDP					; Two::`default constructor closure'
_TEXT	ENDS
;	COMDAT ??_ETwo@@QAEPAXI@Z
_TEXT	SEGMENT
___flags$ = 8
_this$ = -4
??_ETwo@@QAEPAXI@Z PROC NEAR				; Two::`vector deleting destructor', COMDAT
	push	ebp
	mov	ebp, esp
	sub	esp, 68					; 00000044H
	push	ebx
	push	esi
	push	edi
	push	ecx
	lea	edi, DWORD PTR [ebp-68]
	mov	ecx, 17					; 00000011H
	mov	eax, -858993460				; ccccccccH
	rep stosd
	pop	ecx
	mov	DWORD PTR _this$[ebp], ecx
	mov	eax, DWORD PTR ___flags$[ebp]
	and	eax, 2
	test	eax, eax
	je	SHORT $L281
	push	OFFSET FLAT:??1Two@@QAE@XZ		; Two::~Two
	mov	ecx, DWORD PTR _this$[ebp]
	mov	edx, DWORD PTR [ecx-4]
	push	edx
	push	4
	mov	eax, DWORD PTR _this$[ebp]
	push	eax
	call	??_M@YGXPAXIHP6EX0@Z@Z			; `eh vector destructor iterator'
	mov	ecx, DWORD PTR ___flags$[ebp]
	and	ecx, 1
	test	ecx, ecx
	je	SHORT $L282
	mov	edx, DWORD PTR _this$[ebp]
	sub	edx, 4
	push	edx
	call	??3@YAXPAX@Z				; operator delete
	add	esp, 4
$L282:
	mov	eax, DWORD PTR _this$[ebp]
	sub	eax, 4
	jmp	SHORT $L280
$L281:
	mov	ecx, DWORD PTR _this$[ebp]
	call	??1Two@@QAE@XZ				; Two::~Two
	mov	eax, DWORD PTR ___flags$[ebp]
	and	eax, 1
	test	eax, eax
	je	SHORT $L284
	mov	ecx, DWORD PTR _this$[ebp]
	push	ecx
	call	??3@YAXPAX@Z				; operator delete
	add	esp, 4
$L284:
	mov	eax, DWORD PTR _this$[ebp]
$L280:
	pop	edi
	pop	esi
	pop	ebx
	add	esp, 68					; 00000044H
	cmp	ebp, esp
	call	__chkesp
	mov	esp, ebp
	pop	ebp
	ret	4
??_ETwo@@QAEPAXI@Z ENDP					; Two::`vector deleting destructor'
_TEXT	ENDS
;	COMDAT ??_GTwo@@QAEPAXI@Z
_TEXT	SEGMENT
___flags$ = 8
_this$ = -4
??_GTwo@@QAEPAXI@Z PROC NEAR				; Two::`scalar deleting destructor', COMDAT
	push	ebp
	mov	ebp, esp
	sub	esp, 68					; 00000044H
	push	ebx
	push	esi
	push	edi
	push	ecx
	lea	edi, DWORD PTR [ebp-68]
	mov	ecx, 17					; 00000011H
	mov	eax, -858993460				; ccccccccH
	rep stosd
	pop	ecx
	mov	DWORD PTR _this$[ebp], ecx
	mov	ecx, DWORD PTR _this$[ebp]
	call	??1Two@@QAE@XZ				; Two::~Two
	mov	eax, DWORD PTR ___flags$[ebp]
	and	eax, 1
	test	eax, eax
	je	SHORT $L287
	mov	ecx, DWORD PTR _this$[ebp]
	push	ecx
	call	??3@YAXPAX@Z				; operator delete
	add	esp, 4
$L287:
	mov	eax, DWORD PTR _this$[ebp]
	pop	edi
	pop	esi
	pop	ebx
	add	esp, 68					; 00000044H
	cmp	ebp, esp
	call	__chkesp
	mov	esp, ebp
	pop	ebp
	ret	4
??_GTwo@@QAEPAXI@Z ENDP					; Two::`scalar deleting destructor'
_TEXT	ENDS
END



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值