3 puan yazan GN⁺ 2024-04-09 | Henüz yorum yok. | WhatsApp'ta paylaş
  • Modern Hello World programının ardında gizlenen soyutlama dünyasına bir keşif

    • Bu yazı, C ile yazılmış bir Hello World programını ele alıyor. C, yorumlayıcı/derleyici/JIT dünyasında program gerçekten çalışmadan önce dilin ne yaptığını düşünmeyi gerektirmeyen üst düzey diller arasında en alt katmana en yakın olanlardan biri.
    • Aslında kodlama geçmişi olan herkesin anlayabileceği şekilde yazılmak istenmiş, ancak en azından C ya da assembly bilgisine sahip olmak faydalı olacaktır.
  • Hello World programına başlangıç

    • Herkesin Hello World programına aşina olduğu varsayılabilir. Python'da muhtemelen yazdığınız ilk program print('Hello World!') gibi bir şeydi.
    • Bu yazıda C programlama diliyle yazılmış Hello Worlde bakılacak. C'de programı çalıştırmak için bir yorumlayıcı çağrılamaz. Önce derleyicinin çalıştırılması ve programın, bilgisayar işlemcisinin doğrudan çalıştırabileceği makine koduna dönüştürülmesi gerekir.
  • Programımızın analizi

    • Derlenmiş program dosyası incelendiğinde bunun bir ELF yürütülebilir dosyası olduğu ve x86-64 komut kümesi mimarisi için üretildiği görülebilir.
    • ELF yürütülebilir dosyası, Linux'ta Windows'un .exe dosyasına karşılık gelir.
    • x86-64, 1981'de IBM PC'nin tanıtılmasından bu yana PC'lerde kullanılan CPU mimarisidir.
    • Bu dosya, CPU'nun anlayabildiği tek dil olan makine kodunu içerir.
  • Assembly kodunun analizi

    • Programın başlangıç adresi olan entry point bulunup assembly kodu inceleniyor.
    • Assembly dili, makine kodunun insan tarafından okunabilir biçimde ifade edilmiş halidir.
    • Derleyici (daha doğrusu linker) tarafından otomatik olarak eklenen ilklendirme kodu görülüyor ve __libc_start_main fonksiyonunun çağrıldığı fark ediliyor.
    • Ancak bu kod programımızda tanımlı değil; başka bir yerde bulunuyor.
  • C standart kütüphanesi

    • __libc_start_main fonksiyonu, sistemin standart C kütüphanesi olan libc.so.6 içinde tanımlıdır.
    • C standart kütüphanesi, bilgisayardaki neredeyse tüm programların kullandığı rutinler ve fonksiyonlar koleksiyonudur.
    • C kütüphanesi ilklendirme işlerini yapar ve bizim yazdığımız main() fonksiyonunu çağırır. main() döndüğünde de verdiğimiz çıkış koduyla programı sonlandırır.
  • main() fonksiyonunun analizi

    • main() fonksiyonunda stack frame kurulur, Hello World dizgesinin adresi fonksiyon çağrısının argümanı olarak ayarlanır ve ardından puts() fonksiyonu çağrılır.
    • puts(), aslında printf() çağrısının derleyici tarafından yapılan optimizasyonla değiştirilmiş halidir. Çünkü printf() karmaşıktır, puts() ise yalnızca biçimlendirme içermeyen bir dizgeyi yazar.
  • Hello World dizgesi

    • Dizge, "Hello World!" ifadesinin ardından bir NULL sonlandırıcı gelecek şekilde tutulur.
    • C'de dizgelerle birlikte uzunluk bilgisi bulunmadığı için dizgenin sonu NULL sonlandırıcıyla işaretlenir. NULL sonlandırıcı olmazsa program izin verilmeyen belleği okumaya devam eder ve bir Segmentation Fault ile çöker.
    • Derleyici optimizasyonu nedeniyle printf() içinde kullanılan yeni satır (\n) kaldırılmıştır. Çünkü puts() dizgeyi yazdıktan sonra zaten yeni satır ekler.
  • puts() fonksiyonu

    • puts() fonksiyonu yeniden standart kütüphane içindeki kodu çağırır.
    • glibc koduna bakıldığında _IO_puts -> _IO_new_file_xsputn sırasıyla çağrıldığını görmek mümkündür, ancak kod oldukça karmaşıktır ve açıklaması zordur.
    • musl libc durumunda ise yapı daha basittir. puts -> fputs -> fwrite -> __fwritex -> __stdio_write -> syscall sırasıyla çağrılır.
  • Sistem çağrısı

    • C kütüphanesi ne kadar büyük olursa olsun donanımla doğrudan iletişim kuramaz. Bunu yalnızca kernel yapabilir.
    • Bu yüzden puts() çağrısı eninde sonunda işletim sisteminden bir şey yapmasını istemekle sonuçlanır. Burada yapılan şey, çıktı akışına bir dizge yazmaktır.
    • musl libc, birden çok tamponu tek seferde yazmaya izin veren writev adlı sistem çağrısını kullanır.
    • Sistem çağrısı, register'lara parametreler yerleştirilip syscall komutu çalıştırılarak yapılır. Ardından denetim kernel'a geçer; kernel parametreleri okuyup sistem çağrısını gerçekleştirir.
  • Kernel

    • Linux kernel'i, sistem çağrısıyla talep edilen işlemi yerine getirmek zorundadır. write sistem çağrısı kernel'e, dosya sistemindeki açık bir dosyaya ya da akışa yazmasını söyler.
    • write, yazılacak dosya tanımlayıcısı, yazılacak tampon ve yazılacak bayt sayısı olmak üzere 3 parametre alır.
    • Gerçekte nereye yazılacağı duruma göre değişir. Bir terminal emülatörü ise sanal terminal (pty) olarak görünür; uzaktan oturum açma varsa sshd'ye iletilir; fiziksel terminal varsa seri-USB adaptörüne gider. Framebuffer konsoluysa kernel metni render edip ekrana çıkarır.
  • Sonuç

    • Modern yazılım sistemleri donanım üzerinde son derece karmaşık ve sofistike biçimde çalıştığı için, bilgisayarın yaptığı küçük bir işi tamamen anlamaya çalışmak aslında çok anlamlı değildir.
    • Her şeyi açıklayabilmek için pek çok ayrıntının atlanması gerekti.
    • Hello World mesajını göndermek, şu anda bilgisayarda çalışan sayısız sistem çağrısı ve programdan yalnızca biridir.

GN⁺'nin görüşü

  • Bu yazı, bilişim sisteminin her katmanının soyutlama yoluyla alt katmanın karmaşıklığını gizlediğini ve bunun da geliştiricilerin uygulamaları daha rahat geliştirmesini sağladığını gösteriyor.
  • Öte yandan, bir uygulamadaki tek bir satırın çalışması için altta ne kadar çok şey olup bittiğini fark ettiriyor ve hata ayıklamanın neden zor olduğunu da gösteriyor.
  • Her programcının, ağırlıklı olarak kullandığı dilin altındaki sistemleri iyi bilmesi gerektiğini düşünüyorum. Her şeyi bilmek şart değil, ama soyutlanan kısmın gerçekte nasıl çalıştığını bilmek önemli.
  • Üst düzey bir dil kullanılsa bile bellek yapısı, stack ve heap, sistem çağrıları gibi sistem programlama kavramlarını öğrenmek; hata ayıklama ve performans optimizasyonunda büyük fayda sağlar.
  • Uygulama geliştiricilerinin derleyiciye ya da C kütüphanesine doğrudan dokunması pek gerekmeyebilir, ancak yazdıkları programın sonunda sistemi nasıl kullandığını anlamak, iyi bir programcı olmanın vazgeçilmez parçasıdır.

Henüz yorum yok.

Henüz yorum yok.