Hızlı başlangıç

Giriş

Son olarak, eğer hala bu çılgınca fikri denemek ve sembolik makina kodu yazmak istiyorsanız (eğer bu kısma ulaştıysanız gerçekten de bir sembolik makina hayranısınızdır), başlangıç için gerekenleri bu kısımda bulacaksınız.

Daha önce de okuduğunuz gibi, Linux için değişik şekillerde yazabilirsiniz; size doğrudan sistem çağrılarını nasıl yapacağınızı göstereceğim, çünkü bu çekirdek servislerini çağırmanın en hızlı yoludur; kodumuz hiç bir kütüphaneye bağlı değildir, ELF yorumlayıcısını kullanmayınız, çünkü çekirdek ile doğrudan iletişim kurar.

Aynı kodu nasm ve gas için göstereceğim ve böylelikle Intel ve AT&T söz dizimini de göstermiş olacağım.

Aynı zamanda Unix bembolik makne dili ile programlamaya giriş kılavuzunu okumak isteyebilirsiniz; UNIX benzeri işletim sistemleri için örnek kodlar da içermektedir.

İhtiyacınız olan araçlar

Herşeyden önce bir çeviriciye (derleyici) ihtiyacınız vardır - nasm veya gas

İkinci olarak, bir ilintileyiciye (linker) ihtiyacınız vardır - ld, çünkü çeviriciler sadece nesne kodunu üretmektedir. Hemen her dağıtım gas ve ld'yi binutils içerisinde sunmaktadır.

nasm'a gelince, Linux için paketleri ve belgeleri nasm sayfasından indirip kurmanız gerekebilir, pekçok dağıtımın (Stampede, Debian, SuSe, Mandrake) nasm'ı kendi sürümleri içerisinde barındırdıklarını unutmayın, önce bir kontrol edin.

Eğer daha derine inecekseniz, işletim sisteminizin başlık dosyalarını ve mümkünse çekirdek kaynak paketini edinmelisiniz.

Merhaba Dünyalı :-)

Yerleşim

Linux, 32 bitliktir, korumalı kipte çalışır, düz bellek modeline sahiptir ve ikilikler için ELF biçimini kullanır.

Bir program bölümlere ayrılabilir: kodunuz için .text kısnı (salt-okunur), verileriniz için .data kısmı (oku-yaz), ilklendirilmemiş veriler için .bss kısmı (oku-yaz); aslında bir kaç tane daha, kullanıcı tanımlı bölüm yanında, standart bölüm olabilir, fakat onların kullanılacakları durumlar çok nadir olmaktadır ve bizim ilgi alanımız dışındalar. Bir program en azından .text kısmına sahip olmalıdır.

Şimdi ilk programımızı yazacağız.

NASM (hello.asm)

section .text                           ;bölüm bildirimi

                           ;giriş noktasını ELF ilintileyiciye veya yükleyiciye
    global _start          ;göndermeliyiz (export). Giriş noktasını uzlaşımsal
                           ;olarak _start ile belirtiriz. Öntanımlı durumu
                           ;değiştirmek için: ld -e foo kullanın.

_start:

;dizgemizi stdout'a yazar

        mov     edx,len    ;üçüncü argüman: ileti uzunluğu
        mov     ecx,msg    ;ikinci argüman: yazılacak iletinin göstericisi
        mov     ebx,1      ;ilk argüman: dosya tutucu (stdout)
        mov     eax,4      ;sistem çağrısı numarası (sys_write)
        int     0x80       ;çekirdeği çağır

;ve çık

        mov     ebx,0      ;ilk sistem çağrısı argümanı: çıkış kodu
        mov     eax,1      ;sistem çağrı numarası (sys_exit)
        int     0x80       ;çekirdeği çağır

section .data              ;bölüm bildirimi

        msg     db      "Hello, world!",0xa     ;sevgili dizgemiz
        len     equ     $ - msg                 ;sevgili dizgemizin boyu

GAS (hello.S)

.text                                   # bölüm bildirimi

                           ;giriş noktasını ELF ilintileyiciye veya yükleyiciye
    global _start          ;göndermeliyiz (export). Giriş noktasını uzlaşımsal
                           ;olarak _start ile belirtiriz. Öntanımlı durumu
                           ;değiştirmek için: ld -e foo kullanın.

_start:

# dizgemizi stdout'a yazar

        movl    $len,%edx     # üçüncü argüman: ileti uzunluğu
        movl    $msg,%ecx     # ikinci argüman: yazılacak iletinin göstericisi
        movl    $1,%ebx       # ilk argüman: dosya tutucu (stdout)
        movl    $4,%eax       # sistem çağrı numarası
        int     $0x80         # çekirdeği çağır

# ve çık

        movl    $0,%ebx       # ilk sistem çağrısı argümanı: çıkış kodu
        movl    $1,%eax       # sistem çağrı numarası (sys_exit)
        int     $0x80         # çekirdeği çağır

.data                         # bölüm bildirimi

        msg:
                .ascii  "Hello, world!\n"       # sevgili dizgemiz
                len = . - msg                   # sevgili dizgemizin boyu

Çaliştırılabilir bir kod üretmek

Nesne kodu üretimi

Çalıştırılabilir bir kod elde etmenin ilk adımı nesne dosyasını kaynaktan derlemek (veya çevirmek)tir:

Nasm örneği için:

$ nasm -f elf hello.asm

gas örneği için

$ as -o hello.o hello.S

Bu hello.o nesne dosyasını oluşturur.

Çalıştırılabilir üretmek

İkinci adım ilintileyiciyi çağırarak nesne dosyasının kendisinden çalıştırılabilir bir dosya üretmektir:

$ ld -s -o hello hello.o

Sonuç olarak bu hello çalıştırılabilir dosyasını üretecektir.

Hey, çalıştırmayı deneyin... Çalıştı mı? İşte bu. Oldukça basit.

MIPS Örneği

Gerçek dünyada x86 sülalesi dışında da bir evren var. Aşağıda Spencer Parkin tarafından sunulan ve MIPS işlemciler için yazılmış bir örnek vardır. Buraya kadar gelmişken http://www.cuillin.demon.co.uk/nazz/trivia/hw/hw_assembler.html adresindeki Bir Grup Sembolik Makina Dili ile Yazılmış Merhaba Dünya Programına bakabilirsiniz.

# hello.S       by Spencer T. Parkin

# Bu benim ilk MIPS-RISC sembolik makina dili programım!
# Derlemek için:
# > gcc -o hello hello.S -non_shared

# Bu program PlayStation2 MIPS R5900 (EE Çekirdek)
# üzerinde hatasız ve uyarısız derlenir.
# EE Duygu Makinası (Emotion Engine) anlamına gelir

# -non_shared seçeneği gcc'ye
# yeniden tahsis edilebilir kod ile ilgilenmediğimizi söyler.
# Eğer isteseydik, PIC-ABI çağrım kurallarını
# ve diğer protokolleri kullanmalıydık

#include <asm/regdef.h>         // Anaşılabilir yazmaç adları için
#include <asm/unistd.h>         // Sistem servisleri için

        .rdata                  # yalnız okunabilir veri bölümüne başlangıç
        align          2        # belleğin yapım şeklinden dolayı böyle

hello:  .asciz  "Hello, world!\n"  # Null ile sonlanmış bir karakter dizisi
        .align  4               # belleğin yapım şeklinden dolayı
length: .word   .- hello        # length = IC - (hello-addr)

        .text                   # kod bölümü başlangıcı
        .globl  main            # gcc/ld bağlamasından dolayı
        .ent    main            # gdp hata ayıklama bilgisi

main:                           # gcc'ye bir -non_shared alanı sunmalıyız
                                # ya da aşağıdaki üç satır etkin olmalı
#       .set    noreorder       # yeniden komut sıralamasını kapat
#       .cpload t9              # PIC ABI zırvası
#       .set    reorder         # yeniden komut sıralaması aktif

        move    a0,$0           # dosya tanımlayıcısı standart çıktıyı göstersin
        la      a1,hello        # karakter dizisi adresini yükle
        lw      a2,length       # karakter dizisi boyunu yükle
        li      v0,__NR_write   # sistem yazma servislerini belirt
        syscall                 # çekirdeği çağır (karakter dizisini yaz)
        li      v0,0            # geri dönüş kodunu yükle
        j       ra              # çağırana dönüş
        .end    main            # dgb için hata ayıklama bilgisi

# hepsi bu kadar millet!