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