Výuka assembleru

5. Práce s pamětí

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

Při psaní programů v assembleru brzy zjistíme, že nám registry pro ukládání dat nestačí. Pak přijde na řadu ukládání dat do paměti. Tento díl popisuje, jak jsou data v paměti uspořádána a jaké instrukce můžeme pro práci s pamětí využít.

Adresa: byte@paměť.počítač.cz

Aby bylo možné data do paměti uložit a zase je v paměti najít, má paměť pevně danou strukturu. Nejmenší jednotkou dat v paměti je byte, tedy 8 bitů. Každý bajt v paměti má svoji adresu, podobně jako každý obyvatel města. Adresa bytu v paměti je číslo, počítané od nuly. Maximální velikost adresy vždy závisí na tom, kolikatibitový máme operační systém. Současné verze Windows jsou 32bitové, to znamená, že adresa v paměti je 32bitová hodnota. S velikostí adresy v paměti také úzce souvisí maximální množství paměti, kterou může aplikace využívat. Na 32bitových verzích Windows můžeme tedy adresovat maximálně 0FFFFFFFFh dat, tedy přesně 4 GB.

Jednotky dat

Bajt jako nejmenší jednotka dat v paměti nestačí, proto existují jednotky větší. Jejich české názvy jsou odvozeny od názvů anglických a jejich přehled uvádí následující tabulka:

Název Velikost v bitech Velikost v bytech Číselný rozsah Typ v assembleru Typ v C++
Bajt (byte) 8 bitů 1 bajt 0 - 255 byte, db (unsigned) char
Slovo (word) 16 bitů 2 bajty 0 - 65 535 word, dw (unsigned) short
Dvojslovo (double word) 32 bitů 4 bajty 0 - 4 294 967 295 dword, dd (unsigned) long
Čtyřslovo (quadword) 64 bitů 8 bajtů 0 - 18 446 744 073 709 551 615 qword, dq (unsigned) __int64
Kilobajt (kilobyte) - 1024 bajtů - - -
Megabajt (megabyte) - 1024*1024 bajtů - - -

Kam ta data uložit ?

Pro uložení dat v programu je nutné pro ně vyhradit místo, tj. deklarovat proměnnou. Je to obdobné jako při deklaraci proměnných ve vyšších programovacích jazycích (C++, Pascal). Při deklaraci uvádíme název proměnné, její velikost a počáteční hodnotu. Je dobrým zvykem ukládat proměnné do sekce označené .data. Deklaraci několika proměnných různého typu ukazuje příklad:

.data

JedenZnak        db     12h         ; Proměnná "JedenZnak" o velikosti 1 bajt (db)
                                    ; s počáteční hodnotou 12h
PocetBodu        dw     0           ; Proměnná "PocetBodu" o velikosti 2 bajty (dw)
                                    ; s počáteční hodnotou 0
VelikostSouboru  dd     ?           ; Proměnná "VelikostSouboru" o velikosti 4 bajty (dd)
                                    ; bez nastavené počáteční hodnoty
VelikostDisku    dq     ?           ; Proměnná "VelikostDisku" o velikosti 8 bajtů (dq)
                                    ; bez nastavené počáteční hodnoty

.code

; Kód

end

Při překladu programu kompilátor vyhradí pro proměnné vhodné místo v programu a pokud je pro ně nastavena počáteční hodnota, je uložena přímo do programu. Při ukládání a čtení dat z proměnných používáme místo adresy proměnné její jméno.

Instrukce pro přístup do paměti

Pro přístup do paměti se používají stejné instrukce, se kterými jsme se doposud seznámili. Tedy instrukce pro práci s registry a aritmetické instrukce. Pokud chceme nějakou hodnotu uložit/načíst/přičíst/odečíst/atd. z/do paměti místo z/do registru, uvedeme u instrukce operand, znamenající adresu. Tento operand poznáme podle hranatých závorek:

        mov     [eax], ebx      ; Uloží hodnotu registru EBX do paměti, jejíž adresa
                                ; je v registru EAX
        mov     ebx, [eax]      ; Do registru EBX zkopíruje hodnotu z paměti,
                                ; jejíž adresa je v registry EAX
        mov     eax, [00400000] ; Do registru EAX načte dvojslovo z paměti
                                ; o adrese 00400000h
        mov     al, [JedenZnak] ; Do registru AL načte hodnotu proměnné JedenZnak
        add     al, [JedenZnak] ; Do registru AL přičte hodnotu proměnné JedenZnak
        add     [PocetBodu], 1  ; Do proměnné PocetBodu přičte 1
        dec     [PocetBodu]     ; Sníží hodnotu proměnné PocetBodu o 1

Při přístupu do paměti je nutné zachovat shodu velikosti proměnné a registru. Jestliže je např. proménná "JedenZnak" v předchozím příkladě jednobajtová, nemůžeme její hodnotu načíst do dvoubajtového registru:

        mov     ax, [JedenZnak] ; Chyba "invalid instruction operands"

Pokud ukládáme do paměti číslo a jako adresu používáme registr nebo konstantu, musíme navíc uvést, jak velká proměnná na adrese je:

        mov     [eax], 1            ; Chyba - překladač neví, zda "1" je 8bitová,
                                    ; 16bitová, 32bitová nebo 64bitová

        mov     byte ptr [eax], 1   ; Správně (ukládáme 1 bajt)
        mov     word ptr [eax], 1   ; Správně (ukládáme 2 bajty)
        mov     dword ptr [eax], 1  ; Správně (ukládáme 4 bajty)

Platné a neplatné adresy

Adresy v paměti jsou poměrně pevně dané operačním systémem. Při pokusu o zápis nebo čtení hodnoty z paměti, jejíž adresu si "vymyslíme", dojde ve většině případů k vygenerování vyjímky "access violation", což vede ke známému hlášení "Program provedl neplatnou operaci a bude ukončen":

    mov     eax, [0C4568755h]       ; Chyba - z této adresy nelze číst
                                    ; ani do ní zapisovat

Proto se téměř nepoužívá přístup do paměti pomocí adresy zadané číselnou konstantou. Pokud nevíte, co na té adrese je (což vyžaduje velmi dobrou znalost operačního systému), nezapisujte tam ani odtud nenačítejte. Pro ukládání do paměti si vždy nadeklarujte proměnnou, její adresu za vás zařídí překladač a operační systém.

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