Výuka assembleru
5. Práce s pamětí
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.
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.
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ů | - | - | - |
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.
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)
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.
Copyright Ladislav Zezula 2003