FreeBSD pmbr 解读

本文深入分析了FreeBSD在x86平台上的启动引导代码,包括MBR与GPT分区表的区别、代码迁移过程以及关键指令解释。
部署运行你感兴趣的模型镜像

今天我们来研究一下FreeBSD在x86平台上的启动引导代码,源代码的位置boot/i386/pmbr/pmbr.s。在分析代码之前,先简单介绍一些和启动引导有关的背景知识。
早先的硬盘都是使用MBR(主引导记录)方式进行分区管理和引导的。这种方式有几个特点:
  1. MBR是硬盘的第一个扇区(LBA0),开机时由BIOS负责装载到内存0x7c00地址处,然后从第1条指令开始执行;
  2. MBR中包含两部分重要内容:一是引导代码,二是分区表;
  3. MBR方式支持4个主分区,其中一个主分区可设置为扩展分区,扩展分区中的“子分区”,称之为逻辑分区;
  4. MBR的分区表用来表示LBA(逻辑块地址)的存储空间长度为32位,因而最多表示2^32个块,也就是说,MBR方式支持的硬盘容量最大为2TB;
近几年来,随着2T硬盘的使用,MBR就不够用了,替代MBR的,叫GPT。GPT实际上是Intel自20世纪末就开始开发一种新到分区表格式。而当时的硬盘不过几十G容量。Intel开发的新分区表格式使用64位作为LBA(参见pmbr.s中lba定义: lba: .quad 1),因此可以最大支持2^64个块。GPT方式支持的硬盘容量最大为?。

GPT使用硬盘开始的34个块作为分区的管理信息使用,其中:

LBA 0:Protective MBR,兼容BIOS。

LBA 1:  分区表头。Partition table header。

LBA 2-33:共32个块,每个块中包含4个分区表项,每个分区标项128字节。

start的地址,即整个pmbr的链接基准地址为$ORG=0x600,所以main链接地址为0x600+delta, 其中delta=$main-start,即main和start之间的差值。链接地址不等于运行地址,真正的运行地址是BIOS装载的地址,开机后pmbr被装载到$LOAD=0x07c00位置。也就是说,当start标号后的第一条语句”cld”执行时,pc的值是0x7c00。sp即栈指针则指向$EXEC+SECSIZE*4 = 0x600+0x200*4=0xe00。


start: cld
xorw %ax,%ax
movw %ax,%es
movw %ax,%ds
movw %ax,%as
movw $STACK,%sp
到此为止,指令都是从0x7c00顺序执行的。

下面,pmbr要将把自身从main标号开始到结束的代码区域整体搬迁到内存更低到位置去继续执行,具体复制到0x600+delta位置上。由于pmbr原本就是链接到0x600的,所以$start地址在汇编器看来就是0x600,尽管实际上被装载到0x7c00。代码移动之前,汇编器地址和实际运行地址的距离是(LOAD-EXEC);而当代码移动之后,汇编器地址和实际运行地址就重合了。所以目的起始地址为$main;源起始地址是多少呢?我们知道,装载和链接的差值,是(LOAD-EXEC),所以源起始地址为$main+(LOAD-EXEC),即$main-EXEC+LOAD。要移动的长度则是$SECSIZE-(main-start)。


movw$main-EXEC+LOAD,%si
movw $main,%di
movw $SECSIZE-(main-start),%cx
rep
movsb


                               +------------+
                               |            |
                               |            |
                               |            |
                               |            |
                               |            |
                               +------------+ EXEC
               ^               |            |
               |               |            |
  low memory   |               |            |
               |         +---> +------------+ dest = main
               |         |     |            |
               |         |     |            |
               |         |     |            |
               |         |     |            |
               |         |     |            |
               |         |     |            |
               |         |     |            |
               |         |     |            |
               |         |     |            |
               |         |     |            |
               |         |     |            |
               |         |     |            |
               |         |     +------------+ LOAD
               |         |     |   start:   |
               |         |     |            |
  high memory  |         |     |    ...     |
               +         |  +- +------------+ source = main + LOAD - EXEC
                         |  |  |   main:    |
                         |  |  |            |
SECSIZE - (main - start) +--+  |            |
                            |  |            |
                            |  |            |
                            +- +------------+ SECSIZE


当代码移动完成后,就跳转到新到的地址:即$EXEC+(main-start)执行。那是不是应该使用:
jmp EXEC+(main-start) 或 jmp main
错了!汇编器在处理这条指令时,并不知道自己的真实运行地址。汇编器认为pmbr是从ORG或EXEC处开始运行的。start等于EXEC,所以上述地址实际上等于main。由于jmp指令时下一条指令地址为main。所以汇编器在计算jmp 偏移量时得出的结论是:偏移量为0。
为了让汇编器计算出正确的偏移量,我们看一下到底移动了多远。
汇编器在汇编jmp语句时,是要计算出要跳转地址相对于下一条指令地址的相对位移。由于下一条指令地址为main,要向前跳转的位移delta为(LOAD-EXEC),所以要jmp main - (LOAD - EXEC)。即:
jmp main-LOAD+EXEC

您可能感兴趣的与本文相关的镜像

AutoGPT

AutoGPT

AI应用

AutoGPT于2023年3月30日由游戏公司Significant Gravitas Ltd.的创始人Toran Bruce Richards发布,AutoGPT是一个AI agent(智能体),也是开源的应用程序,结合了GPT-4和GPT-3.5技术,给定自然语言的目标,它将尝试通过将其分解成子任务,并在自动循环中使用互联网和其他工具来实现这一目标

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值