GNU/as 汇编实现 x86 操作系统 MBR 程序

  当按下计算机开机键,BIOS 为我们做完一系列检测和初始化工作后,就会尝试从存储设备的第一个扇区,加载可以引导操作系统启动的程序,并将执行权交给它,所以这个特殊的扇区被称为引导扇区(Boot Sector)。引导扇区上存储的内容,被称为主引导记录(MBR,Master Boot Record)。记录在引导扇区上的这段程序,我们称为 MBR 程序。

原文链接:https://blog.csdn.net/word_world/article/details/129105044

1 编写 MBR 程序

  为使 MBR 程序可以被 BIOS 正确加载,需要满足三个条件 :

  • 位于存储设备第一个扇区
  • 长度为 512 字节
  • 最后两字节内容为 0x55 0xaa

  下面是一个极简的 mbr 程序,从 BIOS 获得执行权后,并不做实质的引导,只是打印一个字符串,然后进入死循环。

.code16
.global main
main:
	// 初始化寄存器 ds=cs,es=cs
	mov  %cs,   %ax
	mov  %ax,   %ds
	mov  %ax,   %es
	// puts(str, len, 20, 8)
	mov  $str,  %bp
	mov  $len,  %cx
	mov  $0x14, %dh # 行号 +20
	mov  $0x08, %dl # 缩进 +8 字符
	call puts
	// while(true);
	jmp  .

// void puts(void *str, int len, int row, int col)
//  @str <- %bp
//  @len <- %cx
//  @row <- %dh
//  @col <- %dl
puts:
	mov  $0x1301, %ax # 文字属性
	mov  $0xc,    %bx # 颜色
	int  $0x10        # 调用 0x10 中断
	ret

str:
	.ascii "Hello Lubanix"
	len = . - str     # str长度 = 当前地址 - str首地址

// 引导扇区结束标志 0xaa55
.org 510
magic:
	.byte 0x55, 0xaa

1.1 GNU/as 汇编器

# 汇编得到目标文件 mbr.o
as -o boot/mbr.o boot/mbr.s
# 链接 mbr.o 得到二进制文件 mbr.bin
ld -e main \
	--oformat=binary \
	-o boot/mbr.bin \
	boot/mbr.o \
	--Ttext=0

ld 选项

  • -o    输出文件
  • --oformat 输出格式
  • --Text   代码段起始地址
  • -e    程序入口函数

1.2 AT&T 汇编代码说明

  GNU/as 采用 AT&T 汇编,它与 Intel 汇编有一些不同,特别是源操作数和目标操作数的顺序是相反的。所以这一节对整个 mbr 程序做逐行的说明。

行号语法说明
1.code16使用 16 位指令
2.global导出符号
5mov src, dst数据移动
5~7%reg将寄存器 cs 的值赋给寄存器 ds、es
9$tag将 str 地址放入寄存器 bp,为 0x10 中断设置字符串地址
10$var将变量 len 的值放入寄存器 cx,为0x10中断设置字符串长度
11%dl访问 dx 寄存器低 16(0~15) 位,为 0x10 中断设置行偏移
12%dh访问 dx 寄存器高 16(16~31) 位,为0x10中断设置列偏移
13call调用 puts 函数,显示字符串
15jmp .跳转到当前(指令首)地址
23%axax 为 0x10 中断,设置文字属性
24%bxbx 为 0x10 中断,设置文字颜色
25retputs 函数返回
29.ascii定义 ascii 字符串
30len = . - str计算 str 长度(当前指令首地址-str起始地址),存入变量 len
33.org 510将下面的指令对齐到地址 510
35.byte在地址 510、511 位置填入两个字节 0x55、0xaa

2 调试运行

2.1 用 Bochs 调试运行

# 制作 cd 镜像文件 lubanix-1.0.iso
mkdir -p lubanix-1.0/boot/
mkisofs -r -q \
	-input-charset=utf-8  \
	-o lubanix-1.0.iso  \
	lubanix-1.0
# 将 mbr.bin 写进 cd 镜像文件
cp boot/mbr.bin lubanix-1.0/boot/
mkisofs -R -q \
	-input-charset=utf-8 \
	-no-emul-boot \
	-boot-load-seg 0x7c00 \
	-b boot/mbr.bin \
	-c boot/mbr.catalog \
	-o lubanix-1.0.iso  \
	lubanix-1.0
# 启动 bochs
bochs -q \
	-rc bochs/bochs_debug \
	-f bochs/bochsrc_cd

bochs 选项

  • -rc 指定调试脚本
    写入 bochs 自定义 debug 命令
    b 0x7c00:0 断点在 mbr 程序入口
  • -f  指定 bochs 启动配置
    boot: cdrom 指定光驱引导

2.2 用 QEMU 运行

# 链接 mbr.o 为 qemu 准备 mbr.bin.qemu 程序
ld -e main \
	--oformat=binary \
	-o boot/mbr.bin.qemu \
	boot/mbr.o \
	--Ttext=0x7c00
# 使用 qemu 运行 mbr.bin.qemu 程序
/usr/bin/qemu-system-x86_64 \
	boot/mbr.bin.qemu \
	-S -s

qemu 选项

  • -s / -gdb tcp::1234
    启用 gdb 调试功能
  • -S 虚拟机启动后挂起
    等待 qemu-monitor 或 gdb 的 continue 命令

2.3 用 gdb 调试

# 用 gdb 连接 qemu 调试 mbr.bin.qemu 程序
gdb boot/mbr.bin.qemu \
    -ex "target remote:1234" \
    -ex "b *0x7c00" \
    -ex "c" \
    -ex "layout asm"

  在 qemu 虚拟环境下,可以很方便的用 gdb 对操作系统程序进行调试,节约了 monitor 调试命令的学习成本,这很符合 gnu 精神。作为后端程序员的神器,gdb 值得拥有单独的篇幅,来展示其对服务器程序的调试和干预能力。

参考

写在最后

感谢大家评论、转发、点赞、收藏
欢迎质疑、批评、斧正
一起辩论,追求卓越

作者主页:http://blog.csdn.net/word_world

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

游戏AI开发者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值