NOVINKA! E-learningové kurzy umělé inteligence. Nyní AI za nejlepší ceny. Zjisti více:
NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!

Lekce 14 - Assembler - Registry procesoru

V minulé lekci, Assembler - Výpočty s reálnými čísly, jsme si probrali SSE instrukce pro práci s reálnými čísly.

V dnešním ASM tutoriálu si ukážeme skoro všechny registry procesorů x86 a x64.

Na registry jsme již v našem assembler kurzu narazili a víme, že jsou to "proměnné", napevno vytvořené přímo v procesoru. Jsou velmi rychlé, protože se ušetří cesta mezi procesorem a pamětí RAM. V miniaturním procesoru je samozřejmě také velmi omezené místo, proto je registrů vytvořených jen omezené množství a mají specifická určení. Registry se také výrazně liší podle architektury procesoru.

V dnešním ASM tutoriálu si skoro celé registry CPU konečně zmapujeme. Na začátku kurzu by to pro nás byly příliš vyčerpávající informace, nyní je již však dokážeme využít.

Obecné registry

Při programování nejčastěji pracujeme s obecnými registry (anglicky general-purpose). Do nich lze ukládat celá čísla a nebo adresy (ukazatele do paměti). Používají se při výpočtech, k ukládání dočasných hodnot nebo lokálních proměnných.

16-bitové

V éře MS-DOS a Windows 3.X byly registry pouze 16-bitové. To komplikovalo nejen výpočty s většími čísly, ale hlavně přístupy do paměti, protože 64 KB brzy přestalo aplikacím stačit. V procesoru je těchto 8 obecných registrů:

  • AX - akumulátor (akumulační registr)
  • BX - bázový registr
  • CX - čítač (counter)
  • DX - datový registr
  • SI - index pro zdroj (Source Index)
  • DI - index pro cíl (Destination Index)
  • BP - ukazatel na záznam aktivní procedury na zásobníku (Base Pointer)
  • SP - ukazatel vrcholu zásobníku (Stack Pointer)

Registry BP a SP se používají při volání funkcí. Ostatní registry jsou opravdu obecné a můžeme si do nich ukládat, co chceme. Jejich pojmenování pak slouží k lepší orientaci v kódu, např. do AX uložíme výsledek nějaké aritmetické operace a do CX budeme ukládat počítadlo cyklu.

S registry AX, BX, CX, DX můžeme pracovat také tak, že si je rozdělíme na dva menší osmibitové registry. Horní poloviny se označují AH, BH, CH, DH (High). Dolní poloviny jsou pak AL, BL, CL, DL (Low).

Následující příklad ukazuje, která část registru AX se změní, pokud zapíšeme hodnotu do AH nebo AL:

mov ax, 1122h  ;ax=1122h
mov al, 33h    ;ax=1133h
mov ah, 44h    ;ax=4433h

32-bitové

Dostáváme se do časů Windows 95 - XP. Při rozšíření všech 16-bitových registrů na 32-bitové byl k názvu přidán prefix E (Extended) - EAX, EBX, ECX atd. Do těchto registrů pak můžeme uložit větší čísla. V počítači můžeme mít až 4 GB paměti.

Když v 32-bitové aplikaci zapíšeme hodnotu do 16-bitového registru, pak se změní dolních 16 bitů z 32-bitového registru, zatímco horních 16 bitů se nezmění. Ukažme si příklad:

mov eax,12345678h ;eax=12345678h
mov ax,99aah      ;eax=123499aah
mov al,bbh        ;eax=123499bbh
mov ax,cch        ;eax=123400cch

64-bitové

Dostáváme se k současným procesorům. V 64-bitových aplikacích máme dvakrát více obecných registrů.

Rozšíření původních registrů

Původních 8 registrů bylo rozšířeno a mají prefix R - RAX, RBX atd.

Nové registry

K tomu přibyly registry R8R15. K těm lze přidat sufixy D, W a B pro přístup k nižším 32, 16 a 8 bitům. Např. R8D, R8W, R8B.

V 32-bitových aplikacích jsme měli často nedostatek registrů a lokální proměnné jsme museli ukládat do paměti, což bylo pomalé. V 64-bitových aplikacích máme takové množství registrů, že se do nich vejde většina lokálních proměnných a předávají se v nich i parametry funkcí.

Následující příklad ukazuje, jak se mění registr RAX, pokud zapisujeme hodnoty do AH, AL, AX, EAX:

mov rax,1111222233334444h ;rax=1111222233334444h
mov ah,55h                ;rax=1111222233335544h
mov al,66h                ;rax=1111222233335566h
mov ax,7777h              ;rax=1111222233337777h
mov eax,88888888h         ;rax=0000000088888888h
mov eax,-1                ;rax=00000000ffffffffh

Všimněte si, že při zápisu 8-bitové nebo 16-bitové hodnoty se vyšší bajty registru nemění. Ale při zapsání 32-bitové hodnoty se ostatní bajty vynulují. To můžeme využívat k optimalizaci. Pokud chceme do 64-bitového registru uložit malé nezáporné číslo, můžeme použít 32-bitový registr.

x87 registry

Při výpočtech s reálnými čísly se používají 80-bitové registry ST(0)ST(7). K nim lze přistupovat jako k zásobníku. To znamená, že při výpočtech se můžeme odkazovat na konkrétní registry, ale často nám stačí jen přidávat čísla na vrchol zásobníku a provádět s nimi matematické operace.

MMX registry

Registry MM0MM7 jsou synonyma pro ST(0)ST(7), ale používají se k výpočtům s celými čísly. V dnešní době už nemá smysl je používat, protože SSE je lepší, viz dále.

SSE registry

Do šestnácti 128-bitových registrů XMM0XMM15 můžeme ukládat reálná i celá čísla. Do každého registru se vejde více čísel najednou (dvě 64-bitová čísla nebo čtyři 32-bitová). Jednou instrukcí tak lze vykonat operaci s několika hodnotami naráz. To se nazývá SIMD (Single Instruction, Multiple Data). Této technologie využijeme při práci s vektory nebo zpracování velkých dat. Získáme tím samozřejmě vyšší výkon. Ve 32-bitových aplikacích je přístupná jen polovina registrů (XMM0XMM7).

Kromě datových registrů existuje ještě stavový a řídící registr MXCSR.

AVX registry

Novější procesory mají SSE registry rozšířeny na 256 bitů a nazývají se YMM0YMM15. Ještě novější procesory mají 512-bitové registry ZMM0ZMM15 a navíc opmask registry K0K7.

Příznaky - Registr EFLAGS

O příznacích jsme si již říkali v lekci Assembler - Kombinace skoků a příznaky. Mohou mít hodnotu buď 0 nebo 1 a označují nějakou situaci, ke které při vykonávání instrukcí došlo. Můžeme je následující instrukcí přečíst a na stav programu reagovat.

Registr EFLAGS tedy obsahuje několik jednobitových hodnot. Některé z nich nemůžeme sami v aplikaci měnit a má k nim přístup jen operační systém. Pro nás jsou nejdůležitější aritmetické příznaky CF, ZF, SF a OF, které jsme si již popsali.

Dnes si ukažme úplnější seznam:

  • 0. CF (Carry) - přetečení při aritmetické operaci s čísly bez znaménka, nebo při bitových posuvech a rotacích
  • 2. PF (Parity) - sudá parita, dolní osmice bitů výsledku obsahuje sudý počet jedniček
  • 4. AF (Auxiliary Carry) - přetečení mezi 3. a 4. bitem při BCD aritmetice
  • 6. ZF (Zero) - nulový výsledek
  • 7. SF (Sign) - záporný výsledek
  • 8. TF (Trap) - krokování po instrukcích při ladění
  • 9. IF (Interruption) - povolená hardwarová přerušení
  • 10. DF (Direction) - řetězcové instrukce v opačném směru (např. MOVSB snižuje SI, DI)
  • 11. OF (Overflow) - přetečení při aritmetické operaci s čísly se znaménkem
  • 12-13. IOPL (I/O Privilege Level) - úroveň oprávnění pro instrukce IN/OUT
  • 14. NT (Nested Task) - instrukce IRET při návratu z přerušení přepne na další proces
  • 16. RF (Resume) - maskuje opakování ladícího přerušení
  • 17. VM (Virtual-8086 Mode) - virtualizace 16-bitových aplikací ve 32-bitovém operačním systému
  • 18. AC (Alignment Check) - kontrola zarovnání, vyvolá přerušení při přístupu na adresu, která není dělitelná délkou hodnoty
  • 19. VIF (Virtual Interrupt) - příznak IF při virtualizaci
  • 20. VIP (Virtual Interrupt Pending) - bylo vyvoláno přerušení při virtualizaci
  • 21. ID (Identification) - pokud lze nastavit, je podporována instrukce CPUID

Segmentové registry

Segmenty se používaly v 16-bitových aplikacích. Paměť byla rozdělena na segmenty o velikostech 64 KB:

  • CS - segment kódu
  • DS - datový segment
  • ES - extra segment
  • FS - další extra segment
  • GS - další extra segment
  • SS - segment zásobníku (stack)

Pokud aplikace potřebovala více paměti, musela si segmenty přepínat. Ve 32-bitových aplikacích jsou segmenty zcela zbytečné, protože aplikace může přistupovat až ke 4 GB paměti. V 64-bitových aplikacích pak byly úplně zrušeny segmenty CS, DS, ES, SS. Zůstaly pouze segmenty FS a GS, protože operační systémy je používají k ukládání dat pro běžící vlákno (thread local storage) nebo k informacím o výjimkách (exceptions).

Registr IP

Instruction Pointer ukazuje na právě vykonávanou instrukci. Hodnotu tohoto registru měníme například instrukcemi skoku (JMP, CALL a RET). V 64-bitových aplikacích můžeme používat registr RIP k relativnímu adresování.

Debug registry

Při ladění můžeme nastavovat až 4 datové breakpointy na proměnné. Program se pak zastaví, když se proměnná změní. V registrech DR0, DR1, DR2, DR3 jsou adresy breakpointů. Podle stavového registru DR6 se určí, který z těch 4 breakpointů byl vyvolán. V kontrolním registru DR7 se nastavuje, které breakpointy jsou aktivní, jestli jsou pro zápis nebo pro čtení a kolik bajtů proměnná zabírá.

Kontrolní registry

Registry CR0, CR2, CR3, CR4, CR8 používá operační systém při virtualizaci, stránkování, nastavení zabezpečení nebo přepínání různých režimů procesoru. Jejich význam je nad rámec této lekce.

V příští lekci, Assembler - Rejstřík instrukcí procesoru, si ukážeme stručný přehled nejdůležitějších instrukcí.


 

Předchozí článek
Assembler - Výpočty s reálnými čísly
Všechny články v sekci
Základy assembleru
Přeskočit článek
(nedoporučujeme)
Assembler - Rejstřík instrukcí procesoru
Článek pro vás napsal Petr Laštovička
Avatar
Uživatelské hodnocení:
5 hlasů
Autor se věnuje vývoji webových aplikací v ASP.NET a aplikací pro Windows v C++ nebo C#.
Aktivity