1 z 5 19.2.2007 7:52 Assembler - 5.část poslední změna této stránky: 9.2.2007 1. Pseudoinstrukce a direktivy Zpět Kromě instrukcí můžete v Assembleru psát také další konstrukce, které se obšem nepřekládají na žádný konkrétní kód. Říkáme jim pseudoinstrukce a direktivy. Direktiva určuje způsob práce překladače assembleru a pseudoinstrukce je to, co se chová jako instrukce, i když to ve skutečnosti žádná instrukce není. Využívá se při tom toho, že překladače TASM a MASM jsou tzv. makro-assemblery, tj. mají podporu maker. (Význam maker znáte např. ze Scheme.) $ Znak string se vyhodnocuje na aktuální adresu při překladu. Jinými slovy jde o offset kódového segmentu instrukce, kde je tento znak použit. local jméno1:typ1, jméno2:typ2,... Tato konstrukce slouží k definici lokálních proměnných v proceduře. Musí být vždy uvedena úplně na začátku procedury. Lokální proměnné se vymezí na zásobníku, stejně jako v Céčku. include soubor Stejné jako #include v Céčku. Jméno souboru se uvádí jen tak, bez uvozovek. jméno label typ Takto můžete zpřístupnit paměť následující za touto definicí pod určitým jménem a typem. Můžete např. použít toto: the_byte label byte the_word label word the_dword dd? Anebo toto:
2 z 5 19.2.2007 7:52 the_dword label dword the_lower_word dw? the_upper_word dw? org offset Nastaví počítadlo offsetu kódu při překladu. Používá se obvykle jen pro generování COM souborů, které musí začínat na adrese 100h. 2. Netriviální datové typy Netriviální datové typy jsou v asm stejné jako v Céčku. Můžete je definovat jako struct, union nebo enum. Jejich význam je skutečně stejný jako v Céčku nebo C++ s tím dodatkem, že jména položek strukturovaných datových typů musí být v rámci souboru unikátní. (Bohužel.) Pozor! U netriviálních datových typů jsou zásadní rozdíly v syntaxi MASM a TASM. Dávejte na to bacha. ;platí jen pro TASM! jméno enum hodnota1,hodnota2,hodnota3... ;víceřádková verze - opět jen pro TASM! jméno enum { hodnota1 hodnota2... } Jak je vidět, výčtový typ TASM lze deklarovat dvěma způsoby. Strukturované typy, vhodné k napodobení objektově orientovaného programování, jsou již podporovány MASM i TASM. Syntaxe je však odlišná. ;MASM deklarace jméno struct...deklarace složek... jméno ends ;TASM deklarace jméno struc {...deklarace složek... }
3 z 5 19.2.2007 7:52 Strukturovaný typ struct odpovídá struct v Céčku (pochopitelně :-). Deklarace složek jsou totožné s deklaracemi obyčejných proměnných, tedy např. jméno db?. Deklaraci proměnné takového typu provedeme takto: jméno typ <výchozí hodnoty složek> Výchozí hodnoty složek jsou navzájem odděleny čárkami. Můžete i některé hodnoty vynechat (uvedete několik čárek za sebou). union Typy union se co do deklarace a způsobu použití neliší od typů struct. Význam je stejný jako v Céčku. kolik dup (čeho) Pole se deklarují tak, že vymezíme paměť pro několik stejných proměnných za sebou. K tomu slouží dup. Uvedeme několik příkladů. prazde_pole db 10 dup (?) pole_2d db 2 dup (3 dup (0)) ;pole 2x3 prvky pole_dvojic db 5 dup (0,1) ;opakuje 0,1,0,1,... length jméno Pomocí length zjistíte počet opakování, tj. v našem příkladu length prazdne_pole je rovno 10. size jméno Pomocí size zjistíte velikost jedné buňky v bajtech. Můžete to použít pro libovolné datové typy. U polí to vrací velikost pouze jedné buňky pole. 3. Konstanty Konstanty jsou ekvivalentní použití #define v Céčku. Číselné konstatny navíc můžete používat v makrech k dalším výpočtům, protože se vyhodnocují jako hodnoty ne jako text (tak to známe z Céčka). jméno = hodnota jméno equ hodnota První řádek ukazuje definici číselné konstanty. Druhý řádek ukazuje definici obecné konstanty. Všimněte si následujícího chování:
4 z 5 19.2.2007 7:52 A equ 6 B equ A-2 ;B = 4 C equ <A-2> ;C = A-2 Poslední řádek ukazuje jak zabránit vyhodnocení výrazu. Lomené závorky tedy použijeme tehdy, když si chceme vynutit zachování textové konstanty. Poznámka: V 99% případů se používají jen obecné konstanty definované pomocí equ. Číselné konstanty slouží k výpočtům v makrech, což je ukázáno v následujícím odstavci. rept Konstrukce rept je velmi silný nástroj, zvláště ve spojení s použitím konstant. Umožňuje nám totiž opakovat překlad. Vysvětlení nejlépe podá následující příklad. Dodejme ještě, že konec opakovaného bloku je označen endm. BitMask = 1 ;inicializuj bitovou masku (jednička v 1.bitu) BittBl label byte rept 8 db BitMask BitMask = BitMask * 2 ;posuň (jedničkový) bit doleva endm (Tento příklad je převzat z dokumentace TASM.) 4. Makra Makra, to je velmi složitá kapitola, která nám taky právě proto zbyla na konec. Makra mají v asm podobný význam jako ve Scheme, lze pomocí nich tedy dělat věci, které byste jinak dělat nemohli. Základní princip je stejný jako #define v Céčku. Čili nadefinujete jakoby funkci, která se ovšem na textové úrovni dosadí všude tam, kde bude použita. Na konci makra, na rozdíl od funkce, není instrukce ret a definice je ukončena direktivou endm, ovšem bez uvedení jména makra! jméno macro parametry ;tělo makra
5 z 5 19.2.2007 7:52 jméno endm Následuje malý příklad definice a použití makra. ;definice makra mojemakro macro param1,param2 mov al,param1 mov ah,param2 endm ;použití makra (nepoužívejte pojem "volat" makro - makro se nevolá) mojemakro 20,30 ;přiřadí al=20, ah=30 Na další důležité konstrukce se podívejte do knihy Turbo Assembler 3.0 nebo aspoň do MSDN nápovědy. Zde aspoň stručný přehled toho, co probereme na hodině: purge jméno - zruší platnost makra local jméno - definuje jméno jako lokální návěští (použijte na začátku těla makra) exitm - ukončí rozvíjení makra (analogie instrukce ret ve funkcích) &jméno - nahradí formální parametr makra jeho hodnotou, lze použít např. v poznámkách ;;text - ignorovaný komentář (normální komentáře se v makrech nevypouštějí) <text> - doslovný text, který se nijak nezpracovává, jen se vypustí <>!znak - stejné jako předchozí, ale jen pro jeden znak %parametr - zajistí vyhodnocení parametru před jeho dosazením, možno použít i uvnitř parametru Poznámka: Parametrem makra může být i jméno jiného makra. Potom můžete pomocí výše uvedených konstrukcí vytvářet velmi rychle opravdu krkolomné kódy, které byste ručně psali roky a roky. Assembler navíc narozdíl od C++ umožňuje krokovat makra, protože jim správně generuje debug info. Čili narozdíl od C++, kde špatně napsané šílené makro nikdy neodladíte, v assembleru by nalezení chyby neměl být problém. Zpět