Cvičenia z predmetu Programovanie na strojovej úrovni (ISU), druhý semester bakalárskeho štúdia BIT na FIT VUT/BUT, ak.rok 2021/2022
Toto je archív mojích kódikov z ISU cvičení, ktoré som znovu–objavil na starom VPS (aspoň čo sa zachovalo), plus samouka na testy. Všetky súbory sú závislé na podpornej knižnici rw32-2022.inc
(MOODLE.vut.cz, archive.org).
Ak sa Vám nechce nič nastavovať, vždy je tu SASM.
Windows prevažne bude mať nainštalované knižnice čo potrebujete. Stiahnite si archív z ISU MOODLE isu-tools-2022.zip
(resp. verziu s aktuálnym rokom), kde by ste mali mať súbory bin/nasm.exe
a bin/golink.exe
(prípadne isu-vscode-mingw.zip
). Cez shell potom môžete spustiť napr. test.asm
takto:
bin/nasm.exe -f win32 -g -o build/test.obj test.asm
bin/golink.exe build/test.obj /fo build/test.exe /console /debug coff /entry:_main msvcrt.dll kernel32.dll
build/test.exe
Windows som osobne nepoužíval, tak VSCode súbory nemám po ruke, ale menším refactoringom by sa z priložených linuxáckych dali spraviť. Something something, use Linux.
Na programovanie v x86 Assembly je potrebné mať nainštalovaný asembler NASM spolu s C-čkovými utilitkami a GNU toolchain — GCC, GDB + C knižnice — čo sa všetko dá nainštalovať ako package group. K tomu je treba doinštalovať 32–bitové knižnice.
nasm -f elf32 -g -o build/test.o test.asm
gcc -m32 -o build/test build/test.o
build/test
apt -y update
apt -y install binutils build-essential gdb # Development tools
apt -y install gcc-multilib # 32-bit libraries
apt -y install nasm
dnf -y upgrade
dnf -y group install "C Development Tools and Libraries"
dnf -y install glibc-devel.i686 # 32-bit libraries
dnf -y install nasm
pacman -Syu
pacman -S base-devel # Development tools, install all
pacman -S lib32-gcc-libs # 32-bit libraries
pacman -S nasm
Proces spúšťania si môžete automatizovať súbormi launch.json a tasks.json v priečinku .vscode
, čo spolu s rozšírením GDB Debug[REPO] Vám dá možnosti kód debuggovať.
Pre debugging použite klávesu F5, alebo spustite súbor klávesami CTRL + F5 bez debugu. Na debugging treba do kódu pridať breakpointy (tie červené bodky), kde program sa pozastaví, a môžete v ňom krokovať (pomocou tlačidiel v hornom menu) a pri tom sledovať registre, premenné, a podobne. Pokiaľ Vám nejde pridávať breakpointy, treba ich povoliť vo VSCode nastaveniach (File > Preferences > Settings > Debug: Allow Breakpoints Everywhere).
- x86 and x86_64 Assembly[REPO] — syntax highlighting
- ISU ASM Register Extension[REPO] — lepšie zobrazenie registrov počas debuggingu
- x86 Instruction Reference[REPO] — offline dokumentácia x86 inštrukcií
Všetky tieto rozšírenia sú povolené na cvičeniach aj na testoch (pozor: počas môjho štúdia, pravidlá sa mohli zmeniť!).
Na ľavej strane rozhrania v tabe Run & Debug máte panel Watch, pomocou ktorého môžete zobrazovať aktuálne hodnoty registrov či premenných (= miest v pamäti).
$REG: Zobrazí hodnotu registra REG VAR: Zobrazí hodnotu premennej VAR &VAR: Zobrazí adresu premennej VAR *ADDR: Zobrazí hodnotu miesta v pamäti ADDR *ADDR-ADDR: Zobrazí hodnoty miest v pamäti v rozsahu ADDR-ADDR
Takže napríklad hodnotu EAX zobrazíte výrazom $eax
, alebo BL výrazom $bl
.
Pretože assembly neuchováva typ "premenných" (a po kompilácií ani veľkosť), je nutné použiť cast na pretypovanie.
char
— znakint
— celé číslostring
— reťazec znakovfloat
— číslo s pohyblivou rádovou čiarkou
char
je nositeľ typu aj veľkosti (8–bit), no int
typu je veľkosť automaticky určená, čo nemusí byť vždy správne (hlavne pri poliach).
char
— 8–bitov (DB)short
— 16–bitov (DW)long
— 32–bitov (DD)long long
— 64–bitov (DQ)
Veľkosti a typy môžu byť osobitne, napr. (int)(short)varname
, alebo kombinovane, napr. (short int)varname
- k tomu ešte je možné špecifikovať znamienkovosť, napr. (unsigned short int)varname
(vyberte si, čo Vám vyhovuje najviac — jedine pri 8-bit int treba presne použiť (int)(char)varname
).
A ako posledné máte niekoľko možností formátu výpisu (píše sa za výrazom, oddelené čiarkou):
d
— celé číslo so znamienkomu
— celé číslo bez znamienkax
— celé číslo v hexadecimálnej (šesnáctkovej) sústavet
— celé číslo v binárnej (dvojkovej) sústave (t ako two)o
— celé číslo v oktálovej (trojkovej) sústavec
— znakf
— číslo s pohyblivou rádovou čiarkou
Tu máte zopár možností na výpis (aj s poliami). Vyberte si, čo Vám príde najintuitívnejšie:
Tabuľka výpisových výrazov
Type of value | Watch expression methods |
---|---|
String (any sized ptr) | &varname,s |
Integer at the top of the stack | *(int)$esp |
8-bit (DB) signed int | (char)varname,d (signed char)varname,d (int)(char)varname (signed int)(char)varname |
8-bit (DB) unsigned int | (unsigned int)(char)varname (int)(unsigned char)varname |
8-bit (DB) int in hex | (char)varname,x (int)(char)varname,x |
8-bit (DB) char | (char)var (char)var,c |
16-bit (DB) signed int | (short int)varname (short signed int)varname (short)varname,d |
16-bit (DW) unsigned int | (short unsigned int)varname |
16-bit (DW) int in hex | (short int)var,x (short)var,x |
32-bit (DD) signed int | (long int)var (long signed int)var (long)int,d |
32-bit (DD) unsigned int | (long unsigned int)varname |
32-bit (DD) int in hex | (long int)varname,x (long)varname,x |
32-bit (DD) float | (float)varname |
64-bit (DQ) signed int | (long long int)varname (long long signed int)varname (long long)varname,d |
64-bit (DQ) unsigned int | (long long unsigned int)varname |
64-bit (DQ) int in hex | (long long int)varname,x (long long)varname,x |
64-bit (DQ) float | (double)varname |
10-elm array of 8-bit signed ints | (char[10])varname,d |
10-elm array of 8-bit unsigned ints | (iba ako unsigned char)(unsigned char[10])varname |
10-elm array of 8-bit ints in hex | (char[10])varname,x |
10-elm array of 16-bit signed ints | (short int[10])varname (short[10])varname,d (signed short[10])varname,d |
10-elm array of 16-bit unsigned ints | (unsigned short int[10])varname |
10-elm array of 16-bit ints in hex | (short[10])varname,x (short int[10])varname,x (signed short[10])varname,x |
Debug console je priamy prístup do debuggeru gcc, čo je fajn pomôcka, aj keď menej user-friendly. V tejto konzole môžete písať rovnaké výrazy ako do Watch panelu, alebo vykonávať príkazy pomocou -exec
.
-exec info reg: Zobrazí hodnoty registrov -exec info float: Zobrazí všetko možné o FPU -exec info br: Zobrazí zoznam breakpointov -exec info stack: Zobrazí call stack -exec c: Pokračovať v programe -exec kill: Ukončí program -exec q: Ukončí GDB -exec n: Prejde na ďalšiu inštrukciu (vnorí sa do funkcie) -exec ni: Prejde na ďalšiu inštrukciu (bez vnorenia) -exec p $eax: Vypíše hodnotu registra EAX -exec disassemble: Zobrazí raw asm kód aktuálneho kontextu
Čo z toho je užitočné je už vec názoru, je to skôr niečo pre terminal master race hackermanov, inak za zaobídete aj bez tohoto. Asi jediný príkaz, čo som osobne používal, je -exec info float
.
Dávam sem aj moje 💩 snippety v súbore isu.code-snippets. Je to len čiastočný copy-paste z prezentácií, ktorý som druhú polovicu semestra skoro vôbec neaktualizoval — skôr to prikladám ako šablónu, keby ste sa s tým chceli pohrať a spraviť si vlastné. U nás boli vlastné snippety povolené aj na písomkách (pozor: nemusí platiť aj tento rok!).