Hlavní navigace

Programujeme v jazyce Assembler v Linuxu: jak na adresáře

22. 7. 2004
Doba čtení: 4 minuty

Sdílet

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ějí s kódem při jeho úpravách.

Ú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/in­clude/unistd.h.

Tabulka č. 592
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.

CS24_early

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í.

Byl pro vás článek přínosný?