当前位置: 首页 > news >正文

001主引导扇区

一、主导扇区代码

[bits 16]mov ax,3
int 0x10mov ax,0
mov dx,ax
mov es,ax
mov ss,ax
mov sp,0x7c00mov ax,0xb800
mov ds,ax
mov byte [0],'H'jmp $times 510-($-$$) db 0
db 0x55,0xaa

这里没有使用org 0x7c00 是因为在elf

这是一个典型的 16 位实模式下的引导扇区(Boot Sector)汇编代码。它被设计成一个独立运行的程序,由 BIOS 加载到内存地址 0x7c000x7c000x7c00 处执行。

这段代码非常简洁,主要完成了 清屏、堆栈初始化屏幕输出一个字符 的功能。


💻 汇编代码逐行解析

1. 模式设定和清屏
代码汇编指令作用详解
[bits 16]伪指令设置代码为 16 位模式告诉汇编器(如 NASM),后续的代码要按照 16 位 CPU 的规则(如寄存器大小、指令长度)进行编译。
mov ax,3移动数据准备调用 BIOS 视频服务 3 号功能。AXAXAX 寄存器用于传递功能号。AHAHAH (高 8 位) 设为 0x000x000x00(视频服务)或 0x030x030x03(文本模式)。这里 AX=3AX=3AX=3 表示进入 80×2580 \times 2580×25 彩色文本模式。
int 0x10软件中断调用 BIOS 视频服务。刷新屏幕,进入指定的文本模式。这相当于执行了清屏操作。
2. 寄存器和堆栈初始化

这段代码是为了在代码执行前,清理和设置所有段寄存器以及堆栈指针,以建立一个稳定的运行环境。

代码汇编指令作用详解
mov ax,0移动数据AXAXAX 寄存器清零。
mov dx,ax移动数据DXDXDX 寄存器清零。
mov es,ax移动数据附加段寄存器(ES) 清零(ES=0ES=0ES=0)。
mov ss,ax移动数据堆栈段寄存器(SS) 清零(SS=0SS=0SS=0)。SS:SPSS:SPSS:SP 定义了堆栈的位置。如果 SS=0SS=0SS=0,则堆栈在内存的低地址区域。
mov sp,0x7c00移动数据设置 堆栈指针(SP)由于代码本身被加载到 0x7c000x7c000x7c00,将堆栈指针也设为 0x7c000x7c000x7c00 意味着堆栈从引导代码的起始处向低地址增长,防止覆盖引导代码。
3. 屏幕输出操作

这段代码使用 内存映射 I/O 的方式,直接向 PC 内存中的显存写入数据,以在屏幕上显示字符。

代码汇编指令作用详解
mov ax,0xb800移动数据彩色文本模式显存的起始地址 放入 AXAXAX0xB80000xB80000xB8000 是显存的物理起始地址。在实模式下,段寄存器要用 0xB8000xB8000xB800 来表示这个地址。
mov ds,ax移动数据数据段寄存器(DS) 设置为 0xB8000xB8000xB800之后的内存访问指令将使用 DSDSDS 寄存器作为段地址,指向显存。
mov byte [0],'H'移动数据将字符 ‘H’ 写入显存的第一个位置。DS:0DS:0DS:0(即 0xB800:00000xB800:00000xB800:0000)是屏幕左上角第一个字符的位置。写入 ‘H’ (一个字节) 会让它显示在屏幕上。注意: 完整的显存单元是 2 字节(字符 + 属性),这里只写了字符,属性字节将保持不变(可能为 0x000x000x00 或之前的残留值)。
4. 停止执行
代码汇编指令作用详解
jmp $跳转指令无限循环。$ 表示当前指令的地址。这行代码让 CPU 不断地跳转回自身,使程序停在这里,直到外部干预(如重启或关机)。这是引导扇区在完成任务后常见的停止方式。
5. 填充和签名(MBR 格式要求)
代码汇编指令作用详解
times 510-($-$$) db 0伪指令填充零字节直到第 510 字节。$$ 是文件起始地址,$ 是当前地址。($-$$) 计算了当前代码的总长度。这个指令用 0x000x000x00 填充剩余空间,确保总长度是 510 字节。
db 0x55,0xaa定义字节写入 MBR 签名。这是 主引导记录(MBR) 格式要求的 结束标志。BIOS 会检查这最后两个字节是否为 0x550x550x550xAA0xAA0xAA。如果不是,BIOS 会认为这不是一个有效的引导扇区,并拒绝加载它。

总结

这段代码是一个完整的、最小化的 16 位 MBR 引导程序,它的功能是:

  1. 初始化 AX=3AX=3AX=3 并调用 INT0x10INT 0x10INT0x10 清屏。
  2. 设置段寄存器和堆栈指针。
  3. 通过直接操作 0xB8000xB8000xB800 处的显存,在屏幕左上角显示字符 ‘H’。
  4. 进入无限循环停止执行。
  5. 0x000x000x00 填充到 510 字节,并在最后写入 0x55AA0x55AA0x55AA 签名。

二、如何调试和编写Makefile文件

打开vscode中左侧第四个的debug文件点一下,修改lanch.json文件,先别问为什么将我的文件复制进去就好了,刚开始不需要将时间浪费在配置环境上面

{"version": "0.2.0","configurations": [{"name": "Debug EcpOS (QEMU)","type": "cppdbg","request": "launch","program": "${workspaceFolder}/build/kernel.elf","cwd": "${workspaceFolder}","MIMode": "gdb","miDebuggerPath": "/usr/bin/gdb","miDebuggerServerAddress": "localhost:1234","stopAtEntry": true,"setupCommands": [{"description": "Enable pretty-printing for gdb","text": "-enable-pretty-printing","ignoreFailures": true}]}]
}

Makefile文件的编写

一般就是预处理,汇编,链接,提取纯二进制代码

# 工具链定义
NASM := nasm
GCC := gcc
LD := ld
OBJCOPY := objcopy
QEMU := qemu-system-i386# 编译选项
# 使用 -f elf32 来生成 ld 可以处理的对象文件
AFLAGS := -f elf32 -g -F dwarf
LDFLAGS := -m elf_i386 -nostdlib# 目录和源文件
BUILD_DIR := build
SRC_DIR_BOOT := boot# 源文件
STAGE1_SRC := $(SRC_DIR_BOOT)/stage1.asm# 目标文件
# 1. 对象文件 (.o)
STAGE1_OBJ := $(BUILD_DIR)/boot/stage1.o
# 2. ELF 可执行文件 (用于调试)
KERNEL_ELF := $(BUILD_DIR)/kernel.elf
# 3. 纯二进制文件 (用于镜像)
STAGE1_BIN := $(BUILD_DIR)/boot/stage1.bin
# 4. 最终磁盘镜像
IMG := ecpos.img# 伪目标
.PHONY: all clean run rebuild debug# 默认目标
all: $(IMG)# --- 编译和链接规则 ---# 汇编 stage1.asm 为对象文件 (.o)
$(STAGE1_OBJ): $(STAGE1_SRC)@echo "Assembling $< to $@..."@mkdir -p $(dir $@)$(NASM) $(AFLAGS) $< -o $@# 链接最终的 ELF 文件
# 这是 GDB 进行调试时需要加载的文件
$(KERNEL_ELF): $(STAGE1_OBJ)@echo "Linking $@..."@mkdir -p $(dir $@)$(LD) $(LDFLAGS) -Ttext 0x7c00 $^ -o $@# 从 ELF 文件中提取纯二进制代码
$(STAGE1_BIN): $(KERNEL_ELF)@echo "Extracting binary from $< to $@..."@mkdir -p $(dir $@)$(OBJCOPY) -O binary $< $@# --- 镜像和运行规则 ---# 创建最终的磁盘镜像
$(IMG): $(STAGE1_BIN)@echo "Creating disk image $(IMG)..."# 确保文件大小正好是 512 字节,并带有 MBR 签名cat $^ > $@@echo "Image created successfully: $(IMG) (`stat -c '%s' $@` bytes)"# 运行 QEMU
run: $(IMG)@echo "Booting with QEMU..."$(QEMU) -drive format=raw,file=$(IMG),if=floppy -boot order=a# 以调试模式运行 QEMU
# 注意:debug 依赖于 all,确保在调试前所有文件都已正确生成
debug: all@echo "Booting with QEMU in debug mode (waiting for GDB on localhost:1234)..."$(QEMU) -cpu 486 -s -S -drive format=raw,file=$(IMG),if=floppy -boot order=a# --- 清理规则 ---# 强制重新编译
rebuild: clean all# 清理所有生成的文件
clean:@echo "Cleaning up..."-rm -rf $(BUILD_DIR) $(IMG)

🛠️ 1. 工具链和编译选项 (Toolchain & Flags)

这部分定义了使用的工具和参数。

变量变化及作用
AFLAGS-f elf32 -g -F dwarf保持不变。告诉 NASM 生成 32 位 ELF 格式对象文件,并包含 调试信息
LDFLAGS-m elf_i386 -nostdlib移除了 -Ttext 0x7c00。现在 LDFLAGS 只负责指定链接格式和禁用标准库。
$(LD) ... -Ttext 0x7c00 $^ -o $@(见 KERNEL_ELF 规则)Ttext 地址设置被移到了 KERNEL_ELF 规则的命令行中。这样做使 LDFLAGS 更通用,将特定地址的设置留给具体的目标规则。

📦 2. 文件和目录定义 (Files & Directories)

这部分定义了构建过程中的输入、中间和输出文件,与前一个版本保持一致。

目标文件阶段格式依赖关系 (用于构建)
STAGE1_OBJ汇编阶段ELF 32-bit (.o)stage1.asm
KERNEL_ELF链接阶段ELF 32-bitstage1.o
STAGE1_BIN提取阶段Pure Binary (.bin)kernel.elf
IMG镜像阶段Raw Image (.img)stage1.bin

🏗️ 3. 编译和链接规则 (Build Rules)

这部分定义了从汇编代码到纯二进制文件的转换过程。

规则 1: 汇编 (STAGE1_OBJ)

$(STAGE1_OBJ): $(STAGE1_SRC)$(NASM) $(AFLAGS) $< -o $@
  • 使用 NASM 将汇编源码 (stage1.asm) 汇编为对象文件 (stage1.o)。

规则 2: 链接 (KERNEL_ELF) (关键变更)

$(KERNEL_ELF): $(STAGE1_OBJ)$(LD) $(LDFLAGS) -Ttext 0x7c00 $^ -o $@
  • 功能: 使用 LD 将对象文件链接成 ELF 文件。
  • 关键点: -Ttext 0x7c00 明确放在了命令行中,确保了代码段(.text)的起始虚拟地址被设定为 0x7c000x7c000x7c00,这是 BIOS 加载 MBR 引导扇区的约定地址。

规则 3: 提取纯二进制 (STAGE1_BIN)

$(STAGE1_BIN): $(KERNEL_ELF)$(OBJCOPY) -O binary $< $@
  • 使用 OBJCOPY 从包含调试信息的 ELF 文件中剥离所有元数据,得到一个 纯粹的、可直接执行的机器码文件 (stage1.bin)。

💾 4. 镜像和运行规则 (Image & Run)

这部分定义了如何打包二进制文件和在模拟器中运行。

规则 4: 创建最终镜像 ($(IMG)) (关键变更)

$(IMG): $(STAGE1_BIN)cat $^ > $@
  • 功能: 创建最终的 ecpos.img 文件。
  • 关键点: 这个规则非常简单地使用了 cat $^ > $@ (即 cat stage1.bin > ecpos.img)。
  • 与上一个版本的区别:
    • 旧版本: 使用 dd 先创建 512 字节空白文件,再用 dd 覆盖。这保证了文件大小是 恰好 512 字节
    • 新版本: 使用 cat 直接复制 stage1.bin
  • 隐含要求: 为了让这个 cat 规则能正常工作,您的 stage1.asm 源码中 必须 包含 times 510-($-$$) db 0db 0x55,0xaa 这两条伪指令,以确保 stage1.bin 自身恰好是 512 字节,并且带有正确的 MBR 签名。

规则 5/6: 运行 (run) 和调试 (debug)

  • run 使用 QEMU 正常启动镜像。
  • debug 使用 QEMU 启动,并通过 -s -Slocalhost:1234 开启 GDB 调试服务器并暂停 CPU,等待开发者连接 GDB 进行调试。

总结

这个 Makefile 建立了一个完整的引导程序开发流程:汇编 → 链接定位地址 → 剥离为纯代码 → 创建镜像 → 模拟运行/调试。

如何进行调试

在当前的文件夹中,输入make debug 在程序中打下端点,点击调试按钮
在左侧的watch中可以查看寄存器的值

输入下面指令可以查看内存值

-exec x/1c 0xb8000      # 以字符显示第一个字节,应该为 'H'
-exec x/2bx 0xb8000     # 以十六进制显示字符和属性,例: 0x48 0x07
-exec x/16bx 0xb8000    # 查看更多字节
http://www.dtcms.com/a/562233.html

相关文章:

  • PyCharm的初始设置
  • 天津 交友 网站建设网站建设流费用
  • 阜阳网站优化wordpress素锦 下载
  • 自建站怎么搭建学ui有前途吗
  • 南昌网站建设技术托管wordpress固定链接设置访问出错
  • 河南艾特网站建设果乐宝的网站建设
  • 惠州专业网站设计公司多说插件 wordpress
  • 网站建设分类方案合击版手游带月灵
  • C++世界的混沌边界:undefined_behavior
  • 【AI学习-comfyUI学习-文生图-各个部分学习-第一步】
  • 学习RT-thread(线程、线程调度方式、线程状态)
  • asp.net网站第一次运行慢成长厉程网站
  • 网站如何做攻击防护做啥英文网站赚钱
  • 云南省建设厅网站职称评审wordpress 代码行号
  • 频繁从一个网站链接到另一个网站会影响百度收录么简单的网站开发软件
  • Kubernetes 核心资源:Service 与 Pod 解析
  • 福安市网站建设广告发布平台
  • 关于Dynamics 365多选选项集在使用Contains-value时失效问题的分析与解决
  • 可以免费创建网站的软件数字化文化馆网站建设
  • 【C语言】选择结构和循环结构的进阶
  • 珠海网站建设制作青岛做网站的公司有哪些
  • 免费制作app的手机软件东莞seo建站广告费
  • ssm框架之Spring(上)
  • 【星闪】Hi2821 | USB HID设备类 + HID键盘例程
  • o2o网站建站wordpress json接口
  • 成都自助建站模板网站建设评审表
  • 边界扫描测试原理 15 -- BSDL 9 应用示例
  • 唐山专业网站建设公司阿里云虚拟主机和云服务器的区别
  • 济南旅游网站建设前程无忧网深圳网站建设类岗位
  • 查企业资质上什么网站东华软件是外包公司吗