【内核之旅-2】内核编译

概述

这次介绍内核的编译脚本

参考资料:
x86架构操作系统内核实现

Makefile文件解析

#!Makefile

C_SOURCES = $(shell find . -name "*.c")
C_OBJECTS = $(patsubst %.c, %.o, $(C_SOURCES))
S_SOURCES = $(shell find . -name "*.s")
S_OBJECTS = $(patsubst %.s, %.o, $(S_SOURCES))

CC = gcc
LD = ld
ASM = nasm

C_FLAGS = -c -Wall -m32 -ggdb -gstabs+ -nostdinc -fno-pic -fno-builtin -fno-stack-protector -I include
LD_FLAGS = -T scripts/kernel.ld -m elf_i386 -nostdlib
ASM_FLAGS = -f elf -g -F stabs

all: $(S_OBJECTS) $(C_OBJECTS) link update_image

.c.o:
    @echo 编译代码文件 $< ...
    $(CC) $(C_FLAGS) $< -o $@

.s.o:
    @echo 编译汇编文件 $< ...
    $(ASM) $(ASM_FLAGS) $<

link:
    @echo 链接内核文件...
    $(LD) $(LD_FLAGS) $(S_OBJECTS) $(C_OBJECTS) -o hx_kernel

.PHONY:clean
clean:
    $(RM) $(S_OBJECTS) $(C_OBJECTS) hx_kernel

.PHONY:update_image
update_image:
    sudo mount floppy.img /mnt/kernel
    sudo cp hx_kernel /mnt/kernel/hx_kernel
    sleep 1
    sudo umount /mnt/kernel

.PHONY:mount_image
mount_image:
    sudo mount floppy.img /mnt/kernel

.PHONY:umount_image
umount_image:
    sudo umount /mnt/kernel

.PHONY:qemu
qemu:
    qemu -fda floppy.img -boot a

.PHONY:bochs
bochs:
    bochs -f tools/bochsrc.txt

.PHONY:debug
debug:
    qemu -S -s -fda floppy.img -boot a &
    sleep 1
    cgdb -x tools/gdbinit

命令的参数解释

gcc —— 编译选项

  • -m32 生成32位机器的汇编代码;
  • -ggdb -gstabs+ 调试信息
  • -nostdinc 不搜索默认路径头文件
  • -fno-builtin 不使用内建函数

ld —— 链接器参数:

  • -T , --script= 使用 scriptfile 作为链接器脚本。此脚本将替换 ld 的默认链接器脚本(而不是添加到其中),因此脚本必须指定输出文件所需的所有内容。如果当前目录中不存在脚本文件,ld 会在 -L选项指定的目录中查找

  • -m 模拟指定的链接器
    对于我的环境:Supported emulations: elf_x86_64 elf32_x86_64 elf_i386 elf_iamcu elf_l1om elf_k1om i386pep i386pe

  • -nostdlib: 不连接系统标准启动文件和标准库文件,只把指定的文件传递给连接器。这个选项常用于编译内核、bootloader等程序,它们不需要启动文件、标准库文件。
    C语言程序执行的第一条指令。并不是main函数。生成一个C程序的可执行文件时编译器通常会在我们的代码上加上几个被称为启动文件的代crt1.o,crti.o,crtend.o,crtn.o等,他们是标准库文件。这些代码设置C程序的堆栈等,然后调用main函数。他们依赖于操作系统,在裸板上无法执行

nasm —— 选项

ld脚本解析

/*
 *      kernel.ld -- 针对 kernel 格式所写的链接脚本
 */

ENTRY(start)
SECTIONS
{
    /* 段起始位置 */

    . = 0x100000;
    .text :
    {
        *(.text)
        . = ALIGN(4096);
    }

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

    .bss :
    {
        *(.bss)
        . = ALIGN(4096);
    }

    .stab :
    {
        *(.stab)
        . = ALIGN(4096);
    }
    
    .stabstr :
    {
        *(.stabstr)
        . = ALIGN(4096);
    }

    /DISCARD/ : { *(.comment) *(.eh_frame) }
}

特殊符号.称为location counter,可以理解为当前的虚拟地址(VMA)
第一条赋值语句. = 0x10000指示ld将当前地址设置为0x10000
第二条描述语句指示ld将所有输入文件的.text段输出到输出文件的.text段,*匹配所有输入文件

参考

Linux 命令(65)—— ld 命令
编译时“-nostdlib”的使用
ld脚本设置

你可能感兴趣的:(操作系统实验,linux,开发语言)