Linux Makefile'lar

Linux kodunu incelemeden önce Linux'un nasıl oluşturulduğu, derlendiği ve bağlandığı konusunda bazı temel fikirlere sahip olmalıyız. Bunu en baştan başlayarak yapmanın bir yolu Linux makefile'ları anlamaktır. Çevrimiçi kaynak gösterimini tercih ediyorsanız Cross-Referencing Linux bağlantısını kontrol edin.

linux/Makefile

Bu üst seviye için bazı iyi bilinen makefile hedefleri şunlardır:

xconfig, menuconfig, config, oldconfig
linux/.config çekirdek yapılandırma dosyasını üretir;

depend, dep
alt dizinlerde linux/.depend, linux/.hdepend ve .depend gibi bağımlılık dosyalarını üretir;

vmlinux
en önemli hedef olan linux/vmlinux yerleşik çekirdek görüntüsünü üretir;

modules, modules_install
/lib/modules/$(KERNELRELEASE)içerisindeki modülleri üretir ve kurar;

tags
vim ile kaynağın görüntülenmesi için linux/tags etiket dosyasını üretir.

linux/Makefile anahatları ile aşağıdaki gibidir:

include .depend
include .config
include arch/i386/Makefile

vmlinux: linux/vmlinux üretir
        /* "stext" giriş noktası arch/i386/kernel/head.S dosyasında tanımlı*/
        $(LD) -T $(TOPDIR)/arch/i386/vmlinux.lds -e stext
        /* $(HEAD) */
        + from arch/i386/Makefile
                arch/i386/kernel/head.o
                arch/i386/kernel/init_task.o
        init/main.o
        init/version.o
        init/do_mounts.o
        --start-group
        /* $(CORE_FILES) */
        + from arch/i386/Makefile
                arch/i386/kernel/kernel.o
                arch/i386/mm/mm.o
        kernel/kernel.o
        mm/mm.o
        fs/fs.o
        ipc/ipc.o
        /* $(DRIVERS) */
        drivers/...
                char/char.o
                block/block.o
                misc/misc.o
                net/net.o
                media/media.o
                cdrom/driver.o
                and other static linked drivers
                + from arch/i386/Makefile
                        arch/i386/math-emu/math.o (ifdef CONFIG_MATH_EMULATION)
        /* $(NETWORKS) */
        net/network.o
        /* $(LIBS) */
        + from arch/i386/Makefile
                arch/i386/lib/lib.a
        lib/lib.a
        --end-group
        -o vmlinux
        $(NM) vmlinux | grep ... | sort > System.map
tags: vim için linux/tags üretir
modules: modülleri üretir
modules_install: modülleri kurar
clean mrproper distclean: derlemenin yapıldığı dizini temizler
psdocs pdfdocs htmldocs mandocs: çekirdek belgelerini üretir

include Rules.make

rpm: bir rpm üretir

Burada --start-group ve --end-group, sembol referans sorununu çözmek için ld komut satırı seçenekleridir. Ayrıntılar için Using LD, the GNU linker: Command Line Options belgesine başvurabilirsiniz.

Rules.make çoklu Makefile dosyaları için kurallar içerir.

linux/arch/i386/vmlinux.lds

Derlemeden sonra ld birkaç nesne ve arşiv dosyasını biraraya getirir, verilerini yeniden yerleştirir ve sembol referansları bağlayıp kapatır. linux/arch/i386/vmlinux.lds dosyası linux/Makefile tarafından yerleşik çekirdek görüntüsü linux/vmlinux 'un ilintilenmesinde kullanılan ilintileyici betik olarak tasarlanmıştır.

/* i386 Linux çekirdeği oluşturmak için ld betiği
 * Martin Mares <mj@atrey.karlin.mff.cuni.cz> tarafından yazılmıştır;
 */
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
/* "ENTRY" linux/Makefile içinde "-e stext" komut satırı seçeneği ile değiştirilir */
ENTRY(_start)
/* Çıktı dosyası (linux/vmlinux) yerleşimi.
 * Bakınız Using LD, the GNU linker: Specifying Output Sections */
SECTIONS
{
/* Çıktı bölümü .text 3G+1M adresinden başlar.
 * Bakınız Using LD, the GNU linker: The Location Counter */
  . = 0xC0000000 + 0x100000;
  _text = .;                    /* Metin ve salt okunur veri */
  .text : {
        *(.text)
        *(.fixup)
        *(.gnu.warning)
        } = 0x9090
/* Tahsis edilmemiş oyuklar 0x9090 ile doldurulur, örn. "NOP NOP" için opcode.
 * Bakınız Using LD, the GNU linker: Optional Section Attributes */

  _etext = .;                   /* text bölümünün sonu */

  .rodata : { *(.rodata) *(.rodata.*) }
  .kstrtab : { *(.kstrtab) }

/* Sonraki 16 baytlık sınıra hizalandı.
 * Bakınız Using LD, the GNU linker: Arithmetic Functions */
  . = ALIGN(16);                /* Olağandışılık tablosu */
  __start___ex_table = .;
  __ex_table : { *(__ex_table) }
  __stop___ex_table = .;

  __start___ksymtab = .;        /* Çekirdek sembol tablosu */
  __ksymtab : { *(__ksymtab) }
  __stop___ksymtab = .;

  .data : {                     /* Veri */
        *(.data)
        CONSTRUCTORS
        }
/* "CONSTRUCTORS" için bakınız:
 * Using LD, the GNU linker: Option Commands */

  _edata = .;                   /* data bölümünün sonu */

  . = ALIGN(8192);              /* init_task */
  .data.init_task : { *(.data.init_task) }

  . = ALIGN(4096);              /* Init kodu ve veri */
  __init_begin = .;
  .text.init : { *(.text.init) }
  .data.init : { *(.data.init) }
  . = ALIGN(16);
  __setup_start = .;
  .setup.init : { *(.setup.init) }
  __setup_end = .;
  __initcall_start = .;
  .initcall.init : { *(.initcall.init) }
  __initcall_end = .;
  . = ALIGN(4096);
  __init_end = .;

  . = ALIGN(4096);
  .data.page_aligned : { *(.data.idt) }

  . = ALIGN(32);
  .data.cacheline_aligned : { *(.data.cacheline_aligned) }

  __bss_start = .;              /* BSS */
  .bss : {
        *(.bss)
        }
  _end = . ;

/* Çıktı bölümü /DISCARD/ son ilintileme çıktısına dahil edilmeyecektir.
 * Bakınız Using LD, the GNU linker: Section Definitions */
  /* Çıkarılacak bölümler */
  /DISCARD/ : {
        *(.text.exit)
        *(.data.exit)
        *(.exitcall.exit)
        }

/* Aşağıdaki çıktı bölümleri 0. bellek konumuna adreslenmiştir.
 * Bakınız Using LD, the GNU linker: Optional Section Attributes */
  /* Stab hata ayıklama bölümleri.  */
  .stab 0 : { *(.stab) }
  .stabstr 0 : { *(.stabstr) }
  .stab.excl 0 : { *(.stab.excl) }
  .stab.exclstr 0 : { *(.stab.exclstr) }
  .stab.index 0 : { *(.stab.index) }
  .stab.indexstr 0 : { *(.stab.indexstr) }
  .comment 0 : { *(.comment) }
}

linux/arch/i386/Makefile

linux/arch/i386/Makefile, linux/Makefile tarafından i386'ya özel öğelerin ve kuralların sağlanması için dahil edilmiştir.

Aşağıdaki bütün hedefler linux/Makefile'ının vmlinux hedefine bağımlıdır. Bunlar, linux/arch/i386/boot/Makefile içinde bazı seçenekler ile ilgili hedefler oluşturarak yapılır.

Tablo 1.1. linux/arch/i386/Makefile içindeki hedefler

HedefKomut
zImage[a]@$(MAKE) -C arch/i386/boot zImage[b]
bzImage@$(MAKE) -C arch/i386/boot bzImage
zlilo@$(MAKE) -C arch/i386/boot BOOTIMAGE=zImage zlilo
bzlilo@$(MAKE) -C arch/i386/boot BOOTIMAGE=bzImage zlilo
zdisk@$(MAKE) -C arch/i386/boot BOOTIMAGE=zImage zdisk
bzdisk@$(MAKE) -C arch/i386/boot BOOTIMAGE=bzImage zdisk
install@$(MAKE) -C arch/i386/boot BOOTIMAGE=bzImage install

[a] zImage mahlası: sıkıştırılmış;

[b] -C makefile'ları okumadan önce dizin değiştirmek için kullanılan bir make komut satırı seçeneğidir.

Bakınız GNU make: Summary of Options ve GNU make: Recursive Use of make.

Bu makefile'ın linux/Makefile tarafından ihraç edilen bazı çevre değişkenlerini yeniden tanımlaması önemlidir. Özellikle:

OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S

Etki, altdizindeki makefile'lara geçecek ve aracın davranışı değişecektir. objcopy komut satırı seçeneklerinin ayrıntıları için GNU Binary Utilities: objcopy'ye bakınız.

$(LIBS)'in niçin "$(TOPDIR)/arch/i386/lib/lib.a"'yı iki defa içerdiği belli değildir.

LIBS := $(TOPDIR)/arch/i386/lib/lib.a $(LIBS) $(TOPDIR)/arch/i386/lib/lib.a

Bazı araç dizileri ile ortaya çıkan ilintileme sorunları üzerinde çalıştırmak için olabilir.

linux/arch/i386/boot/Makefile

linux/arch/i386/boot/Makefile ne linux/arch/i386/Makefile içerisine ne de linux/Makefile içerisine dahil edilmediği için biraz daha bağımsızdır.

Bununla birlikte biraz ilişki vardır:

  • linux/Makefile: yerleşik çekirdek görüntüsü linux/vmlinux'u üretir;
  • linux/arch/i386/boot/Makefile: önyükleme kodunu üretir;
  • linux/arch/i386/Makefile: linux/vmlinux'un önyükleme kodu oluşturulmadan önce hazır olduğunu kontrol eder ve hedefleri linux/Makefile'a ihraç eder (bzImage gibi).

zdisk, zlilo veya zdisk hedefleri için gereken $(BOOTIMAGE) değeri linux/arch/i386/Makefile'dan gelir.

Tablo 1.2. linux/arch/i386/boot/Makefile içindeki hedefler

HedefKomut
zImage
$(OBJCOPY) compressed/vmlinux compressed/vmlinux.out
tools/build bootsect setup compressed/vmlinux.out $(ROOT_DEV) > zImage
bzImage
$(OBJCOPY) compressed/bvmlinux compressed/bvmlinux.out
tools/build -b bbootsect bsetup compressed/bvmlinux.out $(ROOT_DEV) \
        > bzImage
zdisk
dd bs=8192 if=$(BOOTIMAGE) of=/dev/fd0
zlilo
if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz
        $(INSTALL_PATH)/vmlinuz.old; fi
if [ -f $(INSTALL_PATH)/System.map ]; then mv $(INSTALL_PATH)/System.map
        $(INSTALL_PATH)/System.old; fi
cat $(BOOTIMAGE) > $(INSTALL_PATH)/vmlinuz
cp $(TOPDIR)/System.map $(INSTALL_PATH)/
if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
install
sh -x ./install.sh $(KERNELRELEASE) $(BOOTIMAGE) $(TOPDIR)/System.map
        "$(INSTALL_PATH)"

tools/build {bootsect, setup, compressed/vmlinux.out}'dan zImage'ı veya {bbootsect, bsetup, compressed/bvmlinux,out}'dan bzImage'ı derler. linux/Makefile "export ROOT_DEV = CURRENT". Dikkat ederseniz $(OBJCOPY) linux/arch/i386/Makefile içerisindeki linux/arch/i386/Makefile tarafından yeniden tanımlanmıştır.

Tablo 1.3. linux/arch/i386/boot/Makefile içindeki hedeflerin desteklenmesi

Hedef: ÖngereksinimlerKomut
compressed/vmlinux: linux/vmlinux@$(MAKE) -C compressed vmlinux
compressed/bvmlinux: linux/vmlinux@$(MAKE) -C compressed bvmlinux
tools/build: tools/build.c$(HOSTCC) $(HOSTCFLAGS) -o $@ $< -I$(TOPDIR)/include[a]
bootsect: bootsect.o$(LD) -Ttext 0x0 -s --oformat binary bootsect.o[b]
bootsect.o: bootsect.s$(AS) -o $@ $<
bootsect.s: bootsect.S ...$(CPP) $(CPPFLAGS) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
bbootsect: bbootsect.o$(LD) -Ttext 0x0 -s --oformat binary $< -o $@
bbootsect.o: bbootsect.s$(AS) -o $@ $<
bbootsect.s: bootsect.S ...$(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
setup: setup.o$(LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $<
setup.o: setup.s$(AS) -o $@ $<
setup.s: setup.S video.S ...$(CPP) $(CPPFLAGS) -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
bsetup: bsetup.o$(LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $<
bsetup.o: bsetup.s$(AS) -o $@ $<
bsetup.s: setup.S video.S ...$(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@

[a] "$@" hedef anlamındadır, "$<" ilk öngereksinim anlamındadır; Bakınız GNU make: Automatic Variables;

[b] --oformat binary çalıştırılabilirin bellek dökümüne eşdeğer bir ham ikilik çıktı arar; Bakınız Using LD, the GNU linker: Command Line Options.

Dikkat ederseniz bootsect.S bbootsect.s'ye ve setup.S bsetup.s'ye derlendiğinde -D__BIG_KERNEL__'e sahipti. Bunların kodları Yerden Bağımsız Kod (Place Independent Code - PIC) olmalı, bu durumda -Ttext seçeneğinin ne yaptığının önemi yoktur.

linux/arch/i386/boot/compressed/Makefile

Bu dosya görüntüsünün sıkıştırılıp çözülmesi mekanizmasını yerine getirir.

Sıkıştırma/çözmeyi önyükleme kodundan ayırmak iyidir. Bu böl-ve-yönet çözümü bizim sıkıştırma/çözme mekanizmasını kolayca geliştirmemize veya yeni bir önyükleme yöntemi uyarlamamıza imkan sağlar.

linux/arch/i386/boot/compressed/ dizini head.S ve misc.c dosyalarını içerir.

Tablo 1.4. linux/arch/i386/boot/compressed/Makefile içindeki hedefler

HedefKomut
vmlinux[a]$(LD) -Ttext 0x1000 -e startup_32 -o vmlinux head.o misc.o piggy.o
bvmlinux$(LD) -Ttext 0x100000 -e startup_32 -o bvmlinux head.o misc.o piggy.o
head.o$(CC) $(AFLAGS) -traditional -c head.S
misc.o
$(CC) $(CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F)))
        -c misc.c[b]
piggy.o
tmppiggy=_tmp_$$$$piggy; \
rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \
$(OBJCOPY) $(SYSTEM) $$tmppiggy; \
gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \
echo "SECTIONS { .data : { input_len = .; \
        LONG(input_data_end - input_data) input_data = .; \
        *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \
$(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-i386 \
        -T $$tmppiggy.lnk; \
rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk

[a] Hedef vmlinux burada linux/Makefile içinde tanımlanana göre değişiktir;

[b] "subst" bir MAKE işlevidir; Bakınız GNU make: Functions for String Substitution and Analysis.

piggy.o input_len değişkeninini ve gzip ile sıkıştırılmış linux/vmlinux'ı içerir. input_len piggy.o'nun başında yer alır ve input_len'in kendisi hariç piggy.o'nun boyutuna eşittir. piggy.o bağlayıcı betiğinde geniş açıklamalar için bakınız Using LD, the GNU linker: Section Data Expressions.

Tam olarak söylemek gerekirse objcopy tarafından üretilen gzip ile sıkıştırılmış olan linux/vmlinux'un kendisi (ELF biçiminde) değil onun ikili görüntüsüdür. Dikkat ederseniz $(OBJCOPY), linux/arch/i386/Makefile linux/arch/i386/Makefile içerisinde -O binary seçeneğini kullanarak ham ikili çıktı almak için yeniden tanımlanmıştır.

{bootsect, setup} veya {bbootsect, bsetup} bağlandığı zaman, $(LD) onların ikili biçimde çıktı alınması için --oformat binary seçeneğini belirtir. zImage (veya bzImage) yapıldığında, $(OBJCOPY) compressed/vmlinux (veya compressed/bvmlinux)'dan da bir ara ikili çıktı üretir. zImage veya bzImage'ın tüm bileşenlerinin ham ikili biçimde olması görüntünün kendi kendini bir yükleyiciye başvurmadan yükleyebilmesi ve yerleştirebilmesi için elzemdir.

Hem vmlinux hem de bvmlinux head.o ve misc.o'yu piggy.o'dan önce hazırlar, fakat farklı başlangıç adreslerine (0x1000 ve 0x100000) bağlanırlar.

linux/arch/i386/tools/build.c

linux/arch/i386/tools/build.c zImage veya bzImage üretmek için konak aracıdır.

linux/arch/i386/boot/Makefile içinde:

tools/build bootsect setup compressed/vmlinux.out $(ROOT_DEV) > zImage

tools/build -b bbootsect bsetup compressed/bvmlinux.out $(ROOT_DEV) > bzImage

-b büyük_çekirdek_mi (is_big_kernel) anlamındadır, sistem görüntüsünün çok büyük olup olmadığını kontrol eder.

tools/build aşağıdaki zImage veya bzImage'a yeniden yönlendirilen çıktıları standart çıktı birimine verir:

  1. bootsect veya bbootsect: linux/arch/i386/boot/bootsect.S'dan, 512 bytes;
  2. setup veya bsetup: linux/arch/i386/boot/setup.S'den, 4 sektör veya daha fazla, sektör hizalı;
  3. aşağıdakileri de içeren, compressed/vmlinux.out veya compressed/bvmlinux.out:

    1. head.o: linux/arch/i386/boot/compressed/head.S dosyasından;
    2. misc.o: linux/arch/i386/boot/compressed/misc.c dosyasından;
    3. piggy.o: input_len ve gzip'li linux/vmlinux dosyasından.

tools/build standart çıktıya yazarken bootsect veya bbootsect'ın bazı içeriklerini değiştirecektir:

Tablo 1.5. tools/build tarafından yapılan değişiklikler

OffsetByteDeğişkenKomut
1F1 (497)1setup_sectorskurulum sektörleri sayısı, >=4
1F4 (500)2sys_sizesystem size in 16-bytes cinsinden sistem boyutu, küçük-biten
1FC (508)1minor_rootroot dev minor
1FD (509)1major_rootroot dev major

Takip eden bölümde compressed/vmlinux vmlinux olarak ve compressed/bvmlinux bvmlinux olarak anılacaktır.

Kaynakça