| |||||||
C-asm karışımı projeler üretiyorsanız bu tercih edilen yoldur. GAS açıklamaları olan Linux çekirdeği .s dosyalarından örnekleri ve GCC belgelerini inceleyiniz (as86 ile ilgili olanları).
32 bitlik geridönüş adresi üzerinde, 32 bitlik bağımsız değişkenler yığıta (stack) ters sözdizimsel sırada itilirler (push) (böylece doğru sırada erişilir/çıkarılırlar (pop)). %ebp, %esi, %edi ve %ebx çağrılan tarafından kullanılır, diğer yazmaçlar ise çağırıcı tarafından kullanılır; %eax sonuçları tutmak içindir veya %edx:%eax 64 bitlik sonuçlar için kullanılır.
FP yığıtı (FP stack): Emin değilim ama, sanırım tüm sonuç, saklanmış çağrıcıların tamamı st(0) içindeydi. Eğer daha fazla ayrıntı istiyorsanız http://www.caldera.com/developer/devspecs/ adresindeki SVR4 i386 ABI belirtimi iyi bir başvuru kaynağıdır.
GCC'nin çağrı uzlaşımlarını değiştirmek için, yazmaçları önceden ayırtan, yazmaçlarda bağımsız değişkenler barındırılmasını sağlayan, FPU'yu dikkate almayan, v.b. seçenekleri olduğunu unutmayın. i386 .info sayfalarına bakınız.
Standart GCC çağrı uzlaşımlarını izleyecek bir işlev için cdecl ve regparm(0) bildirimlerini yapmanız gerektiğine dikkat edin. GCC info sayfasından C Extensions::Extended Asm:: kısmına bakınız. Aynı zamanda Linux'un kendi asmlinkage makrosunu da nasıl tanımladığına bakınız.
Bazı C derleyicileri, diğerleri yapmadığı halde, her sembolden önce bir alt çizgi yerleştirirler.
Özellikle, Linux a.out GCC böylesi bir ön yerleştirmeyi yapar, oysa ki Linux ELF GCC yapmamaktadır.
Eğer her iki davranış biçimiyle de aynı anda uğraşmak isterseniz, varolan paketlerin bunu nasıl yaptıklarına bakınız. Mesela, Elk, qthreads, OCaml... gibi eski bir Linux kaynak ağacı edinin.
Ayrıca, örneğin, foo() işlev çağrısının gerçekte bir makine dili kodu olan bar'ın çağrılmasını sağlaması için şu şekilde bir ek ifade ile örtük C->asm isim değişikliğini zorlayabilirsiniz:
void foo asm("bar") (void);
|
Binutils paketindeki objcopy uygulamasının a.out nesnelerinizi ELF nesnelerine dönüştürmeyi mümkün kılması gerektiğini unutmayın, hatta bazı durumlarda tam tersine de imkan tanır. Daha genel olarak, pekçok dosya biçimi arasında dönüşüm gerçekleştirir.
Genelde C kütüphanesi (libc) kullanmanın tek yol olduğu ve doğrudan sistem çağrıları yapmanın kötü olduğu söylenir. Bu doğrudur. Bir bakıma... Genel olarak, libc kütüphanesinin kutsal olmadığını bilmelisiniz ve pekçok durumda sadece bazı denetimler yapar, sonra çekirdeğe çağrı yapar ve ardından errno'ya atama yapar. Bunu kendi programınızda da yapabilirsiniz (eğer ihtiyacınız varsa) ve programınız bir düzine kat daha küçük olacaktır, bu da gelişmiş bir başarım artışına sebep olacaktır, bu da sırf paylaşımlı kütüphaneleri kullanmadığınızdan kaynaklanacaktır (durağan (static) kütüphaneler daha hızlıdır). Sembolik makina dili ile programlamada libc kullanımı pratik birşeyden çok zevk/inanış meselesidir. Linux'un POSIX standartlarına uygun olmayı hedeflediğini unutmayın, benzer şekilde libc de. Bu da, hemen her libc "sistem çağrısı" sözdizimin gerçek çekirdek sistemi çağrılarındaki sözdizimiyle örtüşmesi anlamına gelir (ve tam tersi). Buna ek olarak, GNU libc (glibc) sürümden sürüme daha yavaş hale gelmekte ve daha çok bellek tüketmektedir. İlerde siz de kendi, değişik türlerde, libc'ye özel işlevlerinizi (sadece birer sistem çağrısı değil) tanımlayacaksınız (printf() ve şürekası)... ve buna hazırsınız, değil mi? :)
Doğrudan sistem çağrıları yapmanın artı ve eksileri şu şekilde özetlenebilir:
Eğer yukarıdaki artı ve eksileri zihninizde iyice ölçüp tarttıysanız ve hala doğrudan sistem çağrılarını kullanmak istiyorsanız, size bazı önerilerim olacak:
Temelde, eax içerisine __NR_sistemçağrı_ismi numarası (asm/unistd.h dosyasındadırlar) ile int 0x80 değeri ve parametreleri de sırasıyla (altıya kadar) ebx, ecx, edx, esi, edi, ebp içine konur.
Sonuç eax içerisinde döndürülür, negatif sonuçlarda hata ile döner, bunun karşılığı da libc içerisinde errno'dur. Kullanıcı yığıtına dokunulmaz, dolayısiyle bir sistem çağrısı yaparken geçerli bir kullanıcı yığıtına ihtiyacınız yoktur.
![]() | Not |
|---|---|
ebp'ye 6 parametre aktarımı Linux 2.4 sürümünde mümkün olmuştur, daha önceki Linux sürümleri yazmaçlarda sadece 5 parametreye bakıyordu. | |
Linux Çekirdeğinin Dahili Yapısı (Linux Kernel Internals) belgesi ve özellikle i386 Mimarisinde Sistem Çağrıları Nasıl Gerçeklenir? (How System Calls Are Implemented on i386 Architecture?) bölümü çok daha sağlıklı bilgi verecektir.
Başlatırken bir sürece parametrelerin aktarılmasında olduğu gibi, genel prensip, yığıtın orjinal olarak argüman sayısını (
Eğer Linux altında doğrudan port erişimi ile G/Ç işlemleri gerçekleştirmek istiyorsanız, bu ya işletim sisteminde bir değişiklik gerektirmeyen basit bir iştir ve bununla ilgili G/Ç portları ve programlama (IO-Port-Programming) küçük nasıl belgesini okumanız yeterli olur ya da bir çekirdek aygıt sürücüsü gereklidir ve çekirdek kaynak kodlarını elden geçirme, aygıt sürücüsü geliştirme, çekirdek modülleri, v.b. ile ilgili daha fazla bilgi edinmeniz gerekir. Bunlarla ilgili pek çok belge ve NASILlar LDP sayfalarında bulunmaktadır.
Belki de, grafik programlama yapmak istersiniz, o zaman GGI veya XFree86 projelerinden birine katılın.
Bazıları daha iyisini bile yapabilir, yorumlanmış belli bir alana özgü bir dilde, GAL, küçük ve güçlü XFree86 sürücüleri yazabilirler, bazı değerlendirmelerden sonra da C ile yazılmış sürücülerin verimini arttırabilirler (sürücüler ne sadece asm'dir ne de sadece C!). Burada sorun, verimi arttırmak için kullanılacak bazı değerlendiricilerin özgür olmamasıdır. Bunların özgür sürümlerini gerçekleştirecek olan var mı?
Herneyse, tüm bu durumlarda, herşeyi sembolik makina kodu ile yazmak yerine GCC satıriçi sembolik makina dilini linux/asm/*.h dosyalarındaki makrolarla kullanmak daha iyi olacaktır.
Böyle bir şey teorik olarak doğrudur (kanıt: DOSEMU'nun programlara seçici bir şekilde port atamalarını nasıl yaptığını inceleyiniz) ve ben de bir yerlerde birilerinin bunu yaptığı söylentilerini de duydum (bir PCI sürücüsü mü? bir VESA erişim aracı mı? ISA PnP mi? bilmiyorum). Eğer bunun hakkında çok net bilginiz varsa, o zaman çok daha memnun olacaksınız. Herneyse, daha ayrıntılı bilgi için bakılması gereken kaynaklar Linux çekirdeğinin kaynak kodları, DOSEMU kaynakları (ve DOSEMU deposundaki diğer programlar) ve de Linux altında pekçok düşük seviyeli programın kaynaklarıdır ... (belki CGI'da olabilir, eğer VESA desteği varsa).
Temel olarak ya 16 bitlik korumalı kipi veya vm86 kipini kullanmalısınız.
İlkinin yapılandırılması daha basittir, fakat sadece segman aritmetiği veya mutlak segman adreslemesi (özellikle 0. segmanı adreslerken) ile ilgili işlemler yapmayacak iyi davranışlı kodla çalışır, fakat şans eseri tüm segmanlar kullanılırsa, LDT ile ileri düzey ayarlama yapılabilir.
İkincisi ise harcıalem 16 bitlik ortamlarla daha bir uyumluluk sağlar, fakat idaresi daha karmaşıktır.
Her iki durumda da 16 bitlik koda geçmeden önce, şunları yapmalısınız:
Tekrar, DOSEMU projesiyle sunulan belgeleri dikkatlice okuyunuz, özellikle Linux/i386 altında ELKS ve/veya .COM programlarını çalıştırmak için kullanılan küçük emülatörlerle ilgili kısımları.
Pekçok DOS çoğaltıcıları (extenders) DOS servisleri için bazı servislerle beraber gelir. Bununla ilgili belgeleri okuyunuz, fakat genelde, int 0x21 ve benzerine benzetim yaparlar (simulate) ve siz de sanki gerçek kipteymiş gibi çalışırsınız (Az gelişmişlik dışında birşeyleri olduğundan ve işlemleri 32 bitlik terimlerle çalışır hale getirdiklerinden şüpheliyim, daha çok gelen kesmeleri gerçek kip veya vm86 eylemcisine yansıtıyor gibiler.)
DPMI hakkındaki belgeler (ve fazlası) ftp://x2ftp.oulu.fi/pub/msdos/programming/ adresinde bulunabilir (yine, asıl x2ftp sitesi kapanıyor (kapandı?), onun için yansıyı kullanın).
DJGPP kendi (sınırlı) glibc türev/altküme/yerdeğiştirmeleri v.b.leri ile gelmektedir.
Linux'tan DOS'a çapraz-derleme (cross-compile) yapmak mümkündür, metalab.unc.edu için olan yerel FTP yansınızın devel/msdos/ dizinine bakınız; Aynı zamanda Utah üniversitesindeki Flux Projesi'nden MOSS DOS-extender (DOS-genişletici)'ye de bakınız.
Diğer belgeler ve SSS, DOS merkezlidir; biz DOS gelişimini tavsiye etmiyoruz.
Denetim duygusu pekçok işletim sistemi geliştiricisini sembolik makina diline çeken şeydir, bu da genelde sembolik makina dili kodları elden geçirmeye yol açmakta veya ondan kaynaklanmaktadır. Her ne kadar temelini oluturan bir sistemin tepesinde çalışabiliyor olsa da (Mac üzerindeki Linux veya Unix üzerindeki OpenGenera), kendi kendine gelişime izin veren bir sistem ancak işletim sistemi olarak isimlendirilebilir.
Böylece, kolay hata ayıklama amaçları için, ilk başlarda kendi işletim sisteminizi Linux üzerinde çalışır şekilde tasarlayabilirsiniz (yavaşlığına rağmen), daha sonra Flux OS aracını kullanarak (kendi işletim sisteminizde Linux ve BSD sürücülerinin kullanımını garanti eder), onu kendi başına çalışır hale getirebilirsiniz. İşletim sisteminiz kararlı olduğunda, artık gerçekten sevdiyseniz, kendi donanım sürücülerinizi yazmanın vaktidir.
Bu NASIL belgesi önyükleyici (bootloader) kodlarını, 32 bitlik kipe geçmeyi, kesmelerle işlem yapmayı, Intel'in temel güvenli kipini veya V86/R86 beyinölümlülüğünü (braindeadness), nesne biçiminizi tanımlamayı ve çağrı uzlaşımlarını kapsaMAmaktadır.
Tüm bunlar için güvenli bilgi bulabileceğiniz yer halihazırdaki işletim sisteminin veya önyükleyicinin kaynak kodlarıdır. Pekçok konu şu adreste mevcuttur: http://www.tunes.org/Review/OSes.html
| ||||||||||