主要内容
建立内核的雏形
一
extern choose ; int choose(int a, int b);
[section .data] ; 数据在此
num1st dd 3
num2nd dd 4
[section .text] ; 代码在此
global _start ; 我们必须导出 _start 这个入口,以便让链接器识别
global myprint ; 导出这个函数为了让 bar.c 使用
_start:
push dword [num2nd] ; `.
push dword [num1st] ; |
call choose ; | choose(num1st, num2nd);
add esp, 8 ; /
mov ebx, 0
mov eax, 1 ; sys_exit
int 0x80 ; 系统调用
; void myprint(char* msg, int len)
myprint:
mov edx, [esp + 8] ; len
mov ecx, [esp + 4] ; msg
mov ebx, 1
mov eax, 4 ; sys_write
int 0x80 ; 系统调用
ret
void myprint(char* msg, int len);
int choose(int a, int b)
{
if(a >= b){
myprint("the 1st one\n", 13);
}
else{
myprint("the 2nd one\n", 13);
}
return 0;
}
先写一个简单的例子,在这里涉及了汇编代码与C代码之间的相互调用,因为在C语言中要用到汇编语言的函数,需要用关键字global导出,因为有本文件外定义的函数,需要用关键字extern声明。
二
因为我们需要用到ELF格式的内核,所以需要先了解ELF文件格式。
ELF文件由四部分组成:ELF头,程序头表,节,节头表(其中只有ELF头的位置固定,其余部分由ELF头来决定)。程序头表紧跟在ELF头之后(用来描述一个段在文件中的位置,大小及进入内存后的大小位置)。目前了解这些就足够了。
三
3.1用loader来加载ELF内核
因为是ELF格式的内核,所以要根据程序头表中的值把内核相应的段放到相应的位置,先准备一个简单的内核。
[section .text] ; 代码在此
global _start ; 导出 _start
_start: ; 跳到这里来的时候,我们假设 gs 指向显存
mov ah, 0Fh ; 0000: 黑底 1111: 白字
mov al, 'K'
mov [gs:((80 * 1 + 39) * 2)], ax ; 屏幕第 1 行, 第 39 列
jmp $
现在让内核进入内存。
org 0100h
BaseOfStack equ 0100h
BaseOfKernelFile equ 08000h ; KERNEL.BIN 被加载到的位置 ---- 段地址
OffsetOfKernelFile equ 0h ; KERNEL.BIN 被加载到的位置 ---- 偏移地址
jmp LABEL_START ; Start
; 下面是 FAT12 磁盘的头, 之所以包含它是因为下面用到了磁盘的一些信息
%include "fat12hdr.inc"
LABEL_START: ; <--- 从这里开始 *************
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, BaseOfStack
mov dh, 0 ; "Loading "
call DispStr ; 显示字符串
; 下面在 A 盘的根目录寻找 KERNEL.BIN
mov word [wSectorNo], SectorNoOfRootDirectory
xor ah, ah ; `.
xor dl, dl ; | 软驱复位
int 13h ; /
LABEL_SEARCH_IN_ROOT_DIR_BEGIN:
cmp word [wRootDirSizeForLoop], 0 ; `.
jz LABEL_NO_KERNELBIN ; | 判断根目录区是不是已经读完,
dec word [wRootDirSizeForLoop] ; / 读完表示没有找到 KERNEL.BIN
mov ax, BaseOfKernelFile
mov es, ax ; es <- BaseOfKernelFile
mov bx, OffsetOfKernelFile ; bx <- OffsetOfKernelFile
mov ax, [wSectorNo] ; ax <- Root Directory 中的某 Sector 号
mov cl, 1
call ReadSector
mov si, KernelFileName ; ds:si -> "KERNEL BIN"
mov di, OffsetOfKernelFile
cld
mov dx, 10h
LABEL_SEARCH_FOR_KERNELBIN:
cmp dx, 0 ; `.
jz LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR; | 循环次数控制, 如果已经读完
dec dx ; / 了一个 Sector