Başlangıç > Asm Dökümanlar > NASM ile Assembly programlama

NASM ile Assembly programlama

[biraz daha genişletip düzenliyeceğim]
Assembler olarak nasm öneririm. masm32 kadar donanımlı görünmeyebilir, küçük bir exe dosyasından ibaret ama yaptıkları çok büyük. Assembly i doğal öğrenmek için nasm ile başlamalısın. .IF .WHILE invoke filan gibi birsürü sahte kod , bilmemne PROC, END PROC gibi fazlalıklarla uğraşmayı hiç sevmedim ben, ayrıca hem windows hem linux hemde diğer sistemlerde çalışabilecek assembly kodu yazmanın yolu nasm dır.

Nasm kullanacaksan önce bir linkere ihtiyacın olacak. Ayrıca, fonksiyonlarını kullanabileceğin bir C kütüphanesi fena olmaz, ekrana yazı yazmak için printf i filan kullanırsın, öğrenme sürecin baya hızlanır. Ben iki tane linker ve C kütüphanesi için olayı anlatacağım. Birincisi, Mingw – gcc, devcpp gibi ideler ile otomatik geldiği gibi son sürümünü kendin de indirip kurabilirsin. İkincisi ise Visual C++ 6.0, neden 6 dersen bende o var ona göre anlatıcam.

Şimdi elinde nasm , visual C++ 6 veya gcc olduğunu varsayıyorum. Tabi bunların bin dizinlerini ortam değişkenlerine eklemen lazım ki heryerde kullanabilelim. Onka cmd den kısaca yapmayı göstermişti de nerde bilmiyorum. İlk örneğe geçiyorum hemen…

örnek1:

Kod:
[bits 32]

global _start

extern _printf
extern _getchar
extern _exit

section .data

mesaj db "Merhaba Dunya",0x0

section .text

_start:
	push	mesaj
	call	_printf

	call	_getchar

	push	0x0
	call	_exit

	ret

C kütüphanesini kullanıyoruz, C’de tüm global nesnelerin fonksiyonların isminin başına _ gelir. Bu yüzden asm de de ben eğer fonksiyon yazıcaksam önüne _ koyarım, malum C kodundan çağırmak gerekebilir.

Şimdi kodu nasıl derleyeceksin, onu göstereyim. öncelikle mingw-gcc ile çalışıyorsan,

Kod:
nasm ornek.asm -Ox -f win32
ld ornek.obj -lmsvcrt -s -e _start -o ornek.exe

ornek.exe çıkacak, bende boyutu 2 kb, eğer çalıştırırsan ekrana merhaba dünya yazar ve tuşa basılmasını bekler.

Gelelim eğer visual C++ 6.0 kullanıyorsan.

Kod:
nasm ornek.asm -Ox -f win32
link ornek.obj msvcrt.lib /subsystem:console /entry:start

Eğer windows apileri kullanmak istiyorsan yapacağın şey aynı, msvcrt ile birlikte mesela kernel32 yi de ekleyebilirsin. şimdi açıklamaları yapayım.

extern _fonksiyon : Burada extern ifadesi bu fonksiyonun bizim kaynak kodumuz içinde olmadığını, ancak varmış gibi çağırılmasını söyler, çünkü link aşamasında o fonksiyon koda eklenecektir. C de de extern aynı şekilde kullanılır ama daha cok global değişkenler için, çünkü fonksiyonlar için gereksizdir.

global _fonksiyon : Bu da fonksiyonun bizim kodumuzda olduğunu, ancak bağlama aşamasında diğer modüllerden erişilebileceğini bildirir. Mesela biz link ederken, programımızın entry pointi olarak bu fonksiyonu seçtik, yani bizim programımızın main idir. aynı şekilde, bir C kodu yazıp, o C kodundan bu fonksiyonu da çağırabilirdik. Eğer global olarak bildirmessek derlenmiş modüle fonksiyon ismi yazılmaz, sadece aynı modül içinden erişilebilir olur.

section kavramı : Tüm exeler disk üzerinde ve bellekte, sectionlara ayrılmıştır, her section bellekte en az bir bellek sayfası (4 kb) olacak şekilde açılır, ya da 4 kb nin katları, her sectionun kendi karakteristiği vardır, koruması vardır, mesela .rdata sadece okunabilir, .text çalıştırılabilir gibi, sectionun kapsadığı tüm bellek sayfaları bu karakteristiğe tabidir. Programın global dataları .data sectionunda tutulur, fonksiyonlar, yani kod, .text de tutulur, dialoglar, iconlar vb resourceler .rc vs. kendi sectionumuzu oluşturabiliriz, karakteristiği doğru ayarlayarak ismini istediğimiz gibi yazarız, bu isimler kesin değildir.

Her section, bellekte ve diskte aynı yeri kaplamaz, PE tablosu altındaki section tablosunda file alignment ve section alignment var, file alignment diskte sectionların kaçar bayt kapladığını belirtir, kod küçükse file alignment 0x200 ayarlanarak exe boyutu önemli ölçüde küçültülür. Section alignment ise bellekteki sectionların kaçar bayt kapladığını belirtir, burada zaten en az 4 kb ve katları olması gerektiğini söylemiştim. Exe MZ imzası dahil tüm PE başlığıyla birlikte komple belleğe yüklenir ancak sectionlar diskteki gibi değil çok daha geniş yerleşir belleğe.

_start: bu bir etikettir esasında, sadece bir adresi belirtir. ancak bu adresi biz global olarak adlandırdık ve programı bu noktadan başlattık, binlerce satırlık asm programı yazabilirsin, en baştan başlar düm düz çalışmaya devam eder, asm herhangi bir programlama paradigmasına bağlı değildir, sadece hex kodlarının sembolik isimlendirmelerinden ibarettir(bazı istisnalar dışında) doğal olarak fonksiyon gibi kavramlar ancak biz koda öyle yaklaşırsak anlamlıdır, herhangi bir kural yoktur.

Ancak kodu yapısal yazmak yönetim açısından çok önemlidir. _etiket: … ret şeklinde onlarca fonksiyon yazıp, bunları call ile çağırmak, içlerinden istediğimizi entry point(main) seçmek iyi bir yöntemdir. Şimdi biraz daha karışık bir örnek.

Kod:
[bits 32]

global _start

extern _printf
extern _scanf
extern _getchar
extern _exit

section .data

sayi1	dd	0
sayi2	dd  0

format_d db "%d",0
sayigir1 db "Bir sayi girin : ",0
sayigir2 db "Bir sayi daha girin :",0
toplam	 db "Toplamlari : %d",0

section .text

_start:
	push	sayigir1
	call	_printf

	push	sayi1
	push	format_d
	call	_scanf

	push	sayigir2
	call	_printf

	push	sayi2
	push	format_d
	call	_scanf

	mov	eax, dword[sayi1]
	add	eax, dword[sayi2]

	push	eax
	push	toplam
	call 	_printf

	call	_getchar
	call	_getchar

	push	0x0
	call	_exit

	ret

Nasm ile yazılmış fonksiyonları C içinden çağırma
Benim en çok kullandığım yöntem bu, gerçi bazen asm de yazdığım fonksiyonu entry point yapıyorum, bu durumda nasm ile yazılmıi fonksiyon içinden C fonksiyonu çağrılmış oluyor, farketmez, bir arada çalışmaları diyelim.

Yukarıda belirttim zaten, C de global nesnelerin önünde _ bulunuyor, bu da demekki asm ile yazdığımız herhangi bir fonksiyona, ya da global değişkene C de erişmek için nesne isminin önüne _ koyacağız.

Önce C kodu. dosya : C.c

Kod:
#include <stdio.h>

extern int topla(int,int);

int main()
{
    int sonuc = topla(55,66);

    printf("%d",sonuc);

    getchar();
    return 0;
}

Şimdi asm ile yazılmış topla fonksiyonu. dosya : asm.asm

Kod:
[bits 32]

global _topla

section .text

_topla:
	mov eax,[esp + 8]
	add eax,[esp + 4]
	ret

Derlerken şu adımları izliyoruz, önce asm yi derleyelim.

Kod:
nasm asm.asm -Ox -f win32

şimdi bir asm.obj dosyamız var, Derleyici olarak gcc kullanıyorsak şöyle devam ediyoruz.

Kod:
gcc C.c asm.obj -Os -s -o C.exe

Visual C++ 6 kullanıyorsak.

Kod:
Cl C.c asm.obj

C.exe yi çalıştırırsanız 121 görmeniz lazım.

Şimdi Asm de yaratılmış bir veri yapısını C ile kullanmayı deneyelim.

Kod:
#include <stdio.h>

extern int data;
extern void setdata(int);

int main()
{
    printf("once  : %d\n",data);
    setdata(55);
    printf("sonra : %d\n",data);

    getchar();
    return 0;
}
Kod:
[bits 32]

global _setdata
global _data

section .data
_data dd 0

section .text

_setdata:
	mov eax,[esp + 4]
	mov dword[_data],eax
	ret

Derleme işlemi aynı şekilde yapılıcak, c.exe de önce : 0 sonra : 55 yazıcak. kodu açıklayım.
Öncelikle asm kodunda bir değişken var, ismi data, bir de fonksiyon var, ismi setdata, fonksiyonun görevi, data global değişkenini set etmek.

C kodunda önce, asm de tanımlanmış olan data değişkeni ekrana yazılıyor, içeriği 0, sonra setdata ile asm fonksiyonu datayi 55 yapıyor, sonra ekrana yine yazdığımızda içeriğini 55 olarak görüyoruz, bu data global değişkeni herhangi bir değişken gibi C de kullanılabilir.

Şimdilik bukadar.

Kaynak: KUTALMIS

Reklamlar
  1. Henüz yorum yapılmamış.
  1. No trackbacks yet.

Bir Cevap Yazın

Aşağıya bilgilerinizi girin veya oturum açmak için bir simgeye tıklayın:

WordPress.com Logosu

WordPress.com hesabınızı kullanarak yorum yapıyorsunuz. Log Out / Değiştir )

Twitter resmi

Twitter hesabınızı kullanarak yorum yapıyorsunuz. Log Out / Değiştir )

Facebook fotoğrafı

Facebook hesabınızı kullanarak yorum yapıyorsunuz. Log Out / Değiştir )

Google+ fotoğrafı

Google+ hesabınızı kullanarak yorum yapıyorsunuz. Log Out / Değiştir )

Connecting to %s

%d blogcu bunu beğendi: