• [ 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