Assembler (Jazyk symbolických adres)

(3. část)

Mikroprocesor si vytváří tzv. frontu instrukcí. Jedná se o několik instrukcí, které budou následovat po právě prováděné instrukci. Tato fronta je průběžně doplňována při operacích nezatěžujících sběrnice z paměti. Protože se ale jedná o několik za sebou jdoucích slabik v paměti, je při instrukcích skoku fronta vyprázdněna. Z tohoto důvodu je vhodné, aby program obsahoval co nejmenší počet skoků. Přesto bychom i relativně jednoduché programy bez nich asi těžko tvořili. Abychom mohli instrukce skoku používat, musíme umět vytvořit návěští, čili cíl skoku.

Návěští

Ve vkládaném Assembleru nejsme v názvech návěští nijak zvlášť omezováni, platí pro něj stejná pravidla jako pro proměnné. Návěští s dvojtečkou uvedeme před instrukci, na kterou se odkazujeme. Při překladu je v místech odkazu na návěští jeho název nahrazen skutečnou adresou instrukce.

Nepodmíněný skok

Je to nepodmíněný skok na jiné místo programu. To může být označené návěštím. Za instrukcí skoku je potom uveden jeho název. Jinak můžeme skákat na adresu v registru nebo zadanou přímo. V programu potom nepodmíněný skok vypadá takto:
      navesti: instrukce na kterou bude odkaz 
      . 
      . 
      JMP navesti 
    
Když používáme skoky, hrozí vždy nebezpečí, že se program zacyklí (a nikdy neskončí). Proto je důležité si vždy rozmyslet, zda a za jakých okolností by k této situaci mohlo dojít.

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

Jedná se o skok podmíněný stavem jednoho nebo více bitů registru příznaků F. 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 F je skok závislý. Podmíněnými skoky lze skákat pouze na adresy +/- 127 bajtů, vzdálenější skoky se realizují podmíněným nepodmíněným skokem, tj. nepodmíněným skokem JMP při splnění podmínky Jcc. Skoky po bezznaménkovém srovnání: Skoky po znaménkovém srovnání:

Otázka: Proč v podmínkách skoku po znaménkovém srovnání musí být SF = OF, resp. SF <> OF, tedy proč nestačí SF = 0, resp. SF = 1? Uveďte příklady porovnání, na kterých je to vidět (vysvětlete).

Při hledání instrukce podmíněného skoku musíme myslet na to, za jakých okolností chceme skok vykonat. K tomu je dobré si uvědomit:

Rozdíl čísel v tomto případě provedeme nejlépe instrukcí CMP. Pro tvorbu cyklu můžeme použít jeden z registrů, který si pro krokovací proměnnou vyčleníme. Jednoduchý cyklus pak vytvoříme podmíněným skokem.

Příklad:
      #include <stdio.h>

      unsigned char cisla[10], i; 

      int main()
      {
      _asm {
      mov edi, 9
      mov cx, 10
      nav:
      mov cisla[edi], cl
      dec edi
      dec cl
      jnz nav  
      }
      for (i = 0; i < 10; ++i) printf("%i ", cisla[i]); 
      printf("\n");
      return 0;
      }
    
Uvedený příklad naplní pole cisla hodnotami 1-10. Registr CX je použit ke krokování, a současně k plnění pole. Prvky pole jsou slabiky. Proto se obsah registru EDI snižuje o jednu. V případě, že by se jednalo o slova, musíme od registru EDI odečítat 2, atd.

Konstrukci if-then-else běžnou ve vyšších programovacích jazycích lze zapsat například takto:

      ;testujeme if(a<b)
	mov ax, a
	cmp ax, b
	jnb else_blok          ;skok když a>=b
	...podmínka platí...
	jmp end_if
	
	else_blok:
	...podmínka neplatí...
	end_if:
	

Pozor! Instrukce skoku JMP a Jcc nikdy nemění hodnoty žádných flagů.

Procesory 386 a novější obsahují vedle instrukcí Jcc také instrukce SETcc, které při splnění podmínky nastavují operand do log. 1 a při nesplnění do log. 0. Podrobnosti však zůstanou jen pro případné zájemce.

Nepodmíněný a podmíněný cyklus

Assembler má pro cyklus i samostatnou instrukci. Její použití však předpokládá, že si rezervujeme registr ECX pro čítání. Do něj před cyklem umístíme počet opakování.

Př. Přepište uvedený příklad s použitím LOOP.

Instrukcí LOOP lze skákat opět pouze na adresy +/- 127 bajtů. Cyklu vytvořenému pomocí LOOP se můžeme programově vyhnout instrukcí:

Podmínka skoku byla jen nenulové číslo v registru ECX. Assembler však umožňuje podmínky opakování obohatit testováním příznaku ZF. Při použití těchto instrukcí dáváme programu možnost uniknout z cyklu i (ne)nastavením příznaku ZF. Nezapomeňte ale, že ZF se musí před koncem cyklu nastavit vhodnou instrukcí.

Př. Napište v bloku Assembleru implementace standardních funkcí strcpy, strcmp a strchr. Řetězce a znak budou v proměnných jazyka C. Výsledek funkce uložte také do nějaké proměnné.



Jan Outrata
outrataj@phoenix.inf.upol.cz