Sembolik Makine Dilinde Yazılmış Fonksiyonların C ve C++’tan Çağrılması

02:03 ,

Bir programın tamamının sembolik makine dilinde yazılması çok özel durumlar dışında tercih edilen bir yol değildir. Bunun nedenleri şöyle sıralanabilir:

  • Sembolik makine dilleri taşınabilir (portable) değildir. Makine komutları işlemciden işlemciye değişebildiği gibi genel sentaks da aynı işlemci söz konusu olduğunda bile derleyiciden derleyiciye değişebilmektedir.
  • Sembolik makine dilleri alçak seviyeli olduğu için bu dillerde programcıların hata yapması daha olasıdır.
  • Sembolik makine dillerinde kod yazım hızı daha düşüktür. Bu da üretkenliği düşürmektedir.
  • Sembolik makine dillerinde programda hata ayıklama daha zordur.

Bu nedenlerden dolayı pratikte kodun büyük bölümünün C, C++ ( bizim için bu diller yüksek seviye :) gibi yüksek seviyeli ve taşınabilir dillerde, yalnızca kritik yerlerin sembolik makine dilinde yazılması daha yaygın kullanım biçimidir.(Örneğin Linux çekirdeğinin yalnızca %3 kadarlık kısmı sembolik makine dilinde yazılmıştır.) Bunlar göz önüne alındığında sembolik makine dilinde yazılan kodların C ve C++ gibi dillerden çağrılmasının önemi anlaşılabilir. Bu yazıda bu işlemin nasıl yapıldığı detaylı bir şekilde anlatılmaya çalışılacaktır.

Sembolik makine dilinde yazılmış bir fonksiyonun C ya da C++’tan çağrılabilmesi için önce onun sembolik makine dili derleyicisiyle derlenmesi gerekir. Bu derleme işleminden bir amaç dosya (object file) elde edilir. (Amaç dosya uzantılarının Windos’ta ".obj" biçiminde, UNIX/Linux sistemlerinde ".o" biçimindedir.) Sonra bu fonksiyonu çağıran C ya da C++ kodu da bu dillerin derleyicileri ile derlenir. Bu işlemden de bir amaç dosya (object file) elde edilir. Nihayet bu amaç dosyalar birlikte link işlemine sokularak çalıştırılabilir (executable) dosya olurulur. Örneğin "run.c" isimli C programından "utility.s" isimli sembolik makine dilinde yazılmış olan fonksiyonlar çağrılmak istensin. Yapılacak işlemleri aşağıdaki şekille özetleyebiliriz:


Yukarıda özetlediğimiz adınmlardan sorunsuz geçilebilmesi için şu noktalara dikkat edilmesi gerekir:

  • Sembolik makine dilinde fonksiyonu yazarken onun için NASM’de "global" bildirimi yapmak gerekir.
  • Derleyiciler global fonksiyonların ve değişkenlerin isimlerini amaç dosyaya yazarken değiştirebilmektedir. Bu duruma "isim dekorasyonu (name decoration)" denilmektedir. Ancak burada şunu ifade etmek istiyoruz: İsim dekorasyonu çağırma biçimine göre, derleyiciye göre ve hatta dile göre değişebilmektedir. Örneğin Windows’ta Microsoft derleyicileri "cdecl" çağırma biçiminde global sembollerin (fonksiyon ve değişkenlerin) başına bir alt tire (underscore) eklemektedir. Halbuki Linux’ta gcc derleyicileri bu isimleri hiç değiştirmeden amaç koda yazmaktadır. (Dolayısıyla Windows’ta bizim de sembolik makine dilinde yazdığımız fonksiyonların başına alt tire eklememiz gerekir. Aksi takdirde linker iki modüldeki isimleri eşleyemez.)
  • C ya da C++’ta belirlenen çağırma biçimine sembolik makine dilinde kod yazarken uyulmalıdır. (Yani örneğin C’de "cdecl" çağırma biçimine sahip olarak çağırdığımız add fonksiyonunu sembolik makine dilinde yazarken parametrelerin sağdan sola stack’e atılacağını bilerek fonksiyonu yazmalıyız ve geri dönüş değerini de EAX yazmacında bırakmalıyız.)
  • Çağrılan fonksiyonun hangi yazmaçları saklaması gerektiği bilinmelidir ve fonksiyonu yazarken bu kurala uyulmalıdır. Örneğin cdecl ve stdcall çağırma biçimlerinde çağrılan fonksiyon EAX, ECD ve EDX yazmaçlarını bozma hakkına sahiptir. Fakat diğerlerinin değerlerini değiştirecekse önce onları stack’te saklamalı fonksiyon sonlanmadan önce geri almalıdır.
  • Semboik makine dilindeki kodlarla C ya da C++’taki kodların aynı bölüm (section) içerisinde bulunması gerekir.Örneğin C ve C++ derleyicileri Windows ve Linux sistemlerinde kodu ".text" isimli bölüme yerleştirmektedir. O halde bizim de fonksiyonları ".text" isimli bölümde yazmamız gerekir. Aynı isimli bölümler linker tarafından birleştirilmektedir. (Yani birleştirme işlemi sonucunda çalıştırılabilen dosyada tek bir ".text" bölümü bulunacaktır)
  • C ya da C++ kaynak programında sembolik makine dilinden çağrılan fonksiyonun prototip bildirimi/çağırma biçimi aynı olacak biçimde yapılmalıdır.