Yusuf Bülbül

An Engineer

Bootable Programlar ve Bootloader

Bu kelime Türkçeye çevrildiğinde manası kaybolmasa Türkçe kullanmayı tercih ederdim ama maalesef bu alandaki bir çok kelimenin Türkçe karşılığı anlamını karşılamıyor.  “Bootable” kelimesini bilgisayarına “Windows” kuran herkes bilir sanırım.  Eğer flash diskinize kopyaladığınız image dosyası, “bootable” değilse bilgisayarınız o dosyayı başlangıçta çalıştırmayacaktır. Bu yüzden işletim sistemi kurulum programını yüklediğiniz flash diskinizi “bootable” yapmanız gerekiyor. Genellikle iyi yazılmış virüs programlarının hemen hemen hepsi “bootable” dır. Bu yazımda “bootable”, “bootloader” gibi kavramlar üzerinde duracağım.

Öncelikle bilgisayarınızın güç düğmesine bastıktan sonra neler olduğuna bir göz atalım. İlk başlangıçta CPU, sadece okunabilen bir hafızada bulunan genel Giriş/Çıkış ünitelerini yapılandıran programı çalıştırmak için bu programı RAM’a yükler ve çalıştırır.  CPU yapılandırıldıktan sonra, bu yapılandırma işlemini yapan program, BIOS ismi verilen programı çalıştırmak için BIOS chip’i içerisindeki BIOS programını CPU’nun çalıştırabilmesi için Ram’a yükler.  BIOS programı BIOS chip’i üzerine yazılmış gömülü(embedded) bir yazılımdır. Bu yazılım, bilgisayarın temel donanımlarını, yapıllandırma ayarlarını test ve kontrol eder. BIOS, bu işlemleri yaptıktan sonra daha önceden BIOS ayarlarında tanımlanmış bilgisayara bağlı ve bootable olan bir disk arar. Bu diski bulduğunda bu disk içerisindeki bootable alanı CPU’un çalıştırabilmesi için RAM’a yükler. Bu bootable alan normal şartlar altında hard diskinizin boot sektörüdür. Eğer bilgisayarınızda Windows işletim sistemi kurulu ise bu alanda Windows’un bootloader’ı bulunur. Bootloader, Windows’u başlatmak için  önce kernel’i sonra da sistem dosyalarını RAM’a yükler ve Windows açılmaya başlar.

Bilgisayarınıza taktığınız herhangi bir hafıza biriminin ilk sektörü bootable olarak  işaretlenmişse BIOS ayarlarından bilgisayarınızın buradan boot olmasını isteyebilirsiniz.  Boot sektör dediğimiz şey, bir hafıza biriminin boot edilmek istendiğini belirten ilk sektörüdür.  Hafıza birimleri sektör sektör ayrılmıştır. Bir defteri hafıza birimi olarak düşünürsek, bu defterdeki her sayfayı bir sektör olarak tanımlayabiliriz. Yani sektör, hafıza birimi içerisinde belli bir uzunlukta ayrılmış bir alanı belirtir.  Kişisel bilgisayarlarda tanımlanan boot sektörü 512 byte’tır. Fakat bir çok yeni mikrodenetleyici içerisinde bulunan sram ve dram sektörleri 32 kbyte, 256 kbyte gibi çok daha büyüktür.  

  Kişisel bilgisayarlar için bir hafıza biriminin ilk 512 byte’ lık alanı bootable olarak işaretleyebilirsiniz.  Bu durumda BIOS, bu hafıza biriminin ilk sektörünü RAM’a yükleyip çalıştırılabilir kod adresi olarak bu adresi belirtecektir.  İşte siz bu bölüme kendi programınızı çalıştıran bir bootloader yazabilirsiniz. Bootloader programı oldukça basit bir programdır.   Bu programın yaptığı şey, belli bir yerde bulunan programı ‘RAM’a yazmak, bu programın çalıştırılması için işlemcinin PC(Program Counter) kaydedicisine RAM’daki ilk “instruction” adresini göstermek ve kullanacağı stack alanını belirtmektir.

Tabi ki bu işlem tamamen işlemci mimarisi ile ilgilidir ve bootloader işlemci mimarisine göre yazılır.  Bir sonraki yazımda x86 gibi mimariler ve normal bir kişisel bilgisayar için bootloader yazmak yerine , arm işlemci ve bu mimariyi kullanan mikrodenetleyiciler için bootloader programına örnek vereceğim. Ama kişisel bir bilgisayar için bootable bir program yazmak isterseniz; buradaki linke göz atabilirsiniz. Bu yazımda burada anlatılan şeyleri kısaca açıklamak istiyorum.

Bu linkte bootable bir image dosyası oluşturup bu image dosyasını bir diske yakarak emilatör yardımıyla programının nasıl çalıştığını göstermiş.  Programı nasıl derlemeniz gerektiğini ve diske image’ı nasıl yakacağınızı anlatmış.  Bu işlemleri Linux üzerinde gerçekleştirmiş. Öncelikle X86 mimarisini simüle eden bochs-x86-64 emilatörünü indirmiş.  Daha sonra bootable olarak işaretlediği 512byte lık bir alan içerisine  BIOS fonksiyonlarını kullanarak ekrana yazı yazdıran küçük bir program yazmış ve bunu derlemiş.  Şimdi burada en önemli nokta programı nasıl derlediği.  Bu yüzden oradan alıntı yapacağım.

// generate 16-bit code
__asm__(".code16\n");

/*jump boot code entry*/
__asm__("jmpl $0x0000, $main\n");

/* user defined function to print series of characters terminated by null character */
void printString(const char* pStr) {
     while(*pStr) {
          __asm__ __volatile__ (
               "int $0x10" : : "a"(0x0e00 | *pStr), "b"(0x0007)
          );
          ++pStr;
     }
}

void main() {
     /* calling the printString function passing string as an argument */
     printString("Hello, World");
}

Yukarıdaki ekrana “Hello World” yazdıran C dilinde yazılmış bir program mevcut. Fakat programın başına assembly ile yazılmış bir başlık eklenmiş.

__asm__(“.code16\n”);  kodu programın 16 bitlik “instructionlar” halinde derlenmesi gerektiğini belirtiyor. Çünkü x86 mimaride bootable kodların 16 bitlik  olması gerekiyor.

__asm__(“jmpl $0x0000, $main\n”); – bu kod Ram’in 0. adresine gidip oradaki kodları çalıştırdıktan sonra return adresini “main” adresi olarak belirler.

Bu programı derleme aşaması biraz önemli. 3 aşamada derleniyor.

gcc -c -g -Os -march=i686 -ffreestanding -Wall -Werror test.c -o test.o

ld -static -Ttest.ld -nostdlib --nmagic -o test.elf test.o

objcopy -O binary test.elf test.bin

 

ilk aşamada test.c olarak kaydettiğiniz dosya obje dosyasına çevriliyor. Bu dosya aslında binary dosyadır fakat çalıştırılabilmesi için link edilmesi ve  kütüphanelerle birleştirilmesi gerekiyor. Burada kullanılan işlemci mimarisi ve standart kütüphanelerin kullanılmayacağı gibi bootloader’a özgü “compiler flag” ları set edilmiş.

ld -static -Ttest.ld -nostdlib --nmagic -o test.elf test.o

komutu obje dosyasını belirlenen linker script vasıtasıyla link edilmesine yarıyor. Linker aşamasında, program kodlarının çalışacağı adres aralığı, kullanacağı hafıza yapısının nasıl olacağı ve hangi adreslerden atlamalar olacağı belirtilir.

Bu bootable program için test.ld isminde şöyle bir linker script yazılmış;

ENTRY(main);
SECTIONS
{
    . = 0x7C00;
    .text : AT(0x7C00)
    {
        *(.text);
    }
    .sig : AT(0x7DFE)
    {
        SHORT(0xaa55);
    }
}

 

Burada, program bölümleri, adres ve uzunlukları belirtiliyor.  0X7C00 adresi bootable olarak derlenmek istenilen bu program için kullanılıyor.  Bu adres, bootable olan her program için sabit bir adrestir. 0X7DFE ise 0X7C00 dan sora yazılan 512 byte’lık alanın son 2 byte’ının 0xaa55 olacağı adrestir.  Bu bootable bir bootable işaretidir. Yani eğer bir diski bootable yapmak istiyorsanız ilk 512 byte’ın son iki byte’ını 0xaa55 yapıyorsunuz.

Son aşamada ise

objcopy -O binary test.elf test.bin

Komutu ile bu binary dosyanın herhangi bir dosya sisteminden bağımsız olduğunu ve direk hafızaya yazıldığını belirtiyoruz. Çünkü biliyorsunuz ki her işletim sistemi dosyaları kendi dosya sistemi ile saklar. Windows NTFS, linux Ext4 dosya sistemini kullanır. Dosya sistemi hardiski belli tablolara ayırır ve dosyaları bu tablolara kendi formatlarında yazar. Fakat bootable bir program bu sistemlerden bağımsız çalışması gerekiyor.

Bu derlenmiş dosyayı bir flashın içerisine image dosyası olarak basıp bilgisayarınızı bu flash ile başlattığınızda hello world yazısını göreceksiniz. Bu şekilde normal bir bilgisayarda bootable programı anlatmış oldum. Bir sonraki yazım, arm mikrodenetleyiciler için bootloader yazmak ve geliştirmek olacak.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Copyright © Tüm Hakları Saklıdır.