Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Microsoft má určité techniky, které používá k opětovnému uspořádání zkompilovaného a propojeného kódu, aby se spustil s vyšší efektivitou. Tyto techniky optimalizují komponentu pro hierarchie paměti a jsou založené na trénovacích scénářích.
Výsledná optimalizace snižuje stránkování (a chyby stránek) a zvyšuje prostorovou lokalitu mezi kódem a daty. Řeší klíčové kritické body výkonu, které by byly zavedeny špatným umístěním původního kódu. Součást, která prošla touto optimalizací, může mít svůj kód nebo datový blok v rámci funkce přesunuté do různých umístění binárního souboru.
V modulech optimalizovaných těmito technikami se umístění kódu a datových bloků často nacházejí na adresách paměti, které se liší od umístění, kde by se nacházely po normální kompilaci a propojení. Kromě toho můžou být funkce rozdělené do mnoha nesouvislých bloků, aby se nejčastěji používané cesty kódu mohly na stejných stránkách nacházet blízko sebe.
Proto funkce (nebo jakýkoli symbol) plus posun nemusí nutně mít stejný význam jako v neoptimalizovatelném kódu.
Ladění Performance-Optimized kódu
Při ladění zjistíte, jestli byl modul optimalizovaný pro výkon pomocí příkazu rozšíření !lmi na libovolném modulu, pro který byly načteny symboly:
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
V tomto výstupu si všimněte termínu perf na řádku "Charakteristiky". To znamená, že tato optimalizace výkonu byla použita pro ntdll.dll.
Debugger dokáže porozumět funkci nebo jinému symbolu bez posunu; to vám umožní nastavit breakpointy u funkcí nebo jiných symbolů bez problémů. Výstup operace dekompilace ale může být matoucí, protože tato dekompilace bude odrážet změny provedené optimalizátorem.
Vzhledem k tomu, že ladicí program se pokusí zůstat blízko původního kódu, mohou se objevit některé zábavné výsledky. Pravidlo při práci s kódy optimalizovanými pro výkon je jednoduché: u optimalizovaného kódu nelze provádět spolehlivou adresovou aritmetiku.
Tady je příklad:
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
V seznamu zarážek vidíte, že adresa IPTransmit je 0xF8640CA6.
Když v 0xF864B4CB zrušíte sestavení části kódu v rámci této funkce, výstup indikuje, že se jedná o 0xE48 bajty za začátkem funkce. Pokud však odečtete základ funkce z této adresy, skutečný posun se zdá být 0xA825.
Co se děje: Ladicí program skutečně ukazuje demontáž binárních instrukcí počínaje 0xF864B4CB. Místo výpočtu posunu jednoduchým odčítáním se ladicí program zobrazí – jak nejlépe dokáže – posun na položku funkce, protože existoval v původním kódu před provedením optimalizace. Tato hodnota je 0xE48.
Na druhou stranu, pokud se pokusíte podívat na IPTransmit+0xE48, uvidíte toto:
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
Co se zde děje, je, že ladicí program rozpozná symbol IPTransmit jako ekvivalent k adrese 0xF8640CA6 a analyzátor příkazů provede jednoduchý doplněk, který zjistí, že 0xF8640CA6 + 0xE48 = 0xF8641AEE. Tato adresa se pak použije jako argument příkazu u (Unassemble). Jakmile je toto umístění analyzováno, ladicí program zjistí, že to není IPTransmit plus posun 0xE48. Ve skutečnosti není součástí této funkce vůbec. Spíše odpovídá funkci ARPTransmit plus posun 0xD8.
Důvod, proč se to děje, je ten, že optimalizace výkonu není reverzibilní prostřednictvím aritmetiky adres. Ladicí program sice může vzít adresu a odvodit originální symbol a posun, ale nemá dostatek informací, aby mohl vzít symbol a posun a převést ho na správnou adresu. V těchto případech proto rozebírání není užitečné.