Programovani v assembleru na OS Linux
Petr Grygarek, petr.grygarek@vsb.cz
Pouzitelne vyvojove nastroje
Nejobvyklejsim prekladacem assembleru pro Linux je GNU verze as (gas). Narozdil od
assembleru TASM v prostredi DOS pouziva gas odlisnou syntaxi zapisu instrukci
(tzv. AT&T syntax), ktera je v prostredi UNIX obvykla. Zavedenim spolecnych, systematickych konvenci pro zapis symbolickych instrukci pro ruzne procesory
je usnadneno generovani ciloveho kodu prekladaci vyssich jazyku, jako napr. gcc.
Syntaxe AT&T se od syntaxe Intelovske lisi zejmena v techto bodech:
- Opacne poradi zdrojoveho a ciloveho operandu (Intel: mov ax,cx AT&T: movl %ecx,%eax)
- Zapis primeho operandu (konstanty): $n (Intel: mov eax,123 AT&T: movl $123,%eax)
- Zapis registroveho operandu: %r (movl %eax,%ebx)
- Sirka oparandu je urcena poslednim znakem mnemoniky instrukce (l,w,b - 32b,16b,8b). Odpadaji tim modifikatory "byte ptr", "word ptr" apod. (Intel: mov [bx], word ptr 0 AT&T: movw $0,(bx)
- Instrukce pro prime dlouhe skoky se zapisuji ve formatu:
lcall/ljmp $section,$offset
Instrukce ret far se zapisuje lret
- Indirekce se zapisuje pomoci kulatych zavorek movl $0,(%ebx)
Indirekce s indexaci se zapisuje takto: movl $123,12(%ebx)
Podrobne informace o assembleru as (GNU verzi) je mozne obdrzet pouzitim prikazu info as . Zejmena je zde uzitecny prehled direktiv.
Pokud se chcete drzet obvykleho zpusobu zapisu instrukci, jak jej pouziva firma
Intel (a vetsina assembleru v prostredi DOS/Windows), muzete si stahnout napriklad volne dostupny assembler NASM.
Taktez jsou k dispozici filtry pro preklad
zdrojoveho kodu assembleru mezi syntaxi AT&T a Intel.
Instrukce assembleru je rovnez mozne vkladat do kodu C zpracovavaneho prekladacem gcc a to s pouzitim klicoveho slova asm. Timto zpusobem je mozne rovnez snadno pristupovat k symbolum zdrojoveho textu programu v C.
Podrobnosti je mozne nalezt v sekci "C Extensions/Extended asm" informacni stranky gcc (prikaz info gcc). Je vhodne upozornit, ze gcc vkladane instrukce nijak nekontroluje a jejich vyhodnoceni prenechava assembleru as.
Zpusob volani sluzeb jadra
Programy v Linuxu pracuji s tzv. flat modelem, tj. veskere adresy jsou 32-bitove.
Program se deli na sekce .text (kod), .data (inicializovana data) a .bss (neinicializovana data). Veskera volani jadra se deji pomoci instrukce int 0x80.
V obsluze tohoto softwaroveho preruseni se provede prepnuti do rezimu jadra, uschovaji se veskere registry, zkontroluje se cislo volani a vola se prislusna funkce jadra (ve zdrojovych textech jadra obvykle nazyvana sys_XXX()). Pri volani jadra je cislo volani v registru eax, dalsi parametry pak postupne v registrech ebx,ecx,edx,esi,edi (z cehoz plyne, ze maximalni pocet parametru sluzeb jadra Linuxu je 5; pokud volani vyzaduje vetsi pocet parametru, predava se zpravidla pointer na prislusnou datovou strukturu umistenou v uzivatelskem datovem prostoru).
Uzivatelsky zasobnik zustava systemovym volanim nedotcen.
Po skonceni volani jadra se vyhodnocuje, zda ma dojit k preplanovani procesu. Pri navratu rizeni volajicimu procesu je navratovy kod (vysledek) funkce jadra ulozen v registru eax.
Cisla jednotlivych volani (umistovana do registru eax) urcuji index do tabulky pointru na funkce jadra (linux/arch/i386/entry.S). Jejich prirazeni jednotlivym funkcim lze nalezt v tabulce ve zminenem zdrojovem kodu (prislusny vysek kodu viz zde).
Parametry jednotlivych funkci je mozne vycist ze sekce 2 manualovych stranek.
Odleva jsou tyto parametry pri volani jadra umistovany postupne do registru
ebx,ecx,edx,esi a edi. Signatury jednotlivych volani lze rovnez nalezt ve zdrojovych textech jadra (nebo v abecednim poradi zde).
Pristup k parametrum prikazove radku
V okamziku vzniku procesu zajistuje Unix, ze zasobnik tohoto procesu bude vypadat definovanym zpusobem. Jeho rozlozeni odpovida obvykle definici vstupni funkce
programu (int main(int argc, char** argv, char** envp)) a volacim konvencim jazyka C.
Na vrcholu zasobniku je tedy pri spusteni procesu pocet do programu predanych
parametru (argc), nasledovany pointry na jednotlive parametry prikazove radky. Je nutne upozornit, ze prvnim parametrem je vzdy jmeno spusteneho programu. Samotne argumenty jsou umistovany postupne na zasobnik v podobe pointru na jednotlive retezce argumentu. Posledni argument je nasledovan NULL pointrem. Za timto ukoncovacem parametru prikazove radky je zpravidla umisteno pole pointru na retezce (jednotlive promenne) environmentu, rovnez ukoncene NULL pointrem. Jednotlive retezce parametru prikazove radky i promennych environmentu jsou ukonceny znakem s hodnotou 0 (C-strings).
Debugging
Pro trasovani programu je k dispozici debugger gdb, pripadne pak jeho nadstavby xxgdb, nebo zdarilejsi ddd.
Ukazkovy priklad
Zde uvedeny priklad demonstruje pouziti volani jadra
pro vypis souboru zadaneho jako parametr programu na standardni vystup.
Z programu je rovnez mozne vycist zpusob pristupu k parametrum prikazove radky.
Priklad se zkompiluje a zlinkuje nasledujicimi prikazy:
as -o vypis.o vypis.s
ld -o vypis vypis.o
Priklad spojeni assembleru (as) s programem v C (gcc)
Priklad sestava z modulu c.c (C) a a.s
(assembler). Modul c.c deklaruje promennou cVar a funkci cFn(),
na obe je pristupovano s assembleru. Assemblerovy modul a.s deklaruje promennou aVar a funkce aFn() a aCall_cFn(), na ktere je pristupovano z C. Program
lze zkompilovat a zlinkovat pouzitim prilozeneho skriptu.
Uzitecne odkazy
Linux Assembly HOWTO
IO-Port-Programming mini HOWTO
Linux/i386 assembly programming page
Linux/i386 system calls
Some examples: Jan's Linux & Assembler HomePage
NASM - The Netwide Assembler Project - FREE 80x86 assembler
Assembly Language Journal