使用Rust开发操作系统(UEFI的内核加载过程)

在上一篇文章中我们编写了AllocatorFile来简化对内存管理和文件的操作,在本章中我们编写ELF文件加载功能在本章中我们需要了解一下ELF文件的相关知识

ELF文件基本介绍

ELF文件有三种不同的类型,可重定位文件,可执行文件和共享目标文件。其中可重定位文件是由编译器和汇编器创建,在运行之前需要经过链接器处理

  • 可重定位文件: 该文件包含代码和数据,用于连接成可执行文件或共享目标文件,静态链接库也属于该类,例如在Linux中.a.o文件
  • 可执行文件: 包含二进制代码和数据,可以直接复制到内存并执行,例如Linux中/bin /usr/bin目录下的文件
  • 共享目标文件: 一种特殊类型的可重定位文件,可以加载或运行时被动态加载到内存并链接,例如Linux中的.so文件(动态链接库)

在Linux中我们可以使用file命令来查看文件的类型,例如我们file命令查看我们编译出的内核文件

$ file kernel
kernel: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, with debug_info, not stripped

我们可以看到kernel文件的信息为 ELF 64位可执行文件,架构为x86-64,已经完成链接,包含调试信息

如果要查看elf文件的详细信息可以使用readelf命令,在使用readelf命令时必须要使用参数,参数的功能如下(常用)

  • -h:仅显示ELF文件的文件头信息
  • -l: 仅显示ELF文件的程序段信息
  • -S: 仅显示ELF文件的section信息
  • -A: 仅显示ELF运行的目标架构
  • -V: 仅显示ELF文件版本信息
  • -a: 等同于-h -l -S -s -r -d -V -A -I等参数组合

ELF文件基本结构

在本章中我们只关注不含有动态链接的可执行ELF文件(主要是分析编译出的内核文件),ELF文件按照不同的视角分为链接视角和可执行视角

ELF头部

ELF头部描述了该ELF文件的自身信息,并提供寻找文件其他段的方法

编译出的内核文件使用readelf -h kernel能获取到以下信息

ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x202060
  Start of program headers:          64 (bytes into file)
  Start of section headers:          34808 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         7
  Size of section headers:           64 (bytes)
  Number of section headers:         11
  Section header string table index: 9

显示的内容中

  • Magic称为幻数,用于标识文件的类型,7F 45 4C 46是ELF文件的幻数,Windows 的PE文件的幻数为 4D 5A
  • Class表示该ELF文件的类别,分为ELF32和ELF64
  • Data表示ELF文件使用的字节序,在本例中为小端序
  • Version表示ELF文件的版本,目前只有一个版本,因此固定为1,
  • Entry point address 表示程序的入口地址,当将elf文件内容加载到内存后,代码执行开始的地址
  • Start of program headers 表示程序头的起始位置(相对于文件而言),在本例中程序头起始位置在该文件的第64字节处
  • Start of section headers表示程序段的起始位置(相对于文件而言),在本例中程序头起始位置在该文件的第34808 字节处
  • Flags: 特定于处理器的标志,32位和64位Intel架构都没有定义标志,因此eflags的值是0
  • Size of this header 表示ELF文件头部所占用的大小
  • Size of program headers 表示所有的ELF程序头所占用的大小
  • Number of program headers表示ELF程序头的个数
  • Size of section headers 表示ELF段头所占用大小
  • Number of section headers表示ELF段头的个数
  • Section header string table index表示段头字符串表的索引

在rust中我们将ELF头部结构定义如下

#[repr(C)]
pub struct ElfHeader64 {
    pub magic: [u8; 4],
    pub class: u8,
    pub endianness: u8,
    pub header_version: u8,
    pub abi: u8,
    pub abi_version: u8,
    pub unused: [u8; 7],
    pub elftype: u16,
    pub machine: u16,
    pub elf_version: u32,
    pub entry: <Self as GenElfHeader>::Word, // u64 in elf 64 file
    pub phoff: <Self as GenElfHeader>::Word, // u64 in elf 64 file
    pub shoff: <Self as GenElfHeader>::Word, // u64 in elf 64 file
    pub flags: u32,
    pub ehsize: u16,
    pub phentsize: u16,
    pub phnum: u16,
    pub shentsize: u16,
    pub shnum: u16,
    pub shstrndx: u16,
}

其中<Self as GenElfHeader>::Word是针对每一个ELF文件位数不同而制定的,例如32位ELF文件中<Self as GenElfHeader>::Word的值就是u32,64位ELF文件的值就是u64

以下是我们编译出来的内核文件二进制内容(节选的开头部分)每一列表示一个字节例如7F就是一个字节大小为u8,2个字节大小为u1

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值