4. cvičení

Adresace paměti

Místo v paměti označuje hodnota (adresa, přímo nebo v registru), která musí být zapsaná v hranatých závorkách.

Pozor! V jedné instrukci můžete pouze jedinkrát adresovat paměť. To znamená, že např. příkaz a = 33; zapíšete normálně jako mov a, 33, ale naopak a = b; takto jednoduše napsat nejde. Byla by zde dvojí adresace v jedné instrukci.

Otázka: Jaké instrukce provedou a = b?

Assembler umožňuje dvě metody adresace.

Přímá adresa

Přímé adresování je takové, kde jsou adresy známé přímo při překladu, tzn. při práci se statickými nebo globálními proměnnými (jazyka C).

MOV AH, [0x1A40] - do registru AH předej 8 bitů z adresy určené číslem
Tuto metodu použijeme, jestliže předem víme adresu hledaného místa v paměti.
      static int thevar, thevar2; // proměnné thevar a thevar2 jsou v paměti za sebou
      _asm {
		mov eax, thevar            ; eax = thevar - do registru eax vlož 32-bitovou hodnotu z paměti na místě ozn. thevar 
		mov eax, thevar + 4        ; eax = thevar + 4 = thevar2 - do registru eax vlož 32-bitovou hodnotu z paměti na místě thevar+4=thevar2
      }
Jméno statické proměnné se tedy vyhodnocuje jako přímá adresa (protože překladač zná adresu hodnoty proměnné v paměti), je to jen textové označení adresy hodnoty proměnné. Instrukce MOV ax,thevar je přepsána na MOV ax, [adresa_hodnoty_promenne_thevar]. S proměnnými jako adresami ještě můžeme provádět základní aritmetické operace.
_asm {
	mov ax, thevar         ; ax = [adresa_hodnoty_thevar]
	mov ax, [thevar]       ; ax = [[adresa_hodnoty_thevar]] = [adresa_hodnoty_thevar]
}
Pokud je thevar statická nebo globální proměnná, pak oba tyto příkazy dělají totéž, čili do AX se přiřadí hodnota proměnné thevar.

Nepřímá adresa

V C (C++) toto adresování odpovídá ukazatelům na hodnoty. Zatímco u přímého adresování známe přesnou adresu hodnoty proměnné již při překladu, u nepřímého adresování máme tuto adresu hodnoty proměnné v jiné proměnné typu ukazatel na hodnotu, čili hodnota proměnné typu ukazatel na hodnotu (např. velikosti byte) je adresa (32-bitová) této hodnoty (velikosti byte) v paměti. Obecný tvar nepřímě adresy je [mem+reg1+reg2*size] (ekvivalentní zápis je mem[reg1][reg2*size]), kde size je konstanta (může být pouze 1, 2, 4, 8), reg1, reg2 libovolné 32-bitové registry a mem je přímé zádání adresy v paměti (tj. číslo), všechny položky jsou nepovinné.


char *thepointer; // 32-bitová proměnná typu ukazatel na 8-bitovou hodnotu
_asm {
	mov ebx, thepointer     ;ebx = thepointer - přímá adresace
	mov esi, 2              ;esi = 2
	mov al, [ebx + esi]     ;al = *(thepointer + 2) = thepointer[2] - nepřímá adresace
}

Reference a dereference

Uvádíme-li v instrukcích pouze jména proměnných, překladač je vždy musí převést do nějakého jiného tvaru, protože samotný název proměnné v assembleru nic neznamená. Každé uvedení pouhého jména se překládá na tvar typ ptr jméno, nebo offset jméno, které odpovídají vyznamově dereferenci a referenci v jazyce C. S vyjimkou instrukcí skoku či volání funkce se používá tvar typ ptr jméno.

Instrukce lea

Výpočet adres se provádí během fáze dekódování instrukce. Jedná se tedy o nejrychlejší možný výpočet. Instrukce lea umožnuje efektivně vypočítat adresu místa v paměti. Tuto instrukci je možné použít i pro rychlé násobení. Např. násobení devíti:

mov eax, a
lea eax, [eax + 8 * eax]

Úkoly

  1. Vytvořte statické pole o velikosti 10 prvků typu int. Napište funkci void nasobky(short n), která do daného pole uloží násobky čísla n.
  2. Vytvořte statické pole o velikosti 10 prvků typu int. Napište funkci void countdown(), která do daného pole uloží posloupnost 10, 9, 8, ..., 1 (v tomto pořadí).
  3. Vytvořte statické pole o velikosti 10 prvků typu short. Napište funkci void mocniny(), která do daného pole uloží čísla 12, 22, ..., 102.
  4. Vytvořte pole (pomocí volání malloc z jazyka C) o velikosti 10 prvků typu int. Napište funkci void mocniny2(), která do daného pole uloží čísla 20, 21, ..., 29.
  5. Vytvořte pole (pomocí volání malloc z jazyka C) o velikosti n prvků typu short, kde n je konstanta. Napište funkci int avg(unsigned int n) pro výpočet aritmetického průměru čísel v tomto poli. Vyzkoušejte, že funguje správně pro kladná i záporná čísla (i jejich mix).
  6. Napište funkci int minimum(), která vrací nejmenší prvek pole. V těle této funkce v jazyce C vytvořte lokální proměnnou typu pole o velikosti 10 prvků typu int, ze které se budou hodnoty výbírat. Vyzkoušejte, že funkce funguje správně pro kladná i záporná čísla.

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


Last update on 7. 3. 2017 18:53
Powered by Schemik.

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