Jak zacząć programować w asemblerze?

Programy pod 32-bit Linux, intel. Dla innych systemów nie wyglądają tak samo.


Na początek przede wszystkim poznać systemy liczbowe oraz jakiś język programowania (polecam c/c++/php/javascript na początek, ale inne jezyki też mogą być, byle tylko rozumieć ideę programowania). Gdy już ten etap masz za sobą, bez problemu możesz przysiąść do asemblera.
Nie będę zaczynać od tlumaczenia zastosowań rejestrów. Ich dogłębniejszy opis można znaleźć tutaj. O rejestrach będę też opowiadać podczas omawiania kodów źródłowych. Tak będzie najlepiej (przynajmniej moim zdaniem xd).

Hello world! (Linux)

Zacznę tradycyjnym programem "witaj świecie". W asemblerze jest on nieco dłuższy niż w high levelach (językach wysokopoziomowych). Jest on językiem niskopoziomowym. Jedna instrukcja asemblera odpowiada praktycznie jednemu rozkazowi procesora. Dlatego kod nabiera trochę większej objętości. Zaletą jest to, ze programy w asemblerze są szybsze od tych pisanych np. w c, cpp, pascalu, itp. itd.

Środowisko


Do pisania programów będą potrzebne:
  • kompilator, nasm
  • linker, ld
  • edytor lub ide (nano, gedit, codeblocks, codelite) ważne aby dało się w tym pisać czysty tekst( nie jak w office)
  • mózg też może być przydatny xd

  • Instalacja narzędzi w dystrybucjach opartych na debianie sprowadza się do
    sudo apt-get install

    Program

    section .data

    Początek sekcji danych (segment data*). W cpp zmienne deklarować można bezpośrednio w kodzie:

    int main()

    {

    //kod

    int x;

    //kod

    return 0;

    }


    W asemblerze tak nie jest. Wszystkie zmienne deklaruje się w sekcji danych.

    section .data

    napis db "Hello world", 0ah

    dnapis equ $-napis


    db oznacza, ze chcemy zadeklarować bajt. Jednak db jest na tyle wyjatkowe, ze pozwala deklarować nie tylko pojedyncze bajty, ale też całe łańcuchy znaków, co zresztą można dostrzec w powyższym przykładzie. Można także deklarować innych rozmiarów zmienne:

    db (byte) 1bajt

    dw (word) 2 bajty

    dd (dword) 4 bajty

    pw 6 bajtów

    dq 8 bajtów

    dt 10 bajtów

    Tajemniczy ciąg znaków 0ah (lub inaczej zapisane 0xa), to zapisana wartość w systemie szesnastkowym (hexadecymalnym, hex), w ascii oznacza ona, uwaga: enter. Czyli 0ah to po prostu zwykły koniec linii.


    No dobra, ale co jest w zmiennej dnapis? Długość napisu. Dyrektywa equ oznacza, że jest to stała (const, wartość się nie zmienia). $-napis to długość napisu.



    section .text

    global _start

    _start:


    Section .text to sekcja kodu (segment code*). Umieszcza się tu kod programu, czyli wywołania funkcji, pętle, itp., itd.

    global _start to informacja, ktorej wymaga linker ld. Jest to symbol globalny, który pokaże linkerowi, gdzie jest start programu. Linijka _start: służy właśnie do takiego pokazania.


    mov eax, 4

    mov ebx, 1

    mov ecx, napis

    mov edx, dnapis

    int 80h


    Eax, ebx, ecx i edx to rejestry ogólnego przeznaczenia. Instrukcja mov służy do kopiowania wartości. W pierwszej linijce do rejestru eax jest kopiowana wartość 4. Dlaczego kopiowana a nie przypisywana? Bo bezpośrednio do rejestru nie można wpisać wartosci. Dlatego się ją kopiuje. Ale co to za wartości 4, 1 (bo napis dnapis chyba oczywiste)? Otóż to spójrz na ostatnią linijkę. Int 80h. Jest to wywołanie przerwania systemowego. Czyli tak jakby wywołanie funkcji. Funkcji, która ma 3 argumenty (od ebx do edx). Eax "mówi", którą funkcję systemową wywołać. W tym przypadku jest to 4 (sys_write), czyli zapis do pliku. Zapis do pliku? Przecież to miał być tradycyjny hello world, piszący tekst na ekranie... Bo będzie. Otóż to rejestr ebx zawiera wartość 1, czyli standardowe wyjście (std out), w tym przypadku ekran (konsoli). Ecx zawiera napis, który ma zostać wyswietlony, a edx jego długość. Wszystko pięknie, ale program trzeba jeszcze zamknąć...


    mov eax, 1

    mov ebx, 0

    int 80h


    Eax- funkcja nr 1 to sys_exit

    Ebx- wyzerowany, aby nie było komplikacji...
    To teraz kod całego programu:

    section .data

    napis db "Hello world", 0ah

    dnapis equ $-napis

    section .text

    global _start

    _start:

    mov eax, 4

    mov ebx, 1

    mov ecx, napis

    mov edx, dnapis

    int 80h

    mov eax, 1

    mov ebx, 0

    int 80h


    Całość zapisujemy (np. hello.asm), następnie kompilujemy:

    nasm -f elf32 hello.asm

    I do linkera:

    ld hello.o -o hello

    I uruchamiamy:

    ./hello

    I widzimy radosny komunukat:

    Hello world


    Mam nadzieję że dzięki temu poradnikowi polubicie asemblera

    Zachęcam do eksperymentowania z rożnymi napisami i nazwami zmiennych


    *elementy zaznaczone gwiazdką nie są konieczne do skumania na tym etapie