Výuka assembleru
3. Aritmetické instrukce
Další sada instrukcí, které jsou v assembleru důležité, jsou aritmetické instrukce. Jejich funkcí je sčítání, odčítání, násobení a dělení. Pomocí aritmetických instrukcí můžeme pracovat s registry nebo s pamětí.
Ke sčítání slouží v assembleru instrukce add. Instrukce přičítá do prvního operandu hodnotu určenou druhým operandem:
add eax, 3 ; Přičte do registru EAX hodnotu 3 add esi, ebx ; Do registru ESI přičte hodnotu v registru EBX. add dword ptr [edi], 1 ; K 32bitové hodnotě v paměti, jejíž adresa ; je uložena v EDI, přičte hodnotu 1 add ebx, al ; Chyba - nesouhlasí velikost operandů
Instrukce musí sčítat operandy stejné velikosti. Nelze přičítat např. operand o velikosti 16 bitů k operandu o velikosti 32 bitů. Instrukce pro odčítání, sub, pracuje na podobném principu jako instrukce add:
sub eax, 3 ; Odečte z registru EAX hodnotu 3 sub esi, ebx ; Z registru ESI odečte hodnotu v registru EBX. sub dword ptr [edi], 1 ; Od 32bitové hodnoty v paměti, jejíž adresa ; je uložena v EDI, odečte hodnotu 1 sub ebx, al ; Chyba - nesouhlasí velikost operandů
Zvláštním případem sčítacích a odčítacích instrukcí jsou instrukce inc a dec. Tyto instrukce zvyšují, resp. snižují hodnotu uloženou v operandu o 1. Jejich výhodou oproti add a sub je menší velikost a rychlejší zpracování procesorem.
inc eax ; Zvýší hodnotu v registru EAX o 1 dec esi ; Sníží hodnotu v registru ESI o 1 inc al ; Zvýší hodnotu v registru AL o 1 dec byte ptr [edi] ; Sníží 8bitovou hodnotu, uloženou v paměti na adrese ; určené registrem EDI, o 1
Při sčítání a odčítání může dojít k tzv. přetečení. Je to situace, kdy se výsledek operace nevejde do registru, se kterým byla operace provedena:
mov eax, 0FFFFFFFFh ; Nejvyšší možná hodnota v registru EAX ... add eax, 4 ; ... a k ní přičteme 4. mov ebx, 0 ; Nejnižší hodnota registru je nula sub ebx, 6 ; Odečteme 6
V takovém případě (výsledek operace je 33-bitové číslo 100000003h) bude do registru, k němuž se přičítá, uloženo pouze spodních 32 bitů výsledku. To, že došlo k přetečení, procesor registruje nastavením příznaku CY (zkratka carry) v registru EFLAGS (V debug módu je hodnota tohoto příznaku zobrazena v okně "Registers" - klávesová zkratka Alt+5). V případě, že k přetečení nedošlo, ke hodnota příznaku CY vynulována. Podobně je situace řešena i v případě podtečení při odčítání.
Hodnotu příznaku CY je možné využít instrukcemi adc (Add with Carry) a sbc (Subtract with Carry). Instrukce adc přičítá do prvního operandu druhý operand a hodnotu příznaku CY (0 nebo 1). Instrukce sbc odečítá od prvního operandu druhý operand a hodnotu příznaky CY.
mov ebx, 1 mov eax, 0FFFFFFFFh ; Nejvyšší možná hodnota v registru EAX ... add eax, 4 ; ... a k ní přičteme 4. adc ebx, 5 ; EBX = EBX + 5 + CY = 7
Instrukce adc a sbc se používají např. při sčítání velkých (64bitových) čísel. Pokud chceme sečíst dvě 64bitové hodnoty uložené v EDX:EAX (první hodnota) a v ECX:EBX (druhá hodnota), provedeme to takto:
add eax, ebx adc edx, ecx
Pro operaci násobení máme v assembleru instrukci mul. Tato instrukce vynásobí registr EAX hodnotou prvního a jediného operandu instrukce. Výsledek operace násobení je 64bitové číslo, které je uloženo v registrech EDX (horních 32 bitů) a EAX (spodních 32 bitů):
mov eax, 1000h ; 1. činitel mov ebx, 2000h ; 2. činitel mul ebx ; Do EDX:EAX bude uložen výsledek EAX*EBX
Dělení se provádí instrukcí div. Instrukce dělí 64bitovou hodnotu uloženou v EDX:EAX hodnotou operandu instrukce. Výsledek je uložen do registru EAX (celočíselný podíl) a EDX (zbytek)
mov edx, 0h ; Horních 32 bitů mov eax, 10 ; Spodních 32 bitů mov ebx, 3 ; Dělitel div ebx ; V EAX je 3, v EDX je 1
Co nastane, pokud se pokusíme vydělit nějaké číslo nulou ? Z matematiky víme, že nulou dělit nelze. Pokud se o to přesto pokusíme, procesor na to reaguje generováním výjimky "Celočíselné dělení nulou". V debug módu Visual Studia se objeví hlášení:
Pokud program spustíte bez asistence Visual Studia nebo jiného debuggeru, dostanete obvyklé hlášení o tom, že program provedl neplatnou operaci a bude ukončen.
Copyright Ladislav Zezula 2003