You are on page 1of 10

Počítače a jejich periférie – pc.

1 1

1 Mikroprocesory x86 – základy pro jejich programování


v jazyce symbolických instrukcí
Programování aplikací na osobních počítačích v jazyce symbolických instrukcí se může
zdát neaktuální. Přesto má dnes pochopení tohoto jazyka své výrazné opodstatnění.
Programování ve vyšších programovacích jazycích programátorovi ušetří rutinní práci
generováním kódu, který se v různých obměnách objevuje v každém programu, ale zároveň
před ním skryje (ale zároveň vyřeší) množství problémů, které je v jazyce symbolických
instrukcí nutné pracně ošetřovat. Jazyk symbolických instrukcí odkrývá spoustu technických
detailů souvisejících s architekturou procesoru, komunikací s hardwarem, strukturou dat a
posloupností kroků, které musí počítač provést, než např. vytiskne jednoduché "Ahoj".
Pochopení fundamentů, na kterých jsou vyšší jazyky vybudovány je dnes určitě největší
přínos tohoto jazyka. Existují oblasti (a budou existovat určitě ještě dlouho), ve kterých je
znalost jazyka symbolických instrukcí nepostradatelná:
• optimalizace algoritmů,
• programování překladačů, OS a ovladačů,
• poznání pozadí programování ve vyšším jazyce,
• návrhy nových čipů, procesorů,
• ochrana proti zpětnému inženýrství (dissasembling a cracking),
• tvorba virů a antivirů.

V počítačovém cvičení tohoto kursu se seznámíme se základy programování procesorů


řady x86 v jazyce symbolických instrukcí. Významným zjednodušením této problematiky
bude programování těchto mikroprocesorů v reálném režimu. V reálném režimu se může ke
všem mikroprocesorům kompatibilním s řadou x86 přistupovat jako k mikroprocesoru 8086.
Další podrobnosti o reálném režimu mikroprocesorů x86 jsou náplní přednášek tohoto kursu.

1.1 Registry mikroprocesoru 8086


15 8 7 0 15 0
AH AL AX CS
BH BL BX SEGMENTOVÉ DS
DATOVÉ
REGISTRY REGISTRY
CH CL CX SS
DH DL DX ES
IP
UNIVERZÁLNÍ 15 0
UKAZATELÉ BP
REGISTRY FLAGS
SP
SI
INDEXY
DI

Obrázek 1.1: Přehled základních registrů mikroprocesoru 8086

Ing. Miroslav Balík. Ph.D.


2 Fakulta elektrotechniky a komunikačních technologií VUT v Brně

K dispozici je z dnešního pohledu poměrně malý počet registrů. Konkrétně je zde 9


univerzálních registrů, které se dělí na datové registry, ukazatele a indexy. Pro práci s pamětí
se používají 4 segmentové registry. Z pohledu programátora je také důležitý registr příznaků,
který umožňuje zpětnou vazbu během vykonávání instrukcí běžícího programu. Všechny tyto
registry jsou 16-i bitové.
Každý z datových registrů je rozdělen na svou dolní a horní část, kdy každá z částí je
vždy 8-i bitová. Pro 16-i bitový registr ax platí, že jeho dolní část se označuje al (low) a horní
část se označuje ah (high).
Výčet registrů:
ax akumulátor, střadač (accumulator)
bx bázový registr (base)
cx čítač (counter)
dx datový registr (data)
ip ukazatel na instrukci (instruction pointer)
bp ukazatel na bázi (base pointer)
sp ukazatel do zásobníku (stack pointer)
si zdrojový index (source index)
di cílový index (destination index)
cs kodový segmentový registr (code segment register)
ds datový segmentový registr (data segment register)
ss zásobníkový segmentový registr (stack segment register)
es extra segmentový registr (extra segment register)
flags registr příznaků nebo také tzv. vlajky

1.2 Implicitní využití registrů

Aktuální použití registrů je buď určeno explicitně, tedy je specifikováno přímým


zápisem v jazyce symbolických instrukcí nebo implicitně, kdy se k vykonání dané operace
použije jeden nebo více registrů automaticky bez jejich přímé specifikace. Z pohledu
programátora je důležité, aby implicitní využití registrů znal, jinak může docházet k nechtěné
změně obsahu registrů, které způsobí nefunkčnost programu.

Vybrané implicitní využití registrů:


ax násobení, dělení a V/V s 16-i bitovými slovy
al násobení, dělení a V/V s 8-i bitovými slovy, desítková aritmetika
ah násobení, dělení s 8-i bitovými slovy
cx řetězcové operace, smyčky
cl posuvy, rotace
dx násobení, dělení s 16-i bitovými slovy, nepřímé V/V

Ing. Miroslav Balík. Ph.D.


Počítače a jejich periférie – pc.1 3

Podrobný výčet implicitně používaných registrů je vždy uveden v nápovědě ke každé


operaci (instrukci nebo službě). Tyto informace jsou uvedeny např. v systémovém manuálu
(Sysman).

1.3 Organizace paměti v reálném režimu

Maximální adresovatelný prostor má velikost 1 MB (220)


• 20-i bitová adresa v rozsahu 0...0FFFFFh
Paměť je vždy rozdělena na tzv. segmenty s těmito vlastnostmi.
• je adresován 16-i bity (216)
• vždy je to souvislá část paměti o velikosti 64 kB
• počáteční (bázová) adresa segmentu je vždy dělitelná 16-i
• mohou se dotýkat, překrývat, mohou být oddělěny
Segmenty se rozdělují na (nezaměňovat s názvy segmentových registrů):
• kódový (code segment CS) – část paměti pro program
• zásobníkový (stack segment SS) – část paměti pro účely zásobníku, odkládání
mezivýsledků apod.
• datový (data segment DS) – část paměti pro data a operandy
• extra datový (extra segment ES) – část extra paměti, většinou pro další data

Konkrétní místo v segmentu je určeno pouze tzv. relativní adresou – offsetem. Způsob
adresování ukazuje Obrázek 1.2.

ROSTOUCÍ OPERAČNÍ
ADRESA
PAMĚŤ

KÓDOVÝ ADRESA V K.S.


15 0 64kB
SEGMENT OFFSET
CS
B.A.
SS
ZÁSOBNÍKOVÝ ADRESA V Z.S.
DS 64kB
SEGMENT OFFSET
ES B.A.
ADRESA V D.S.
DATOVÝ
64kB
SEGMENT OFFSET

B.A.

Obrázek 1.2: Použití segmentových registrů při adresování segmentů

Ing. Miroslav Balík. Ph.D.


4 Fakulta elektrotechniky a komunikačních technologií VUT v Brně

Obecně se pro adresování např. kódového segmentu použije bázová adresa (B.A.)
uložená v kódovém segmentovém registru CS. Podobně je tomu i u ostatních segmentů.
Konkrétní adresa je pak určena pouze její „vzdáleností“ od báze daného segmentu relativní
adresou – offsetem. Adresa je tedy specifikována dvousložkově, jednou složkou je obsah
odpovídajícího segmentového registru a druhou složkou je offset v rámci odpovídajícího
segmentu.
„Vytváření“ hodnoty offsetu je dáno způsobem adresování a je podrobně uvedeno
v přednáškách.

1.4 Logická a fyzická adresa

Jak bylo uvedeno dříve, z programátorského hlediska se používá tzv. dvousložková


adresa. Skutečné adresy v paměti jsou však vždy jednosložkové. Během procesu adresování je
vždy nutné transformovat jeden typ adresy na druhy typ adresy. Pro dvousložkovou adresu se
používá název logická adresa a pro jednosložkovou adresu fyzická adresa. Obrázek 1.3
znázorňuje souvislost mezi logickou a fyzickou adresou a také možným umístěním segmentů
v paměti.
FYZICKÁ ADRESA

12340h 12348h 12350h

0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2

PAMĚŤ

1234 : 0000h 1234 : 0008h 1234 : 0010h

POČÁTEK SEGMENT
SEGMENTU

1235 : 0000h

LOGICKÁ ADRESA POČÁTEK


SEGMENTU

Obrázek 1.3: Logická a fyzická adresa, umístění segmentů v paměti

Na obrázku je znázorněna část paměti (19 paměťových buněk) s rostoucí adresou.


Nahoře je paměť popsána pomocí fyzických adres a dole je paměť popsána odpovídajícími
logickými adresami. Všechny adresy jsou uvedeny v hexadecimálním kódu.
Jak již bylo zmíněno, celkový adresovatelný prostor je 220 (1 M) byte, takže fyzická
adresa v hexadecimálním kódu má vždy 5 platných číslic (20-i bitová adresa). Fyzická adresa
12340h odpovídá např. logické adrese 1234:0000h, tedy v 16-i bitovém segmentovém registru
je uložena hodnota 1234h a offset je nastaven na hodnotu 0000h.

Ing. Miroslav Balík. Ph.D.


Počítače a jejich periférie – pc.1 5

Vždy, když je v logické adrese offset roven 0, tak je na této adrese počátek (báze)
segmentu. Počátek dalšího segmentu tedy může existovat každých 16 adres v paměti. Takže
fyzické adrese 12350h odpovídá kromě logické adresy 1234:0010h, také adresa 1235:0000h a
následně dle tohoto principu také další logické adresy.
Výpočet fyzické adresy:
1. Posun binárního obsahu segmentového registru o 4 bity vlevo (v hexadecimálním
kódu posun o 1 platnou číslici vlevo).
2. Přičtení offsetu.

Příklad výpočtu: 1234 : 0022h Logická adresa

12340h
0022h
12362h Fyzická adresa

1.5 Nejpoužívanější typy operandů

Typy operandů jsou u mikroprocesoru 8086 poměrně omezené. Obecně se operandy


dělí na čísla a znaky. Obecně platí, že se mohou vyjadřovat v různých číselných soustavách.
Používají se nejčastěji tyto číselné soustavy:
• Binární (dvojková) 1110b
• Dekadická (desítková) 14d
• Hexadecimální (šestnáctková) Eh
• Oktalová (osmičková) 16q
Při vyjadřování hodnoty čísel je vždy nutné používat písmeno na konci čísla, které
podává informaci o číselné soustavě, v které jsou čísla uvedena. Z hlediska úspory délky
zdrojového kódu se ve většině případů používá k vyjadřování čísel hexadecimální soustava.

HEXADECIMÁLNÍ POPIS BINÁRNÍ POPIS

ŠÍŘKA 8 BITŮ
ULOŽENÁ
HODNOTA

F1h 1 1 1 1 0 0 0 1 b
ADRESA

Fh 1h
1111b 0001b

Obrázek 1.4: Způsob uložení jednoduchého operandu (byte) v paměti

Ing. Miroslav Balík. Ph.D.


6 Fakulta elektrotechniky a komunikačních technologií VUT v Brně

Do jedné buňky paměti je možné uložit právě 8 bitů (1 byte). Obrázek 1.4 ukazuje
způsob uložení 1 byte v paměti a souvislost mezi hexadecimálním a binárním popisem
uložené hodnoty. Je samozřejmě nutné pracovat i s operandy, které mají větší rozsah, než
umožňuje popis pomocí 1 byte.

Typy operandů:
1. Čísla – celá (se znaménkem i bez znaménka).
8 bitů INTEGER BYTE
16 bitů INTEGER WORD
32 bitů INTEGER DOUBLEWORD

2. Znaky – kód ASCII (American Standard Code for Information Interchange), znak
je vyjádřen číslem, které vyjadřuje pořadí v tabulce 0 – 255 (definováno právě
jedním Bytem).

3. Řetězce znaků – souvislý soubor znaků, které jsou jednotlivě popsaný kódem
ASCII

1.6 Způsob ukládání operandů

Operandy je možné ukládat do registru nebo do paměti. Způsoby ukládání se od sebe


liší dle typu operandu. Prakticky je vždy výhodnější (pokud jsou volné registry k dispozici)
ukládat operand do registru, protože operace zápisu a čtení registru je mnohonásobně
rychlejší, než stejný přístup do paměti.
Pokud se ukládá operand o velikosti 1 byte, je možné jej uložit přímo do 8-i bitové dolní
nebo horní části registru nebo do 16-i bitového registru přímo (pak je uložen vždy v jeho
dolní části). Pokud se ukládá 1 byte do paměti, je to jednoduché, operand obsadí právě jednu
buňku v paměti, která je popsána svou adresou.
Pokud se ukládají operandy, které svou velikostí přesahují 1 byte, jednotka pro správu
sběrnice funguje následujícím způsobem, který znázorňuje Obrázek 1.5.

• Do registru je možné uložit maximálně 2 byte:


• Číslo – nejvyšší bit MSB (most significant bit) je vždy uložen vlevo.
• Řetězec znaků – uložen v přirozeném pořadí zleva doprava.
• Do paměti:
• Číslo – uloženo v obráceném pořadí, nejméně významný byte je vždy
uložen na adrese operandu, významnější byty jsou uloženy postupně na
vyšších adresách. Na nejvyšší adrese je uložen nejvýznamnější byte.
• Řetězec znaků – uložen v přirozeném pořadí, na adrese operandu je uložen
první znak řetězce, na vyšších adresách se postupně uloží další znaky až
do konce řetězce.

Ing. Miroslav Balík. Ph.D.


Počítače a jejich periférie – pc.1 7

32b CELÉ ČÍSLO ŘETĚZEC ZNAKŮ

„AHOJ“ - ŘETĚZEC ČTYŘ ZNAKŮ


F1A26327h
41h, 48h, 4Fh, 4Ah - ASCII KÓD

n+3 F1h m+3 4Ah


n+2 A2h m+2 4Fh
n+1 63h m+1 48h
n 27h m 41h
ADRESA ADRESA
ČÍSLA ŘETĚZCE

Obrázek 1.5: Srovnání uložení operandů velikostí přesahujících 1 byte

1.7 Jazyk symbolických instrukcí

V jazyce symbolických instrukcí se požívají dva prostředky – instrukce a direktivy


(pseudo-instrukce). Instrukce je během překladu změněna do hexadecimální podoby a po
spuštění programu existuje jako datová položka v kódovém segmentu. Direktiva se během
překladu přímo nemění do nějaké konkrétní hexadecimální podoby, direktiva pouze slouží
jako informace pro překladač, jakým způsobem se má překlad konkrétního zdrojového kódu
provést. Direktiva se v přeloženém hexadecimálním kódu nijak přímo nevyskytuje (na rozdíl
od instrukce).
Syntaxe instrukce a direktivy:

INSTRUKCE:
[návěští:] _ název instrukce _ [operandy] _ [;komentář]

DIREKTIVA (PSEUDO-INSTRUKCE):
[identifikátor] _ název direktivy _ [parametry] _ [;komentář]

Položky uvedené v závorce jsou z hlediska syntaxe nepovinné. Obecně se zápisem


instrukce nebo direktivy začíná od začátku řádku, pokud mají návěští nebo identifikátor. Další
odpovídající si položky je vhodné řadit pod sebe, aby byl zdrojový kód přehledný. Znak „ _ “
znamená obecně mezeru popředí, ve zdrojovém kódu se doporučuje používat tabelátor pro
zajištění řazení položek pod sebe. Syntaxe direktiv ve verzi NASM nemá tak striktní podobu,
jako ve verzi TASM, v NASM se může syntaxe měnit dle direktivy. I když je komentář
nepovinný, doporučuje se jej psát pro pochopení prováděných operací.

Ing. Miroslav Balík. Ph.D.


8 Fakulta elektrotechniky a komunikačních technologií VUT v Brně

1.8 Nejpoužívanější direktivy

Direktiva SEGMENT nebo SECTION – definuje segment v paměti.


section _ .name _ [align] _ [use] _ [class]
align – zarovnání (4 B,8 B,16 B)
use – volba USE16/USE32
class – třída segmentu (CODE, DATA, STACK)

Direktivy DB, DW, DD, DQ, DT – definují název (identifikátor), datový typ adresy a
výchozí hodnotu dat.
[name] _ dX _ value1[,value2]
name – jméno (identifikátor) adresy
value – hodnota, která bude na adrese uložena po spuštění programu. Je možné
zadávat více hodnot najednou, hodnoty se oddělují čárkou. Každá zadaná
hodnota zabírá podle nadefinovaného typu odpovídající počet buněk
(bytů) paměti.
dX – volba datového typu: db – 1B, dw –2B, dd – 4B, dq – 8B, dt – 10B

Direktiva TIMES – opakování stejné hodnoty nebo specifické instrukce, příklad uveden
pro použití s direktivou dX
name _ times _ value1 _ db _ value2
name – jméno (identifikátor) adresy
value1 – počet opakování
value2 – opakovaná hodnota
od adresy se jménem name bude směrem k vyšším adresám value1 krát
opakována hodnota value2

Direktivy RESB, RESW, RESD, RESQ, REST – definují název (identifikátor) a


datový typ adresy, která není inicializována.
name: _ resx _ value
name – jméno (identifikátor) adresy
value – počet jednotek zvoleného datového typu
resx – volba datového typu: resb – 1B, resw –2B, resd – 4B, resq – 8B, rest –
10B

Direktiva EQU – přiřadí jménu konstantní hodnotu.


name _ equ _ value

Ing. Miroslav Balík. Ph.D.


Počítače a jejich periférie – pc.1 9

Direktiva ORG – nastaví hodnotu lokačního čítače v segmentu.


org _ value
value – obsah (číslo) lokačního čítače v aktuálním segmentu

Direktiva MACRO (párová) – definuje makro – sloučí sousled instrukcí pod


jednoduché jméno (identifikátor) s možností předání parametrů.
%macro _ name _ value
…%1…
…%2…
%endmacro
name – jméno (identifikátor) makra
value – počet vstupních parametrů
%X – identifikátory parametrů, které se používají uvnitř makra, číslo X
představuje pořadí zadání parametru během volání makra

Direktiva STRUC (párová) – definuje strukturu – sloučí definici více názvů a typů
adres do struktury, využívá se pro násobné definování stejné struktury v paměti.
struc _ name
[name1] _ dX _ value1[,value2]
[name2] _ dX _ value3[,value4]
[name3] _ dX _ value5[,value6]


endstruc
name – jméno (identifikátor) struktury
namex – jména (identifikátory) adres, viz direktiva DB, DW, DD, DQ, DT,
Položka struktury se pak v kódu volá konvencí name.namex.

1.9 Návěští v NASM

Ve verzi NASM se s návěštími pracuje odlišně v porovnání s TASM. Návěští jsou


v tomto případě použity např. pro definici adres neinicializovaných dat, jak bylo patrné
v předcházející kapitole. V NASM také neexistuje direktiva pro definování podprogramů. Pro
definici začátku podprogramu se jednoduše použije návěští a konec podprogramu je
automaticky chápán jako návrat z podprogramu instrukcí ret.
Zdrojové kódy, které mají být po překladu do formátu .obj dále linkovány, používají pro
první instrukci speciální návěští ..start: se dvěmi tečkami. Ve zdrojových kódech, které se
překládají přímo (typicky .com) je nutné obvyklé návěští start:.

Ing. Miroslav Balík. Ph.D.


10 Fakulta elektrotechniky a komunikačních technologií VUT v Brně

1.10 Rozdělení instrukcí

Mikroprocesor 8086 má instrukční soubor s celkovým počtem 104 jedinečných


instrukcí. Instrukce lze rozdělit do 5 skupin:
• Instrukce přenosu dat (15) – přenos dat může probíhat mezi registry, mezi registry
a pamětí, mezi registry a zásobníkem a mezi registry a V/V branami.
• Aritmetické a logické instrukce (33) – zahrnují sčítání, odečítání, násobení a
dělení různých formátů dat. Slovní nebo slabikové posuvy a rotace, logické funkce
negace, součinu, součtu a neekvivalence. Podle výsledku se nastavují příznakové
bity.
• Instrukce pro práci s řetězci (18) – přesuny, porovnávání a prohlížení hodnot
řetězců až do délky 64 kB. Speciální instrukční předpona rep (times) dovoluje
opakování řetězcové operace technickými prostředky s možností přerušení.
• Instrukce řízení běhu programu (26) – podmíněné a nepodmíněné skoky, cykly,
volání a návraty z podprogramů. Tyto instrukce mění obsah registru ip (případně
cs).
• Instrukce řízení procesoru (12) – nulování a nastavování příznakových bitů,
synchronizace procesoru s externími ději, vyvolání a návrat z přerušení.
Podrobný výčet a popis instrukcí je mimo rozsah tohoto textu a je popsán v kapitole
instrukční soubor 8086 nebo v systémovém manuálu (Sysman).

Ing. Miroslav Balík. Ph.D.

You might also like