Aracılığıyla paylaş


Açıklamalı x86 Ayrıştırma

Aşağıdaki bölümde bir ayrıştırma örneğinde size yol gösterilir.

Kaynak kodu

Aşağıda, analiz edilecek işlevin kodu yer alır.

HRESULT CUserView::CloseView(void)
{
    if (m_fDestroyed) return S_OK;

    BOOL fViewObjectChanged = FALSE;
    ReleaseAndNull(&m_pdtgt);

    if (m_psv) {
        m_psb->EnableModelessSB(FALSE);
        if(m_pws) m_pws->ViewReleased();

        IShellView* psv;

        HWND hwndCapture = GetCapture();
        if (hwndCapture && hwndCapture == m_hwnd) {
            SendMessage(m_hwnd, WM_CANCELMODE, 0, 0);
        }

        m_fHandsOff = TRUE;
        m_fRecursing = TRUE;
        NotifyClients(m_psv, NOTIFY_CLOSING);
        m_fRecursing = FALSE;

        m_psv->UIActivate(SVUIA_DEACTIVATE);

        psv = m_psv;
        m_psv = NULL;

        ReleaseAndNull(&_pctView);

        if (m_pvo) {
            IAdviseSink *pSink;
            if (SUCCEEDED(m_pvo->GetAdvise(NULL, NULL, &pSink)) && pSink) {
                if (pSink == (IAdviseSink *)this)
                    m_pvo->SetAdvise(0, 0, NULL);
                pSink->Release();
            }

            fViewObjectChanged = TRUE;
            ReleaseAndNull(&m_pvo);
        }

        if (psv) {
            psv->SaveViewState();
            psv->DestroyViewWindow();
            psv->Release();
        }

        m_hwndView = NULL;
        m_fHandsOff = FALSE;

        if (m_pcache) {
            GlobalFree(m_pcache);
            m_pcache = NULL;
        }

        m_psb->EnableModelessSB(TRUE);

        CancelPendingActions();
    }

    ReleaseAndNull(&_psf);

    if (fViewObjectChanged)
        NotifyViewClients(DVASPECT_CONTENT, -1);

    if (m_pszTitle) {
        LocalFree(m_pszTitle);
        m_pszTitle = NULL;
    }

    SetRect(&m_rcBounds, 0, 0, 0, 0);
    return S_OK;
}

Derleme Kodu

Bu bölüm açıklamalı ayrıştırma örneğini içerir.

Çerçeve işaretçisi olarak ebp yazmaçını kullanan işlevler aşağıdaki gibi başlar:

HRESULT CUserView::CloseView(void)
SAMPLE!CUserView__CloseView:
71517134 55               push    ebp
71517135 8bec             mov     ebp,esp

Bu işlem, işlevin parametrelerine ebp'den pozitif uzaklıklar ve yerel değişkenlere negatif uzaklıklar olarak erişebilmesi için çerçeveyi ayarlar.

Bu, özel COM arabirimindeki bir yöntemdir, bu nedenle çağırma kuralı __stdcall. Bu, parametrelerin sağdan sola gönderildiği (bu örnekte hiç yok), "bu" işaretçisinin gönderildiği ve ardından işlevin çağrıldığı anlamına gelir. Bu nedenle, işleve girdikten sonra yığın şöyle görünür:

[esp+0] = return address
[esp+4] = this

Yukarıdaki iki yönergeden sonra parametrelere şu şekilde erişilebilir:

[ebp+0] = previous ebp pushed on stack
[ebp+4] = return address
[ebp+8] = this

Çerçeve işaretçisi olarak ebp kullanan bir işlev için, gönderilen ilk parametreye [ebp+8] adresinden erişilebilir; sonraki parametrelere art arda daha yüksek DWORD adreslerinden erişilebilir.

71517137 51               push    ecx
71517138 51               push    ecx

Bu işlev yalnızca iki yerel yığın değişkeni gerektirir, bu nedenle alt esp, 8 yönergesi. Ardından gönderilen değerler [ebp-4] ve [ebp-8] olarak kullanılabilir.

ebp çerçeve işaretçisi olarak kullanılan bir işlevde, yığın çerçevesindeki yerel değişkenlere ebp yazmaçtan negatif uzaklıklarda erişilebilir.

71517139 56               push    esi

Şimdi derleyici, işlev çağrıları arasında korunması gereken yazmaçları kaydeder. Aslında, bunları gerçek kodun ilk satırıyla kesişen parçalar halinde kaydeder.

7151713a 8b7508           mov     esi,[ebp+0x8]     ; esi = this
7151713d 57               push    edi               ; save another registers

Öyle oluyor ki CloseView, altta yatan nesnede 12. konumda bulunan ViewState üzerindeki bir yöntemdir. Sonuç olarak, bu bir ViewState sınıfına bir işaretçidir, ancak başka bir temel sınıfla olası karışıklık olduğunda daha dikkatli bir şekilde (ViewState*)bu olarak belirtilir.

    if (m_fDestroyed)
7151713e 33ff             xor     edi,edi           ; edi = 0

Bir yazmacı kendi ile XORlamak, onu sıfırlamanın standart bir yoludur.

71517140 39beac000000     cmp     [esi+0xac],edi    ; this->m_fDestroyed == 0?
71517146 7407             jz      NotDestroyed (7151714f)  ; jump if equal

cmp yönergesi iki değeri karşılaştırır (çıkararak). jz yönergesi, sonucun sıfır olup olmadığını denetler ve karşılaştırılan iki değerin eşit olduğunu gösterir.

cmp yönergesi iki değeri karşılaştırır; sonraki j yönergesi, karşılaştırmanın sonucuna göre atlar.

    return S_OK;
71517148 33c0             xor     eax,eax           ; eax = 0 = S_OK
7151714a e972010000       jmp     ReturnNoEBX (715172c1) ; return, do not pop EBX

Derleyici, EBX yazmacını kaydetmeyi fonksiyonun ilerleyen kısmına kadar geciktirdi, bu nedenle program bu testte "erken çıkacaksa" çıkış yolunun EBX'i geri yüklemeyen yol olması gerekmektedir.

    BOOL fViewObjectChanged = FALSE;
    ReleaseAndNull(&m_pdtgt);

Bu iki kod satırının yürütülmesi iç içe geçmiştir, bu yüzden dikkatli olun.

NotDestroyed:
7151714f 8d86c0000000     lea     eax,[esi+0xc0]    ; eax = &m_pdtgt

Lea yönergesi, bellek erişiminin etki adresini hesaplar ve hedefte depolar. Gerçek bellek adresi başvurulmaz.

Lea yönergesi bir değişkenin adresini alır.

71517155 53               push    ebx

Bu EBX kaydını hasar görmeden önce kaydetmeniz gerekir.

71517156 8b1d10195071     mov ebx,[_imp__ReleaseAndNull]

ReleaseAndNull'ı sık sık çağıracağınız için adresini EBX'te önbelleğe almak iyi bir fikirdir.

7151715c 50               push    eax               ; parameter to ReleaseAndNull
7151715d 897dfc           mov     [ebp-0x4],edi     ; fViewObjectChanged = FALSE
71517160 ffd3             call    ebx               ; call ReleaseAndNull
    if (m_psv) {
71517162 397e74           cmp     [esi+0x74],edi    ; this->m_psv == 0?
71517165 0f8411010000     je      No_Psv (7151727c) ; jump if zero

Bir süre önce EDI kaydını sıfırladınız ve EDI'nin işlev çağrıları arasında korunan bir kayıt olduğunu unutmayın (bu nedenle ReleaseAndNull çağrısı bunu değiştirmedi). Bu nedenle, hâlâ sıfır değerini taşır ve hızlı bir şekilde sıfır testi yapmak için kullanılabilir.

        m_psb->EnableModelessSB(FALSE);
7151716b 8b4638           mov     eax,[esi+0x38]    ; eax = this->m_psb
7151716e 57               push    edi               ; FALSE
7151716f 50               push    eax               ; "this" for callee
71517170 8b08             mov     ecx,[eax]         ; ecx = m_psb->lpVtbl
71517172 ff5124           call    [ecx+0x24]        ; __stdcall EnableModelessSB

Yukarıdaki desen, COM yöntemi çağrısının telltale işaretidir.

COM yöntem çağrıları oldukça popülerdir, bu nedenle bunları tanımayı öğrenmek iyi bir fikirdir. Özellikle, üç IUnknown yöntemini doğrudan Vtable uzaklıklarından tanıyabilmeniz gerekir: QueryInterface=0, AddRef=4 ve Release=8.

        if(m_pws) m_pws->ViewReleased();
71517175 8b8614010000     mov     eax,[esi+0x114]   ; eax = this->m_pws
7151717b 3bc7             cmp     eax,edi           ; eax == 0?
7151717d 7406             jz      NoWS (71517185) ; if so, then jump
7151717f 8b08             mov     ecx,[eax]         ; ecx = m_pws->lpVtbl
71517181 50               push    eax               ; "this" for callee
71517182 ff510c           call    [ecx+0xc]         ; __stdcall ViewReleased
NoWS:
        HWND hwndCapture = GetCapture();
71517185 ff15e01a5071    call [_imp__GetCapture]    ; call GetCapture

Microsoft Win32'de işlev ithalatları, global değişkenler aracılığıyla yapılan dolaylı çağrılar yoluyla uygulanır. Yükleyici, hedefin gerçek adresine işaret etmek için genel değerleri düzeltir. Bu, kilitlenmiş bir makineyi araştırırken rulmanlarınızı almak için kullanışlı bir yoldur. İçeri aktarılan işlevlere yapılan çağrıları ve hedefteki çağrıları arayın. Genellikle, kaynak kodun neresinde olduğunuzu belirlemek için kullanabileceğiniz içeri aktarılan bazı işlevlerin adına sahip olursunuz.

        if (hwndCapture && hwndCapture == m_hwnd) {
            SendMessage(m_hwnd, WM_CANCELMODE, 0, 0);
        }
7151718b 3bc7             cmp     eax,edi           ; hwndCapture == 0?
7151718d 7412             jz      No_Capture (715171a1) ; jump if zero

İşlev dönüş değeri EAX register içine yerleştirilir.

7151718f 8b4e44           mov     ecx,[esi+0x44]    ; ecx = this->m_hwnd
71517192 3bc1             cmp     eax,ecx           ; hwndCapture = ecx?
71517194 750b             jnz     No_Capture (715171a1) ; jump if not

71517196 57               push    edi               ; 0
71517197 57               push    edi               ; 0
71517198 6a1f             push    0x1f              ; WM_CANCELMODE
7151719a 51               push    ecx               ; hwndCapture
7151719b ff1518195071     call    [_imp__SendMessageW] ; SendMessage
No_Capture:
        m_fHandsOff = TRUE;
        m_fRecursing = TRUE;
715171a1 66818e0c0100000180 or    word ptr [esi+0x10c],0x8001 ; set both flags at once

        NotifyClients(m_psv, NOTIFY_CLOSING);
715171aa 8b4e20           mov     ecx,[esi+0x20]    ; ecx = (CNotifySource*)this.vtbl
715171ad 6a04             push    0x4               ; NOTIFY_CLOSING
715171af 8d4620           lea     eax,[esi+0x20]    ; eax = (CNotifySource*)this
715171b2 ff7674           push    [esi+0x74]        ; m_psv
715171b5 50               push    eax               ; "this" for callee
715171b6 ff510c           call    [ecx+0xc]         ; __stdcall NotifyClients

Kendi yönteminizden farklı bir temel sınıfta bir yöntemi çağırırken "bu" işaretçinizi nasıl değiştirmek zorunda kaldığınıza dikkat edin.

        m_fRecursing = FALSE;
715171b9 80a60d0100007f   and     byte ptr [esi+0x10d],0x7f
        m_psv->UIActivate(SVUIA_DEACTIVATE);
715171c0 8b4674           mov     eax,[esi+0x74]    ; eax = m_psv
715171c3 57               push    edi               ; SVUIA_DEACTIVATE = 0
715171c4 50               push    eax               ; "this" for callee
715171c5 8b08             mov     ecx,[eax]         ; ecx = vtbl
715171c7 ff511c           call    [ecx+0x1c]        ; __stdcall UIActivate
        psv = m_psv;
        m_psv = NULL;
715171ca 8b4674           mov     eax,[esi+0x74]    ; eax = m_psv
715171cd 897e74           mov     [esi+0x74],edi    ; m_psv = NULL
715171d0 8945f8           mov     [ebp-0x8],eax     ; psv = eax

İlk yerel değişken psv'dir.

        ReleaseAndNull(&_pctView);
715171d3 8d466c           lea     eax,[esi+0x6c]    ; eax = &_pctView
715171d6 50               push    eax               ; parameter
715171d7 ffd3             call    ebx               ; call ReleaseAndNull
        if (m_pvo) {
715171d9 8b86a8000000     mov     eax,[esi+0xa8]    ; eax = m_pvo
715171df 8dbea8000000     lea     edi,[esi+0xa8]    ; edi = &m_pvo
715171e5 85c0             test    eax,eax           ; eax == 0?
715171e7 7448             jz      No_Pvo (71517231) ; jump if zero

Derleyicinin, m_pvo üyesinin adresini tahmini olarak hazırladığına dikkat edin çünkü onu sık sık kullanacağınız için böyle yapmaktadır. Bu nedenle, adresin elinizin altında olması daha kısa kodla sonuçlanır.

            if (SUCCEEDED(m_pvo->GetAdvise(NULL, NULL, &pSink)) && pSink) {
715171e9 8b08             mov     ecx,[eax]         ; ecx = m_pvo->lpVtbl
715171eb 8d5508           lea     edx,[ebp+0x8]     ; edx = &pSink
715171ee 52               push    edx               ; parameter
715171ef 6a00             push    0x0               ; NULL
715171f1 6a00             push    0x0               ; NULL
715171f3 50               push    eax               ; "this" for callee
715171f4 ff5120           call    [ecx+0x20]        ; __stdcall GetAdvise
715171f7 85c0             test    eax,eax           ; test bits of eax
715171f9 7c2c             jl      No_Advise (71517227) ; jump if less than zero
715171fb 33c9             xor     ecx,ecx           ; ecx = 0
715171fd 394d08           cmp     [ebp+0x8],ecx     ; _pSink == ecx?
71517200 7425             jz      No_Advise (71517227)

Derleyicinin gelen "bu" parametresinin gerekli olmadığı sonucuna vardığını unutmayın (uzun zaman önce bunu ESI kaydına sakladığından). Bu nedenle, belleği pSink yerel değişkeni olarak yeniden kullandı.

İşlev bir EBP çerçevesi kullanıyorsa, gelen parametreler EBP'den pozitif uzaklıklara ulaşır ve yerel değişkenler negatif uzaklıklara yerleştirilir. Ancak, bu durumda olduğu gibi, derleyici bu belleği herhangi bir amaçla yeniden kullanabilir.

Çok dikkatliyseniz, derleyicinin bu kodu biraz daha iyi iyileştirmiş olabileceğini göreceksiniz. Lea edi, [esi+0xa8] yönergesi, iki push 0x0 yönergesinden sonraya ertelenebilirdi ve yerlerine push edi konulabilirdi. 2 bayt tasarruf etmiş olurdu.

                if (pSink == (IAdviseSink *)this)

Sonraki birkaç satır, C++, (IAdviseSink *)NULL değerinin hala NULL olması gerektiği gerçeğini telafi etmek içindir. Öyleyse "this" gerçekten "(ViewState*)NULL" ise, dönüştürmenin sonucu IAdviseSink ile IBrowserService arasındaki uzaklık değil NULL olacaktır.

71517202 8d46ec           lea     eax,[esi-0x14]    ; eax = -(IAdviseSink*)this
71517205 8d5614           lea     edx,[esi+0x14]    ; edx = (IAdviseSink*)this
71517208 f7d8             neg     eax               ; eax = -eax (sets carry if != 0)
7151720a 1bc0             sbb     eax,eax           ; eax = eax - eax - carry
7151720c 23c2             and     eax,edx           ; eax = NULL or edx

Pentium koşullu taşıma yönergesine sahip olsa da, temel i386 mimarisi yoktur, bu nedenle derleyici herhangi bir atlama yapmadan koşullu taşıma yönergesinin benzetimini yapmak için belirli teknikleri kullanır.

Koşullu değerlendirme için genel desen aşağıdaki gibidir:

        neg     r
        sbb     r, r
        and     r, (val1 - val2)
        add     r, val2

neg r, r sıfır değilse taşıma bayrağını ayarlar, çünkü neg sıfırdan çıkararak değeri olumsuzlar. Sıfırdan çıkarma, sıfır olmayan bir değeri çıkarırsanız bir borç (taşıyı ayarlama) oluşturur. Ayrıca r yazmaçtaki değere de zarar verir, ancak yine de üzerine yazmak üzere olduğunuz için bu kabul edilebilir bir durumdur.

Ardından , sbb r, r yönergesi kendi içinden bir değer çıkarır ve bu da her zaman sıfırla sonuçlanır. Bununla birlikte, taşıma (ödünç alma) bitini de çıkarır, bu nedenle net sonuç, taşımanın sırasıyla net mi yoksa ayarlanmış mı olduğuna bağlı olarak r'yi sıfıra veya -1'e ayarlamaktır.

Bu nedenle sbb r, r, özgün r değeri sıfır ise r'yi sıfıra ayarlar; eğer özgün değer sıfır değilse, r değerini -1 yapar.

Üçüncü yönerge bir maskeme yapar. r yazmaç sıfır veya -1 olduğundan, "bu" r'nin sıfır kalmasına veya r'yi -1'dan (val1 - val1) olarak değiştirmeye hizmet eder, bu durumda -1 ile herhangi bir değerin ANDing, orijinal değeri korur.

Bu nedenle, "ve r, (val1 - val1)" sonucunun sonucu, r'nin özgün değeri sıfır ise r'yi sıfıra veya r'nin özgün değeri sıfır değilse "(val1 - val2)" olarak ayarlamaktır.

Son olarak, r'yeval2 eklersiniz ve sonuç olarak val2 veya (val1 - val2) + val2 = val1 olur.

Bu nedenle, bu yönerge serisinin nihai sonucu, başlangıçta sıfır ise r'yi val2'ye veya sıfır olmayansa val1'e ayarlamaktır. Bu, r = r ? val1 : val2'nin montaj eşdeğeridir.

Bu örnekte, bunu val2 = 0 ve val1 = (IAdviseSink*)görebilirsiniz. (Derleyicinin, hiçbir etkisi olmadığından, son add eax, 0 yönergesini atladığına dikkat edin.)

7151720e 394508           cmp     [ebp+0x8],eax ; pSink == (IAdviseSink*)this?
71517211 750b             jnz     No_SetAdvise (7151721e) ; jump if not equal

Bu bölümün önceki bölümlerinde, EDI'yi m_pvo üyesinin adresine ayarlarsınız. Şimdi kullanacaksınız. Daha önce ECX kaydını da sıfırlamıştınız.

                    m_pvo->SetAdvise(0, 0, NULL);
71517213 8b07             mov     eax,[edi]         ; eax = m_pvo
71517215 51               push    ecx               ; NULL
71517216 51               push    ecx               ; 0
71517217 51               push    ecx               ; 0
71517218 8b10             mov     edx,[eax]         ; edx = m_pvo->lpVtbl
7151721a 50               push    eax               ; "this" for callee
7151721b ff521c           call    [edx+0x1c]        ; __stdcall SetAdvise
No_SetAdvise:
                pSink->Release();
7151721e 8b4508           mov     eax,[ebp+0x8]     ; eax = pSink
71517221 50               push    eax               ; "this" for callee
71517222 8b08             mov     ecx,[eax]         ; ecx = pSink->lpVtbl
71517224 ff5108           call    [ecx+0x8]         ; __stdcall Release
No_Advise:

Tüm bu COM yöntemi çağrıları çok tanıdık görünmelidir.

Sonraki iki deyimin değerlendirmesi araya eklenir. EBX'in ReleaseAndNull adresini içerdiğini unutmayın.

            fViewObjectChanged = TRUE;
            ReleaseAndNull(&m_pvo);
71517227 57               push    edi               ; &m_pvo
71517228 c745fc01000000   mov     dword ptr [ebp-0x4],0x1 ; fViewObjectChanged = TRUE
7151722f ffd3             call    ebx               ; call ReleaseAndNull
No_Pvo:
        if (psv) {
71517231 8b7df8           mov     edi,[ebp-0x8]     ; edi = psv
71517234 85ff             test    edi,edi           ; edi == 0?
71517236 7412             jz      No_Psv2 (7151724a) ; jump if zero
            psv->SaveViewState();
71517238 8b07             mov     eax,[edi]         ; eax = psv->lpVtbl
7151723a 57               push    edi               ; "this" for callee
7151723b ff5034           call    [eax+0x34]        ; __stdcall SaveViewState

Daha fazla COM yöntemi çağrısı aşağıdadır.

            psv->DestroyViewWindow();
7151723e 8b07             mov     eax,[edi]         ; eax = psv->lpVtbl
71517240 57               push    edi               ; "this" for callee
71517241 ff5028           call    [eax+0x28]        ; __stdcall DestroyViewWindow
            psv->Release();
71517244 8b07             mov     eax,[edi]         ; eax = psv->lpVtbl
71517246 57               push    edi               ; "this" for callee
71517247 ff5008           call    [eax+0x8]         ; __stdcall Release
No_Psv2:
        m_hwndView = NULL;
7151724a 83667c00         and     dword ptr [esi+0x7c],0x0 ; m_hwndView = 0

Bellek konumunu sıfırlamakla, o konumu sıfırla AND işlemine tabi tutmak aynıdır, çünkü herhangi bir şeyin AND sıfırı sıfırdır. Derleyici bu formu kullanır çünkü daha yavaş olsa da eşdeğer mov yönergesinden çok daha kısadır. (Bu kod hız için değil boyut için iyileştirilmiştir.)

        m_fHandsOff = FALSE;
7151724e 83a60c010000fe   and     dword ptr [esi+0x10c],0xfe
        if (m_pcache) {
71517255 8b4670           mov     eax,[esi+0x70]    ; eax = m_pcache
71517258 85c0             test    eax,eax           ; eax == 0?
7151725a 740b             jz      No_Cache (71517267) ; jump if zero
            GlobalFree(m_pcache);
7151725c 50               push    eax               ; m_pcache
7151725d ff15b4135071     call    [_imp__GlobalFree]    ; call GlobalFree
            m_pcache = NULL;
71517263 83667000         and     dword ptr [esi+0x70],0x0 ; m_pcache = 0
No_Cache:
        m_psb->EnableModelessSB(TRUE);
71517267 8b4638           mov     eax,[esi+0x38]    ; eax = this->m_psb
7151726a 6a01             push    0x1               ; TRUE
7151726c 50               push    eax               ; "this" for callee
7151726d 8b08             mov     ecx,[eax]         ; ecx = m_psb->lpVtbl
7151726f ff5124           call    [ecx+0x24]        ; __stdcall EnableModelessSB
        CancelPendingActions();

CancelPendingActions'ı çağırmak için bunu (ViewState*)this dosyasından (CUserView*)this konumuna taşımanız gerekir. CancelPendingActions'ın __stdcall yerine __thiscall çağırma kuralını kullandığını da unutmayın. __thiscall göre, "bu" işaretçisi yığına geçirilmek yerine ECX yazmaçta geçirilir.

71517272 8d4eec           lea     ecx,[esi-0x14]    ; ecx = (CUserView*)this
71517275 e832fbffff       call CUserView::CancelPendingActions (71516dac) ; __thiscall
    ReleaseAndNull(&_psf);
7151727a 33ff             xor     edi,edi           ; edi = 0 (for later)
No_Psv:
7151727c 8d4678           lea     eax,[esi+0x78]    ; eax = &_psf
7151727f 50               push    eax               ; parameter
71517280 ffd3             call    ebx               ; call ReleaseAndNull
    if (fViewObjectChanged)
71517282 397dfc           cmp     [ebp-0x4],edi     ; fViewObjectChanged == 0?
71517285 740d             jz      NoNotifyViewClients (71517294) ; jump if zero
       NotifyViewClients(DVASPECT_CONTENT, -1);
71517287 8b46ec           mov     eax,[esi-0x14]    ; eax = ((CUserView*)this)->lpVtbl
7151728a 8d4eec           lea     ecx,[esi-0x14]    ; ecx = (CUserView*)this
7151728d 6aff             push    0xff              ; -1
7151728f 6a01             push    0x1               ; DVASPECT_CONTENT = 1
71517291 ff5024           call    [eax+0x24]        ; __thiscall NotifyViewClients
NoNotifyViewClients:
    if (m_pszTitle)
71517294 8b8680000000     mov     eax,[esi+0x80]    ; eax = m_pszTitle
7151729a 8d9e80000000     lea     ebx,[esi+0x80]    ; ebx = &m_pszTitle (for later)
715172a0 3bc7             cmp     eax,edi           ; eax == 0?
715172a2 7409             jz      No_Title (715172ad) ; jump if zero
        LocalFree(m_pszTitle);
715172a4 50               push    eax               ; m_pszTitle
715172a5 ff1538125071     call   [_imp__LocalFree]
        m_pszTitle = NULL;

Bu yazmaçlar işlev çağrıları tarafından korunduğu için EDI'nin hala sıfır olduğunu ve EBX'in hala &m_pszTitle olduğunu unutmayın.

715172ab 893b             mov     [ebx],edi         ; m_pszTitle = 0
No_Title:
    SetRect(&m_rcBounds, 0, 0, 0, 0);
715172ad 57               push    edi               ; 0
715172ae 57               push    edi               ; 0
715172af 57               push    edi               ; 0
715172b0 81c6fc000000     add     esi,0xfc          ; esi = &this->m_rcBounds
715172b6 57               push    edi               ; 0
715172b7 56               push    esi               ; &m_rcBounds
715172b8 ff15e41a5071     call   [_imp__SetRect]

Artık "this" değerine ihtiyacınız olmadığını, bu nedenle derleyicinin adresi tutmak için başka bir yazmaç kullanmak yerine yerinde değiştirmek için ekleme yönergesini kullandığına dikkat edin. Bu aslında Pentium u/v boru hattı nedeniyle bir performans kazancıdır, çünkü v hattı aritmetik yapabilir, ancak adres hesaplamaları yapamaz.

    return S_OK;
715172be 33c0             xor     eax,eax           ; eax = S_OK

Son olarak, korumanız gereken yazmaçları geri yükler, yığını temizler ve gelen parametreleri yığından kaldırarak çağrı sahibine geri dönersiniz.

715172c0 5b               pop     ebx               ; restore
ReturnNoEBX:
715172c1 5f               pop     edi               ; restore
715172c2 5e               pop     esi               ; restore
715172c3 c9               leave                     ; restores EBP and ESP simultaneously
715172c4 c20400           ret     0x4               ; return and clear parameters