| |||||||
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.
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.
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.
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
|
.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
|
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!
|
| ||||||||||