Aleš Keprt - Elektronická učebnice Assembleru
http://student.inf.upol.cz/keprt/vyuka/asm/asm4.aspx
Assembler - 4.část poslední změna této stránky: 9.2.2007 Zpět
1. Proměnlivý počet parametrů Funkce s proměnlivým počtem parametrů lze v Assembleru implementovat stejně jako v C++. Abyste to dokázali, je třeba vědět, jak to vlastně v C++ funguje. Pokud to zatím neznáte, podívejte se na jednoduchou funkci v C++, která sečte tři čísla: long add(long a,...) { #define val(n) (&a)[n] return val(0)+val(1)+val(2); }
#undef val
Funkce je definována pomocí tří teček (tzv. ellipsis, česky výpustka). Konstrukce &a bere a jako první prvek pole. A to je klíčové místo, protože tímto způsobem snadno zpřístupníme další parametry. Parametry jsou prostě "někde v paměti" (na zásobníku) pěkně za sebou a to je celá finta. Když první parametr pojmenujete, máte zpřístupněny i všechny ostatní. V asm můžete pracovat identicky (pomocí pojmenování prvního parametru) nebo složitě pomocí ebp registru pro adresování zásobníku (což už jsme se ale také učili :-).
2. Aritmetické instrukce Zopakujeme si znovu instrukce po skupinách. Nejprve tedy instrukce aritmetické. Podrobné informace k jednotlivým instrukcím naleznete v literatuře (a samozřejmě na hodinách). operace
1 z 11
instrukce
19.2.2007 7:51
Aleš Keprt - Elektronická učebnice Assembleru
sčítání
add, adc, inc
odčítání
sub, sbb, dec
porovnání
cmp, test
negace
neg
násobení
mul, imul
dělení
div, idiv
přetypování
cbw, cwd, cwde [386], cdq [386]
http://student.inf.upol.cz/keprt/vyuka/asm/asm4.aspx
logické a bitové operace and, or, xor, not Aritmetické instrukce pochopitelně mění flagy. Srovnávací instrukce nedávají žádný jiný výsledek, ostatní dávají výsledek v prvním operandu.
Pozor! Instrukce inc a dec nemění flag carry.
3. Instrukce pro přenos dat operace
instrukce
přiřazení
mov, movzx [386], movsx [386]
záměna
xchg
práce s porty
in, out
výpočet efektivní adresy lea, lds, les, lfs [386], lgs [386], lss [386] práce se zásobníkem
push, pusha, pushad [386], pushf, pop, popa, popad [386], popf
Pozn.: Instrukce pusha a pushad se od sebe navzájem liší tím, že první z nich pracuje s 16bitovými registry, zatímco druhá pracuje s 32bitovými registry. Totéž platí o instrukcích popa a popad. V praxi tedy používáme pouze ty s písmenem d na konci. Pozn.: Instrukce lds, les, lfs, lgs, lss fungují stejně jako lea, navíc však nastaví příslušný segmentový registr. V paměťovém modelu small tedy nemají význam.
2 z 11
19.2.2007 7:51
Aleš Keprt - Elektronická učebnice Assembleru
http://student.inf.upol.cz/keprt/vyuka/asm/asm4.aspx
4. Instrukce posunů a rotací operace
instrukce
posun (shift)
shl=sal, shr, sar, shld, shrd
rotace přes carry rcl, rcr rotace
3 z 11
rol, ror
19.2.2007 7:51
Aleš Keprt - Elektronická učebnice Assembleru
4 z 11
http://student.inf.upol.cz/keprt/vyuka/asm/asm4.aspx
19.2.2007 7:51
Aleš Keprt - Elektronická učebnice Assembleru
5 z 11
http://student.inf.upol.cz/keprt/vyuka/asm/asm4.aspx
19.2.2007 7:51
Aleš Keprt - Elektronická učebnice Assembleru
6 z 11
http://student.inf.upol.cz/keprt/vyuka/asm/asm4.aspx
19.2.2007 7:51
Aleš Keprt - Elektronická učebnice Assembleru
http://student.inf.upol.cz/keprt/vyuka/asm/asm4.aspx
5. Výkonné instrukce
7 z 11
operace
instrukce
skoky
jmp, jcc, jcxz, jecxz [386], loop, loope, loopne
19.2.2007 7:51
Aleš Keprt - Elektronická učebnice Assembleru
entry/exit code
enter, leave
přerušení
int, iret
nastavování flagů
stflag, clflag, cmc
http://student.inf.upol.cz/keprt/vyuka/asm/asm4.aspx
nastavení segmentu seg
Instrukce loop Tato instrukce slouží ke snadnému programování cyklů. Píše se na konec cyklu ve formě loop
, kde ukazuje na začátek cyklu. Instrukce loop sníží hodnotu registru cx/ecx o jedničku a nemění přitom žádné flagy! Je-li nová hodnota registru nenulová, je proveden skok na uvedený label. To, který registr se použije, se řídí typem code segmentu. Na 16bitových systémech (DOS) se používá cx, na 32bitových systémech (vše mimo DOS) se používá ecx.
Instrukce loopz/loope a loopnz/loopne Tyto dvě instrukce jsou rozšířením obyčejného loop. Fungují stejně jako loop a využívají přitom vlastnost, že loop samotný nijak nemění flagy. Instrukce loopz provede totéž co loop, ovšem krom počítadla cx/ecx testuje i příznak z a vyžaduje ZF=1. Řečeno názvem instrukce: "Loop while ecx is nonzero and zero-flag is set." neboli "Opakuj, dokud ecx je nenulové a zero-flag je nastaven." Instrukce loopnz provede totéž co loop, ovšem krom počítadla cx/ecx testuje i příznak z a vyžaduje ZF=0. Řečeno názvem instrukce: "Loop while ecx is nonzero and zero-flag is reset." neboli "Opakuj, dokud ecx je nenulové a zero-flag je nulován." Existují také loope a loopne. Jsou to pouze jiné názvy pro tytéž instrukce. Pozor! Uvedením prefixu nebo jiného tvaru instrukce je možné explicitně změnit použití registru z ecx na cx nebo naopak. Použití je problematické v tom, že se zde jednotlivé překladače assembleru rozcházejí (syntace je různá, proto doporučuji tuto vlastnost nepoužívat).
Instrukce enter Entry code procedury, čili vytvoření rámce pro lokální proměnné na zásobníku, je obvykle: push ebp
8 z 11
19.2.2007 7:51
Aleš Keprt - Elektronická učebnice Assembleru
http://student.inf.upol.cz/keprt/vyuka/asm/asm4.aspx
mov ebp,esp sub esp,velikost_lokálních_proměnných
Právě tuto sekvenci zajistí instrukce enter velikost_lokálních_proměnných,0. Druhý parametr se používá při vnořených procedurách (v Pascalu).
Instrukce leave Exit code procedury provádí instrukce leave (vždy bez operandů). Lze ji nahradit opisem: mov esp,ebp pop ebp
Lokální proměnné se takto adresují přes registr ebp, který je implicitně asociován se segmentem ss (podobně jako registr esp). Entry/exit code je nezávislý na paměťovém modelu. Aby se v C++ daly používat pointery, je nutno v modelech small a medium mít ds=ss. (Dokažte!) Ve chráněném režimu (Win32/Linux) to funguje jen díky tomu, že oba segmenty mají společnou bázi a architektura CPU je navržena tak, aby při nepřímém adresování pomocí offesetů byly tyto dva segmenty zaměnitelné. (Vysvětlení žádejte na přednášce.)
6. Řetězcové instrukce operace
instrukce
nastavení směru cld, std opakování
rep, repnz
přesun
movsb, movsw, movsd
načtení
lodsb, lodsw, lodsd
uložení
stosb, stosw, stosd
porovnání
cmpsb, cmpsw, cmpsd, scasb, scasw, scasd
Řetězcové instrukce pracují s dvojicí ds:esi jako source a es:edi jako destination. movs... přesune obsah [ds:esi] na adresu [es:edi]. lods... načte obsah [ds:esi] do al/ax/eax. stos... uloží al/ax/eax na adresu [es:edi]. scas... porovnává [ds:esi] s registrem al/ax/eax. Je tedy vhodná pro vyhledávání znaku v řetězci.
9 z 11
19.2.2007 7:51
Aleš Keprt - Elektronická učebnice Assembleru
http://student.inf.upol.cz/keprt/vyuka/asm/asm4.aspx
cmps... je určena k porovnávání dvou řetězců na adresách [ds:esi] a [es:edi]. Všechny tyto instrukce posouvají esi a edi, pokud s nimi pracují. Při použití cld se oba tyto registry zvyšují, při použití std se oba tyto registry snižují. Změna (zvýšení nebo snížení) hodnoty těchno registrů je o 1, 2 nebo 4 bajty - podle posledního písmena instrukce (b = byte, w = word, d=dword).
Pozor! Udržujte v programu stále nulový stav DF (cld). Je to obvyklá konvence, tj. ihned po použití std (což je samo o sobě raritní) ihned vraťte flag zpět pomocí cld. V modelech small a medium je implicitně udržováno ss=ds=es, jinak by tyto řetězcové instrukce nemohly fungovat. Zatímco cílový registr es je pevně daný, zjistil jsem, že zdrojový ds lze nahradit jiným segmentem pomocí instrukce segmenotého prefixu (seges, segfs nebo seggs). Tato vlastnost je nedokumentována, avšak předpokládám, že to nějakým způsobem plyne přímo z architektury procesoru, takže by to mělo fungovat vždy a všude. (Vyzkoušejte.)
Opakovací prefixy rep, repe/repz, repne/repnz Opakovací prefixy slouží k opakování řetězcové instrukce. Tyto prefixy jsou použitelné u každé instrukce procesoru, avšak pouze zde mají smysluplný význam. instrukce vhodný prefix lods
-
movs
rep
cmps
repe, repne
scas
repe, repne
stos
rep
Pro příklad uveďme funkci na kopírování paměti. V CRT (C runtime library) knihovně je funkce memcpy, která kopíruje blok paměti o zadané délce z jednoho místa na druhé. Ukažme tedy, jak toto napsat v Assembleru. memcpy proc kam:dword, odkud:dword, kolik:dword mov esi,odkud mov edi,kam mov ecx,kolik cld rep movsb ret memcpy endp
Uvedená ukázka je nejjednodušší možnou variantou, jak tuto funkci napsat. Lepší si můžete vyzkoušet sami v rámci cvičení.
10 z 11
19.2.2007 7:51
Aleš Keprt - Elektronická učebnice Assembleru
http://student.inf.upol.cz/keprt/vyuka/asm/asm4.aspx
6. Práce s bity Procesory 386 a novější mají instrukční sadu rozšířenou o instrukce pracující s jednotlivými bity. Na rozdíl od původních instrukcí (jako test) tyto nové instrukce číslují bity 0-7, 0-15 resp. 0-31.
Poznámka: Instrukce je třeba se naučit nazpaměť, včetně flagů, které ovlivňují. Jinak se v assembleru programovat nedá. Zpět
11 z 11
19.2.2007 7:51