Úvod
V každém operačním systému má programátor k dispozici sadu systémových volání k operacím s adresáři. Použití Asmutils je hodně podobné programování ve vyšších programovacích jazycích.
V dnešní části přistoupíme poněkud k praktičtejšímu zacházení s Assemblerem, kde si ukážeme, co vlastně jednotlivé konstanty Asmutils provádí :) s kódem při jeho úpravách.
Zde je tabulka hodnot nejdůležitějších systémových volání. Některá z nich si ukážeme vždy v sekci kódu bez použití Asmutils. Kompletní seznam těchto hodnot lze nalézt v souboru /usr/src/linux/include/unistd.h.
chdir | 12 |
chmod | 15 |
setuid | 23 |
mkdir | 39 |
rmdir | 40 |
geteuid | 49 |
ioctl | 54 |
readdir | 89 |
getcwd | 183 |
Budiž světlo – vytvoření adresáře
Použijeme systémové volání mkdir. Toto volání má jako první parametr ukazatel na jméno vytvářeného adresáře, ve druhém parametru předáváme přístupová práva. Na filesystémech, které nepodporují přístupová práva, jsou tyto parametry vynechávány, pokud jsou však v kódu uvedeny, nezpůsobí chybu, dojde k jejich ignoraci a běh programu pokračuje dál. Pro práva lze použít symbolické konstanty.
Adresář testdir uděláme takto:
%include "system.inc" CODESEG START: sys_mkdir jmeno, S_IRWXU sys_exit 0 DATASEG jmeno DB "/home/murphy/testdir", 0 END
bez použití symbolických konstant Asmutils program může vypadat takto:
SECTION .text global _start _start: mov eax, 39 mov ebx, jmeno mov ecx, 700q int 0x80 mov eax, 1 mov ebx, 0 int 0x80 SECTION .data jmeno db "/home/murphy/testdir", 0xa
Vytvořili jsme si adresář testdir.
Budiž tma – smazání adresáře
Využijeme systémové volání rmdir. Jeho jediným parametrem je jméno adresáře.
S použitím asmutils:
%include "system.inc" CODESEG START: sys_rmdir jmeno sys_exit 0 DATASEG jmeno DB "/home/murphy/testdir", 0 END
Bez použití symbolických konstant:
SECTION .text global _start _start: mov eax, 40 mov ebx, jmeno int 0x80 mov eax, 1 mov ebx, 0 int 0x80 SECTION .data jmeno db "/home/murphy/testdir", 0xa
Vstupte prosím – výběr aktuálního adresáře
Tato funkce má jediný parametr, a tím je adresář společně s jeho cestou, který se má stát aktuálním (přejeme si do něho vstoupit). Jedná se o syscall chdir.
Tento program po svém startu vstoupí do mého domovského adresáře /home/murphy:
Se symbolickými konstantami:
%include "system.inc" CODESEG START: sys_chdir vstup ... ;zbytek programu sys_exit 0 DATASEG vstup DB "/home/murphy/", 0 END
a bez použití konstant:
SECTION .text global _start _start: mov eax, 12 mov ebx, vstup int 0x80 ... ;zbytek programu mov eax, 1 mov ebx, 0 int 0x80 SECTION .data jmeno db "/home/murphy/testdir", 0xa
Kde to jsme – zjištění aktuálního adresáře
Od jádra 2.0 výše je tento proces velmi zjednodušen. Použijeme systémové volání getcwd, které má dva parametry, první ukazuje na místo, kam se aktuální adresář uloží, druhý specifikuje velikost volné paměti, na niž odkazuje první parametr.
Použití je jednoduché:
S konstantami:
sys_getcwd path, PATHSIZE
a bez konstant
mov eax 183 mov path, ebx mov size, ecx int 0x80
Tento program zjistí aktuální adresář a skončí na novém řádku:
Se symbolickými konstantami:
sys_getcwd path, PATHSIZE mov esi, ebx xor edx, edx .next: inc edx lodsb or al, al jnz .next mov byte [esi - 1], __n sub esi, edx sys_write STDOUT, esi, EMPTY sys_exit_true
a bez konstant:
SECTION .text global _start _start: mov eax, 183 mov path, ebx mov size, ecx int 0x80 mov esi, ebx xor edx, edx .next: inc edx lodsb or al, al jnz .next mov byte [esi - 1], __n sub esi, edx mov eax, 4 mov ebx, 1 mov ecx, path mov edx, size int 0x80 mov eax, 1 mov ebx, 0 int 0x80
Kdopak to tu píše – vstup z klávesnice
Klávesnice je reprezentována standardním vstupem (stdin). Chceme-li číst znaky z klávesnice do stisku klávesy enter, použijeme syscall read.
S konstantami:
sys_read STDIN, data_z_klavesnice, MAX_DATA
a bez konstant:
mov eax, 3 mov ebx, 0 mov data, ecx mov max, edx
Někdy potřebujeme číst klávesy po jedné nebo je při čtení nezobrazovat na standardní výstup. Změnit chování standardního vstupu můžeme pomocí syscall ioctl.
Voláme dále – volání IOCTL
Ovladače zařízení si nepřidávají nová systémová volání. Vytvářejí pro obsluhu svého zařízení soubor funkcí dostupných přes systémové volání IOCTL. Prostřednictvím IOCTL můžeme komunikovat s ovladačem příslušného zařízení a ovlivňovat jeho funkci. Jedná se o zkratku I/O Control (input output control). Zde se zmíníme o ioctl terminálu.
Toto volání má pouze jeden povinný parametr. Je to identifikační číslo souboru, nad kterým budeme volání provádět. Ostatní parametry jsou specifické pro jednotlivé funkce IOCTL.
V Linuxu měníme chování terminálu pomocí dvou nejčastěji používaných funkcí TCGETS a TCSETS. Voláním TCGETS dostaneme nastavení terminálu, změny se provádí voláním druhé funkce.
Díky Asmutils máme potřebné struktury pro zacházení s terminálem. Kdybychom chtěli číst klávesy po jedné a nezobrazovat je při stisku na obrazovku, měníme atributy terminálu ICANON a ECHO na 0. Přečteme je pomocí TCGETS, změníme bitovou masku a uvedeme v platnost pomocí IOCTL TCSETS. V definici struktury B_STRUC se objevuje speciální makro, které rozšiřuje standardní makro STRUC (definice je v souboru system.inc).
mov edx, termattrs sys_ioctl STDIN, TCGETS mov eax, [termattrs.c_lflag] push eax and eax, ~(ICANON | ECHO) mov [termattrs.c_lflag] ,eax sys_ioctl STDIN, TCSETS pop dword [termattrs.c_lflag]
Závěrem
V dnešním dílu jsme si popsali další důležité systémové vlastnosti. Na závěr nás již čeká v posledním dílu jen alokace paměti, která se do tohoto dílu nevešla, a odlaďování a testování hotových aplikací.