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: 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