3. cvičení

Registry

Registr je speciální paměťové místo přímo v procesoru. Práce s nimi je tedy mnohem rychlejší než s pamětí. Procesor v nich uchovává hodnoty, s kterými právě pracuje.

  • datové registry - mají všeobecná použití (jsou univerzální), níže uvedené jsou jejich vyžadovaná použití při některých operacích, 32-bitové, ke spodním 16 bitům lze přistupovat pod jménem bez E, a tuto 16-bitovou část je možné ještě rozdělit na poloviny po osmi bitech, dolních osm bitů označuje jméno končící L, horních pak jméno končící H. Horních 16 bitů z celého 32-bitového registru nelze přímo adresovat (nejsou přístupné přes nějaké jméno). Např. EAX je 32-bitový registr, ke spodním 16 bitům lze přistupovat pod jménem AX, a z těchto 16 bitů dolních 8 označujeme jako registr AL, horních pak AH.
    • EAX, AX, AH ,AL (Accumulator) - střadač pro násobení a dělení, vstupně-výstupní operace
    • EBX, BX, BH, BL (Base) - nepřímá adresace paměti
    • ECX, CX, CH, CL (Counter) - počitadlo při cyklech, posuvech a rotacích
    • EDX, DX, DH, DL (Data) - nepřímá adresace vstupů/výstupů
  • ukazatele a indexregistry - používají se pro umístění adresy, 32-bitové, spodních 16 bitů označuje jméno bez E a nelze je dále dělit (na rozdíl od předchozích univerzálních registrů):
    • EBP, BP (Base Pointer) - bázový registr, adresace parametrů funkcí a lokálních proměnných na zásobníku (adresa dna zásobníku), není rozumné jej libovolně měnit
    • ESP, SP (Stack Pointer) - ukazatel na vrchol zásobníku (adresa vrcholu zásobníku), tento také není rozumné libovolně měnit
    • EDI, DI (Destination Index) - adresa cíle
    • ESI, SI (Source Index) - adresa zdroje
    • EIP, IP (Instruction Pointer) - ukazatel na aktuální místo programu, adresa instrukce následující za právě prováděnou instrukcí, není možné jej přímo měnit (jen patřičnými instrukcemi)

Převod mezi datovými typy

  • zúžení na menší typ provedeme bez ohledu na to, zda je číslo znaménkové, či neznaménkové. Použijeme buď menší část registru nebo v případě práce s pamětí použijeme operátor ptr
    int main() {
    	char p1;
    	short p2;
    	int p4 = 0xdeadbeef;
    	_asm {
    		mov ebx, 0xdeadbeef
    		mov p1, bl
    		mov p2, bx
    		mov al, byte ptr p2
    		mov al, byte ptr p4
    		mov ax, word ptr p4
    	}
    }
    
  • pří rozšíření hodnoty z menší na vetší u beznaménkových hodnot doplníme nuly na nově přidané pozice:
    mov eax, 0
    mov al, bl
    
    Případně můžeme použít operaci movzx, která je variantou operace mov a umožnuje, aby druhý operand byl menší než první.
  • pří rozšíření hodnoty z menší na vetší u znaménkových hodnot doplníme na nově přídané pozice hodnotu nejvyššího bitu. K tomuto účelu slouží operace movsx.
  • při dělení můžeme použít následující operace, které se postarají o vhodné rozšíření hodnot:
    • cbw - rozšíří al->ax
    • cwd - rozšíří ax->dx:ax
    • cdq - rozšíří eax->edx:eax
    • cwde - rozšíří ax->eax
  • Vyzkoušejte si: převody mezi různě velkými hodnotami.

Podmíněné a nepodmíněné skoky

  • Návěstí: označuje místo v paměti (kódu). Zapisuje se ve tvaru: label:
  • Nepodmíněný skok: jmp misto -- provede nepodmíněný skok na část kódu uvozenou návěstím `misto'

Podmíněný skok (Jcc - jump conditional code)

Jedná se o skok podmíněný stavem jednoho nebo více bitů registru příznaků EF. Jen tímto způsobem je možné provádět v Assembleru přímé větvení programu. Před instrukcí podmíněného skoku proto vždy provedeme instrukci (např. CMP, TEST, aj.), která použitý příznak nastaví. V případě, že není splněna podmínka skoku, pokračuje program dál, jako by zde instrukce skoku vůbec nebyla. Instrukce podmíněného skoku začínají vždy písmenkem J. Za ním je zkratka udávající na jakých bitech registru ef(lags) je skok závislý.

  • JE / JZ návěští - skok, je-li rovno, ZF = 1
  • JNE / JNZ návěští - skok, není-li rovno, ZF = 0
  • JS návěští - skok, je-li znaménko, SF = 1
  • JNS návěští - skok, není-li znaménko, SF = 0
  • JO návěští - skok, je-li přetečení, OF = 1
  • JNO návěští - skok, není-li přetečení, OF = 0
  • JP / JPE návěští - skok, je-li sudá parita, PF = 1
  • JNP / JPO návěští - skok, je-li lichá parita, PF = 0
Skoky po bezznaménkovém srovnání:
  • JA / JNBE návěští - skok, je-li větší, (CF = 0) AND (ZF = 0)
  • JAE / JNB / JNC návěští - skok, je-li větší nebo rovno, CF = 0
  • JB / JNAE / JC návěští - skok, je-li menší, CF = 1
  • JBE / JNA návěští - skok, je-li menší nebo rovno, (CF = 1) OR (ZF = 1)
Skoky po znaménkovém srovnání:
  • JG / JNLE návěští - skok, je-li větší, (SF = OF) AND (ZF = 0)
  • JGE / JNL návěští - skok, je-li větší nebo rovno, SF = OF
  • JL / JNGE návěští - skok, je-li menší, SF <> OF
  • JLE / JNG návěští - skok, je-li menší nebo rovno, (SF <> OF) OR (ZF = 1)
int abs(int a) {
    int i;
    _asm {
        mov eax, a
        cmp eax, 0
	jge konec
        neg eax
konec:
        mov i, eax
    }
    return i;
}

Úkoly

  1. Napište funkci int avg_int(int a, int b, int c) pro výpočet aritmetického průměru tří čísel typu int. Vyzkoušejte, že funguje správně pro kladná i záporná čísla (i jejich mix).
  2. Napište funkci short avg_short(short a, short b, short c) pro výpočet aritmetického průměru tří čísel typu short. Vyzkoušejte, že funguje správně pro kladná i záporná čísla (i jejich mix).
  3. Napište funkci int sgn(int i), která vrací hodnoty -1, 0, 1, v závislosti na tom, zda-li je hodnota i záporná, nulová nebo kladná.
  4. Napište funkci int min3(unsigned char a, short b, int c), která vrací nejmenší hodnotu.
  5. Napište funkci int kladne(int a, int b, int c), která vrací 1, pokud jsou všechny argumenty kladné, jinak 0.
  6. Napište funkci int mocnina(int n, unsigned int m) vracející mocninu nm.

Pro získání bodového hodnocení je potřeba splnit úkoly 2, 4 a 6.


Last update on 28. 2. 2017 18:30
Powered by Schemik.

© Petr Krajča, 2010, 2012
petr.krajca (at) upol.cz