BLACK FRIDAY! Slevy až 80 % jsou všude. Tak je nepropásni a přejdi do rostoucího IT oboru!
BF Sales

Lekce 7 - Assembler - Datové typy a proměnné

V minulé lekci, Assembler - ASCII tabulka a spuštění v DOSBox, jsme si vysvětlili ASCII tabulku, dokončili popis Hello world! programu a spustili si jej jako .com soubor v emulátoru DOSBox.

V dnešní lekci se budeme podrobněji věnovat datovým typům v ASM a samozřejmě proměnným.

Typový systém

Datové typy v ASM nejsou rozdělené klasicky podle toho, pro jaký typ obsahu jsou určeny. Každý z nás zná určitě Int, String nebo Boolean z vyšších programovacích jazyků, které potom ve finále zabíraly v paměti určitý počet bajtů. Překladač také kontroloval, zda jednotlivé datové typy všude sedí. V ASM definujeme rovnou kolik paměti se má pro určitou proměnnou vyhradit a již nikdo nekontroluje, co do tohoto prostoru potom ukládáme.

Definice proměnných v ASM

Ve většině programovacích jazyků lze používat lokální a globální proměnné. Lokální proměnné existují jen dočasně během vykonávání funkcí. Budeme se jim tedy věnovat v lekci o funkcích. V této lekci se naučíme používat globální proměnné. Ty mají výhodu v tom, že existují po celou dobu běhu programu a jsou odevšad přístupné. Naopak velkou nevýhodou je, že je nelze použít při paralelních výpočtech v multithreaded aplikacích.

V minulých lekcí jsme si již proměnnou vytvářeli a také určili její datový typ. Bylo to u programu Hello world, kde proměnná hlwrld typu DB obsahovala text "Hello world!", končící ještě znaky pro konec řádku a řetězce:

hlwrld db "Hello, World!", 10, 13, 0

Globální proměnné v ASM tedy deklarujeme stylem: název definice_typu hodnota. Z toho vyplývá, že DB určuje nějaký datový typ proměnné. Pojďme si tyto direktivy představit blíže.

Direktivy DB, DW, DD, ...

V Assembleru nalezneme těchto pět typů proměnných, ale ve skutečnosti je to takový menší podvod. Jediný rozdíl je totiž jejich velikost. V této tabulce jsou direktivy a jejich velikosti:

Direktiva Celý název Typ Velikost Rozsah celých čísel Rozsah reálných čísel
DB Define Byte byte 1 bajt -128 až 255  
DW Define Word word 2 bajty -32768 až 65535  
DD Define Doubleword dword 4 bajty -2147483648 až 4294967295 -3.4e38 až 3.4e38
DQ Define Quadword qword 8 bajtů -9.2e18 až 1.8e19 -1.8e308 až 1.8e308
DT Define Ten Bytes tbyte 10 bajtů   -1.2e4932 až 1.2e4932

Typ tbyte je v překladači MASM. V překladači NASM je místo něj typ tword.

Nenechte se zmást slovem "Word", nejedná se o nic ve spojitosti se slovem nebo textem, ale pouze o termín určující velikost 2 bajty.

U direktiv define (to jsou všechny v tabulce uvedené) musíme proměnnou zároveň také inicializovat, nebo místo hodnoty napsat otazník.

Uložení čísla do proměnné

Číslo do proměnné v Assembleru uložíme velmi jednoduše, pouze určíme velikost v bajtech pomocí příslušné direktivy:

male_cislo DW 15
cislo DW 23093
negativni_cislo DW -23093
vetsi_cislo DD 342183449
desetinne_cislo DD 1.552
desetinne_cislo2 DQ 123.456
desetinne_cislo3 DT 13.8e200

Negativní čísla se ukládají jako dvojkové doplňky. Pro vícebajtové hodnoty procesor používá malou endianitu. Pokud vám tyto pojmy nic neříkají, jsou vysvětleny v kurzu Principy fungování počítačů.

Uložení řetězce do proměnné

Jak je ale možné, že do proměnné velikosti 1 byte můžeme uložit libovolně dlouhý textový řetězec? Při použití řetězce v uvozovkách nebo apostrofech '' v direktivě DB se pro každé písmeno samozřejmě vyhradí jeden bajt. Tento kód:

hlwrld db "Hello, World!", 10, 13, 0
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

Je vlastně jen zkrácený zápis:

hlwrld db "H", "e", "l", "l", "o", ",", " ", "W", "o", "r", "l", "d", "!", 10, 13, 0

Což je zkrácený zápis z:

hlwrld db "H"
       db "e"
       db "l"
       db "l"
       db "o"
       db ","
       db " "
       db "W"
       db "o"
       db "r"
       db "l"
       db "d"
       db "!"
       db 10
       db 13
       db 0

Doplnění řetězce na násobky bajtů

Možná vás napadlo, co by se stalo, kdybychom proměnnou s řetězcem definovali namísto DB např. pomocí DW nebo dalšími direktivami pro větší datové typy. Fungovalo by to, ale výsledek by vždy zabíral násobek počtu bajtů daného datového typu (např. v případě DW násobek 2) a text by byl na konci doplněný nulovými znaky, aby měl požadovanou délku. Např. text "ABCDEF" by byl při deklaraci jako:

text dd 'ABCDE'

uložený jako:

0x41 0x42 0x43 0x44 0x45 0x00 0x00 0x00

(tedy jako 8 bajtů, což jsou 2 doubleword)

Ale co ta divná čísla? Hodnoty bajtů v paměti většinou vypisujeme jako hexadecimální čísla, protože je tento zápis kratší. Kromě písmena H se čísla v šestnáctkové soustavě označují někdy také jako 0x. Již víme, že ASCII kód znaku A je 65 a vidíme, že první bajt má hodnotu 0x41, kde 41 hex je opravdu 65 dec a tedy znak A.

Jako řetězec můžeme uložit např. i znak "y"/"n" pro reprezentaci volby uživatele:

znovu DB 'y'

Neinicializovaná data

Když potřebujeme vyhradit v paměti určitý počet bajtů, například pro delší text nebo číselné pole, použijeme operátor DUP:

buffer DB 1000 dup(?)

V NASM se používá operátor TIMES:

buffer times 1000 DB 0

Proměnné a registry

Teď již víme, jak proměnné deklarovat a jaké jsou velikosti jednotlivých typů. Nyní si ukážeme, jak se dají proměnné kombinovat s registry a mezi sebou.

Stejně jako u registru je důležité dodržovat velikost. Nejdříve si ukážeme příklady pro kombinaci s registry pro překladač NASM.

value1 db 0           ; Definujeme proměnnou value1.
value2 dw 0           ; Definujeme proměnnou value2.
value3 dd 0           ; Definujeme proměnnou value3.
value4 dq 0           ; Definujeme proměnnou value4.

; s 8bitovým registrem
mov byte [value1], al ; Do proměnné value1 přesuneme hodnotu z registru AL.
mov al, byte [value1] ; Do registru AL přesuneme hodnotu z proměnné value1.

; s 16bitovým registrem
mov word [value2], ax ; Do proměnné value2 přesuneme hodnotu z registru AX.
mov ax, word [value2] ; Do registru AX přesuneme hodnotu z proměnné value2.

; s 32bitovým registrem
mov dword [value3], eax ; Do proměnné value3 přesuneme hodnotu z registru EAX.
mov eax, dword [value3] ; Do registru EAX přesuneme hodnotu z proměnné value3.

; s 64bitovým registrem
mov qword [value4], rax ; Do proměnné value4 přesuneme hodnotu z registru RAX.
mov rax, qword [value4] ; Do registru RAX přesuneme hodnotu z proměnné value4.

V překladači MASM je syntaxe trochu jednodušší:

value1 db 0           ; Definujeme proměnnou value1.
value2 dw 0           ; Definujeme proměnnou value2.
value3 dd 0           ; Definujeme proměnnou value3.
value4 dq 0           ; Definujeme proměnnou value4.

; s 8bitovým registrem
mov value1, al ; Do proměnné value1 přesuneme hodnotu z registru AL.
mov al, value1 ; Do registru AL přesuneme hodnotu z proměnné value1.

; s 16bitovým registrem
mov value2, ax ; Do proměnné value2 přesuneme hodnotu z registru AX.
mov ax, value2 ; Do registru AX přesuneme hodnotu z proměnné value2.

; s 32bitovým registrem
mov value3, eax ; Do proměnné value3 přesuneme hodnotu z registru EAX.
mov eax, value3 ; Do registru EAX přesuneme hodnotu z proměnné value3.

; s 64bitovým registrem
mov value4, rax ; Do proměnné value4 přesuneme hodnotu z registru RAX.
mov rax, value4 ; Do registru RAX přesuneme hodnotu z proměnné value4.

Přiřazení z proměnné do proměnné

Pokud chceme přenést hodnotu z jedné proměnné do druhé, musíme použít registr:

; přenesení hodnoty z jedné proměnné do druhé (v překladači NASM)
mov al, byte [value1] ; Do registru AL přesuneme hodnotu z proměnné value1
mov byte [value2], al ; Do proměnné value2 přesuneme hodnotu z registru AL

value1 db 0           ; Proměnná value1
value2 db 0           ; Proměnná value2

Takto bychom pracovali s číselnými hodnotami, ale jak se to dělá s textem?

Ukazovací registry

Pokud chceme pracovat s textem, je dobré naučit se pracovat s ukazovacími registry. Ty spadají pod univerzální registry a patří sem registry DI a SI. Pro "čtení" textu se používá SI a pro nějaké úpravy DI. Oba dva registry jsou 16bitové. Již jsme se s nimi setkali v lekci o programu Hello world.

Registr SI (Source Index)

Registr SI je ukazatel na zdrojová data při kopírovacích operacích.

Registr DI (Destination Index)

Registr DI je ukazatel na cílová data při kopírovacích operacích.

Zde je kód k programu nazvanému Písmenka. Program "analyzuje" větu v proměnné veta a vybere z ní písmenka "a", která přesune do proměnné pismenka. Pracuje se zde jak s registrem DI, tak s registrem SI. Kód je napsaný pro emulátor EMU8086, který najdete v příloze spolu s kódem:

org 100h

main:
mov di, [pismenka]                      ; Nastavíme registr DI na proměnnou pismenka
mov si, [veta]                          ; Nastavíme registr SI na proměnnou veta

get_char:
lodsb                                   ; Načteme znak z proměnné veta do registru AL
cmp al, 'a'                             ; Pokud je znak 'a'...
jz add_char                             ; ...skoč na add_char
cmp al, 0                               ; Pokud je číslo znaku 0 (null)...
jz continue                             ; ...skoč na continue
jmp get_char

add_char:
mov byte [di], al                       ; Přesuneme znak do registru DI (do proměnné pismenka, namísto registru AL můžeme napsat i 'a') a...
inc di                                  ; ...posuneme se na další místo v proměnné
jmp get_char

continue:
mov byte [di], 0                        ; Do registru DI (do proměnné pismenka) přesuneme číslo 0 (null)

mov si, [pismenka]                      ; Nastavíme registr SI na proměnnou pismenka

print:
lodsb                                   ; Načteme znak z proměnné pismenka do registru AL
cmp al, 0                               ; Pokud je číslo znaku 0 (null)...
jz return                               ; ...skoč na return
mov ah, 0eh                             ; Funkce BIOSu pro teletypový výstup
mov bx, 7h
int 10h                                 ; Vypiš znak
jmp print

return:
ret                                     ; Vrať kontrolu operačnímu systému

veta: db "Ahoj, jak se mas, Karle?", 0  ; Proměnná veta
pismenka: db 0                          ; Proměnná pismenka

Můžete si všimnout, jak se s takovými ukazovacími registry pracuje. Tady je jednodušší příklad:

mov di, [text]
mov byte [di], 97
inc di
mov byte [di], 98
inc di
mov byte [di], 99
inc di
mov byte [di], 0

mov si, text
print_string:
lodsb
or al, al
jz short end
mov ah, 0eh
mov bx, 7h
int 10h
jmp print_string
end:
ret

text: db 0

Přesunutím proměnné text do registru DI řekneme registru, na co má ukazovat. Následovně nastavíme první znak na "a", instrukcí INC posuneme ukazatel na další znak, kam zapíšeme "b" a tak dále...

Instrukce INC (Increment)

Instrukce INC má jeden parametr a tím může být registr nebo proměnná. Z anglického increment vyplývá, že instrukce má za úkol "přičíst číslo jedna" buď do registru, nebo do proměnné.

V příští lekci, Assembler - Instrukce pro práci s čísly, si probereme instrukce pro práci s čísly.


 

Stáhnout

Staženo 48x (2.68 MB)

 

Předchozí článek
Assembler - ASCII tabulka a spuštění v DOSBox
Všechny články v sekci
Základy assembleru
Článek pro vás napsal Jakub Verner
Avatar
Jak se ti líbí článek?
1 hlasů
Autor se věnuje programování v Assembleru a v C#. Rád se zlepšuje, rozšiřuje si znalosti a věří, že když člověk chce, dokáže cokoliv.
Aktivity (10)

 

 

Komentáře

Avatar
Jakub A. Štigler:3. července 15:07

Neměl by v tabulce být jeden byte 0 až 255 nebo -127 až 127 místo -128 až 255 (a ostatní hodnoty stejným způsobem)?

Editováno 3. července 15:09
 
Odpovědět
3. července 15:07
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Jakub Verner
Redaktor
Avatar
Odpovídá na Jakub A. Štigler
Jakub Verner:15. července 3:46

Ahoj, v Assembleru existuje BYTE (0 - 255), ale také SBYTE - SIGNED BYTE (-128 - 127). Oba dva se definují pomocí zkratky DB. Svým způsobem máš tedy pravdu, ale celkový číselný rozsah pro zkratku DB je tedy -128 - 255. Vlastně jsme jenom BYTE a SBYTE spojili dohromady pod jednu zkratku. U WORDu a ostatních je to to samé. Díky za komentář. :-)

Editováno 15. července 3:48
 
Odpovědět
15. července 3:46
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 2 zpráv z 2.