dodání ihned! nové
Black Friday je tu! Využij jedinečnou příležitost a získej až 80 % znalostí navíc zdarma! Více zde
BF

Lekce 1 - Úvod do programování v Assembleru

Vítejte u kurzu, ve kterém se spolu ponoříme až do hloubek, kam se vůbec jako programátoři můžeme dostat. Obejdeme programovací jazyk i kompiler a zjistíme, jak funguje samotný stroj. Budeme posílat přímo instrukce procesoru, pochopíme architekturu x86, BIOS, jak se adresuje paměť a zavádí operační systém. Tato problematika souvisí také s reverse-engineeringem, crackováním softwaru a samozřejmě hackingem. Naučí vás používat nástroje jako disassemblery, cheat enginy a lépe pracovat s debuggery.

Hacking

Kurz zahajme slavnou citací:

Don't learn to hack, hack to learn!

Předpoklady

Kurz předpokládá znalost alespoň základů fungování počítače po hardwarové stránce a zkušenost s libovolným vysokoúrovňovým programovacím jazykem (např. C nebo Java).

Proč se dnes učit Assembler?

Vždy mě zajímalo, jak věci v základu fungují a namísto toho, abych používal něco, co už existuje, jsem si raději udělal něco svého. Například máme doma rádio. A já, namísto toho, abych ho používal, začal jsem se stavbou vlastního AM rádia. A nebo většina z nás používá operační systém Windows... No a co jsem asi udělal... Ano, začal jsem pracovat na vlastním operačním systému v Assembleru.

Co se tu budeme učit je samozřejmě velmi speciální a úzké zaměření. Komerčně dnes tyto znalosti uplatníte ve sféře kyberbezpečnosti nebo při programování pro některá nízkoúrovňová embedded zařízení, případně pro high-performance programování. A nebo když se budete chtít pokusit donutit dělat nějakou cizí aplikaci to, co od ní chcete, případně si naprogramovat zavaděč operačního systému. To samozřejmě není tak snadné, ale někde se začít musí :)

Abychom pochopili, jak vůbec ASM funguje, podívejme se ve zkratce na historii programovacích jazyků.

Vývoj programovacích jazyků

1. generace jazyků - Strojový kód

Procesor počítače umí vykonávat jen omezené množství jednoduchých instrukcí, které jsou uloženy jako sekvence bitů, jsou to tedy čísla. Ta se mu obvykle zadávají v hexadecimální (šestnáctkové) soustavě. Instrukce jsou tak elementární, že umožňují pouze např. práci s registry procesoru (to je paměť v CPU) nebo skoky. Nelze např. jednoduše sečíst dvě čísla, musíme se na čísla dívat jako na adresy v paměti a takové sečtení čísel zabere několik instrukcí. Program sčítající dvě čísla by vypadal např. takto:

B853000000
BBFEFFFFFF
03C3
C3
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

Instrukce se procesoru předloží v binární podobě. Takovýto kód je samozřejmě extrémně nečitelný a závisí na instrukční sadě daného CPU. Každý počítačový program musí být nakonec do tohoto jazyka přeložen, aby mohl být na procesoru počítače spuštěn.

Strojový kód

2. generace jazyků - Assembler

Assembler neboli JSA (Jazyk Symbolických Adres) se objevil někdy v polovině 20. století. Konkrétně se jednalo o jazyk druhé generace. Od jazyků první generace se lišil tím, že namísto toho, abychom si museli pamatovat číselné kódy instrukcí, jsme mohli psát jejich slovní kódy (například: MOV, CMP, ADD).

Díky Assembleru bylo psaní programů jednodušší a přehlednější, než kdybychom je psali v číslech. Další výhodou bylo, že adresy v programu se nemusely měnit přepisováním celého programu jako tomu bylo u první generace. Co se týče kódu samotného, nemusely se opět např. složitě vypočítávat adresy skoků. Kód tedy začal být vůbec lidsky čitelný, i když není o nic jednodušší, než původní strojový kód.

Stejný program by v ASM vypadal takto:

.code
main:
mov eax,83
mov ebx,-2
add eax,ebx
ret
end main

Vidíme, že je to poněkud lidštější, ale stále nezasvěcení lidé vůbec netuší, jak program funguje.

3. generace jazyků

Jazyky v třetí generaci konečně nabízí uživateli určitou abstrakci nad tím, jak program vidí počítač, zaměřují se na to, jak program vidí člověk. Jsou označovány jako tzv. vyšší programovací jazyky (anglicky High Level Languages, někdy zkráceně HLL). Naše čísla jsou vnímána již jako proměnné, zdrojový kód připomíná matematický zápis.

Jedním z prvních vysokoúrovňových programovacích jazyků byl jazyk C. I když jej předběhl Fortran nebo Pascal, tak to byl právě jazyk C, který dobyl svět. Opět ten samý programy by v jazyce C vypadal takto:

int main(void)
{
    int a, b, c;
    a = 83;
    b = -2;
    c = a + b;
    return c;
}

V kontrastu současných objektově orientovaných moderních jazyků je jazyk C často označován jako jazyk nízkoúrovňový. Jak to tedy je? Od příchodu jazyka C zkrátka uběhlo již několik dekád a záleží s čím jej porovnáváme. V našem kontextu s ASM je nazýván vysokoúrovňovým, v kontextu např. s jazykem C# .NET je naopak nízkoúrovňový.

Všichni asi tušíme, co program dělá, sečte čísla 83 a -2 a výsledek uloží do proměnné c. U všech jazyků třetí generace je samozřejmě výhodou vysoká čitelnost.

Překlad vyšších programovacích jazyků

Tyto jazyky tedy mají svůj zdrojový kód v jazyce, kterému lidé dobře rozumí. Zdrojový kód se samozřejmě musí přeložit do binárního kódu, aby ho bylo možné na procesoru spustit. Tento překlad zajišťuje překladač (kompiler), který přeloží najednou celý program do strojového kódu. Některé kompilátory umějí kromě strojového kódu vygenerovat také kód assembleru.

Kompiler

Některé moderní programovací jazyky (např. C#, Java) se nepřekládají přímo do strojového kódu, ale používají binární mezikód. Ten se kompiluje do strojového kódu až na počítači uživatele (buď hned po instalaci aplikace nebo při jejím spuštění). To má výhodu v tom, že binární mezikód je nezávislý na procesoru. Vývojář aplikace tedy nemusí dávat ke stažení zvlášť verze pro x86, x64, nebo ARM. Nevýhodou je to, že uživatel musí mít nainstalovaný framework pro daný programovací jazyk.

Pokud budeme vědět, jak vypadají v ASM rutiny např. C překladače, budeme schopní pochopit, jak tyto programy fungují nebo je dokonce modifikovat, aniž bychom od nich měli zdrojový kód. Jedná se ale samozřejmě o velmi komplexní problematiku, protože sebemenší funkce vyústí ve velké množství ASM instrukcí a kompiler ve výsledné podobě ještě provádí četné optimalizace. Pojďme jim věnovat alespoň krátký odstavec.

Optimalizace překladače

Když bychom psali v čistém ASM, velmi pravděpodobně bude náš program pomalejší než ten samý program zkompilovaný např. z jazyka C. Jak je to možné? Kompiler totiž kód upraví tak, aby byl velmi rychlý a to často za cenu, že je pro člověka pak špatně čitelný. Určitě jste všichni někdy použili cyklus. Ten má nějakou řídící proměnnou, podmínku a zkrátka režii navíc. Proto se může někdy optimizer rozhodnout, že bude lepší cyklus nepřeložit, ale namísto toho kód jen několikrát zopakovat za sebou. Pokud vás problematika zajímá, doporučuji krásný článek Překladače pod pokličkou - optimalizace.

Specifika programování v Assembleru

A jak tedy takové programování v Assembleru vypadá?

Pokud si budeme programovat svůj vlastní operační systém, pak nemáme k dispozici žádné předem vytvořené funkce. Nebudeme moct použít žádné PrintString(), ClearScreen(), ani SetCursorPosition(). Úplně všechno si budeme muset vytvořit sami.

Pokud bychom vytvářeli aplikaci pro historický operační systém MS-DOS, pak máme k dispozici několik funkcí, které se volají přerušením INT 21H (k přerušením se v kurzu brzy dostaneme). Toto přerušení je dostupné pouze v operačním systému MS-DOS, což znamená, že ho (ani ostatní) nebudeme používat. My si vystačíme s přerušeními, která nabízí BIOS.

Při programování aplikací pro moderní operační systémy (např. Windows nebo Linux) můžeme v Assembleru využívat všechna API konkrétního operačního systému. Například můžeme číst a zapisovat data do souborů, ovládat aplikaci klávesnicí a myší, zobrazit text na obrazovce. Naopak ale nesmíme používat přerušení BIOSu. Také nemůžeme používat všechny instrukce procesoru. Některé instrukce jsou totiž privilegované a jsou povoleny pouze pro jádro operačního systému a ovladače. V naší aplikaci nemůžeme přímo přistupovat k hardware, používat přerušení nebo přepínat režimy procesoru.

Ukázka kódu

Na závěr úvodního dílu si ukážeme a popíšeme zdrojový kód funkce print_string pro výpis textu jen pomocí rutin BIOSu. Metodu budeme používat příště, kde si ji také vysvětlíme. Zde se na ni můžete podívat jen proto, abyste věděli, jak programování v ASM vypadá a do čeho se to vlastně pouštíme.

Funkce print_string:

print_string:
mov ah, 0x0e     ; Funkce BIOSu pro teletype output
xor bh, bh       ; Pro výpis vybereme page 0

.print_char:
lodsb            ; Načteme hodnotu z DS:SI do AL
or al, al        ; Provedeme bitový součet, který nastaví příslušné příznaky
jz short .return ; Pokud je nastaven příznak nuly (AL = NULL), skočíme na .return

int 10h          ; Vytiskneme znak
jmp .print_char  ; Opakujeme cyklus

.return:
ret              ; Vrátíme se na místo, odkud jsme metodu zavolali (na další instrukci)

No a to je pro dnešek vše.

V příští lekci, Instalace kompilátoru assembleru ve Windows, si nainstalujeme kompilátor a vytvoříme první zatím prázdný ASM projekt.


 

Všechny články v sekci
Základy assembleru
Přeskočit článek
(nedoporučujeme)
Instalace kompilátoru assembleru ve Windows
Článek pro vás napsal Jakub Verner
Avatar
Uživatelské hodnocení:
6 hlasů
Autor se věnuje programování v x86 Assembleru.
Aktivity

 

 

Komentáře
Zobrazit starší komentáře (10)

Avatar
Jakub Verner
Člen IT Redactor Gang
Avatar
Jakub Verner:15. ledna 15:51

Objektový Assembler? :-? Nemyslíš kompilování do formátu .OBJ?

 
Odpovědět
15. ledna 15:51
Avatar
DarkCoder
Člen
Avatar
DarkCoder:15. ledna 16:15

Zdá se jedná o nízkoúrovňový či vysokoúrovňový programovací jazyk není dáno programovacím paradigmem, ale tím, jak velká je odlišnost od způsobu fungování procesoru počítače.

Jazyk C je procedurální programovací jazyk, u něhož je vše založené na funkcích. Žádný uživatelsky přívětivý programovací jazyk se bez funkcí neobejde.

jenom to není tak pohodlné jako v těch "skutečných" vysokoúrovňových jazycích.

V čem je nepohodlné provést komplexní činnost programu prostým voláním funkce?

Odpovědět
15. ledna 16:15
"„Učíš-li se proto, aby sis zapamatoval, zapomeneš. Učíš-li se proto, abys porozuměl, zapamatuješ si."
Avatar
Jakub Verner
Člen IT Redactor Gang
Avatar
Odpovídá na DarkCoder
Jakub Verner:15. ledna 16:55

To je pravda. Můžeme je rozdělit podle přístupu k hardwaru a C má nízkoúrovňový přístup jenom k paměti. Proto je to tak trochu diskutabilní.

 
Odpovědět
15. ledna 16:55
Avatar
Odpovídá na DarkCoder
Nositelka Změny:15. ledna 19:24

Spíš jsem měla na mysli, že bez objektového programování to je někdy těžké. Třeba knihovna GLib je ukázka toho, že to bez nich jde, ale s nimi je to jednodušší a přehlednější. A asi by se toho našlo víc, ale nic mě už nenapadá.

Odpovědět
15. ledna 19:24
j.k.j
Avatar
Jakub Verner
Člen IT Redactor Gang
Avatar
Odpovídá na DarkCoder
Jakub Verner:15. ledna 22:17

Ale Céčkař nejsem a ani s ním nemám moc zkušeností, takže mohu říct pouze svůj názor. :-D

 
Odpovědět
15. ledna 22:17
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Jakub Verner
Člen IT Redactor Gang
Avatar
Jakub Verner:15. ledna 22:52

Tak si představ, že opravdu existuje objektový Assembler. Konkrétně se jmenuje High Level Assembly a podporuje pokročilejší datové typy a OOP programování. Někdy se tak prý označuje i MASM. Docela zajímavé. P.S.: Při hledání se mi podařilo narazit na to, že C je prý vyšší programovací jazyk s prvky nižšího programovacího jazyka, takže je opravdu těžké říct, co tedy je... Je pravda, že C, pokud vím, není závislý na konkrétním procesoru a má takové typické prvky vyššího programovacího jazyka (nezávislost na procesoru, větší srozumitelnost, atd.), ale na druhou stranu, jsou tam znaky, jako třeba práce s pamětí, které nahrávají tomu, že je nižší. Pokud mám být tedy konkrétní, C je multiplatformní, což z něj činí vysokoúrovňový jazyk, ale jeho přístup k paměti z něj dělá nízkoúrovňový jazyk. Jsme tedy někde mezi. Přijde mi jako takový mezikrok.

 
Odpovědět
15. ledna 22:52
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Jakub Verner
DarkCoder:16. ledna 12:13

C má nízkoúrovňový přístup jenom k paměti.

Nejen k paměti, ale i k hardwaru lze pomocí jazyka C přistupovat, jen to není tak přímočaré.
Ne nadarmo je jazyk C brán jako primární jazyk pro embedded systémy.

O tom, jaké jsou možnosti jazyka C k přístupu hardwaru, viz. odkaz.
Manipulating hardware with C

Pokud Tě baví assembler, nebylo by na škodu se k němu naučit C. Velmi Ti to usnadní práci a poskytne další pohled na věc a možnosti.

Odpovědět
16. ledna 12:13
"„Učíš-li se proto, aby sis zapamatoval, zapomeneš. Učíš-li se proto, abys porozuměl, zapamatuješ si."
Avatar
Jakub Verner
Člen IT Redactor Gang
Avatar
Odpovídá na DarkCoder
Jakub Verner:16. ledna 12:30

Já vím, že by mi C mohlo usnadnit práci, ale Assembler má prostě své kouzlo. Určitě není na škodu, naučit se ho, ale operáky hodlám psát výhradně v ASM. :-D Hrozně mě baví vymýšlet všechno od píky. Na druhou stranu, C je prostě takový lepší Assembler, takže proč ne. Nikdy není na škodu, umět něco víc. A děkuji za názory. :-)

 
Odpovědět
16. ledna 12:30
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Nositelka Změny
DarkCoder:16. ledna 12:31

Uspořádání celků do objektů je vhodné, hlavně z důvodu přehlednosti, naprosto souhlasím. Lze se však bez něj obejít. Způsob programování v C se trochu liší od ostatních jazyků, neboť se jedná o procedurální jazyk a celé je to stavěné na funkcích namísto designu, tak jak je tomu u klasických jazyků využívající OOP. Způsob, jakým se to v C řeší, je obrácený. Jasně se řekne co se má dělat a objekt se předá jako ukazatel.

Knihovna GLib je psaná v C a její zápis je rovněž typické pro programy psané v C. Takových příkladů je spousty. Namátkově další knihovny GLFW, SDL, RAYLIB, atd.

Nicméně každému vyhovuje něco jiného, proto vzniká spousta jazyků, kde každý se hodí pro něco jiného. Stačí si jen vybrat.

Odpovědět
16. ledna 12:31
"„Učíš-li se proto, aby sis zapamatoval, zapomeneš. Učíš-li se proto, abys porozuměl, zapamatuješ si."
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Jakub Verner
DarkCoder:16. ledna 12:37

Souhlasím. Čím více se ponoříš do základů, tím více pochopíš jak co funguje a můžeš tak cokoli zlepšit. :-)

Odpovědět
16. ledna 12:37
"„Učíš-li se proto, aby sis zapamatoval, zapomeneš. Učíš-li se proto, abys porozuměl, zapamatuješ si."
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 10 zpráv z 20. Zobrazit vše