Výuka assembleru

3. Aritmetické instrukce

<< Předchozí díl
Další díl >>

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í.

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

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

Násobení a dělení

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í:

Celočiselné dělení nulou

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.

<< Předchozí díl
Další díl >>