飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 6846|回复: 20

[C/C++] VS2013下的new[]和delete[]分析

[复制链接]
  • TA的每日心情
    无聊
    2016-10-10 10:27
  • 签到天数: 26 天

    [LV.4]偶尔看看III

    发表于 2014-9-19 23:55:32 | 显示全部楼层 |阅读模式
    本帖最后由 Crack_Qs 于 2014-9-20 07:11 编辑

    编译模式: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[]分析.rar (2.3 KB, 下载次数: 3, 售价: 1 枚飘云币)

    PYG19周年生日快乐!
  • TA的每日心情
    无聊
    2016-10-10 10:27
  • 签到天数: 26 天

    [LV.4]偶尔看看III

     楼主| 发表于 2014-9-19 23:59:02 | 显示全部楼层
    一楼备用,请大家指教
    PYG19周年生日快乐!
  • TA的每日心情
    奋斗
    2024-4-13 20:08
  • 签到天数: 2046 天

    [LV.Master]伴坛终老

    发表于 2014-9-20 08:33:04 | 显示全部楼层
    谢谢楼主的分析呀,不过我还真是看不太懂呀。。。。可能C基础太差了吧。看来的多努力学习一下这方面的知识呀。。。。
    PYG19周年生日快乐!
  • TA的每日心情
    开心
    2 小时前
  • 签到天数: 627 天

    [LV.9]以坛为家II

    发表于 2014-9-20 09:57:20 | 显示全部楼层
    我不懂但我支持楼主的好东西,
    PYG19周年生日快乐!
  • TA的每日心情
    奋斗
    2017-3-10 20:59
  • 签到天数: 243 天

    [LV.8]以坛为家I

    发表于 2014-9-20 12:11:19 | 显示全部楼层
    支持一下了,感谢
    PYG19周年生日快乐!
  • TA的每日心情
    慵懒
    2019-3-12 17:25
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    发表于 2014-9-23 08:15:27 | 显示全部楼层
    本帖最后由 whypro 于 2014-9-23 08:20 编辑

    有源代码非要装逼,网上分析文章一裤衩,在这板块太装逼了。
    1. /***
    2. *new.cxx - defines C++ new routine
    3. *
    4. *       Copyright (c) Microsoft Corporation.  All rights reserved.
    5. *
    6. *Purpose:
    7. *       Defines C++ new routine.
    8. *
    9. *******************************************************************************/


    10. #ifdef _SYSCRT
    11. #include <cruntime.h>
    12. #include <crtdbg.h>
    13. #include <malloc.h>
    14. #include <new.h>
    15. #include <stdlib.h>
    16. #include <winheap.h>
    17. #include <rtcsup.h>
    18. #include <internal.h>

    19. void * operator new( size_t cb )
    20. {
    21.     void *res;

    22.     for (;;) {

    23.         //  allocate memory block
    24.         res = _heap_alloc(cb);

    25.         //  if successful allocation, return pointer to memory

    26.         if (res)
    27.             break;

    28.         //  call installed new handler
    29.         if (!_callnewh(cb))
    30.             break;

    31.         //  new handler was successful -- try to allocate again
    32.     }

    33.     RTCCALLBACK(_RTC_Allocate_hook, (res, cb, 0));

    34.     return res;
    35. }
    36. #else  /* _SYSCRT */

    37. #include <cstdlib>
    38. #include <new>

    39. _C_LIB_DECL
    40. int __cdecl _callnewh(size_t size) _THROW1(_STD bad_alloc);
    41. _END_C_LIB_DECL

    42. void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
    43.         {       // try to allocate size bytes
    44.         void *p;
    45.         while ((p = malloc(size)) == 0)
    46.                 if (_callnewh(size) == 0)
    47.                 {       // report no memory
    48.                         _THROW_NCEE(_XSTD bad_alloc, );
    49.                 }

    50.         return (p);
    51.         }

    52. /*
    53. * Copyright (c) 1992-2002 by P.J. Plauger.  ALL RIGHTS RESERVED.
    54. * Consult your license regarding permissions and restrictions.
    55. V3.13:0009 */
    56. #endif  /* _SYSCRT */
    复制代码



    PYG19周年生日快乐!
  • TA的每日心情
    慵懒
    2019-3-12 17:25
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    发表于 2014-9-23 08:36:53 | 显示全部楼层
    1. /***
    2. *dbgdel.cpp - defines C++ scalar delete routine, debug version
    3. *
    4. *       Copyright (c) Microsoft Corporation.  All rights reserved.
    5. *
    6. *Purpose:
    7. *       Defines C++ scalar delete() routine.
    8. *
    9. *******************************************************************************/

    10. #ifdef _DEBUG

    11. #include <cruntime.h>
    12. #include <malloc.h>
    13. #include <mtdll.h>
    14. #include <dbgint.h>
    15. #include <rtcsup.h>

    16. /***
    17. *void operator delete() - delete a block in the debug heap
    18. *
    19. *Purpose:
    20. *       Deletes any type of block.
    21. *
    22. *Entry:
    23. *       void *pUserData - pointer to a (user portion) of memory block in the
    24. *                         debug heap
    25. *
    26. *Return:
    27. *       <void>
    28. *
    29. *******************************************************************************/

    30. void operator delete(
    31.         void *pUserData
    32.         )
    33. {
    34.         _CrtMemBlockHeader * pHead;

    35.         RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));

    36.         if (pUserData == NULL)
    37.             return;

    38.         _mlock(_HEAP_LOCK);  /* block other threads */
    39.         __TRY

    40.             /* get a pointer to memory block header */
    41.             pHead = pHdr(pUserData);

    42.              /* verify block type */
    43.             _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));

    44.             _free_dbg( pUserData, pHead->nBlockUse );

    45.         __FINALLY
    46.             _munlock(_HEAP_LOCK);  /* release other threads */
    47.         __END_TRY_FINALLY

    48.         return;
    49. }

    50. #endif  /* _DEBUG */
    复制代码
    PYG19周年生日快乐!
  • TA的每日心情
    无聊
    2016-10-10 10:27
  • 签到天数: 26 天

    [LV.4]偶尔看看III

     楼主| 发表于 2014-9-23 09:03:48 | 显示全部楼层

    第一点,vs2013确实跟进去没有源码(最起码我这不行,有方法的话欢迎指教)
    第二点,别的一些版本确实可以跟进去,但是我对比着跟过,个别细节不一样
    第三点,我最近研究vs13的东西,你不喜欢那就算了,我的代码是实打实逆出来的,而非网上抄袭。
    PYG19周年生日快乐!
  • TA的每日心情
    奋斗
    2016-1-13 12:25
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    发表于 2014-9-23 09:39:58 | 显示全部楼层
    哇,这代码分析得不错,支持楼主!!!加油
    PYG19周年生日快乐!
    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表