11.5. Taşınabilir Kod Yazmak

Taşınabilirlik genel olarak Assembly dilinin etkili olduğu bir özellik değildir.Lakin birden fazla platform için özellikle nasm ile Assembly kodu yazmak mümkündür. Bizim yazmışolduğumuz bir assembly kütüphanesi Windows ve FreeBSD gibi değişik işletim sistemlerini destekliyordu.

Birbirinden farklıfakat aynımimari üzerinde bulunan iki platform üzerinde kodunuzu çalıştırmanız çok daha mümkündür.

Mesela FreeBSD Unix tir ve Linux ise Unix benzeridir. Bunlar arasındaki tek fark çağrıdüzenlerinin ,fonksiyon numaralarının ve dönüş sistemlerinin farklıolmasıdır.

11.5.1. Sistemler arasındaki fonksiyon numaralarının farklılığı problemini çözmek

Bir çok durumda fonksiyon numaralarısistemler arasında aynıdır. Farklıolsa bile bunu çözmek çok zor değildir. Bunun için programınızda sayılarıkullanmak yerine önceden sisteme göre tanımlamışolduğunuz sabit değerleri kullanabilirsiniz.

%ifdef LINUX %define SYS_execve 11 %else %define SYS_execve 59 %endif

11.5.2. Farklıdüzenler problemini çözmek

Çağrıdüzenleri ve dönüşdeğerleri problemi makrolarıkullanarak çözülebilir.

%ifdef	LINUX
%macro	system	0
	call	kernel
%endmacro
align 4
kernel:
	push	ebx
	push	ecx
	push	edx
	push	esi
	push	edi
	push	ebp
	mov	ebx, [esp+32]
	mov	ecx, [esp+36]
	mov	edx, [esp+40]
	mov	esi, [esp+44]
	mov	ebp, [esp+48]
	int	80h
	pop	ebp
	pop	edi
	pop	esi
	pop	edx
	pop	ecx
	pop	ebx
	or	eax, eax
	js	.errno
	clc
	ret
.errno:
	neg	eax
	stc
	ret
%else
%macro	system	0
	int	80h
%endmacro
%endif

11.5.3. Diğer taşınabilirlik problemlerini çözmek

Yukarıda anlatılanlar FreeBSD ve Linux arasında taşınabilirliği çoğunlukla sağlar. Yine de bazıçekirdek yapılarında farklılıklar çok daha büyüktür.

Bu durumda sistem çağrılarıiçin iki farklıbölüm yazmalısınız ve bundan sonra şartlıbir şekilde kodlamalısınız. Eğer şanslıiseniz kodunuzun büyük kısmıçekirdek çağrılarından farklıişlem gerçekleştirecektir.Kodun geri kalan kısmında sadece bir kaç satır kodda durum kontrolü koyup taşınabilirlik problemi ile başa çıkabilirsiniz.

11.5.4. Kütüphane kullanmak

Taşınabilirlik problemlerinden kurtulmak için sistem çağrıları için bir kütüphane yazmak da bir çözüm olabilir. FreeBSD ve Linux için ayrıbir kütüphane yazarak ana kodunuzun dışında problemi çözebilirsiniz.

Kütüphanenizde herbir sistem çağrısıiçin ayrıbir fonksiyon(yada eğer klasik Assembly terminolojisini kullanacak olursak prosedür) yazınız. Parametreleri göndermek için C çağrıdüzenini kullanın. Fakat çağrınumarasınıgöndermek için EAX yazmacını kullanmaya devam edin. Bu durumda sizin FreeBSD kütüphaneniz oldukça basit olacaktır.Değişik fonksiyonlar aynıkod için etiketetlenecektir.

sys.open: sys.close: [etc...] int 80h ret

Linux kütüphanesi ise daha fazla fonksiyon gerektirecek. Ama yinede sistem çağrılarınıaynıparametre sayılarına göre gruplayabilirsiniz.

sys.exit: sys.close: [etc... one-parameter functions] push ebx mov ebx, [esp+12] int 80h pop ebx jmp sys.return ... sys.return: or eax, eax js sys.err clc ret sys.err: neg eax stc ret

Kütüphane yaklaşımıilk bakışta kullanışsız gibi görülebilir çünkü kodunuz birden fazla dosyaya bağlıolacaktır.Fakat bunun çok fazla avantajıvardır : İlk olarak bu kütüphaneyi bütün kodlarınız için sadece bir kere yazmak zorundasınız hatta bir kere yazdığınızda diğer Assembly programcılarına da dağıtabilirsiniz. Fakat kütüphanenizin en büyük avantajıkodunuz diğer sistemlere de taşınabilir, başka programcılar tarafından bile olsa . Bunun için gereken sadece yeni bir kütüphane yapmaktır kod üzerinde değişikliğe bile ihityaç duymaz.

Eğer yinede kütüphane yazmak fikri hoşunuza gitmedi ise bütün sistem çağrılarınızın olduğu diğer bir Assembly dili dosyasınıana programınıza bağlayabilirsiniz. Yine burada diğer sistemlere taşınacağında yeni bir obje dosyasıoluşturmak yeterli olacaktır.

11.5.5. Include dosyalarıkullanmak

Eğer bir yazılım sürümünü kodlarıile birlikte yayınlıyor iseniz , makrolarıayrıbir dosya içine yerleştirip ana kodunuzda bunun eklenmesini sağlayabilirsiniz(Include dosyaları).

Diğer sisteme aktaran kişilerin yapmasıgereken sadece yeni bir include dosyasıoluşturmak olacaktır. Herhangi bir obje kodu yada kütüphane gerektirmeyecek . Böylece sizin programınız kodun değiştirilmesine gerek olmaksızın taşınabilirlik kazanmış olacak.

Not: Bu yaklaşım bu ünitede geçen diğer bölümlerde kullanılacaktır. system.inc adlıdosyamız herhangi bir kod yazdığımızda eklenerek yeni sistem çağrılarıiçin kullanılacaktır.

system.inc dosyamızının içinde standart dosya tanımlayıcıları :

%define	stdin	0
%define	stdout	1
%define	stderr	2

Her bir sistem çağrısıiçin sembolik bir isim üretiyoruz

%define	SYS_nosys	0
%define	SYS_exit	1
%define	SYS_fork	2
%define	SYS_read	3
%define	SYS_write	4
; [etc...]

Kısa bir prosedür için uzun bir isim tanımlıyoruz , göreceksiniz ki bu ismi yanlışlıkla kullanmak hiç de kolay değil.

section	.text
align 4
access.the.bsd.kernel:
	int	80h
	ret

Burada tanımlıyacağımız makro ise bir argüman alır, syscall numarası

%macro	system	1
	mov	eax, %1
	call	access.the.bsd.kernel
%endmacro

Son olarak her sistem çağrısıiçin herhangi bir argüman almayan birer makro tanımlıyoruz.

%macro	sys.exit	0
	system	SYS_exit
%endmacro
%macro	sys.fork	0
	system	SYS_fork
%endmacro
%macro	sys.read	0
	system	SYS_read
%endmacro
%macro	sys.write	0
	system	SYS_write
%endmacro
; [etc...]

Bundan sonra bu kodlarısystem.incolarak kaydediyoruz. Eğer daha fazla sistem çağrısıkullanacaksanız onlarıda eklemelisiniz.