Nynaeve.

Nynaeve.

Trad Lokal Lagring, Del 2: Eksplisitt TLS.

Tidligere skisserte jeg noen av de generelle designprinsippene bak begge smaker av TLS i bruk pa Windows. Alle kan se design og hoyt grensesnitt til TLS ved a lese MSDN, skjont; De interessante delene er knyttet til implementeringen selv.

Den eksplisitte TLS API er (langt) den enkleste av de to klassene av TLS nar det gjelder implementeringen, da den berorer de f rre delene som beveger seg & # 8221 ;. Som jeg nevnte sist, er det egentlig bare fire nokkelfunksjoner i den eksplisitte TLS API. De viktigste to er TlsGetValue og TlsSetValue, som styrer den faktiske innstillingen og henting av per-thread pointers.

Disse to funksjonene er enkle a annotere helt. Den viktige mekanismen bak dem er at de i utgangspunktet bare er «dumme tilbehorete & # 8221; inn i en array (to arrays i virkeligheten, TlsSlots og TlsExpansionSlots) i TEB, som er indeksert av dwTlsIndex-argumentet for a returnere (eller sette) onsket per-trad-variabel. Implementeringen av TlsGetValue pa Vista (32-bit) er som folger (TlsSetValue er lik, bortsett fra at den skriver til arrays i stedet for a lese fra dem, og har stotte for ettersporselsfordeling av TlsExpansionSlots-arrayet, mer om det senere):

(Monteringsversjonen (annotert) er ogsa tilgjengelig.)

TlsSlots-serien i TEB er en del av hver trad, som gir hver trad et garantert sett med 64 trad lokale lagringsindekser. Senere besluttet Microsoft at 64 ikke hadde nok TLS-spor for a ga rundt og legge til TlsExpansionSlots-arrayet, for ytterligere 1024 TLS-spor. TlsExpansionSlots-arrayet er ettersporselsallokert i TlsAlloc hvis det forste settet pa 64 spor er overskredet.

(Dette er forresten naturen til de tilsynelatende vilkarlig 64 og 1088 TLS-sporbegrensningene nevnt av MSDN, for de som holder poeng.)

TlsAlloc og TlsFree er for all hensikt implementert akkurat som det man ville forvente. De kjoper en las, soker etter et gratis TLS-spor (retur indeksen hvis man er funnet), ellers indikerer til den som ringer at det ikke er ledig plass. Hvis de forste 64 sporene er utmattet og TlsExpansionSlots-arrayet ikke er opprettet, vil TlsAlloc allokere og null plass til 1024 flere TLS-spor (pekerstorrelsesverdier), og deretter oppdatere TlsExpansionSlots for a referere til den nylig tildelte lagringen.

Internt bruker TlsAlloc og TlsFree Rtl bitmap-pakken til a spore bruken av individuelle TLS-spor Hver bit i en bitmap beskriver om et bestemt TLS-spor er ledig eller i bruk. Dette muliggjor rimelig rask (og plassbesparende) kartlegging av TLS-sporet bruk for bokforing.

Hvis man har fulgt sa langt, er sporsmalet om hva som skjer nar TlsAlloc kalles slik at det ma opprettes TlsExpansionSlots-arrayet etter at det allerede er mer enn en trad i den nav rende prosessen, kanskje kommet til tankene. Dette ser ut til a v re et problem ved forste oyekast, da TlsAlloc bare lager oppsettet for gjeldende trad. Selv om man kan fristes til a konkludere med at, med tanke pa denne oppforselen til TlsAlloc, er eksplisitt TLS derfor ikke palitelig over 64 TLS-spor hvis de ekstra sporene tildeles etter at den andre traden i prosessen er opprettet, er dette faktisk ikke saken. Det eksisterer en smart handskikk som utfores av TlsGetValue og TlsSetValue, som kompenserer for det faktum at TlsAlloc bare kan opprette TlsExpansionSlots minneblokken for gjeldende trad.

Spesifikt, hvis TlsGetValue kalles med en arrayindeks innenfor rammen av TlsExpansionSlots-arrayet, men arrayet ikke er blitt tildelt for gjeldende trad, returneres null. (Dette er standardverdien for et uninitialisert TLS-spor, og er dermed juridisk.) Pa samme mate, hvis TlsSetValue kalles med en arrayindeks som faller under TlsExpansionSlots-arrayet, og arrayet enna ikke er opprettet, allokerer TlsSetValue minneblokken pa foresporsel og initialiserer det forespurte TLS-sporet.

Det finnes ogsa en endelig vri i TlsFree som kreves for a stotte oppforselen til a slippe et TLS-spor mens det er flere trader som kjorer. Et potensielt problem eksisterer hvor en trad slipper ut et TLS-spor, og deretter blir det omfordelt, hvoretter det forrige innholdet i TLS-sporet fortsatt er tilstede pa andre trader som kjorer i prosessen. TlsFree lindrer dette problemet ved a sporre kjernen for hjelp, i form av ThreadZeroTlsCell-tradinformasjonsklassen. Nar kjernen ser en NtSetInformationThread-samtale for ThreadZeroTlsCell, regner den opp alle trader i prosessen og skriver en verdi for null pointerlengde for hver kjorer trads forekomst av det forespurte TLS-sporet, og spyler derfor det gamle innholdet og tilbakestiller sporet til den ufordelte standardstatusen. (Det er ikke strengt nodvendig at dette har blitt gjort i kjernemodus, selv om designerne valgte a ga denne ruten.)

Nar en trad gar ut normalt, hvis TlsExpansionSlots-pekeren er tildelt, blir den frigitt til prosesshoften. (Selvfolgelig, hvis en trad er avsluttet av TerminateThread, er TlsExpansionSlots-arrayet lekket. Dette er enda en grunn blant utallige andre hvorfor du bor holde seg unna TerminateThread.)

Neste opp: Undersok implisitt TLS-stotte (__declspec (trad) variabler).

Denne oppforingen ble postet tirsdag 23. oktober 2007 klokken 7:00 og er arkivert under NT Internals, Reverse Engineering, Windows. Du kan folge eventuelle svar pa denne oppforingen gjennom RSS 2.0-feed. Du kan legge igjen et svar, eller trackback fra ditt eget nettsted.

4 Responses to & # 8220; Trad Lokal Lagring, Del 2: Eksplisitt TLS & # 8221;

I denne artikkelen:

PTEB Teb = NtCurrentTeb (); // fs: [0x18]

konflikter med forrige artikkel:

Dette tillater en tilgang til fs: [0A-0] (eller gs: [0A-0] pa x64) for alltid a fa tilgang til TEB som er tildelt for gjeldende trad, & # 8230; & # 8221;

Hvorfor uoverensstemmelsen mellom offsets (0x18 vs 0x0)?

Vel, her er avtalen. Du kan fa tilgang til hvilken som helst del av TEB via to metoder:

1) Du kan referere til feltet du vil ha av fs, med fs: [offsetof (TEB, Field)]. Dette er ubeleilig, men kompilatoren vant ikke dette automatisk; det er ikke en mate a fortelle kompilatoren at en struktur er basert pa & # 8221; pa et segmentregister. Kode som bruker denne metoden, er typisk enten generert av kompilatoren eller skrevet i assembler (selv om det med den nye __readfsdword og venner-familien av intrinsikk, kan dette gjores i rett C na generisk med CL).

2) Du kan lose den fulle adressen til TEB og bruke den til fremtidige tilganger. Dette er den vanligste maten a gjore det pa. Pa x86, ved + 0x18 i TEB er en (flat adresseplass) peker til TEB:

+ 0x018 Selv: Ptr32.

Og for a v re mer noyaktig, vil du bare referere til fs: [0x00] hvis du vil ha det forste feltet i TEB. (Du kan gjore dette ved a lose flat adressen pa + 0x18 og deretter dereferere pekeren med et offset pa + 0x00, eller bare referanse fs: [0x00] direkte.)

Offset 0 fra TEB start skjer for a v re unntakshandteringslinjelisten:

+ 0x000 ExceptionList: Ptr32.

Kode som refererer til fs: [0x00] spesifikt pa x86, tilfoyer og fjerner derfor ofte en unntakshandterer. Pa samme mate vil fs: [0x0E10] pa x86 fa deg tradens garanterte TLS-slot-array, akkurat som om du lost den flatadressen og brukte den pekeren.

+ 0xe10 TlsSlots: [64] Ptr32 Void.

Mest C-kode bruker sistnevnte metode som det er en felles makro, NtCurrentTeb, som returnerer en flat peker til TEB basert pa feltet Teb-> NtTib.Self (ved + 0x18 pa x86). Derfra kan man fa tilgang til felt i TEB naturlig gjennom en typet strukturpeker.

[& # 8230;] Nynaeve Adventures i Windows debugging og reverse engineering. & Laquo; Trad Lokal Lagring, Del 2: Eksplisitt TLS [& # 8230;]