-
[ Pobierz całość w formacie PDF ]
; NASM casm1.asm
section .text use32
global _suma
_suma:
; po wykonaniu push ebp i mov ebp, esp:
; w [ebp] znajduje się stary EBP
; w [ebp+4] znajduje się adres powrotny z procedury
; w [ebp+8] znajduje się pierwszy parametr,
; w [ebp+12] znajduje się drugi parametr
; itd.
%idefine a [ebp+8]
%idefine b [ebp+12]
push ebp
mov ebp, esp
mov eax, a
add eax, b
; LEAVE = mov esp, ebp / pop ebp
leave
ret
oraz plik casm.c:
Bogdan Drozdowski 97
Bogdan Drozdowski Język asembler dla każdego 2007-11-12
#include
extern int _suma (int a, int b); /* deklaracja funkcji zewnętrznej */
int suma (int a, int b); /* prototyp funkcji */
int c=1, d=2;
int main()
{
printf("%d\n", suma(c,d));
return 0;
}
Kompilacja odbywa się tak:
nasm -o casm1.obj -f obj casm1.asm
bcc32 casm.c casm1.obj
Uwaga: w kompilatorach GNU: DJGPP, Dev-C++, MinGW, CygWin format wyjściowy NASMa powinien
być ustawiony na COFF. Możliwe, że format COFF trzeba będzie wybrać także w innych.
W wyniku otrzymujemy programik, który na ekranie elegancko wyświetla wynik równy 3.
Może się zdarzyć też, że chcemy tylko korzystać z funkcji języka C, ale główną część programu chcemy
napisać w asemblerze. Nic trudnego: używane funkcje deklarujemy jako zewnętrzne (pamiętając o znaku
podkreślenia), ale uwaga - swoją funkcję główną musimy nazwać _main. Jest tak dlatego, że teraz punkt
startu programu nie jest w naszym kodzie, lecz w samej bibliotece języka C. Program zaczyna się między
innymi ustawieniem tablic argumentów listy poleceń i zmiennych środowiska. Dopiero po tych operacjach
biblioteka C uruchamia funkcję _main instrukcją CALL.
Inną ważną sprawą jest to, że naszą funkcję główną powinniśmy zakończyć instrukcją RET (zamiast
normalnych instrukcji wyjścia z programu), która pozwoli przekazać kontrolę z powrotem do biblioteki C,
umożliwiając posprzątanie (np. wyrzucenie buforów z wyświetlonymi informacjami w końcu na ekran).
Krótki przykładzik:
section .text
global _main
extern _printf
_main:
; printf("Liczba jeden to: %d\n", 1);
push dword 1 ; drugi argument
push dword napis ; pierwszy argument
call _printf ; uruchomienie funkcji
add esp, 2*4 ; posprzątanie stosu
; return 0;
xor eax, eax
ret ; wyjście z programu
section .data
napis: db "Liczba jeden to: %d", 10, 0
98 Bogdan Drozdowski
2007-11-12 Język asembler dla każdego Bogdan Drozdowski
Kompilacja powinna odbyć się tak:
nasm -o casm2.obj -f obj casm2.asm
bcc32 casm2.obj
Jedna uwaga: funkcje biblioteki C mogą zamazać nam zawartość wszystkich rejestrów (poza EBX, EBP, ESI,
EDI), więc nie wolno nam polegać na zawartości rejestrów po uruchomieniu jakiejkolwiek funkcji C.
Kompilator GNU gcc wymaga osobnego wytłumaczenia. Składnia wstawek asemblerowych różni się od
powyższej dość znacznie, a jej opisy możecie znalezć w podręczniku GCC (sekcje: 5.34 i 5.35), na stronach
DJGPP oraz (w języku polskim) na stronie pana Danileckiego.
Jak zauważycie, różni się nawet sam wygląd instrukcji, gdyż domyślnie gcc używa składni AT&T języka
asembler. U siebie mam krótkie porównanie tych składni.
Fortran 77
W tym języku nie wiem nic o wstawkach asemblerowych, więc przejdziemy od razu do łączenia modułów.
Fortran dekoruje nazwy, stawiając znak podkreślenia PO nazwie funkcji lub zmiennej (wyjątkiem jest funkcja
główna - blok PROGRAM - która nazywa się MAIN__, z dwoma podkreśleniami).
Nie musimy pisać externów, ale jest kilka reguł przekazywania parametrów:
" parametry przekazywane są od prawej do lewej, czyli tak jak w C.
" jeśli to jest tylko możliwe, wszystkie parametry przekazywane są przez referencję, czyli przez
wskaznik. Gdy to jest niemożliwe, przekazywane są przez wartość.
" jeśli na liście parametrów pojawia się łańcuch znakowy, to na stosie przed innymi parametrami
umieszczana jest jego długość.
" wyniki są zwracane w tych samych miejscach, co w języku C.
Na przykład, następujący kod:
REAL FUNCTION aaa (a, b, c, i)
CHARACTER a*(*)
CHARACTER b*(*)
REAL c
INTEGER i
aaa = c
END
[...]
CHARACTER x*8
CHARACTER y*5
REAL z,t
INTEGER u
t=aaa (x, y, z, u)
[...]
będzie przetłumaczony na asemblera tak (samo uruchomienie funkcji):
push 5
Bogdan Drozdowski 99
Bogdan Drozdowski Język asembler dla każdego 2007-11-12
push 8
push u_ ; adres, czyli offset zmiennej "u"
push z_
push y_
push x_
call aaa_
(to niekoniecznie musi wyglądać tak ładnie, gdyż zmienne x, y, u i z są lokalne w funkcji MAIN__, czyli są
na stosie, więc ich adresy mogą wyglądać jak [ebp-28h] lub podobnie).
Funkcja uruchamiająca sprząta stos po uruchomieniu (podobnie jak w C).
Dołączać moduły można bezpośrednio z linii poleceń (w każdym razie pod Linuksem z kompilatorem
F77/G77).
Podam teraz przykład łączenia Fortrana 77 i asemblera. W oryginale użyłem narzędzi Linuksowych: NASMa
i F77, ale po minimalnych przeróbkach powinno to też działać pod Windows. Oto pliki:
; NASM - asm1fl.asm
section .text use32
global suma_
suma_: [ Pobierz całość w formacie PDF ] - zanotowane.pl
- doc.pisz.pl
- pdf.pisz.pl
- matkadziecka.xlx.pl