X86 Assembly/İlk programımız
Assembly kodlarını yazmak ve makina koduna dönüştürmek için C:\WINDOWS\System32 klasöründeki debug programını kullanacağız. Bu programı komut isteminde debug
yazıp enter'a basarak çalıştırabilirsiniz. Debug programı çalıştığında komut isteminde en solda bir çizgi görünür. Bu çizgi bize debug modunda olduğumuzu söyler. Assembly moduna geçmek için, yani Assembly dilini kullanarak bellek gözeneklerine komut ya da veri girebilmek için a
komutunu kullanırız. Şimdiye kadar yaptıklarımızı destekçi olması açısından bir görelim:
Assembly modunda bellek gözeneklerine Assembly dilini kullanarak komut ve veri gireriz. Bellek gözenekleri arasında dolaşmak için enter tuşunu kullanırız. Yani bir bellek gözeneğine veri girdikten sonra enter'a basarsak sonraki bellek gözeneği veri girilmesi için aktifleştirilir. Assembly modundan çıkmak için ilgili bellek gözeneğine hiçbir şey yazmadan enter'a basarız. Soldaki : ile ayrılmış sayılar bize hangi bellek gözeneğinde olduğumuzu söylerler. İlk sayı bellek gözeneğinin segment adresi, ikinci sayı da ofset adresidir. Sizde segment adresi değişebilir ama ofset adresinin buradaki gibi 100 olması gerekir. segment:ofset yöntemi belleği adreslemek için kullanılan bir yönemdir. 64 KB'lık bellek bölümlerinin her birine bir segment denir. Bir segmentteki her bir bayta da ofset denir. X86 mimarisinde üzerinde işlem yapılabilen en küçük bellek gözeneği 1 bayttır. Şimdi Assembly modunda ilk programımızı yazalım:
Assembly dilinde asıl komutla komutun kullandığı argümanlar (örneğin mov ile ah,9) arasında en az bir boşluk bırakılması gerekir. Ancak ben daha okunaklı olması için tab kullanıyorum. Sizin de tab kullanmanızı tavsiye ediyorum. Ayrıca Assembly dilinin büyük-küçük harf duyarlılığı olmayan bir dil olduğunu bilmenizde fayda var. Kodları inceleyecek olursak
- Mov herhangi bir yazmaca bir değer yazılmasını sağlar. Yazmacın şimdilik işlemcinin içindeki veri depolamaya yarayan gözenekler olduğunu bilmeniz yeterli. En çok kullanacağımız yazmaçlar al, ah, ax, bl, bh, bx, cl, ch, cx, dl, dh ve dx'tir. Asıl yazmaçlar sonu x ile bitenlerdir ve 2 bayt veri depolayabilirler. Sonu l ile bitenler ilgili x'li yazmacın düşük değerlikli baytını, sonu h ile bitenler de ilgili x'li yazmacın yüksek değerlikli baytını ifade eder.
- Int önceden yazılmış bir servisi çalıştırmak için kullanılır. Windows'un içine gömülü çeşitli int servisleri bulunmaktadır. int 21 servisinin 9. fonksiyonu ekrana yazı yazdırmaya yarar. Bu fonksiyon dx yazmacındaki ofsetten itibaren $ karakterine kadar olan bütün karakterleri ekrana yazdırmaya yarar. Int 21, fonksiyonunu ah yazmacından alır. Int 20 servisi programı sonlandırır.
- Db talimatı ise bellek gözeneklerine komut değil de karakter yazılmasını sağlar.
Buraya kadar bellek gözeneklerine çeşitli veri ve komutlar girdik. Ancak henüz komutları çalıştırmadık. Komutları çalıştırmak için assembly modundan çıktıktan hemen sonra g komutunu veririz.
Bu yazdığımız programı sabit diske kaydetmek içinse sırasıyla şu adımları izleriz:
- Cx yazmacına programın boyutunu yazarız. Debug modundayken bir yazmaçtaki değeri değiştirmek için
r yazmaç
komutu kullanılır. Cx yazmacındaki değeri değiştirmek için tabii ki doğal olarakr cx
komutunu vermemiz gerekir. Bu komutu verdikten sonra ilgili yazmaçtaki hâli hazırdaki değer gösterilip yeni bir değer girişi için beklenir. Yeni bir değer girmek istemiyorsak sadece entera basılır. Programın boyunu bulmak içinse ilk ofsetle son ofset arasındaki aralığı sayabilirsiniz. Örneğimizde 100. ofsete ilk komutumuzu yazmışız, son sınır ofset de 111 olmuş. O hâlde programımızın boyutu 11 bayttır. İllaki 11 bayt yazmak zorunda değilsiniz. 11 veya daha yüksek bir değer yazabilirsiniz. Ancak 11 yazarsanız sabit diskten tasarruf yapmış olursunuz. - N komutu ile dosyamıza isim veririz. Örneğin dosyamızın isminin program.com olmasını istiyorsak
n program.com
komutunu veririz. - Son olarak w komutunu veririz.
- Debug programından çıkmak için q komutunu veririz.
- Dosyamız debug programını hangi klasördeyken başlatmışsak o klasörde oluşur.
Notlar
[değiştir]- Debug programındaki bütün sayılar 16'lık sayı sistemindedir. Dolayısıyla bütün hesaplamalar 16'lık düzene göre yapılmalıdır.
- Assembly modunda yazdığımız her kod bir baytlık değildir. Hatta çoğu kodlar bellekte 2-3 bayt yer kaplar. Dolayısıyla ofsetler arasında 2'şer 3'er atlamalar olağandır.
- Talimatlar (örneğin db gibi) komutların aksine assembly modunda yazılır yazılmaz çalıştırılır. Halbuki komutlar henüz çalıştırılmaz. Yalnızca ilgili komut ilgili bellek gözeneğine yazılır.
- Şimdilik yalnızca com uzantılı program dosyaları oluşturabiliriz.
- Yalnızca a komutunu verirsek aktif segment ve aktif ofset Assembly komutlarını girmek için açılır. Debug programını ilk açtığımızda aktif segment herhangi boş bir segment yapılır. Aktif ofsetse debug programı ilk açıldığında daima 100'dür. Ancak kod yazdıkça aktif ofset zamanla değişir. Henüz aktif segmenti değiştirmeyeceğimiz ve bunlar biraz ileri konular olduğu için biz şimdilik sadece ofsetlerle ilgileneceğiz. Assembly modunu aktif ofsette değil de istediğimiz bir ofsette açmak için debug modundayken
a ofset
komutunu kullanırız. Örnek:
-a 102
Burada aktif segmentteki 102. ofset Assembly kodları girişi için açılır ve biz kodları girip entera bastıkça aktif ofset değişir.