Aracılığıyla paylaş


Performans Açısından Optimize Edilmiş Kodda Hata Ayıklama

Microsoft,derlenmiş ve bağlı kodu daha verimli bir şekilde yürütecek şekilde yeniden düzenlemek için kullandığı belirli tekniklere sahiptir. Bu teknikler, bellek hiyerarşileri için bileşeni iyileştirir ve eğitim senaryolarını temel alır.

Sonuçta elde edilen iyileştirme disk belleğini (ve sayfa hatalarını) azaltır ve kod ile veriler arasındaki uzamsal yerelliği artırır. Özgün kodun kötü konumlandırılmasıyla ortaya çıkan önemli performans sorunlarını giderir. Bu iyileştirmeden geçmiş bir bileşenin kodu veya veri bloğu bir işlev içinde ikilinin farklı konumlarına taşınmış olabilir.

Bu teknikler tarafından iyileştirilmiş modüllerde, kod ve veri bloklarının konumları genellikle normal derleme ve bağlama sonrasında bulundukları konumlardan farklı bellek adreslerinde bulunur. Ayrıca, en yaygın kullanılan kod yollarının aynı sayfalarda birbirine yakın bulunabilmesi için işlevler bitişik olmayan birçok bloka bölünmüş olabilir.

Bu nedenle, bir işlevin (veya herhangi bir simgenin) yanına bir kaydırma eklenmesi, optimize edilmemiş kodda sahip olacağı anlamıyla aynı olmayabilir.

Performance-Optimized Kodunda Hata Ayıklama

Hata ayıklarken, simgelerin yüklendiği herhangi bir modülde !lmi uzantı komutunu kullanarak bir modülün performans açısından iyileştirilmiş olup olmadığını görebilirsiniz:

0:000> !lmi ntdll
Loaded Module Info: [ntdll]
         Module: ntdll
   Base Address: 77f80000
     Image Name: ntdll.dll
   Machine Type: 332 (I386)
     Time Stamp: 394193d2 Fri Jun 09 18:03:14 2000
       CheckSum: 861b1
Characteristics: 230e stripped perf
Debug Data Dirs: Type Size     VA  Pointer
                 MISC  110,     0,   76c00 [Data not mapped]
     Image Type: DBG      - Image read successfully from symbol server.
                 c:\symbols\dll\ntdll.dbg
    Symbol Type: DIA PDB  - Symbols loaded successfully from symbol server.
                 c:\symbols\dll\ntdll.pdb

Bu çıktıda , "Özellikler" satırında performans terimine dikkat edin. Bu, bu performans iyileştirmenin ntdll.dlluygulandığını gösterir.

Hata ayıklayıcı, uzaklık olmadan bir işlevi veya başka bir simgeyi anlayabilir; bu, işlevlerde veya diğer etiketlerde kesme noktalarını sorunsuz bir şekilde ayarlamanıza olanak tanır. Ancak, bir ayrıştırma işleminin çıkışı kafa karıştırıcı olabilir, çünkü bu ayrıştırma iyileştirici tarafından yapılan değişiklikleri yansıtır.

Hata ayıklayıcı özgün koda yakın kalmaya çalışacağından, bazı eğlenceli sonuçlar görebilirsiniz. Performans için iyileştirilmiş kodlarla çalışırken temel kural, iyileştirilmiş kod üzerinde güvenilir adres aritmetiği gerçekleştirememenizdir.

Aşağıda bir örnek verilmiştir:

kd> bl
 0 e f8640ca6     0001 (0001) tcpip!IPTransmit
 1 e f8672660     0001 (0001) tcpip!IPFragment

kd> u f864b4cb
tcpip!IPTransmit+e48:
f864b4cb f3a4             rep     movsb
f864b4cd 8b75cc           mov     esi,[ebp-0x34]
f864b4d0 8b4d10           mov     ecx,[ebp+0x10]
f864b4d3 8b7da4           mov     edi,[ebp-0x5c]
f864b4d6 8bc6             mov     eax,esi
f864b4d8 6a10             push    0x10
f864b4da 034114           add     eax,[ecx+0x14]
f864b4dd 57               push    edi

Kesme noktası listesinden IPTransmit adresinin 0xF8640CA6 görebilirsiniz.

0xF864B4CB adresinde bu işlev içindeki bir kod bölümünü çözdüğünüzde, çıktı, bunun işlevin başlangıcından 0xE48 bayt sonrasında olduğunu gösterir. Ancak, işlevin tabanını bu adresten çıkarırsanız, gerçek uzaklık 0xA825 gibi görünür.

Olan şey şudur: Hata ayıklayıcı gerçekten de 0xF864B4CB'de başlayan ikili yönergelerin ayrıştırılması gösteriyor. Ancak hata ayıklayıcısı, uzaklığı basit çıkarma işlemiyle hesaplama yerine, iyileştirmeler gerçekleştirilmeden önce özgün kodda var olan işlev girdisine uzaklığı en iyi şekilde görüntüler. Bu değer 0xE48.

Öte yandan, IPTransmit+0xE48'a bakmaya çalışırsanız şunu görürsünüz:

kd> u tcpip!iptransmit+e48
tcpip!ARPTransmit+d8:
f8641aee 0856ff           or      [esi-0x1],dl
f8641af1 75fc             jnz     tcpip!ARPTransmit+0xd9 (f8641aef)
f8641af3 57               push    edi
f8641af4 e828eeffff       call    tcpip!ARPSendData (f8640921)
f8641af9 5f               pop     edi
f8641afa 5e               pop     esi
f8641afb 5b               pop     ebx
f8641afc c9               leave

Burada olan şey, hata ayıklayıcının IPTransmit sembolünü adres 0xF8640CA6 eşdeğeri olarak tanıması ve komut ayrıştırıcısının 0xF8640CA6 + 0xE48 = 0xF8641AEE bulmak için basit bir ekleme yapmasıdır. Bu adres daha sonra u (Unassemble) komutunun bağımsız değişkeni olarak kullanılır. Ancak bu konum çözümlendiğinde, hata ayıklayıcı bunun IPTransmit olmadığını ve 0xE48 uzaklığı olmadığını bulur. Aslında bu işlevin bir parçası değildir. Bunun yerine, ARPTransmit işlevine ve 0xD8 uzaklığına karşılık gelir.

Bunun nedeni, performans iyileştirmesinin adres aritmetiği aracılığıyla geri alınamaz olmasıdır. Hata ayıklayıcı, bir adres alıp özgün sembolünü ve ofsetini çıkarabilir, ancak bir sembol ve ofset alıp doğru adrese çevirmek için yeterli bilgiye sahip değildir. Sonuç olarak, sökme bu gibi durumlarda yararlı değildir.