PE ve ELF Çalıştırılabilen Dosyalarındaki Bölüm (Section) Kavramı

06:59 , ,

PE (Portable Executable) | ELF (Executable and Linkable Format) 



Bugün için en çok kullanılan çalıştırılabilir (executable) dosya formatları PE ve ELF’tir. PE formatını Microsoft 32 bit Windows sistemleri ilk çıktığında tasarlamıştır.  Microsoft daha önce 16 bit Windows 3.X sistemlerinde NE (New Executable) denilen bir format kullanmıştır. Microsoft’un DOS’ta kullandığı çalıştırılabilen dosya formatı da MZ (by Mark Zbikowski = aynı zamanda exe'yi tasarlayan kişi) formatıydı. 


UNIX/Linux dünyasında da pek çok çalıştırılabilir dosya formatı denenmiştir. "a.out" isimli format uzun süre pek çok UNIX türevi sistemde kullanılmıştır. Linux'te başlangıçta bu formatı kullanıyordu. Artık UNIX türevi sistemlerin büyük kısmı ELF formatını birincil çalıştırılabilen format olarak desteklemektedir. Ayrıca bir işletim sistemi birden fazla çalıştırılabilen dosya formatını destekliyor olabilir. Örneğin Linux sistemleri ELF formatının yanı sıra hala klasik "a.out" formatını da desteklemektedir. Windows’un pek çok versiyonu NE ve MZ formatlarını da desteklemiştir. PE ve ELF formatlarının 32 bitlik ve 64 bitlik birbirine çok benzeyen biçimleri de vardır. Böylece bazen bu formatlar PE32, PE64, ELF32, ELF64 isimleriyle de belirtilmektedir. PE ve ELF formatları genel tasarım olarak aslında birbirlerine benzemektedir. Her iki formatta da önemli bilgilerin dosyanın neresinde bulunduğunu gösteren bir başlık (header) kısmı vardır. Her iki format da bölümlerden (sections) oluşmaktadır. Bu formatlara sahip bir program çalıştırılmak istendiğinde işletim sistemi çalıştırılabilen dosyayı açar formattaki bölümleri inceler ve bölümleri belleğe (RAM’e) yükler.



İşletim sisteminin çalıştırılabilen dosyayı okuyarak çalıştırmak üzere belleğe yükleyen kısmına kavramsal olarak yükleyici (loader) denilmektedir. Bölümler aynı özelliklere sahip ardışıl sayfalardan (page) oluşmaktadır. Bölümlerin birer isimleri vardır. ELF ve PE formatında geleneksel olarak bölümler başında "." olacak biçimde isimlendirilmektedir. Tabii aslında böyle bir zorunluluk yoktur. İşletim sistemi bölümler için bellekte yer ayırıp içini çalıştırılabilen dosyadan ilgili alanları okuyarak yüklemektedir.

PE ve ELF Formatlarındaki Çok Karşılaşılan Bölümler



PE ve ELF formatlarında en çok karşılaşılan bölümler şunlardır:

.text Bölümü: 

Bir programın bütün makine kodları (yani kaynak kodları) bu bölümde bulunur. Yani yukarıdaki C programında programdaki main, foo, bar ve tar fonksiyonlarının kodları .text bölümüne yerleştirilmektedir.

.data Bölümü:

Bu bölümde ilk değer verilmiş global değişkenler ve static yerel değişkenler tutulmaktadır. Yani örneğin yukarıdaki C programında g_a ve count değişkenleri derleyici tarafından tipik olarak ".data" bölümünde tutulacaktır. Derleyiciler ilk değer verilmiş global değişkenleri ilk değerleriyle birlikte çalıştırılabilen dosyanın ".data" bölümüne yerleştirirler. İşletim sisteminin yükleyicisi de onları bu bölümden alıp blok olarak fiziksel belleğe yüklemektedir. Bu nedenle ".data" bölümündeki değişkenlerin çalıştırılabilen dosyada yer kaplamaktadır. Ancak bazı çalıştırılabilen dosya formatları bölümler içerisinde hangi ilk değerden ne miktarda olduğunu tutma yeteneğine sahiptir (örneğin Windows’un PE formatı böyledir). Böylece aşağıdaki gibi global bir dizi bu sistemlerdeki çalıştırılabilen dosyalarda çok fazla yer kaplamayabilir:

int g_x[1000000] = {1, 2, 3};

Ancak ELF gibi bazı formatların bu yeteneği yoktur. Dolayısıyla bu formatlarda yukarıdaki dizinin hepsi ".data" bölümünde ilk değerleriyle bulunacak, dolayısıyla bu da çalıştırılabilen dosyanın uzunluğunu büyütecektir.

.rdata | .rodata Bölümleri: 

PE formatındaki ".rdata", ELF formatındaki ".rodata" bölümleri global ve static read-only verileri tutmak için düşünülmüştür. String ifadeleri genellikle bu sistemlerdeki derleyiciler tarafından bu bölümlerde saklanmaktadır. Örneğin yukarıdaki C programında g_b, g_name ve ival değişkenleri derleyici tarafından tipik olarak ".r(o)data" bölümünde tutulacaktır. Windows ve Linux’un yükleyicileri bu bölümlerdeki bilgileri "read-only" sayfalara yüklerler. Dolayısıyla programın çalışma zamanı sırasında buradaki değerler değiştirilmek istenirse exception (page fault) oluşur.

.bss Bölümü: 

Bu bölümde ilk değer verilmemiş global değişkenler (g_c, g_d) ve ilk değer verilmemiş static değişkenler tutulmaktadır. Bunlara ilk değer verilmediği için bunların çalıştırılabilen dosyalarda boşuna yer kaplamasına gerek de yoktur. PE ve ELF formatlarında bu bölümün yalnızca uzunluğu çalıştırılabilen dosya içerisinde tutulur. İşletim sisteminin yükleyicisi bu uzunluğa bakarak ".bss" bölümünü bellekte (RAM) tahsis eder ve orayı sıfırlar. (C ve C++’ta ilk değer verilmemiş global ve static yerel nesnelerini içerisinde 0 değeri bulunmaktadır. || bss alanının sıfırlanması henüz akış main fonksiyonuna girmeden derleyicilerin başlangıç kodları (startup codes) tarafından da yapılabilmektedir.)