
C dili ile yazılmış bir embedded projesinde build tuşuna bastığımızda, .c dosyalarından başlayarak MCU’ya yüklenebilir .hex dosyasına ulaşana kadar arka planda birçok işlem gerçekleşir. Yüksek seviyeli C dili ile yazdığımız .c ve .h uzantılı source dosyalarımız bu süreç sonunda kullandığımız editöre ve kullandığımız MCU’ya uygun olarak bir .hex dosyası üretilmiş olur.
Bu tüm süreç aslında 5 aşamada anlatılabilir;
- Pre-processing Stage
- Compilation Stage
- Assembly Stage
- Linking Stage
- Locating Stage
The Pre-Processing Stage
Bu ilk süreç ile kodlarımızı yazdığımız .c ve .h dosyaları işleme alınır. Bu sürecin amacı ise elimizdeki C kodlarının derleyicinin anlayabileceği ‘temizlenmiş ve genişletilmiş’ bir forma dönüştürmektir. Bu işlemleri yapan Preprocessor’dur.
Preprocessor 3 temel iş yapar:
- Yorumların Silinmesi: Tüm yorumlar silinir, sadece asıl kodlar kalır. Kod mantığı değişmeden tüm gereksiz şeyler çıkarılır.
- Preprocessor Direktiflerinin İşlemesi : # ile başlayan makrolar burada değerlendirilir ve kod içinde kullanıldıkları yerlere değerleri yazılır. Bu iş boyunca tip kontrolü yapılmaz , sadece yerine koyma yapılır.
- Output Üretimi: Bu işten önce yapılan tüm işler sonucunda toparlanan kodlar ile ‘.i’ uzantılı bir dosya oluşturulur. Derleyiciye gidecek olan dosya budur.
Bu aşamada Preprocessor sadece metinsel işlemler yapar, C dilinden anlamaz, syntax kontrolü yapmaz , type checking yapmaz. Yani bu aşamada sadece kod temizleme, makro genişletme, dosya birleştirme işlemleri yapılır ve sonuç olarak bir .i uzantılı dosya oluşturulur.
The Compilation Stage
Bu aşama C dilinde yazılmış yüksek seviyeli kodun hedef işlemciye özel assembly diline çevrildiği süreçtir.
Bu aşamada önceki aşamada elde edilen .i uzantılı dosyadaki kodların yapısı analiz edilir. Fonksiyonlar , değişkenler, scope, tipler, pointer işlemleri analiz edilir. Syntax kontrolü yapılır, type checking yapılır, hatalar tespit edilir.
Sonrasında kod optimizasyonu yapılır. Kullanılmayan değişkenler silinir, gereksiz kodlar kaldırılır. Loop unrolling yapılır, register allocation yapılır, sabit ifadeler hesaplanır.
En son olarak assembly üretilir. Mesela STM32F411 için ARM Cortex-M4 mimarisi kullanıldığı için compiler tarafından ARM Cortex-M4 instruction set’ine uygun assembly üretilir. Bu aşama ile çıktı olarak .s uzantılı bir assembly dosyası üretilir. Bu aşamada üretilen assembly kodu insan tarafından okunabilir formdadır, CPU’nun doğrudan çalıştırabileceği makine kodu değildir.
The Assembly Stage
Bu aşamada ARM assembly dili ile yazılmış .s dosyasındaki kodlar makine kodlarına(binary) çevrilir. Her assembly komutu 1 ve 0 ‘lara dönüştürülür.
Çıktı olarak makine kodlarını içeren .o uzantılı bir dosya üretilir fakat bu dosyalardan projedeki dosyaların sayısına bağlı olarak birden fazla .o uzantılı dosya üretilebilir. Yani henüz her bir .c dosyası için bir tane .o uzantılı dosya oluşturulmuştur ama tüm dosyalar tek bir dosyada birleştirilmemiştir.
Sonraki aşamada bu işlemler yapılır.
The Linking Stage
Önceki aşama ile elimizdeki birden fazla .o uzantılı makine kodları içeren dosyalar elde edilmişti. Bu aşama ile birlikte tüm bu object dosyalarını ve gerekli kütüphanelerin birleştirilmesi ile tek bir bütün proğram haline getilirmesi sağlanır.
Adım adım şu şekildedir;
- Object dosyalarının hepsi birleştirilir.
- Symbol resolution işlemi ile başka dosyalardan import edilen fonksiyonlar bulunur ve her fonksiyonun adresi çağrıldığı yere koyulur.
- Memory allocation işlemleri yapılır. Kod Flash’ta nereye koyulacağı , global değişkenlerin RAM’de nereye konacağı, Stack nereden başlayacağı, Heap nerede olacağı belirlenir. Bu spesifik bilgiler Linker Script( .ld uzantılı dosya) içerisinde tanımlıdır.
- Relocation(Adreslerin düzenlenmesi) işlemleri yapılır. Linker, gerçek Flash başlangıç adresini alır, fonksiyonların gerçek adreslerini hesaplar ve tüm referansları düzeltir.
Sonuç olarak bu işlemler sonucunda adreslerine göre düzenlenmiş kodları içeren , tüm adresleri belirlenmiş ve yürütülebilir bir ELF dosyası oluşturulur.
The Locating Stage
Relocatable adresleri, hedef MCU’nun gerçek bellek adreslerine kesin olarak yerleştirilir. Bu işlem yine Linker Script rehberliğinde yapılır. Linker Script içinde MCU’ya özel tüm bellek adresleri ve boyutlarının bilgisi bulunur.
Tüm adresler gerçek fiziksel adreslere çevrilir.
Çıktı olarak .bin ve .hex uzantılı dosyalar üretilir ,bu dosyalar MCU’ya yüklenir.
Son olarak ELF — BIN — HEX dosyaları arasındaki farklar şu şekildedir;
- ELF : Debug bilgisi içerir, symbol table içerir , IDE tarafından kullanılır.
- BIN : Saf binary’den oluşur, Flash’a direkt yazılır.
- HEX: ASCII formatlıdır, adres bilgisi içerir, MCU’ya yüklenmeye hazır proğram dosyasıdır.
