交流
商城
MCN
登入
注册
首页
提问
分享
讨论
建议
公告
动态
发表新帖
发表新帖
10 读取fat32 格式下的文件
分享
未结
0
2732
李延
LV6
2022-06-30
悬赏:20积分
# 1 目标 之前我们代码都是只有一个bootsect 文件, 而且有一下的问题 - 最大只有512字节。 - 每次修改都需要通过工具写入到硬盘。 前面我们已经学会了fat32文件格式与读取磁盘的逻辑。 那么我们完全就可以通过bootsect去加载我们虚拟硬盘里的某个文件去执行。 这样我们bootsect 代码就可以固定为加载文件,其他逻辑都可以完全交给文件里的代码执行,这样就不需要每次都都bootsect文件进行修改,我们代码改动只需要替换磁盘内的文件即可,方便我们之前操作。 所以之后我们bootsect的目标就可以修改为: - 读取硬盘第一个分区根目录下的 init_os 文件。 - 执行init_os文件 # 2 准备工作 与第一章相同,我们创建一个虚拟硬盘,并初始化为fat32格式   这样我们就可以在我的电脑里直接看到我们刚创建的磁盘,之后我就可以把文件丢进来。 这里我们使用在第7章,页面打印时的代码。 ```asm .code16 .global _start .equ GRAPHICS_INDEX, 0x3d4 # original address of boot-sector .equ GRAPHICS_READ, 0x3d5 # original address of boot-sector _start: movw $msg1,%bx .print_loop: ## 传输打印的字符 movw (%bx),%cx call put_char inc %bx ## 当字符位\0的时候跳出循环 cmp $0,(%bx) jne .print_loop load_cursor: pushw %bx pushw %dx movw $GRAPHICS_INDEX,%dx movb $0x0e,%al out %al,%dx movw $GRAPHICS_READ,%dx in %dx,%al mov %al,%ah movw $GRAPHICS_INDEX,%dx movb $0x0f,%al out %al,%dx movw $GRAPHICS_READ,%dx in %dx,%al popw %dx popw %bx ret set_cursor: pushw %ax pushw %bx pushw %dx movw %ax,%bx movw $GRAPHICS_INDEX,%dx movb $0x0e,%al out %al,%dx movw $GRAPHICS_READ,%dx movb %bh,%al out %al,%dx mov %al,%ah movw $GRAPHICS_INDEX,%dx movb $0x0f,%al out %al,%dx movw $GRAPHICS_READ,%dx movb %bl,%al out %al,%dx popw %dx popw %bx popw %ax ret # 打印一个字符 # ax 光标位置 , cl 需要打印的字符 put_char: pushw %ax pushw %bp pushw %es call load_cursor movw %ax,%bp movw $0xb800,%ax movw %ax,%es shl $1,%bp movb %cl,%es:(%bp) shr $1,%bp inc %bp movw %bp,%ax call set_cursor popw %es popw %bp popw %ax ret msg1: .string "hello word!!!!!!!!!!!\0" ``` 我们将它重命名为ini_os.s并将它编译 ```shell as --32 -o init_os.o init_os.s ld -m elf_i386 -o init_os init_os.o objcopy -R .pdr -R .comment -R.note -S -O binary init_os ``` 这样我们就得到了ini_os 文件。然后我们将它放到我们刚准备好的硬盘中  下面我们就进行编写bootsect 程序,加载并执行这个init_os文件,如果成功,我们就可以在屏幕上看到hello word!!!!!!!!!!! 打印 # 3 代码 ```asm .code16 .global _start .equ BOOTSEG, 0x07c0 # original address of boot-sector .equ INIT_OS, 0x0900 # init_os程序加载到0x09000内存处 _start: mov $BOOTSEG,%ax mov %ax,%ds mov $INIT_OS,%ax mov %ax,%ss mov %ax,%es mov $0x9000,%sp #堆栈在 0x9000处 # 找到mbr分区的第一个分区所在的扇区号 movw %ds:(0x1c6),%si movw %ds:(0x1c8),%di mov $0x0,%bx # 读到9000+00处内存 mov $1,%ax # 读取1个扇区 call read_hard_disk # 找到文件分配表位置 # 文件分配表位置 = 隐藏扇区+保留扇区数 movzwl %es:(0x0e),%eax movl %es:(0x1c),%ebx addl %eax,%ebx push %ebx #将分配表先保存起来 # 找到根目录位置 movl %es:(0x24),%eax movzbl %es:(0x10),%ecx imul %ecx,%eax addl %eax,%ebx push %ebx #将分配表先保存起来 # 读取根目录 movl %ebx,%esi movl %ebx,%edi # 将16-32为的地址移到di上 movl $0,%ebx shr $16,%edi mov $1,%ax call read_hard_disk # 以32个字节为单位,找到init_os movw $0,%ax # 记录第几个目录 .file_loop: movw %ax,%si imul $32 ,%si # 乘以32,获取到当前文件描述符字节位置 movw $INIT_OS_FIlE_NAME, %di # 文件名 # 对比 bx 与cx movw $0,%dx #记录每个字符与文件名字符相等的字符 movw $7,%cx # init_os的长度 .file_name_loop: push %ax push %cx movw %si,%bx movb %es:(%bx),%cl movw %di,%bx movb %ds:(%bx),%al cmp %cl,%al pop %cx pop %ax je .file_name_eq jmp .file_name_to_loop .file_name_eq: inc %dx .file_name_to_loop: inc %si inc %di loop .file_name_loop cmp $7,%dx # 如果7个字都相等,跳转到.file_loop_ok je .file_loop_ok inc %ax #否则就查询下一个文件名 jmp .file_loop # 找到文件,%ax 就是这个文件的索引 .file_loop_ok: imul $32 ,%ax movw %ax,%bx movl %es:0x1c(%bx),%edx #文件大小 movzbl %es:0x1a(%bx),%ecx #第一个簇 # 计算在哪个扇区 subl $2,%ecx imul $8,%ecx pop %ebx # 取出根目录位置 add %ebx,%ecx # 假设文件大小只有一个簇 movl %ecx,%esi movl %ecx,%edi # 将16-32为的地址移到di上 movl $0,%ebx shr $16,%edi mov $8,%ax call read_hard_disk # 将init_os 加载到0x9000 处,之后跳转到那里执行。 mov $INIT_OS,%ax mov %ax,%ss mov %ax,%es mov %ax,%ds ljmp $INIT_OS, $0 # si 读取扇区 第 16位 # di 读取扇区 高 16u 0位 # bx,es 存放的内存地址: %es:(%bx) # ax 读取扇区大小 read_hard_disk: push %bx push %cx push %dx push %si push %ax movw $0x1f2 ,%dx out %al,%dx inc %dx movw %si,%ax out %al,%dx inc %dx movb %ah,%al out %al,%dx inc %dx movw %di,%ax out %al,%dx inc %dx movb $0xe0,%al #LBA28模式,主盘 or %ah,%al #LBA地址27~24 out %al,%dx inc %dx movb $0x20,%al # 读命令 out %al,%dx .waits: in %dx,%al and $0x88,%al cmp $0x08,%al jnz .waits pop %ax mov $256,%ecx imul %ax,%cx mov $0x01f0,%dx push %ax .readw: in %dx,%ax movw %ax,%es:(%bx) add $2,%bx loop .readw pop %ax pop %si pop %dx pop %cx pop %bx ret INIT_OS_FIlE_NAME: .string "INIT_OS" .org 400 ```
回帖
消灭零回复
提交回复
热议榜
java 相关知识分享
8
好的程序员与不好的程序员
6
写给工程师的十条精进原则
5
spring boot以jar包运行配置的logback日志文件没生成
5
一步一步分析SpringBoot启动源码(一)
5
MockMvc测试
5
【吐槽向】是不是有个吐槽的板块比较好玩
4
logstash jdbc同步mysql多表数据到elasticsearch
3
IntelliJ IDEA 优质License Server
3
.gitignore忽略规则
3
SpringBoot启动源码分析
3
一步一步分析SpringBoot启动源码(三)
3
2
一步一步分析SpringBoot启动源码(二)
2
积分不够将无法发表新帖
2
官方产品
Meta-Boot - 基于MCN
MCN - 快速构建SpringBoot应用
微信扫码关注公众号