Advanced C and C++ Compiling İnceleme

Özet

C veya C++ dili ile yazılmış bir projede çalışan geliştiricilerin belki de karşılarına en çok çıkan kavram kütüphane (library) kavramıdır. Hem projenin içerisinde hem de projenin dışından (üçüncü parti) kullanılan bu kütüphanelerin bu projelere nasıl entegre edildiği, türlerinin ne olduğu (statik veya dinamik), kodlarda nasıl kullanıldığı, proje ile beraber nasıl dağıtıldığı gibi konular geliştiriciler için önem arz etmektedir. Bu kitap aslında tamamen bu gibi konuların üzerine yoğunlaşmakta ve statik kütüphane, dinamik kütüphane, derleme aşaması işlemleri, bağlama aşaması işlemleri, yükleme aşaması işlemleri gibi her projede karşımıza çıkabilecek kavramlar üzerinde durmaktadır. Kitabın hedef kitlesi halihazırda C veya C++ programlama dilleri ile uğraşan kişiler olsa da kütüphanelerin işletim sistemleri tarafından nasıl ele alındığını merak eden kişiler için de bu kitap oldukça değerlidir.

İnceleme

Bölüm 1: Multitasking OS Basics (Çok Görevli OS Temelleri)

Bu bölümde öncelikle çok görevli bir işletim sisteminde yer alan temel kavramlar (byte stream, sanal bellek, process, sanal makine, komut seti vb.) açıklanmaktadır. Bu tip sistemlerdeki bellek hiyerarşisi ve önbellekleme stratejileri anlatılmakta, sanal bellek (virtual memory) kavramının ne olduğuna değinilmektedir. Daha sonra ise sanal adresleme (virtual addressing) mantığı bir diyagram üzerinde gösterilmektedir. Sonraki kısımlarda bellek üzerinde çalışan bir Process’in standart şeması gösterilmekte ve bu Process’in kesitleri (sections) açıklanmaktadır. Açıklanan kesitler şöyledir:

  • Kod kesiti (code section)
  • Veri kesitleri (data sections)
  • Heap kesiti
  • Stack kesiti
  • Sistem (kernel) kesiti

Son olarak ise kısaca ikilik dosyalar, derleyiciler, bağlayıcılar ve yükleyiciler arasındaki ilişki kısaca açıklanmaktadır.

Bölüm 2: Simple Program Lifetime Stages (Basit Program Yaşam Aşamaları)

Bu bölümde bir programın yazılmasından çalıştırılmasına kadar olan aşamalar ayrıntılı bir şekilde incelenmektedir. İncelenen aşamalar şu şekildedir:

  1. Kaynak kodu oluşturma
  2. Derleme
  3. Bağlama
  4. Yükleme
  5. Çalıştırma

Öncelikle basit bir C projesi üzerinden kaynak kod oluşturma, kaynak kod dosyaları ve başlık dosyalarını ayırma gibi konular gösterilmektedir. Daha sonra derleme (compiling) işleminin, derleyicinin (compiler), translasyon biriminin (translation unit), amaç dosyaların (object files), bağlama (linking) işleminin ne olduğu tek tek açıklanmakta ve görsel olarak da gösterilmektedir. Birkaç tane daha ek kavramın açıklaması yapıldıktan sonra, derlemenin şu aşamaları ayrıntılı bir şekilde anlatılmaktadır:

  • Ön işleme (preprocessing)
  • Dilbilimsel analiz (linguistic analysis)
  • Assembling
  • Optimizasyon
  • Kod çıkarımı (code emission)

Daha sonra ise GNU/Linux üzerindeki Executable and Linkable Format (ELF) isimli formatın ne olduğu açıklanmakta ve amaç dosyaların içeriği hakkında bilgi verilmektedir. Derleme işlemindeki bazı kısıtlamalardan da bahsedilmektedir. Daha sonra ise bağlamanın şu aşamalarından ayrıntılı bir şekilde bahsedilmektedir:

  • Yeniden konumlandırma (relocation)
  • Referansları çözme (resolving references)

Bundan sonra ise görseller ile bağlayıcı programın gözünden sizin yazdığınız programın nasıl gözüktüğü açıklanmaktadır. Bölümün sonunda çalıştırılabilir dosyaların (executable files) özellikleri ele alınmakta ve ELF formatında kullanılan sembol türlerinin bir listesi ile bölüm sonlandırılmaktadır.

Bölüm 3: Program Execution Stages (Program Çalışma Aşamaları)

Bu bölümde bir programı oluşturduktan sonra onu çalıştırdığınızda, işletim sisteminin hangi aşamalarda işlem yaptığı ayrıntılı bir şekilde incelenmektedir. Öncelikle kabuk (shell) programın ne olduğu ve nasıl çalıştığı açıklanmakta, daha sonra kernelin programın çalışmasındaki rolüne değinilmektedir. Yükleyici (loader) programın ne olduğu ve çalışan programları nasıl gördüğü görsel olarak gösterilmektedir. Yükleyici programın, çalıştırılabilir programı belleğe yüklerkenki aşamaları ele alınmaktadır. Bölümün sonunda ise çalıştırılabilir bir programın giriş noktaları (entry points) hakkında konuşulmakta ve işletim sisteminin çalıştırma prosedüründe hangi sırayla neleri yaptığı açıklanmaktadır.

Bölüm 4: The Impact of Reusing Concept (Yeniden Kullanma Kavramının Etkisi)

Bu bölümde kütüphaneler ile ilgili ayrıntılara girmeden önce yeniden kullanma (reusing) kavramı hakkında biraz konuşulmaktadır. Öncelikle statik kütüphanelerin (static libraries) ne olduğundan daha sonra ise dinamik kütüphanelerin (dynamic libraries) ne olduğundan kabaca bahsedilmekte ve bu konular ile ilgili görseller verilmektedir. Dinamik bağlama (dynamic linking) denilen işlemin ne olduğundan ve detaylarından bahsedilmektedir. Dinamik bağlama işleminin Windows üzerindeki bazı garip senaryoları ele alınmaktadır. Dinamik kütüphanelerin doğası açıklanmakta ve Application Binary Interface (ABI) kavramından kısaca bahsedilmektedir.

Daha sonra statik ve dinamik kütüphaneler arasındaki farklar incelenmektedir. Hangisinin hangi durumlarda kullanılması gerektiği ve birbirilerine göre avantaj ile dezavantajları açıklanmkatadır. Statik kütüphane, dinamik kütüphane ve çalıştırılabilir dosyalar arasındaki farkları daha iyi anlamak için çeşitli analojiler verilmektedir. Son olarak ise bölüm boyunca anlatılanlar kısaca özetlenmektedir.

Bölüm 5: Working with Static Libraries (Statik Kütüphaneler ile Çalışma)

Bu bölümde statik kütüphaneler ile çalışmanın ayrıntıları anlatılmaktadır. Öncelikle bir GNU/Linux dağıtımı üzerindeki bir GCC derleyicisi ile bir statik kütüphaneyi nasıl oluşturabileceğimiz gösterilmekte, daha sonra ise Windows’ta bunu nasıl yapacağınız kısaca gösterilmektedir. Oluşturulan statik kütüphaneleri nasıl kullanabileceğimiz açıklanmaktadır. Statik kütüphaneler ile ilgili bazı ipuçları verilmektedir. Verilen ipuçları şu şekildedir:

  • Potansiyel sembol görünürlüğünü ve eşsizliğini kaybetme riski
  • Karşıt kullanım senaryoları
  • Statik kütüphaneleri bağlamanın belirli kuralları
  • Statik kütüphaneyi dinamik kütüphaneye dönüştürme
  • 64-bit Linux dağıtımlarında statik kütüphane sorunları

Bölüm 6: Designing Dynamic Libraries: Basics (Dinamik Kütüphaneleri Tasarlama: Temeller)

Bu bölümde dinamik kütüphaneler ile ilgili temel bilgiler sağlanmaktadır. Öncelikle bir GNU/Linux dağıtımı üzerindeki bir GCC derleyicisi ile bir dinamik kütüphaneyi nasıl oluşturabileceğiniz gösterilmekte, daha sonra ise Windows’ta bunu nasıl yapacağınız kısaca gösterilmektedir. GCC üzerinde "-fPIC" bayrağının ne olduğu açıklanmaktadır. Daha sonra dinamik kütüphaneleri nasıl tasarlayabileceğiniz hakkında konuşulmaktadır. C ve C++ arasındaki sembol isimleri farklılıklarından ve bunları nasıl aşabileceğinizden bahsedilmektedir. C++’ta Static Initialization Order Fiasco denilen sorunun ve şablonlar (templates) ile ilgili problemlerin nasıl ele alınacağı anlatılmaktadır. Kütüphanede açacağınız fonksiyonlar ile ilgili şu şekilde rehber bilgiler verilmektedir:

  1. Dinamik Kütüphane ABI’sini C-stili fonksiyonlar şeklinde implement etme
  2. Tam ABI bildirimini içeren başlık dosyasını kütüphane kullanıcılarına sağlama
  3. Geniş destekli C anahtar kelimelerini kullanma
  4. “Class Factory Mechanism/Module” denilen teknik ile kütüphaneleri tasarlama
  5. Sadece çok önemli olan sembolleri dışarı açma (export)
  6. Sembol ismi çakışmalarını önlemek için isim alanlarını (namespaces) kullanma

Dinamik kütüphane sembollerinin görünürlüğünü (visibility) nasıl değiştirebileceğiniz ile ilgili bazı teknikler anlatılmaktadır. "–no-undefined" bağlayıcı bayrağı hakkında bilgiler verilmektedir. Bölümün sonunda ise şu dinamik bağlama modları ayrıntılı bir şekilde anlatılmakta ve karşılaştırılmaktadır:

  1. Statik olarak farkında olan (yükleme zamanı) dinamik bağlaması
  2. Çalışma zamanı dinamik bağlaması

Çalışma zamanı dinamik bağlaması için POSIX API üzerinde ("dlopen", "dlsym" vb.) ve Windows API üzerinde ("LoadLibrary", "GetProcAddress" vb.) kullanabileceğiniz fonksiyonlar açıklanmakta ve kod örnekleri verilmektedir.

Bölüm 7: Locating the Libraries (Kütüphanelerin Yerini Belirleme)

Bu bölümde öncelikle kütüphanelerin geliştirme aşamasındaki ve son kullanıcı aşamasındaki kullanım senaryoları incelenmektedir. Linux üzerinde Build zamanında kütüphanelerin yerini nasıl gösterebileceğiniz hakkında bilgiler verilmektedir. Bu verilen bilgiler sırasıyla şöyledir:

  • Linux’ta statik kütüphanelerin isimlendirme kuralları (dosya ismi, kütüphane ismi, versyon bilgisi, soname)
  • Kütüphane ismine bir bağlayıcının ve bir insanın bakışı arasındaki farklar
  • Linux’ta Build zamanında kütüphanelerin yerini gösterme ile ilgili kuralların detayları
  • Yapılan bazı yanlışlıklar

Daha sonra Wndows üzerinde Build zamanında kütüphanelerin yerini nasıl gösterebileceğiniz hakkında bilgiler verilmektedir. Bu verilen bilgiler sırasıyla şöyledir:

  • Projenin bağlayıcı ayarları
  • “#pragma” yorumu
  • Kütüphane projesine kapalı bir şekilde referans gösterme

Build zamanını anlattıktan sonra sırasıyla Linux ve Windows üzerinde çalışma zamanında kütüphanelerin yerini göstermeyle ilgili konuşulmaktadır. Windows üzerinde fazla ayrıntı verilmese de Linux dağıtımlarında kullanılan şu yöntemlerden bahsedilmektedir:

  • Önceden yüklenmiş kütüphaneler (“LD_PRELOAD” ortam değişkeni)
  • “rpath” alanı
  • “LD_LIBRARY_PATH” ortam değişkeni
  • “runpath” alanı
  • “ldconfig” önbelleği
  • “/lib” ve “/usr/lib” gibi varsayılan kütüphane yolları

Bölümün sonunda ise bir Linux dağıtımı üzerinde Build zamanı ve çalışma zamanında kütüphanelerin konumunu gösterme ile ilgili örnek bir uygulama verilmektedir.

Bölüm 8: Designing Dynamic Libraries: Advanced Topics (Dinamik Kütüphaneleri Tasarlama: İleri Düzey Konular)

Bu bölümde dinamik kütüphaneler ile ilgili bazı ileri düzey konular üzerinde durulmaktadır. Öncelikle bellek adreslerinin çözümlenmesinin neden bir zorunluluk olduğu anlatılmaktadır. Daha sonra referansları çözümleme ile ilgili karşılaşılabilecek problemler örneklendirilmektedir. Elbette bunların çözüm yöntemleri de anlatılmaktadır. Yine adres dönüşümü ile ilgili problemler senaryolar halinde incelenmektedir.

Bir sonraki kısımda ise bağlayıcı program ile yükleyici program arasındaki koordinasyon ve iletişim mekanizması anlatılmaktadır. Özellikle ELF formatını destekleyen sistemlerde bağlayıcının yükleyiciye verebileceği komutlar listelenmekte ve örnekler verilmektedir. Bağlayıcı-yükleyici koordinasyonunun implementasyon teknikleri tartışılmaktadır. Bu teknikler şunlardır:

  • Load Time Relocation (LTR)
  • Position Independent Code (PIC)

Position Independent Code (PIC) konusunda tembel bağlama (lazy binding), dinamik bağlamanın özyineli zincirlerinin kuralları ve kısıtlamaları, güçlü implementasyon tercihleri gibi alt konular ayrıntılı bir şekilde ele alınmaktadır.

Bölüm 9: Handling Duplicate Symbols When Linking In Dynamic Libraries (Dinamik Kütüphaneleri Bağlarken Yinelenen Sembolleri Ele Alma)

Bu bölümde dinamik kütüphaneler ile bağlama yapılırken sıklıkla karşılaşılan yinelenen sembol (duplicate symbol) problemleri ele alınmaktadır. Öncelikle tipik yinelenen sembol senaryoları incelenmekte, C ve C++ sembolleri ile ilgili örnek gösterilmektedir. Yinelenen sembollerin varsayılan davranışları ile ilgili bir örnek verilmektedir (statik kütüphaneler için). Yinelenen sembollerin dinamik kütüphanelerde ortaya çıkması ile ilgili senaryolar incelenmektedir. Bu senaryolar ile ilgili çözüm stratejileri örneklerle açıklanmaktadır. bölümün sonunda ise şu 4 durum ile ilgili birer örnek üzerinden yinelenen sembol durum analizi yapılmaktadır:

  1. Kütüphaneyi kullanan ikilik dosyada yer alan sembollerin, dinamik kütüphane ABI sembolleri ile çakışması
  2. İki dinamik kütüphanenin ABI sembollerinin birbirleri ile çakışması
  3. Bir dinamik kütüphanenin ABI sembollerinin, diğer bir dinamik kütüphanedeki yerel semboller ile çakışması
  4. Bir dinamik kütüphanedeki dışarı açılmamış sembollerin, diğer bir dinamik kütüphanedeki dışarı açılmamış semboller ile çakışması

Bölüm 10: Dynamic Libraries Versioning (Dinamik Kütüphaneleri Versiyonlama)

Bu bölümde öncelikle versiyon kavramından ve versiyon ismindeki Major, Minor, Patch elemanlarının ne olduğundan bahsedilmektedir. Daha sonra Linux’ta dinamik kütüphaneleri versiyonlama şemalarının anlatımına geçilmektedir. Bu kısımda Linux’ta soname bazlı versiyonlama şeması ve sembol bazlı versiyonlama şeması örneklerle tek tek açıklanmaktadır. Yine bu kısımda GCC bağlayıcı programına verebileceğiniz versiyon Sctipt’lerinin (version scripts) nasıl yazılacağı ve kullanılacağı da anlatılmaktadır. Bölümün sonunda Windows ortamında dinamik kütüphanelerin versiyonlaması ile ilgili çeşitli bilgiler verilmektedir.

Bölüm 11: Dynamic Libraries: Miscellaneous Topics (Dinamik Kütüphaneler: Çeşitli Konular)

Bu bölümde dinamik kütüphaneler ile ilgili geriye kalan kavramların açıklaması yapılmaktadır. Öncelikle Plug-in kavramından başlanmakta, Plug-in oluşturma ve kullanma ile ilgili çeşitli bilgiler ve ipuçları verilmektedir. Daha sonra dinamik kütüphanelerin faydaları hakkında kısa açıklamalar yapılmaktadır. Bölümün sonunda ise şu konular ile ilgili açıklamlar ve örnekler verilmektedir:

  • Dinamik kütüphaneleri çalıştırılabilir hale dönüştürmek
  • Windows kütüphanelerinde ortaya çıkan çalışma zamanında bellek çakışması problemini ele alma
  • Bağlayıcıda kullanılan zayıf semboller (weak symbols)

Bölüm 12: Linux Toolbox (Linux Araç Kutusu)

Bu bölümde Linux ortamında kütüphaneler ile çalışabileceğiniz araçlar şu kategoriler altında tek tek anlatılmaktadır:

  • Hızlı bakış araçları (“file”, “size”)
  • Detaylı analiz araçları (“ldd”, “nm”, “objdump”, “readelf”)
  • Dağıtım aşaması araçları (“chrpath”, “patchelf”, “strip”, “ldconfig”)
  • Çalışma zamanı analiz araçları (“strace”, “addr2line”, “gdb”)
  • Statik kütüphane araçları (“ar”)

Bölüm 13: Linux How To’s (Linux Nasıl Yapılırları)

Bu bölümde Linux ortamında şu işlemleri nasıl yapacağınız ile ilgili bilgiler ve örnekler verilmektedir:

  • Bağlama aşamasını debug etme
  • İkilik dosyanın türüne karar verme
  • İkilik dosyada yer alan giriş noktasını (entry point) bulma
  • Sembolleri listeleme
  • Kesitleri (sections) listeleme ve inceleme
  • Bölümleri (segments) listeleme ve inceleme
  • Kodu disassemble etme
  • Debug Build tanımlama
  • Yükleme zamanı bağımlılıklarını listeleme
  • Yükleyicinin bildiği kütüphaneleri listeleme
  • Dinamik olarak bağlanmış kütüphaneleri listeleme
  • Statik kütüphane oluşturma ve bakımını yapma

Bölüm 14: Windows Toolbox (Windows Araç Kutusu)

Bu bölümde Windows’ta kütüphane oluşturma ve onu inceleme ile ilgili "lib.exe" ve "dumbpbin" araçları ile ilgili ayrıntılı bilgiler ve örnekler verilmektedir. Dependency Walker uygulamasını tanıtarak bölüm sonlandırılmaktadır.

Değerlendirme

Bu kitabın hedef kitlesi olarak 3 grubu sayabiliriz: C veya C++ dillerini halihazırda bilenler ve kullananlar, bilgisayar bilimleri arka planı olan ve operasyonel bilgilerini artırmak isteyen yazılımcılar, ikilik dosyaların doğasını anlamak isteyen ve onların işletim sistemiyle etkileşimini öğrenmek isteyen kişiler. Özellikle ikinci grubun 12-14 arası bölümlere odaklanması daha iyi olacaktır. Kitapta kullanılan dil sade ve anlaşılırdır. Ancak kavramların açıklamaları tek tek yapılsa bile başlangıç seviyesindeki yazılımcıları biraz zorlayabilir. Kitabın yazıldığı yıl 2014 olsa da anlatılan araçların ve metotların kullanımı hala değişmediğinden, kitabın çok güncel olmaması çok sorun yaratmamaktadır.

Kitapta oldukça iyi ve açıklayıcı görseller kullanılmaktadır. Derleyici, bağlayıcı ve yükleyici programın ikilik dosyalara bakışı çok iyi bir şekilde görsele dökülmüştür. Process’lerin bellekte yerleşimi, statik ve dinamik kütüphanelerin bağlama ve yükleme aşamasında bellekteki durumları, dinamik kütüphaneler ile ilgili özelliklerin bellekte gösterimi çok iyi yapılmıştır. Sadece çok ufak 1-2 yerde görsel kullanımı biraz etkisiz kalmıştır. Özellikle Windows tarafını anlatırken kullanılan görseller, kullanılan programların eskimesiyle yetersiz kalabilmektedir. Ancak kitabın genelini çok fazla etkilemediğinden bu büyük bir problem değildir.

Piyasada birçok C ve C++ ile ilgili kitap bulunmasına ve bazılarının derleme, bağlama, yükleme aşamalarını ele almasına rağmen, doğrudan bu aşamaların ayrıntısına ve statik/dinamik kütüphanelerin yapısına odaklanan bir kitap bulunmamaktadır. Bu nedenle kitabın anlattığı konu içeriğinin kendi başına eşsizlik durumu vardır (elbette bu konular farklı kaynaklarda parça parça anlatılsa da bütün olarak bir kitapta anlatılması durumu eşsizdir). Bunun yanında kitapta genellikle GNU/Linux dağıtımlarına yönelik anlatım yapılsa da (ikilik dosya formatları açık kaynak olduğundan) Windows üzerinde de anlatımlar yapılmaktadır. Ayrıca Linux dağıtımları ve Windows arasındaki farklara da değinilmektedir.

Kitapta kullanılan kod örnekleri oldukça fazladır. Zaten bazı anlatılan konuların örnekler olmadan anlaşılması oldukça zordur. Kitapta anlatılan kritik konuların yanında, ek olarak verilen ipuçlarında bile örneklerden faydalanılmıştır. Örnekler genellikle C dili üzerinden verilmektedir. Name mangling gibi konularda C++ örnekleri verilebilmektedir. Örnekleri derleme ve ikilik dosyaları oluşturup kullanma komutları genellikle GCC derleyicisi üzerinden anlatılmaktadır. Windows üzerindeki anlatımlar komut satırı üzerinden değil, Visual Studio IDE programı üzerinden yapılmaktadır. Bu da tıpkı görsel kullanımında belirttiğim gibi, versiyondan kaynaklı bazı farklılıklara yol açabilmektedir.

Sonuç olarak bu kitap, C ve C++ dillerinde neredeyse sürekli karşımıza çıkan statik ve dinamik kütüphane konularını anlamanızda faydalı olması açısından oldukça kullanışlı bir kitaptır. Kitapta hem GNU/Linux hem de Windows tarafı için anlatımlar mevcuttur. Windows tarafı anlatımları görsel bir anlatım olduğundan, sizin sisteminizde farklılıklar görülebilir. Kitabın isminde "ileri düzey" ibaresi yer alsa da aslında orta seviye zorluktaki konuları barındırdığını söyleyebiliriz. Yani halihazırda C veya C++ dillerinden birini bilenler için kitabı okumak ve anlamak çok da zor olmayacaktır. Görsel kullanımları yerindedir. Bazı Windows görselleri eski kalmış olabilir. Örnekler oldukça iyidir. İçerik kalitesi ve eşsizliği bana göre çok iyidir. Bu nedenle hedef kitlelerine kesinlikle okumasını tavsiye ederim.

Advanced C and C++ Compiling İnceleme Özeti


Tam İsim: Advanced C and C++ Compiling
Basım No: 1st Edition
Yazarlar: Milan Stevanovic
Yayımlama Tarihi: 28 Nisan 2014
Sayfa Sayısı: 358
Anlaşılabilirlik/Okunabilirlik
Görsel/Diyagram Kullanımı
İçerik Kalitesi/Eşsizliği
Örneklendirme/Örnek Kalitesi

Sonuç Özeti

Sonuç olarak bu kitap, C ve C++ dillerinde neredeyse sürekli karşımıza çıkan statik ve dinamik kütüphane konularını anlamanızda faydalı olması açısından oldukça kullanışlı bir kitaptır. Kitapta hem GNU/Linux hem de Windows tarafı için anlatımlar mevcuttur. Windows tarafı anlatımları görsel bir anlatım olduğundan, sizin sisteminizde farklılıklar görülebilir. Kitabın isminde “ileri düzey” ibaresi yer alsa da aslında orta seviye zorluktaki konuları barındırdığını söyleyebiliriz. Yani halihazırda C veya C++ dillerinden birini bilenler için kitabı okumak ve anlamak çok da zor olmayacaktır. Görsel kullanımları yerindedir. Bazı Windows görselleri eski kalmış olabilir. Örnekler oldukça iyidir. İçerik kalitesi ve eşsizliği bana göre çok iyidir. Bu nedenle hedef kitlelerine kesinlikle okumasını tavsiye ederim.

4.5
0 0 votes
Article Rating
Subscribe
Bildir
guest

0 Yorum
Eskiler
En Yeniler Beğenilenler