Assembler
-=-=-=-=-=-
"The C Programming Language -- A language which combines the
flexibility of assembly language with the power of assembly
language."
Použití inline assembleru jsem už popsal ve výhni #8. Proto
se teď budu zabývat linkováním assemblerových objetů. Pro psaní
assembleru jde použít buď standardní program gas (GNU assembler).
Ten používá AT&T syntax, kterou jsem už také popsal ve výhních #8
a #7, nebo program NASM, který má syntax (až na drobné vyjimky)
shodnou s TASManem a proto asi bude lepší v případě, že máte nějaký
assemblerový kód a chcete ho použít. Díky rozdílům mezí 16 a 32
bitovým kódem stejně ale zdroják asi bude chtít částečně upravit.
Existuje také převadeč ta2as, který se stará o překlad z Intelí
syntaxe do AT&T. Není ale příliš spolehlivý.
Dál budu psát hlavně o gasu, protože NASM nepoužívám (nechtěl
by o něm někdo napsat?). Hodně věcí ale asi bude stejných.
Asi jeden z nejjedodušších způsobů, jak se naučit gas je vzít
jednoduchý zdroják v C a přeložit ho do assembleru (pomocí -S).
Základní struktura souboru je asi následující:
.file "jméno"
.data
mojedato: .word 0
.text
.globl __myasmfunc
__myasmfunc:
...
ret
Vlastní GAS je velmi jednoduchý proram. Nemá žádnou podporu
pro makra. Pokud ale použijete jako příponu .S (ne .s), prožene se
nejprve zdroják preprocesorem. Proto lze použít makra a konstanty
preprocesoru. DJGPP má standardně celkem šikovnou sadu maker
v souboru libc/asmdefs.h
#include <libc/asmdefs.h>
.file "jmeno.S"
.data
.align 2
mojedata: .word 0
...
.text
.align 4
FUNC(__mojefunkce)
ENTER
movl ARG1, %eax
...
jmp label
...
label:
...
LEAVE
Takto napsané funkce se potom chovájí jako standardní céčkové
funkce. Prototyp vypadá asi takto:
void mojefunkce(int p);
Volací konvence jsou standardní céčkové - parametry jsou
na zásobníku pospátku (první pop vyzvedne první parametr).
O vrácení zásobníku se stará volající funkce. Pokud máte kód napsaný
pro pascal, tedy funkce po sobě uklízí samy, je nutné k prototypu
napsat:
void mojefunkce(int p) __attribute((stdcall));
GCC také umí registrové volací konvence. Potom je prvních n
parametrů uloženo v registrech (n<=3). To se deklaruje:
void mojefunkce(int a, int b, int c) __attribute((regparm(3)));
Použijí se registry EAX, EDX, ECX. Registrové volací konvence
jsou často rychlejší, než zásobníkové, proto takové prototypy se
občas vyplatí použít i u často volaných céčkových funkci.
Nejdůležitější pseudoinstrukce GASu jsou:
.allign n - zarovná adresu následující instrukce tak, aby byla
dělitelná číslem n.
Pseudoinstrukce pro určování segnetu
.data datový segment
.text kódový segment
Scope:
.globl symbol
symbol je globální
.comm symbol, délka
následující symbol je common (takových symbolů může být v
objektech víc se stejným jménem a linker je potom spojí za sebe.
Pseudoinstrokce pro zadávání dat:
.ascii
.asciz jako .ascii ale přidá nakonec nulu
.byte
.short (16 bitů)
.int (32 bitů)
.quad (64 bitů)
.double
.float
.fill kolikrát, velikost, hodnota
Novější gasy podoporují i věci jako .ifdef, .macro atd. Zdá se
mi ale lepší použít preprocesor. Více je v dokumentaci (info -f gas)
výheň