天天看點

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	[email protected]@[email protected]@Z					; Two::Two
PUBLIC	[email protected]@[email protected]					; Two::~Two
PUBLIC	[email protected]@QAEXXZ					; Two::`default constructor closure'
PUBLIC	[email protected]@[email protected]				; Two::`scalar deleting destructor'
PUBLIC	[email protected]@[email protected]				; Two::`vector deleting destructor'
PUBLIC	_main
EXTRN	[email protected]@[email protected]:NEAR			; `eh vector constructor iterator'
EXTRN	[email protected]@[email protected]:NEAR			; `eh vector destructor iterator'
EXTRN	[email protected]@Z:NEAR				; operator new
EXTRN	[email protected]@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	[email protected]@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	[email protected]@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	[email protected]@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	[email protected]@Z				; operator delete
	add	esp, 4

; 45   : 	Two a;

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

; 46   : 	Two b[3];

	push	OFFSET FLAT:[email protected]@[email protected]		; Two::~Two
	push	OFFSET FLAT:[email protected]@QAEXXZ		; Two::`default constructor closure'
	push	3
	push	4
	lea	eax, DWORD PTR _b$[ebp]
	push	eax
	call	[email protected]@[email protected]			; `eh vector constructor iterator'
	mov	BYTE PTR __$EHRec$[ebp+8], 1

; 47   : 	Two *p2 = new Two;

	push	4
	call	[email protected]@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	[email protected]@[email protected]@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	[email protected]@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	[email protected]@[email protected]@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	[email protected]@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:[email protected]@[email protected]		; Two::~Two
	push	OFFSET FLAT:[email protected]@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	[email protected]@[email protected]			; `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	[email protected]@[email protected]			; 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	[email protected]@[email protected]			; 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	[email protected]@[email protected]			; 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:[email protected]@[email protected]		; Two::~Two
	push	3
	push	4
	lea	ecx, DWORD PTR _b$[ebp]
	push	ecx
	call	[email protected]@[email protected]			; `eh vector destructor iterator'
	mov	DWORD PTR __$EHRec$[ebp+8], -1
	lea	ecx, DWORD PTR _a$[ebp]
	call	[email protected]@[email protected]				; 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 [email protected]@[email protected]@Z
_TEXT	SEGMENT
_this$ = -4
[email protected]@[email protected]@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
[email protected]@[email protected]@Z ENDP					; Two::Two
_TEXT	ENDS
;	COMDAT [email protected]@[email protected]
_TEXT	SEGMENT
_this$ = -4
[email protected]@[email protected] 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
[email protected]@[email protected] ENDP					; Two::~Two
_TEXT	ENDS
;	COMDAT [email protected]@QAEXXZ
_TEXT	SEGMENT
_this$ = -4
[email protected]@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	[email protected]@[email protected]@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
[email protected]@QAEXXZ ENDP					; Two::`default constructor closure'
_TEXT	ENDS
;	COMDAT [email protected]@[email protected]
_TEXT	SEGMENT
___flags$ = 8
_this$ = -4
[email protected]@[email protected] 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:[email protected]@[email protected]		; 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	[email protected]@[email protected]			; `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	[email protected]@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	[email protected]@[email protected]				; 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	[email protected]@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
[email protected]@[email protected] ENDP					; Two::`vector deleting destructor'
_TEXT	ENDS
;	COMDAT [email protected]@[email protected]
_TEXT	SEGMENT
___flags$ = 8
_this$ = -4
[email protected]@[email protected] 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	[email protected]@[email protected]				; 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	[email protected]@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
[email protected]@[email protected] ENDP					; Two::`scalar deleting destructor'
_TEXT	ENDS
END