Jdeme programovat. Programování v Assembleru – 2. část

Jdeme programovat. Programování v Assembleru – 2. část

První část seriálu najdete na: Programujte přímo pomocí instrukcí procesoru. Aneb programování v Assembleru – 1. část. Abychom pořád jen neomílali teorii, zkusíme si něco konečně naprogramovat. Těšíte se? Asi největším neduhem je, že pro každý operační systém je v tomto programovacím jazyce odlišný styl. My budeme demonstrovat programování ve Windows. K překladu zdrojového kódu si musíte nainstalovat vhodný překladač. 

My použijeme asi nejznámější a bezplatný překladač NASM, který si stáhnete vč. pomocných souborů pod touto adresou:

http://uloz.to/xs9SNEt/assembler-serial-zip             heslo na stažení je asm

Nejdřív si vysvětlíme, jak programy spouštět. Uložíme si obsah archivu (ne složku, ale přímo jednotlivé soubory) na disk C: do složky NASM (složku musíme vytvořit), nebo pokud patříte mezi uživatele dobře ovládající příkazový řádek, tak na libovolné místo. Nebudeme zde totiž vysvětlovat jednotlivé příkazy příkazového řádku.

Složka obsahuje program s názvem prvni.asm. Pokusíme se tento program společně pustit. Práce v příkazovém řádku se bát opravdu nemusíte, pokud jste v příkazovém řádku nikdy nepracovali a máte obsah archivu v doporučeném adresáři, postupujte přesně podle těchto pokynů:

  1. Spustíme příkazový řádek – v nabídce Start napíšeme do vyhledávacího pole cmd a stiskneme Enter.
  2. Zadáme příkaz cd \
  3. Následuje příkaz cd nasm, kterým se přesuneme do naší složky s obsahem archívu.
  4. Nyní už spustíme zkušební program, napíšeme run.bat prvni (příkaz run.bat slouží k překladu programu, za něj vždy napíšeme název námi vytvořeného programu bez přípony, v našem případě tedy prvni)
  5. Pokud je nyní příkazový řádek na vašem počítači stejný, jako okno vyfocené na obrázku níže, můžeme se směle pustit do psaní dalších prográmků. V opačném případě zkuste stáhnout archiv znovu nebo mě kontaktujte.

Windows - cmd

V čem psát programy?

Na tuto otázku je odpověď velmi jednoduchá. Postačí jakýkoliv textový editor. Doporučujeme ale takový, který umí počítat řádky. Doporučuji PSPad Editor, který je přiložen v archívu.

Důvod je jednoduchý. Pokud totiž při psaní prográmku uděláte někde chybu, překladač Vám sám v chybovém hlášení oznámí, na kterém řádku sen chyba vyskytla. Na níže uvedeném obrázku je ukázka překladu programu prvni.asm s úmyslnou chybou na 16 řádku:

Windows - cmd

Nebudeme zatím zkoumat zdrojový kód našeho prvního programu, podobný za okamžik každý sám napíšeme.

Zapamatujte si!!

  • Vytvořené programy mají vždy příponu .asm
  • Ukládáme je vždy do stejné složky, kam jsme zkopírovali archív (abychom je mohli přeložit)
  • Překladač zdrojového kódu nerozlišuje malá a velká písmena, je tedy jedno, která budete používat

Základní instrukce

Každá instrukce je zapsána ve tvaru:

NÁZEV INSTRUKCE mezera OPERAND 1 a případně čárka  OPERAND 2

Prvním operandem může být registr nebo místo v paměti. My budeme v rámci seriálu zkoušet pouze operace s registry. Používat budeme prozatím pouze čtveřici registrů EAX, EBX, ECX, EDX a jejich 16-bitové a osmibitové varianty (viz. Tabulka Registry procesoru). Druhým operandem může být navíc i číselná hodnota. Některé instrukce mají jen jeden operand.

Začneme tedy první důležitou instrukcí, a tou je instrukce MOV. Tato instrukce nám poslouží pro naplnění registru nějakou hodnotou:

MOV EAX,5                 ; EAX = 5

Pro ujasnění zápisu – MOV je název instrukce, EAX je první operand instrukce, 5 je druhý operand instrukce. Instrukce má tedy dva operandy. Do prvního operandu se nahraje hodnota druhého (přepíše se původní hodnota oprandu1). Čili v uvedeném případě se do registru EAX nahraje číslo 5. Za instrukcí může a nemusí následovat středník, za kterým je napsán komentář k provedené instrukci. Tyto komentáře slouží ke zpřehlednění programu.

Příklad s registry:

MOV EAX, EBX           ; do registru EAX nahrajeme hodnotu EBX

Sčítání a odčítání

Sčítáme pomocí instrukce ADD. Pravidla pro ni platí shodná jako pro instrukci MOV, u této instrukce ovšem druhý operand nepřepíše první, ale přičte k jeho hodnotě svoji. K odečítání slouží SUB. Její funkce je logicky opačná instrukci ADD, od hodnoty operandu 1 se odečte operand 2. Pokud chceme přičítat nebo odečítat jedničku, je praktické využít instrukce INC (zvýšení operandu o 1) a DEC (snížení operandu o 1). Na následujícím úseku kódu si se sčítáním a odčítáním dostatečně pohrajeme:

MOV EAX,5                 ; do EAX nahrajeme číslo 5

MOV EBX,3                 ; do EBX nahrajeme číslo 3

ADD EAX,4                  ; přičteme k EAX 4, čili EAX = 5+4 = 9

SUB EAX,EBX              ; od EAX odečteme hodnotu EBX, EAX = 9-3 = 6

INC EAX                      ; EAX = 6+1 = 7, pozor! tato instrukce má jen jeden operand

DEC EBX                     ; zmenšíme o jedničku EBX, EBX bude 2

Posledními instrukcemi, které si v tomto díle předvedeme, budou instrukce násobení (MUL, IMUL) a dělení (DIV, IDIV).

Jako první otázka, která Vám v hlavě naskočí zřejmě je, proč mají tyto instrukce dvě varianty a jaký je mezi nimi rozdíl. Vysvětlíme si na příkladech:

MUL vs. IMUL

MUL EBX         ;jak si můžeme všimnout, MUL má pouze jeden operand, první je automaticky   ;EAX, druhým může být libovolný registr, čili operace vytvořená touto instrukcí ;bude EAX = EAX*EBX

IMUL EBX,ECX                        ;instrukce na stejném principu jako ADD, EBX= EBX*ECX

DIV vs. IDIV

Rozdíl těchto dvou instrukcí není totožný, jako předchozí případ. Stejně jako DIV, tak také IDIV má pouze jeden operand. Prvním operandem je automaticky EAX, příp. jeho osmibitové nebo šestnáctibitové varianty. Druhým operandem může být opět pouze registr.

DIV EBX           ; dělení celočíselné beze zbytku, EAX = EAX/EBX

IDIV EBX          ; dělení celočíselné se zbytkem, zbytek se ukládá do EDX, v případě použití ;osmibitových registrů do registru AH     , EAX = EAX/EBX…….EDX = zbytek ;po dělení

 ! Nelze – DIV 2         ;u instrukcí s jedním operandem musí být operandem pouze registr

PRAKTICKÝ PROGRAM

Zkusíme si vytvořit jednoduchý prográmek, který:

  1. Načte číslo, které uživatel zadá pomocí klávesnice.
  2. Toto číslo zmenší o jedničku a vydělí dvěma.
  3. Načteme z klávesnice nové číslo, které k němu přičteme.
  4. Výsledek vypíšeme na obrazovku.

Doporučuji si každé zadání příkladu rozepsat do číselných bodů, tak jako jsme to nyní předvedli. Psaní programu bude snažší, lépe se v něm budete orientovat.

Zdánlivě lehký program nás však hned na začátku zaskočí. Jak provést načtení z klávesnice? K tomu využijeme podpůrných funkcí knihovny, vytvořených docenty na Fakultě informačních technologií VUT. Kompletní seznam funkcí najdeme v textovém souboru pomocne funkce.txt umístěném v archivu. K načtení čísla zavoláme funkci ReadInt32. Náš první příkaz v programu bude tedy:

Call ReadInt32                        ;call užíváme, pokud voláme nějakou funkci z knihovny (rw32.inc)

V popisu funkce najdeme, že číslo, které zadáme z klávesnice, se automaticky načte do registru EAX.

DEC EAX          ;číslo zmenšíme o jedničku

DIV 2               ; Nyní vydělíme EAX dvěma

!! Obrovská chyba. Instrukce div má pouze jeden operand, kterým dělíme EAX, ale musí jim být registr, proto musíme k této operaci použít nějaký pomocný registr, např. EBX.

MOV EBX,2     ;do EBX nahrajeme číslo 2

DIV EBX           ;vydělíme EAX dvojkou

Nyní potřebujeme načíst nové číslo z klávesnice. Nesmíme být ale zbrklí! Než znovu použijeme ReadInt32, musíme si náš výpočet zálohovat, neboť jinak bychom si ho přepsali novým číslem z klávesnice, které se do EAX nahraje funkcí ReadInt32.

MOV ECX, EAX                        ;náš výsledek si tedy zálohujeme do ECX

Call ReadInt32                        ;načteme nové číslo

ADD EAX, EDX            ;čísla sečteme, výsledek bude uložen do EAX

K vypsání výsledku na obrazovku užijeme pomocnou funkci WriteInt32.

Call WriteInt32           ;tato funkce vypisuje vždy pouze obsah registru EAX, pokud bychom ;tedy potřebovali  vypsat obsah jiného registru, musíme nejdříve tento obsah nahrát do EAX!

Tak nebudeme déle váhat, spustíme PSPad nebo jakýkoliv jiný editor a přepíšeme program. Programy v Assembleru musejí mít tuto konstrukci:

%include ‚rw32.inc’     ; natazeni knihovny rw32.inc, knihovna

;obsahuje funkce čtení z klávesnice atd.

 

[segment .code use32]   ; definice zacatku kodoveho segementu

 

prologue; slovem prologue začíná zdrojový kód programu

.

.

.    zde bude stát náš zdrojový kód

.

 

epilogue                ; toto slovo ukončí program

Celý program si následně přeložíme způsobem, který jsem demonstroval na pilotním příkladu a je hotovo. Napsali jsme první program!

Tento díl nás tedy seznámil s jazykem jako takovým, vysvětlili jsme si základní souvislosti, principy a také předvedli tvorbu programu i jeho překladu. Příště se spolu vrhneme na složitější příklady. Vytvoříme program, který dokáže poznat, zda je číslo sudé nebo liché, povíme si, jak se v Assembleru provádějí podmínky, cykly for, while a také si pořádně pohrajeme s binárními čísly. Jednoduše řečeno, už se pustíme do toho „opravdového“ programování.

Nyní si můžete ověřit, jak pevné jsou vaše základy Assembleru jednoduchým testem:

  1. Jaký je rozdíl mezi Assemblerem a jazykem C? Je Assembler vhodný pro tvorbu rozsáhlých programů?
  2. Převeďte do dvojkové soustavy čísla 18, 12 a -8 užitím doplňkového kódu.
  3. Které z těchto instrukcí mají pouze jeden operand?

MOV, DIV, IDIV, IMUL, DEC, SUB

4. Je správný tento zápis: SUB EAX, 4

5. Jakým příkazem (příkazy) vypíšeme hodnotu EDX na obrazovku?

6. Napište program, který načte dvě čísla (uživatel je zadá pomocí klávesnice), první o jedničku zmenší, ke druhému přičte osmičku. Provede dělení se zbytkem a zbytek vypíše na obrazovku. Při počítání užívejte 32-bitové registry.

Poznámka k zadanému programu: Nezapomínejte, že funkcí ReadInt32 se číslo z klávesnice nahraje vždy do EAX a přepíše původní obsah. Bude potřeba využít některý další registr pro zálohu prvního čísla, abychom si ho načtením druhého čísla nepřepsali. Zbytek po dělení se při užití 32-bitových registrů ukládá do EDX. Hodnotu EDX tedy budeme muset nahrát do EAX, abychom mohli vypsat na obrazovku požadovaný zbytek po dělení.

Odpovědi na tyto otázky rozebereme v příštím díle seriálu.

Komentáře

Nahoru