首页 > 代码库 > VS2013下的new[]和delete[]分析
VS2013下的new[]和delete[]分析
编译模式:Debug
编译环境:Microsoft Visual Studio Ultimate 2013 (12.0.30501.00) Update 2
//////////////////////////////////////////////////////////////////////////////
一. New[]:
C++代码:
int *lpNum = new int[16];
汇编代码:
PUSH 0x40 ; new申请的空间大小
CALL XXXXXXXX ; CALL NEW
ADD ESP, 0x4 ; _cdecl调用约定的平栈
MOV DWORD PTR SS:[EBP-0xD4], EAX ; 把返回值(申请空间的地址)给临时变量(猜测用于保存)
MOV EAX, DWORD PTR SS:[EBP-0xD4] ; 从临时变量中取出地址
MOV DWORD PTR SS:[EBP-0x8], EAX ; 赋值给函数内的指针
看一下New里面干了什么:
PUSH EBP ; void *New(int nSize);
MOV EBP, ESP ; ebp+0x8 nSize的栈空间
SUB ESP, 0x10
MOV EAX, DWORD PTR SS:[EBP+0x8] ; 取nSize
PUSH EAX ; 压入nSize
CALL malloc ; call malloc
ADD ESP, 0x4 ; _cdecl调用约定的平栈
MOV DWORD PTR SS:[EBP-0x4], EAX ; 返回值为malloc申请的地址
CMP DWORD PTR SS:[EBP-0x4], 0x0 ; 如果返回值 == NULL
JNZ SHORT msvcr120.0FB0C2A3
MOV ECX, DWORD PTR SS:[EBP+0x8] ; 取大小
PUSH ECX ; 压入大小
CALL _callnewh ; _callnewh(size)
ADD ESP, 0x4 ; _cdecl调用约定的平栈
TEST EAX, EAX ; 如果返回值等于 NULL
JNZ SHORT msvcr120.0FB0C2A1
LEA ECX, DWORD PTR SS:[EBP-0x10]
CALL bad_alloc ; call bad_alloc
PUSH msvcr120.0FB753D8
LEA EDX, DWORD PTR SS:[EBP-0x10]
PUSH EDX
CALL _CxxThrowException ; CALL _CxxThrowException
JMP SHORT msvcr120.0FB0C266
MOV EAX, DWORD PTR SS:[EBP-0x4] ; 不等于NULL,返回值给EAX,返回到main函数
MOV ESP, EBP
POP EBP
RETN
因VS2013无法查看其实现代码,以下为个人猜测如有错误忘请不吝赐教:
void* _cdecl operator new(unsigned int nSize)_THROW1(_STD bad_alloc)
{
void *lpBuf;
while ((lpBuf = malloc(nSize)) == NULL)
{
if (_callnewh(nSize) == NULL)
{
static const std::bad_alloc nomem;
_RAISE(nomem);
}
}
return lpBuf;
}
二. Delete[]:
C++代码:
int *lpNum = new int[16];
delete lpNum;
汇编代码:
MOV EAX, DWORD PTR SS:[EBP-0x8] ; 从变量中取出lpNum地址
MOV DWORD PTR SS:[EBP-0xD4], EAX ; 放入临时变量EBP-0xD4
MOV ECX, DWORD PTR SS:[EBP-0xD4] ; 从临时变量中取出地址
PUSH ECX ; 压入参数
CALL NewDELET.013011DB ; call delete
ADD ESP, 0x4 ; _cdecl调用约定平栈
CMP DWORD PTR SS:[EBP-0xD4], 0x0 ; 判断临时变量EBP-0xD4中的地址值是否等于NULL
JNZ SHORT NewDELET.01301A54
MOV DWORD PTR SS:[EBP-0xE8], 0x0 ; 如果临时变量EBP-0xD4不为NULL就把临时变量EBP-0xE8填为NULL
JMP SHORT NewDELET.01301A64
MOV DWORD PTR SS:[EBP-0x8], 0x8123 ; 给lpNum传入一个值0x8123
MOV EDX, DWORD PTR SS:[EBP-0x8] ; 从lpNum取出值
MOV DWORD PTR SS:[EBP-0xE8], EDX ; 临时变量EBP-0xE8填为0x8123
看一下Delete里面干了什么:
PUSH EBP ; void _cdecl operator delete (void *pBuf)
MOV EBP, ESP ; EBP+0x8 pBuf的栈空间
PUSH -0x2
PUSH msvcr120.52499400
PUSH msvcr120.5243FEF0
MOV EAX, DWORD PTR FS:[0]
PUSH EAX
ADD ESP, -0xC
PUSH EBX
PUSH ESI
PUSH EDI
MOV EAX, DWORD PTR DS:[0x524A8100]
XOR DWORD PTR SS:[EBP-0x8], EAX
XOR EAX, EBP
PUSH EAX
LEA EAX, DWORD PTR SS:[EBP-0x10]
MOV DWORD PTR FS:[0], EAX
CMP DWORD PTR SS:[EBP+0x8], 0x0 ; 判断pBuf是否 == NULL
JNZ SHORT msvcr120.5243A9CB
JMP msvcr120.5243AA68 ; 跳向函数尾部 (return)
PUSH 0x4 ; 4
CALL msvcr120._lock ; call _lock
ADD ESP, 0x4 ; _cdecl调用约定平栈
MOV DWORD PTR SS:[EBP-0x4], 0x0
MOV EAX, DWORD PTR SS:[EBP+0x8] ; pBuf - 0x20
SUB EAX, 0x20
MOV DWORD PTR SS:[EBP-0x1C], EAX ; 临时变量[EBP-0x1C] = pBuf - 0x20
MOV ECX, DWORD PTR SS:[EBP-0x1C] ; 取出运算后的pBuf
MOV EDX, DWORD PTR DS:[ECX+0x14] ; 取pBuf+0x14 由此可以判断ebp-0x1c是一个结构体变量 结果为1 是个逻辑值
AND EDX, 0xFFFF
CMP EDX, 0x4 ; [[EBP-0x1C]+0x14] & 0xffff != 4
JE SHORT msvcr120.5243AA3C
MOV EAX, DWORD PTR SS:[EBP-0x1C]
CMP DWORD PTR DS:[EAX+0x14], 0x1 ; [[EBP-0x1C]+0x14] != 0x1
JE SHORT msvcr120.5243AA3C
MOV ECX, DWORD PTR SS:[EBP-0x1C]
MOV EDX, DWORD PTR DS:[ECX+0x14]
AND EDX, 0xFFFF ; [[EBP-0x1C]+0x14] & 0xffff != 0x2
CMP EDX, 0x2
JE SHORT msvcr120.5243AA3C
MOV EAX, DWORD PTR SS:[EBP-0x1C]
CMP DWORD PTR DS:[EAX+0x14], 0x3 ; [[EBP-0x1C]+0x14] != 0x3
JE SHORT msvcr120.5243AA3C
PUSH msvcr120.52321BF8 ; UNICODE "_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)"
PUSH msvcr120.5230127C ; UNICODE "%s"
PUSH 0x0 ; NULL
PUSH 0x34 ; __LINE__
PUSH msvcr120.52321C48 ; __FILE__
PUSH 0x2
CALL msvcr120._CrtDbgReportW ; call _CrtDbgReportW : _CrtDbgReportW(0x2,?,0x34,0x0,%s,_BLOCK_TYPE_IS_VALID(pHead->nBlockUse))
ADD ESP, 0x18 ; _cdecl调用约定平栈
CMP EAX, 0x1 ; if( _CrtDbgReportW == 1)
JNZ SHORT msvcr120.5243AA3C
INT3
MOV EDX, DWORD PTR SS:[EBP-0x1C]
MOV EAX, DWORD PTR DS:[EDX+0x14]
PUSH EAX ; push [[EBP-0x1C]+0x14]
MOV ECX, DWORD PTR SS:[EBP+0x8]
PUSH ECX ; push pBuf
CALL msvcr120._free_dbg ; call _free_dbg : _free_dbg(pbuf,[[EBP-0x1C]+0x14])
ADD ESP, 0x8 ; _cdecl调用约定平栈
MOV DWORD PTR SS:[EBP-0x4], -0x2
CALL msvcr120.5243AA5D ; 调用下面的 _unlock
JMP SHORT msvcr120.5243AA68
PUSH 0x4
CALL msvcr120._unlock ;call _unlock : _unlock(4)
ADD ESP, 0x4 ; _cdecl调用约定平栈
RETN
MOV ECX, DWORD PTR SS:[EBP-0x10] ; 函数尾部
MOV DWORD PTR FS:[0], ECX
POP ECX
POP EDI
POP ESI
POP EBX
MOV ESP, EBP
POP EBP
RETN
因VS2013无法查看其实现代码,以下为个人猜测如有错误忘请不吝赐教:
void _cdecl operator delete (void *pBuf)
{
_CrtMemBlockHeader * pHead;
if (pBuf == NULL)
{
return;
}
_lock(4);
pHead = ((_CrtMemBlockHeader *)pBuf) - 0x20;
if ((pHead->nBlockUse & 0xFFFF) == 4
|| (pHead->nBlockUse) == 1 || (pHead->nBlockUse & 0xFFFF) == 2
|| (pHead->nBlockUse) == 3
&& (1 == _CrtDbgReport(0x2, __FILE__, __LINE__, NULL,
(pHead->nBlockUse & 0xFFFF) == 4
|| (pHead->nBlockUse) == 1 || (pHead->nBlockUse & 0xFFFF) == 2
|| (pHead->nBlockUse) == 3) )
)
{
__asm
{
int 3
}
}
_free_dbg( pBuf, pHead->nBlockUse );
_munlock(4)
return;
}
int _CrtDbgReport( int reportType, const char *filename, int linenumber, const char *moduleName, const char *format [, argument] ... );
VS2013下的new[]和delete[]分析