Yukarıda yazmışolduğumuz hex isimli program eğer girişçıkış dosyalarının isimlerini içeren komut satırıargümanlarıile çağırılabiliyor olsaydıçok daha kullanışlıolacaktı. Fakat bu komutlara nasıl ulaşabiliriz ?
Bir UNIX programıbaşlamadan önce bazıverileri yığınına kaydeder.Bundan sonra _start isimli etiketin bulunduğu yere zıplar.Evet fonksiyon çağrısıdeğil sadece zıplama.Bu da demek oluyor ki bu verilere [esp+offset] ile yada basitçe (pop) işlemi ile rahatlıkla ulaşılabilir.
Yığının en üstünde bulunan sayıgenellikle 'argc' olarak adlandırılan argüman sayısıdır.
Bundan sonra gelenler ise argümanların değerleridir.Genel olarak 'argv' olarak adlandırılır ve argv[0] dan argv[argc -1] e kadar gider.Bunlar gerçek argüman değillerdir. Fakat argümanların nerede olduğunu gösteren işaretçilerdir. Argümanların kendisi NULL ile bitirilmişstringlerdir.
argv listesinin sonunda NULL işaretçisi yani 0 bulunur.Dahasıda var ama bizim için şimdilik bu kadar yeter.
Not: Eğer MS-DOS programlama ortamından geçişyaptıiseniz ana farklılık her bir argümana ayrıbir string atanmasıdır. İkinci olarak pratik olarak argüman sayısında herhangi bir sınırlama söz konusu değildir.
Bu bilgi ile donandıktan sonra hex.asm'nin yeni versiyonunu yapmaya neredeyse hazırız.Ama öncelikle system.inc dosyasına bir iki satır kod ekleyeceğiz.
İlk olarak iki yeni sistem çağrınumarasınıdosyamıza eklemeliyiz.
%define SYS_open 5 %define SYS_close 6
Bundan sonra iki yeni makroyu da dosyanın sonuna yazıyoruz.
sys.open: sys.close: [etc...] int 80h ret
İşte şimdi kaynak kodumuzun değiştirilmişhali :
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
Programımızın .data bölümünde fd.in ve fd.out isimli iki değişken kullanarak girdi çıktıdosyalarımızın numalarınıtuttuk.
.text bölümünde standart girişve çıkış olan stdin ve stdout yerine [fd.in] ve [fd.out] ile kendi girişçıkışdosyalarımızıkullandık.Hata durumunda işlenecek kodu _start etiketinden önce tanımladık böylece hatanın oluşabileceği yere daha yakın olacaktır.
Doğal olarak programımız yine _start etiketinden başlıyor.İlk olarak yığından argc ve argv[0] değişkenlerini siliyoruz : Şu anda bizi ilgilendirmiyorlar.
Argv[1]' i ECX yazmacına çıkarıyoruz. Çünkü bu yazmaç işaretçiler için daha uygun ve en son NULL işaretçisi kontrol ederken
jecxzkomutunu kullanacağız.Argümanıaldıktan sonra eğer NULL değilse dosyayıaçmayıdeniyor eğer açamaz ise önceki programımızda olduğu gibi
stdinile girdi işlemine devam ediyor ve çıktıyı
stdout'a yapıyor.Eğer girdi dosyasının açılması sırasında bir hata oluşur ise hata karşılama(error handler) kodunu çalıştırır.
Programımızın geri kalan kısmıesikisi gibi sadece bir farkla : Programdan çıkmadan önce [fd.in] ve [fd.out] dosyalarınıkapatıyoruz.
Çalıştırılabilir dosyamız 768 byte gibi devasa (!) bir yer kaplıyor.
Hala programıgeliştiremez miyiz ? Elbette geliştirebiliriz , bütün programlar geliştirilebilir. Burada örnek olacak bir kaç fikir yazalım :
Hata mesajınızıstderr gönderen bir hata karşılama fonksiyonu yazabilirsiniz.
Read ve write fonksiyonlarına birer hata karşılama fonksiyonu yazabilirsiniz.
Girdi dosyasınıaçtığımızda stdin'i çıktıdosyasını açtığımızda stdout'u kapatabilirsiniz.
Komut satırında -o yada -i gibi seçenekler alarak girdi ve çıktıdosyalarıbelirtmesini sağlayabilirsiniz böylece stdin'den almışolduğumuz veriyi işleyip bir dosyaya kaydetmek mümkün olacaktır.
Hatalıgirişyapıldığında kullanımıtarif eden bir uyarı gönderebilirsiniz.
Bunlarıdaha da arttırabiliriz gerisini okuyucuya bırakıyoruz.Bunlarıgerçekleştirmek için gerekli bütün şeyleri artık biliyorsunuz.