32 BİT İŞLETİM SİSTEMLERİNDE ÇEKİRDEK KODLARININ

advertisement
32 BİT İŞLETİM SİSTEMLERİNDE ÇEKİRDEK KODLARININ
DERLENMESİ
Kaan Aslan
[V: 1]
Özet: Bu makalede 32 bit işletim sistemlerinin geliştirmesinde gerekli olan düz ikili
(plain binary) dosyaların elde edilmesi ve yüklenmesi konuları ele alınmaktadır. Makale
çekirdek kodlarının derlenmesi ve yükleme işlemine hazır hale getirilmesi süreci ile
ilgilidir.
1. GİRİŞ
İşletim sistemi geliştiricilerinin çözmek zorunda olduğu problemlerden biri de yazılan
çekirdek kodun hiçbir yükleme bilgisi içermeyecek biçimde elde edilmesi ve yüklemeye
hazır biçime getirilmesidir. Ticari amaçla olu şturulmuş derleyici ve bağlayıcı sistemleri
genellikle işletim sistemi yazarları için kolaylıklar sunmazlar. Çünkü ticari sistemlerde
amaç yeni bir sistem oluşturmak değil, mevcut sistem üzerinde uygulamalar ve araçlar
geliştirmektir. Yeni bir sistemin oluşturulması çoğu kez işletim sistemini satan şirketlerin
istemediği bir durumdur. Bu nedenle işletim sistemi geliştirebilmek için gereken uygun
araçlar daha çok araştırma kurumları tarafından ya da bu konuda çalışan kişilerin bireysel
gayretleri ile oluşturulmaktadır. Çekirdek kodların yüklemeye hazır hale getirilmesi için
yaygın olarak kullanılan ticari derleyiciler ve bağlayıcılar kullanışsız kalmaktadır. Bu
derleyicilerin kullanıldığı uygulamalarda amaç kodun ya da çalışabilen kodun istenilen
biçime dönüştürülmesi için ek birtakım araçlara gereksinim duyulur.
Düz ikili dosyaların oluşturulmasında GNU lisansı ile kullanıma sunulan nasm ve gcc
derleyicileri ile ld bağlayıcılarının iyi bir araç olduğu söylenebilir. Pek çok işletim sistemi
projesinde derleme araçları olarak bu programlar kullanılmaktadır.
2. DÜZ İKİLİ DOSYA NEDİR?
Bir işletim sisteminde derleme işlemi yapıldığında üretilen amaç kodun belli bir
formatı vardır. Örneğin, Win32 sistemleri COFF formatını, GNU/Linux sistemleri temel
olarak ELF formatını kullanırlar. Amaç kodlar tipik olarak bağlayıcının modülleri
birleştirebilmesi için gereken bilgileri bulundurmaktadır. Bağlayıcı bu modülleri girdi
olarak alır ve işletim sistemine uygun bir çalışabilir kod oluşturur. Bir sistemde derlenmiş
ve çalışabilir duruma getirilmiş olan programlar tipik olarak dört kısma sahiptir.
1
C ve Sistem Programcıları Derneği - CSD İşletim Sistemi Geliştirme Projesi
2.1. Derleyicilerin Başlangıç Kodu (Start-up Code)
Process başlatıldığında çalışma derleyici tarafından yerleştirilmiş bir başlangıç kodundan
başlar. Bu process’in gerçek giriş noktasıdır. Yükleyiciler process’i yarattıklarında
kontrolün aktarılacağı adresi çalışabilen dosyanın başlık kısmından alırlar. Şüphesiz bu
adres bağlayıcı tarafından amaç koddaki bilgilerden hareketle oluşturulmuştur. Yükleyici
çalışabilen dosyayı yükledikten sonra kontrolü formatta belirtilen adrese geçirir. Bu
başlangıç kodu çeşitli önişlemleri yaparak programlama dilince öngörülen giriş
fonksiyonunu çağıracaktır. Örneğin C’de main fonksiyonu derleyicilerin başlangıç
kodları tarafından çağrılır. Başlangıç kodları aynı zamanda varsayılan çıkış işlemlerini de
yapar. Örneğin tipik olarak C’de akış main fonksiyonunu bitirdiğinde ya da main
fonksiyonu içerisinde return işlemi yapıldığında akış yeniden başlangıç koduna
dönmekte ve process orada sonlandırılmaktadır. Başlangıç kodu temel olarak aşağıdaki
gibi bir yapıya sahiptir:
........
Process’in gerçek başlangıç noktası
Birtakım ilk işlemler yapılıyor
........
call _main
push eax
call _exit
........
Process’in sonlanma noktası
Derleyicilerin başlangıç kodları genellikle normal bir modül olarak bağlama işlemine
sokulur. Process’in gerçek başlangıç noktası başlangıç kodundaki modülde belirlenir. Bu
modül içerisinde programlama dilinin belirlediği giriş fonksiyonu extern olarak
bildirildiğinden bu fonksiyon bağlayıcı tarafından programı oluşturan diğer modüllerde
otomatik olarak aranacaktır. C’de main fonksiyonunun hiçbir modülde bulunmamasından
dolayı oluşan bağlama hatasının nedeni budur.
Derleyicilerin başlangıç kodları işletim sisteminin çekirdeği için gereksiz ve zararlıdır.
Başlangıç kodlarında derleme işleminin yapıldığı işletim sistemine özgü pek çok işlemler
yapılmaktadır. Buradaki işlemler geliştirilmekte olan işletim sistemi için bir anlam
taşımaz. Neyse ki derleyicinin başlangıç kodundan kurtulmak çok kolaydır. Tek
yapılacak şey bağlama aşamasında giriş kodunun bulunduğu modülü bağlama işlemine
dahil etmemektedir. Düz ikili dosyalarda derleyicilerinin giriş kodları bulunmamalıdır.
2.2 Çalışabilen Dosyanın Başlık Kısmı
2
C ve Sistem Programcıları Derneği - CSD İşletim Sistemi Geliştirme Projesi
Çalışabilen dosyalar yükleyici için bilgiler bulunduran başlık kısımlarına sahip olurlar.
Başlık kısımlarındaki bilgiler derleme işleminin yapıldığı sisteme ilişkin oldukları için
işletim sistemi geliştiricileri için gereksiz ve zararlıdırlar. İşletim sisteminin çekirdek
kodlarının herhangi bir başlık kısmı olmamalıdır. Ancak maalesef hemen hemen tüm
ticari derleyiciler başlık kısmını oluşturmak isterler. Başlık kısmı manuel olarak sonradan
dosyadan atılabilse de bu durum ek bir yük oluşturmaktadır. Düz ikili dosyalarda böyle
bir başlık kısmı olmamalıdır.
2.3. Sisteme Özgü Bilgiler
Çalışabilen dosyada derleme işleminin yapıldığı sisteme özgü olan birtakım özel
bölümler oluşturulmuş olabilir. Örneğin Win32 sistemlerinde import tablosu, export
tablosu, kaynak bölümü tamamen Win32 sistemlerine özgü bölümlerdir. Bu bölümlerin
işletim sisteminin çekirdek kodlarında bulunmaması gerekir. Ancak pek çok derleyici
sisteminde bu bölümler default olarak oluşturulmaktadır. Bu bölümlerin dikkate
alınmaması ve dosyadan çıkartılması manuel yöntemlerle mümkün olabilmektedir.
2.4. Gerçek Kod ve Veriler
Nihayet derlenmiş ve bağlanmış olan çalışabilen kod işlemcinin yürütebileceği kod ve
verilere sahiptir. Tipik bir çalışabilen kodda programı oluşturan kod, statik veri ve yığın
alanları vardır. Pek çok sistemde bu alanlara bölüm (section) denilmektedir. Bölümleri
oluşturan sayfalar bellek üzerinde aynı koruma özellikleriyle biçimlendirilir. Tipik olarak
kodun bulunduğu bölüm .text, ilkdeğer verilmiş statik verilerin bulunduğu bölüm .data,
ilkdeğer verilmemiş statik verilerin bulunduğu bölüm .bss ve yığın bölümü de .stack
biçiminde isimlendirilir.
2.5 Özetle...
Düz ikili dosyalar giriş koduna ve başlık kısmına sahip olmayan, sisteme özgü bölüm
içermeyen dosyalardır. Düz ikili dosyalar yalnızca kod ve statik veri içerirler. Düz ikili
dosyalar bellekte bir adrese blok olarak yüklendiğinde problemsiz çalışabilmelidirler. Bu
dosyalarda derleme işleminin yapıldığı sisteme yönelik hiçbir ek bilgi bulunmamalıdır.
3. DÜZ İKİLİ DOSYALAR NASIL ELDE EDİLİR?
Yaygın kullanılan ticari derleyici sistemlerinin düz ikili dosya elde edilmesine yönelik
özellikleri yoktur. Bu özelliklere sahip araçlardan en yaygın olanları GNU lisansıyla
yazılmış olan nasm (netwide assembler) sembolik makine dili derleyicisi, C/C++
derleyicisi ve ld bağlayıcıdır. Bu geliştirme araçları tipik olarak GNU/Linux sistemlerinde
kullanılırlar. Ancak bunların Win32 sistemlerinde çalışan uyarlamaları da vardır. Fakat
maalesef Win32 sistemlerinde çalışan uyarlamalarında düz ikili dosya oluşturma
konusunda problemler gözlenmiştir. Bu nedenle düz ikili dosyaların bu araçlarla
GNU/Linux sistemlerinde derlenmesi iyi bir seçenektir. Tabi bu durum işletim sisteminin
tamamen GNU/Linux sistemlerinde geliştirilmesini zorunlu hale getirmez. 32 bit işletim
3
C ve Sistem Programcıları Derneği - CSD İşletim Sistemi Geliştirme Projesi
sistemlerinin geliştirilmesi başka başka sistemlerde ve başka derleyicilerle yapılabilir.
Ancak düz ikili dosya elde etmek için geliştirme işlemi bittiğinde bu sistemlerde derleme
ve bağlama yapılmalıdır. (Bu durumda kodun taşınabilir yazılması ve derleyicilere özgü
birtakım eklentilerin kullanılmaması gerekir. Eğer eklentiler kullanılacaksa bunun son
derlemenin yapılacağı sisteme uygun olması anlamlıdır.)
4. SEMBOLİK MAKİNE DİLİNDE YAZILAN KODLARIN DÜZ İKİLİ
FORMATA DÖNÜŞTÜRÜLMESİ
Düz ikili dosya üretebilen en yaygın sembolik makine dili derleyicisi nasm (Netwide
Assembler)’dır. nasm pek çok amaç kodu destekleyen bir sembolik makine dili
derleyicisidir. Bu derleyici Linux a.out, ELF, NetBSD/FreeBSD, COFF ve Microsoft 16bit OBJ amaç kod formatlarını destekler. GNU lisansıyla yazılmış olan bu derleyicilerin
Linux, DOS ve Win32 uyarlamaları Internet’te pek çok siteden ücret ödemeksizin
indirilebilir (http://nasm.sourceforge.net/). Derleme için gereken komut satırı
argümanlarının yalın biçimi şöyledir:
nasm -f <format> <kaynak dosya ismi> [-o <amaç dosya ismi>]
-f seçeneği üretilecek amaç kodun formatını belirtir. –o seçeneği ile üretilecek amaç
kodun ismi verilebilir. Eğer –o seçeneği kullanılmazsa dosya isminin sonuna, –f ile
belirtilen dosyanın formatı DOS ya da Win32 sistemlerinde kullanılan formatlardan
biriyse .obj, Unix/Linux sistemlerinde kullanılan bir formatlardan biriyse .o eklenir. İkili
dosyanın üretilmesi durumunda –o belirlemesi yapılmazsa üretilecek dosyaya herhangi
bir uzantı eklenmez. Örneğin:
nasm -f elf x.asm
nasm –f coff y.asm
ilk derlemeden ELF formatında x.o, ikinci derlemeden COFF formatında y.o dosyaları
elde edilir. Seçeneklerden sonra boşluk bırakılmayabilir. Örnğin:
nasm -felf x.asm
Liste dosyası (assembly lsiting file) almak için,
–l <lise dosyasının ismi>
seçeneği komuta eklenmelidir. Örneğin:
nasm kernel.asm -l kernel.lst
Düz ikili dosya elde edebilmek için –f bin seçeneği kullanılır. Örneğin:
nasm –f bin kernel.asm –l kernel.lst –o kernel.bin
4
C ve Sistem Programcıları Derneği - CSD İşletim Sistemi Geliştirme Projesi
ile kernel.asm dosyası derlenecek, kernel.lst isimli liste dosyası ile kernel.bin isimli düz
ikili dosya elde edilecektir. -f seçeneği hiç girilmezse default olarak zaten düz ikili dosya
üretilmektedir. Yukarıdaki derleme işlemi ile aşağıdaki tamamen eşdeğerdir:
nasm kernel.asm –l kernel.lst –o kernel.bin
Ya da örneğin:
nasm kernel.asm
işlemi ile kernel isimli düz ikili dosya elde edilir. nasm derleyicisinin yukarıda
açıkladıklarımızın dışında pek çok seçeneği vardır. Örneğin –u, -e, -a gibi… Bu
seçeneklerle ilgili ayrıntılı bilgileri nasm dökümantasyon notlarından elde edebilirsiniz
(http://nasm.sourceforge.net/)
5. C’DE YAZILAN KODLARIN DÜZ İKİLİ FORMATA DÖNÜŞTÜRÜLMESİ
C’de yazılan kodlar ilk aşamada gcc derleyicisi ile –c seçeneği kullanarak
derlenmelidir. Bilindiği –c seçeneği “yalnızca derle” anlamına gelmektedir. Kaynak
dosya –c seçeneği ile derlendiğinden .o uzantılı amaç dosya oluşturulmuş olur. Bu amaç
dosyadan düz ikili dosyanın elde edilmesi için ld programından faydalanılabilir.
Aşağıdaki C programı üzerinden ilerleyelim:
test.c
int g_x = 10;
void func(void)
{
}
int main(void)
{
func();
return 0;
}
ld bağlayıcısı düz ikili dosya elde etmek için aşağıdaki örnekte belirtildiği gibi
kullanılabilir:
ld test.o –o test.bin –Ttext 0x0 –e main --oformat binary -N
5
C ve Sistem Programcıları Derneği - CSD İşletim Sistemi Geliştirme Projesi
Burada test.o daha önce –c seçeneğiyle derlenmiş olan amaç dosyayı belirtmektedir.
Örneğimizde –o test.bin üretilecek düz ikili dosyayının ismini belirlemek için
kullanılmıştır. Yani işlemden sonra test.bin dosyası üretilecektir. Eğer bu belirleme
yapılmazsa düz ikili dosya a.out ismiyle üretilir. –T seçeneği ile bölümlerin
yerleştirileceği adresler belirlenebilir. Bu komut:
–T<bölüm ismi> <yeri>
biçimindedir. Bölüm ismi text, data, bss gibi herhangi bir bölüm ismi olabilir.
Örneğimizde text bölümü sıfır adresinden başlatılmıştır. Bölümün yeri defaault olarak
hex sistemde belirtilmektedir. Yani yer belirten sayıyı 0x seçeneği ile başlatmasaydık da
yine sayı hex olarak yorumlanacaktı. Bölümlerin yerleri offset üretiminde etkili olur.
Bağlayıcı en düşük bölümü dosyanın başına alarak dizilimi yapar. Örneğin test.c
programı aşağıdaki gibi bağlanmış olsun:
ld test.o –o test.bin –Tdata 0x50 –Ttext 0x100 –e main --oformat binary -N
Burada düz ikili dosya data bölümü ile başlatılacak ve data bölümünün ilk sembolü olan x
50 offsetinde bulunacaktır. Daha sonra dosyaya 0x50 ile 0x10 arasında boşluk verilecek
ve func fonksiyonunun kodu 0x100’den başlatılacaktır. Bölümlerin düzenlenmesi sonraki
bölümde ele alınmaktadır. Çalışabilen kodun başlangıç noktası ,
–e <fonksiyon ismi>
ile belirlenebilir. Gerçi düz ikili dosyalarda bu belirlemenin bir önemi yoktur. Ancak
bağlayıcının uyarısını kesmek için bu seçenek eklenebilir. Örneğimizde –e main
biçiminde bir belirleme yapılmıştır. (Burada main yerine herhangi bir fonksiyon
olabilirdi.) --oformat seçeneği bağlayıcının üreteceği dosyanın formatını belirlemekte
kullanılır. Düz ikili dosya için,
–oformat binary
seçeneği kullanılmalıdır. Normal olarak ld bağlayıcısı bölümleri sayfa başlarına hizalar.
Yani örneğin, text bölümünü izleyen data bölümü text bölümünün hemen aşağısında
değil bir sayfa (Intel mimarisinde 4K) sonra sayfa başında bulunacaktır. –N seçeneği
bunu engellemek için kullanılmakatadır.
Şimdi test.c dosyasından düz ikili dosyanın elde edilmesini adımlarla yeniden
açıklayalım.
1. Adım:
gcc –c test.c
2. Adım:
6
C ve Sistem Programcıları Derneği - CSD İşletim Sistemi Geliştirme Projesi
ld test.o –o test.bin –Ttext 0x0 –e main --oformat binary –N
işlem sonrasında test.bin dosyası oluşacaktır. Bu dosyayı bir disassembler programıyla
inceleyebilirsiniz. Disassembler olarak nasm ile aynı pakette bulunan ndisasm programını
kullanabilirsiniz:
ndisasm –b32 test.bin
-b32 seçeneği 32 bit modda görüntüleme yapmak için kullanılır. Yukarıdaki programı
disassembler altında şöyle görmelisiniz:
00000000
00000001
00000003
00000005
00000006
00000007
00000009
00000010
00000011
00000013
00000016
0000001B
0000001D
0000001F
00000020
00000022
00000023
00000024
0000002A
00000030
00000032
55
89E5
89EC
5D
C3
89F6
8DBC2700000000
55
89E5
83EC08
E8E5FFFFFF
31C0
EB01
90
89EC
5D
C3
8DB600000000
8DBF00000000
0A00
0000
push ebp
mov ebp,esp
mov esp,ebp
pop ebp
ret
mov esi,esi
lea edi,[edi+0x0]
push ebp
mov ebp,esp
sub esp,byte +0x8
call 0x0
xor eax,eax
jmp short 0x20
nop
mov esp,ebp
pop ebp
ret
lea esi,[esi+0x0]
lea edi,[edi+0x0]
or al,[eax]
add [eax],al
Burada gördüğünüz gibi data bölümünde bulunan g_x global değişkeni –N seçeneği
sayesinde hemen text bölümünden sonraya yerleştirilmiştir. Aynı dosyayı –N seçeneğini
kullanmadan düz ikili formata dönüştürmeyi deneyip karşılaştırma yapabilirsiniz.
5.1 Bölümlerin Organizasyonu
Çalışabilen dosya tipik olarak text, data, bss ve stack bölümlerinden oluşur.
Fonksiyonların makina kodları text bölümüne, ilkdeğer verilmiş statik ömürlü nesneler
data bölümüne ve ilkdeğer verilmemiş statik ömürlü nesneler ise bss bölümüne
yerleştirilir. stack programın stack alanını belirtmektedir. Örneğin:
int g_a = 10;
int g_b[100];
int main(void)
{
7
C ve Sistem Programcıları Derneği - CSD İşletim Sistemi Geliştirme Projesi
int i;
g_a = 10;
for (i = 0; i < 100; ++i)
g_b[i] = 0;
return 0;
}
gibi bir programda g_a data bölümüne g_b ise bss bölümüne yerleştirilir. main
fonksiyonunun kodu da text bölümünde bulunur. Aksi belirtilmediği sürece bu bölümler
gcc derleyicisi ve ld bağlayıcısı tarafından aşağıdaki sırada oluşturulmaktadır:
text
data
bss
stack
Aslında bss ve stack bölümleri çalışabilen dosyanın içerisinde yer kaplamaz. Genellikle
bu bölümlerin yalnızca uzunlukları çalışabilen dosya formatında tutulur. Yükleycici
dosyayı sanal belleğe yüklediğinde bss ve stack aşağıda (yüksek anlamlı bölgede)
kalmaktadır. bss bölümü yükleme sonrasında sıfırlanmaktadır (ilkdeğer verilmemiş yerel
statik ömürlü nesnelerin içerisinde 0 olduğunu biliyorsunuz). Dosya sanal belleğe
yüklendikten sonra aşağıdaki gibi bir görünüm elde edilir:
...
text
data
bss
heap
stack
...
esp
8
C ve Sistem Programcıları Derneği - CSD İşletim Sistemi Geliştirme Projesi
Görüldüğü gibi heap alanı bss alanının hemen altından başlatılıp aşağıya doğru
büyümektedir. Böylelikle bss ve stack alanlarının çalışabilen dosya içerisinde yer
kaplaması engellenmiş olur.
Düz ikili dosya üretilirken aksi belirtilmediği sürece yukarıdaki sıraya uygun kod
üretilir. bss bölümünün sonda bırakılması düz ikili dosyada yer kaplamasını
önlemektedir. Ancak tabi bu bölümdeki nesneler için offset sanki bu bölüm varmış gibi
üretilir.
Kaynaklar
1. The GNU Binary Utilities – ld Linker, Pesh H. Roland, Osier M. Jeffrey, Support
Cygnus,1993
2. Making Plain Binary Files Using a C Compiler (i386+), Frank Cornelis, 2000
(http://class21.ssm.samsung.co.kr/pds/data/CompilingBinaryFilesUsingACompiler.pdf)
9
C ve Sistem Programcıları Derneği - CSD İşletim Sistemi Geliştirme Projesi
Download