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

MyOS第三天——进入32位模式并导入C语言

MyOS 进入32位模式并导入C语言

在ubuntu下编译第三天的代码

修改Makefile

  1. 重新定义工具和参数
# 定义工具和参数
# Ubuntu下使用系统自带的工具,无需再指定z_tools路径
MAKE     = make
NASM     = nasm
GCC      = gcc
LD       = ld
OBJCOPY  = objcopy
QEMU     = qemu-system-i386
RM       = rm -f
CP       = cp# GCC编译选项:
# -m32: 生成32位代码 (Haribote运行在32位保护模式)
# -nostdlib: 不使用标准库 (我们是在写操作系统内核)
# -fno-pie: 关闭位置无关可执行文件 (内核需要固定地址)
# -I. : 头文件路径
CFLAGS   = -m32 -nostdlib -fno-pie -I. -Os -Wall -Wextra# 链接选项:
# -m elf_i386: 指定生成32位的 elf 格式 (配合 -m32 使用)
# -Ttext 0xc200: 将代码段起始地址指定为0xc200,对应haribote的bootpack装载地址
LDFLAGS  = -m elf_i386 -Ttext 0xc200# 默认动作
default :$(MAKE) img# 1. 编译IPL (启动区)
ipl10.bin : ipl10.nas$(NASM) ipl10.nas -o ipl10.bin -l ipl10.lst# 2. 编译汇编启动头 (asmhead)
asmhead.bin : asmhead.nas$(NASM) asmhead.nas -o asmhead.bin -l asmhead.lst# 3. 编译C语言内核文件 (bootpack)
#   将 .c 文件直接编译为 32位 的 .o 对象文件
bootpack.o : bootpack.c Makefile$(GCC) $(CFLAGS) -c bootpack.c -o bootpack.o# 4. 编译汇编函数文件
naskfunc.o : naskfunc.nas Makefile$(NASM) -f elf32 naskfunc.nas -o naskfunc.o -l naskfunc.lst# 5. 链接生成内核二进制文件
#   链接所有 .o 文件,并输出为 elf 格式,再用 objcopy 转为纯二进制
bootpack.bin : bootpack.o naskfunc.o Makefile$(LD) $(LDFLAGS) bootpack.o naskfunc.o -o bootpack.elf$(OBJCOPY) -O binary bootpack.elf bootpack.bin# 6. 合并启动头与内核,生成最终系统文件
haribote.sys : asmhead.bin bootpack.bincat asmhead.bin bootpack.bin > haribote.sys# 7. 制作磁盘镜像 (使用dd命令创建软盘镜像并写入文件)
haribote.img : ipl10.bin haribote.sys# 创建一个空的1440KB软盘镜像dd if=/dev/zero of=haribote.img bs=512 count=2880 2>/dev/null# 将ipl10.bin写入第一个扇区dd if=ipl10.bin of=haribote.img bs=512 count=1 conv=notrunc 2>/dev/null# 拷贝系统文件到镜像中 (这里借助mcopy工具,如果没有请先安装: sudo apt install mtools)# 或者你也可以利用后续的run指令直接通过QEMU挂载文件夹,不一定要打包进imgmcopy -i haribote.img haribote.sys ::# 8. 运行 (通过QEMU直接启动)
run : haribote.sys$(QEMU) -drive file=haribote.sys,format=raw,if=floppy -boot a# 9. 完整制作镜像
img :$(MAKE) haribote.img# 10. 清理临时文件
clean :$(RM) *.bin *.lst *.o *.elf *.sys *.img# 11. 彻底清理(包括镜像)
src_only :$(MAKE) clean$(RM) haribote.img

修改nas文件

  1. 修改 RESB 关键字
; ipl10.nas
; haribote-ipl
; TAB=4CYLS	EQU		10				; 声明CYLS=10ORG		0x7c00			; 指明程序装载地址; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy codeJMP		entryDB		0x90DB		"HARIBOTE"		; 启动扇区名称(8字节)DW		512				; 每个扇区(sector)大小(必须512字节)DB		1				; 簇(cluster)大小(必须为1个扇区)DW		1				; FAT起始位置(一般为第一个扇区)DB		2				; FAT个数(必须为2)DW		224				; 根目录大小(一般为224项)DW		2880			; 该磁盘大小(必须为2880扇区1440*1024/512)DB		0xf0			; 磁盘类型(必须为0xf0)DW		9				; FAT的长度(必??9扇区)DW		18				; 一个磁道(track)有几个扇区(必须为18)DW		2				; 磁头数(必??2)DD		0				; 不使用分区,必须是0DD		2880			; 重写一次磁盘大小DB		0,0,0x29		; 意义不明(固定)DD		0xffffffff		; (可能是)卷标号码DB		"HARIBOTEOS "	; 磁盘的名称(必须为11字?,不足填空格)DB		"FAT12   "		; 磁盘格式名称(必??8字?,不足填空格)RESB	18				; 先空出18字节; 程序主体entry:MOV		AX,0			; 初始化寄存器MOV		SS,AXMOV		SP,0x7c00MOV		DS,AX; 读取磁盘MOV		AX,0x0820MOV		ES,AXMOV		CH,0			; 柱面0MOV		DH,0			; 磁头0MOV		CL,2			; 扇区2readloop:MOV		SI,0			; 记录失败次数寄存器retry:MOV		AH,0x02			; AH=0x02 : 读入磁盘MOV		AL,1			; 1个扇区MOV		BX,0MOV		DL,0x00			; A驱动器INT		0x13			; 调用磁盘BIOSJNC		next			; 没出错则跳转到finADD		SI,1			; 往SI加1CMP		SI,5			; 比较SI与5JAE		error			; SI >= 5 跳转到errorMOV		AH,0x00MOV		DL,0x00			; A驱动器INT		0x13			; 重置驱动器JMP		retry
next:MOV		AX,ES			; 把内存地址后移0x200(512/16十六进制转换)ADD		AX,0x0020MOV		ES,AX			; ADD ES,0x020因为没有ADD ES,只能通过AX进行ADD		CL,1			; 往CL里面加1CMP		CL,18			; 比较CL与18JBE		readloop		; CL <= 18 跳转到readloopMOV		CL,1ADD		DH,1CMP		DH,2JB		readloop		; DH < 2 跳转到readloopMOV		DH,0ADD		CH,1CMP		CH,CYLSJB		readloop		; CH < CYLS 跳转到readloop; 读取完毕,跳转到haribote.sys执行!MOV		[0x0ff0],CH		; IPLがどこまで読んだのかをメモJMP		0xc200error:MOV		SI,msgputloop:MOV		AL,[SI]ADD		SI,1			; 给SI加1CMP		AL,0JE		finMOV		AH,0x0e			; 显示一个文字MOV		BX,15			; 指定字符颜色INT		0x10			; 调用显卡BIOSJMP		putloopfin:HLT						; 让CPU停止,等待指令JMP		fin				; 无限循环msg:DB		0x0a, 0x0a		; 换行两次DB		"load error"DB		0x0a			; 换行DB		0;		RESB	0x7dfe-$		; 填写0x00直到0x001fetimes 0x1fe-($-$$) db 0DB		0x55, 0xaa
  1. 修改 asmhead.nas 文件
; haribote-os boot asm
; TAB=4BOTPAK	EQU		0x00280000		; 加载bootpack
DSKCAC	EQU		0x00100000		; 磁盘缓存的位置
DSKCAC0	EQU		0x00008000		; 磁盘缓存的位置(实模式); BOOT_INFO相关
CYLS	EQU		0x0ff0			; 引导扇区设置
LEDS	EQU		0x0ff1
VMODE	EQU		0x0ff2			; 关于颜色的信息
SCRNX	EQU		0x0ff4			; 分辨率X
SCRNY	EQU		0x0ff6			; 分辨率Y
VRAM	EQU		0x0ff8			; 图像缓冲区的起始地址ORG		0xc200			;  这个的程序要被装载的内存地址; 画面モードを設定MOV		AL,0x13			; VGA显卡,320x200x8bitMOV		AH,0x00INT		0x10MOV		BYTE [VMODE],8	; 屏幕的模式(参考C语言的引用)MOV		WORD [SCRNX],320MOV		WORD [SCRNY],200MOV		DWORD [VRAM],0x000a0000; 通过BIOS获取指示灯状态MOV		AH,0x02INT		0x16 			; keyboard BIOSMOV		[LEDS],AL; 防止PIC接受所有中断
;	AT兼容机的规范、PIC初始化
;	然后之前在CLI不做任何事就挂起
;	PIC在同意后初始化MOV		AL,0xffOUT		0x21,ALNOP						; 不断执行OUT指令OUT		0xa1,ALCLI						; 进一步中断CPU; 让CPU支持1M以上内存、设置A20GATECALL	waitkbdoutMOV		AL,0xd1OUT		0x64,ALCALL	waitkbdoutMOV		AL,0xdf			; enable A20OUT		0x60,ALCALL	waitkbdout; 保护模式转换;[INSTRSET "i486p"]				; 说明使用486指令LGDT	[GDTR0]			; 设置临时GDTMOV		EAX,CR0AND		EAX,0x7fffffff	; 使用bit31(禁用分页)OR		EAX,0x00000001	; bit0到1转换(保护模式过渡)MOV		CR0,EAXJMP		pipelineflush
pipelineflush:MOV		AX,1*8			;  写32bit的段MOV		DS,AXMOV		ES,AXMOV		FS,AXMOV		GS,AXMOV		SS,AX; bootpack传递MOV		ESI,bootpack	; 源MOV		EDI,BOTPAK		; 目标MOV		ECX,512*1024/4CALL	memcpy; 传输磁盘数据; 从引导区开始MOV		ESI,0x7c00		; 源MOV		EDI,DSKCAC		; 目标MOV		ECX,512/4CALL	memcpy; 剩余的全部MOV		ESI,DSKCAC0+512	; 源MOV		EDI,DSKCAC+512	; 目标MOV		ECX,0MOV		CL,BYTE [CYLS]IMUL	ECX,512*18*2/4	; 除以4得到字节数SUB		ECX,512/4		; IPL偏移量CALL	memcpy; 由于还需要asmhead才能完成
; 完成其余的bootpack任务; bootpack启动MOV		EBX,BOTPAKMOV		ECX,[EBX+16]ADD		ECX,3			; ECX += 3;SHR		ECX,2			; ECX /= 4;JZ		skip			; 传输完成MOV		ESI,[EBX+20]	; 源ADD		ESI,EBXMOV		EDI,[EBX+12]	; 目标CALL	memcpy
skip:MOV		ESP,[EBX+12]	; 堆栈的初始化JMP		DWORD 2*8:0x0000001bwaitkbdout:IN		 AL,0x64AND		 AL,0x02JNZ		waitkbdout		; AND结果不为0跳转到waitkbdoutRETmemcpy:MOV		EAX,[ESI]ADD		ESI,4MOV		[EDI],EAXADD		EDI,4SUB		ECX,1JNZ		memcpy			; 运算结果不为0跳转到memcpyRET
; memcpy地址前缀大小ALIGNB	16
GDT0:
;		RESB	8				; 初始值times 8 db 0DW		0xffff,0x0000,0x9200,0x00cf	; 写32bit位段寄存器DW		0xffff,0x0000,0x9a28,0x0047	; 可执行的文件的32bit寄存器(bootpack用)DW		0
GDTR0:DW		8*3-1DD		GDT0align	16
bootpack:
  1. 修改nasfunc.nas文件
; [FORMAT "WCOFF"]		; ← 删除或注释掉,nasm不需要
; [BITS 32]			; ← 这个可以保留,但nasm会通过命令行参数指定
[BITS 32]				; 制作32位模式用的机器语言; 制作目标文件的信息
; [FILE "naskfunc.nas"]	; ← 删除或注释掉,nasm不需要GLOBAL	_io_hlt		; 程序中包含的函数名; 以下是实际的函数实现
_io_hlt:	; void io_hlt(void);HLTRET

nasm支持以上内容,无需特意声明

详解 ipl.nas 文件

; haribote-ipl
; TAB=4CYLS	EQU		10				; 声明CYLS=10ORG		0x7c00			; 指明程序装载地址; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy codeJMP		entryDB		0x90DB		"HARIBOTE"		; 启动扇区名称(8字节)DW		512				; 每个扇区(sector)大小(必须512字节)DB		1				; 簇(cluster)大小(必须为1个扇区)DW		1				; FAT起始位置(一般为第一个扇区)DB		2				; FAT个数(必须为2)DW		224				; 根目录大小(一般为224项)DW		2880			; 该磁盘大小(必须为2880扇区1440*1024/512)DB		0xf0			; 磁盘类型(必须为0xf0)DW		9				; FAT的长度(必??9扇区)DW		18				; 一个磁道(track)有几个扇区(必须为18)DW		2				; 磁头数(必??2)DD		0				; 不使用分区,必须是0DD		2880			; 重写一次磁盘大小DB		0,0,0x29		; 意义不明(固定)DD		0xffffffff		; (可能是)卷标号码DB		"HARIBOTEOS "	; 磁盘的名称(必须为11字?,不足填空格)DB		"FAT12   "		; 磁盘格式名称(必??8字?,不足填空格)RESB	18				; 先空出18字节; 程序主体entry:MOV		AX,0			; 初始化寄存器MOV		SS,AXMOV		SP,0x7c00MOV		DS,AX; 读取磁盘MOV		AX,0x0820MOV		ES,AXMOV		CH,0			; 柱面0MOV		DH,0			; 磁头0MOV		CL,2			; 扇区2readloop:MOV		SI,0			; 记录失败次数寄存器retry:MOV		AH,0x02			; AH=0x02 : 读入磁盘MOV		AL,1			; 1个扇区MOV		BX,0MOV		DL,0x00			; A驱动器INT		0x13			; 调用磁盘BIOSJNC		next			; 没出错则跳转到finADD		SI,1			; 往SI加1CMP		SI,5			; 比较SI与5JAE		error			; SI >= 5 跳转到errorMOV		AH,0x00MOV		DL,0x00			; A驱动器INT		0x13			; 重置驱动器JMP		retry
next:MOV		AX,ES			; 把内存地址后移0x200(512/16十六进制转换)ADD		AX,0x0020MOV		ES,AX			; ADD ES,0x020因为没有ADD ES,只能通过AX进行ADD		CL,1			; 往CL里面加1CMP		CL,18			; 比较CL与18JBE		readloop		; CL <= 18 跳转到readloopMOV		CL,1ADD		DH,1CMP		DH,2JB		readloop		; DH < 2 跳转到readloopMOV		DH,0ADD		CH,1CMP		CH,CYLSJB		readloop		; CH < CYLS 跳转到readloop; 读取完毕,跳转到haribote.sys执行!MOV		[0x0ff0],CH		; IPLがどこまで読んだのかをメモJMP		0xc200error:MOV		SI,msgputloop:MOV		AL,[SI]ADD		SI,1			; 给SI加1CMP		AL,0JE		finMOV		AH,0x0e			; 显示一个文字MOV		BX,15			; 指定字符颜色INT		0x10			; 调用显卡BIOSJMP		putloopfin:HLT						; 让CPU停止,等待指令JMP		fin				; 无限循环msg:DB		0x0a, 0x0a		; 换行两次DB		"load error"DB		0x0a			; 换行DB		0;		RESB	0x7dfe-$		; 填写0x00直到0x001fetimes 0x1fe-($-$$) db 0DB		0x55, 0xaa
http://www.jsqmd.com/news/899194/

相关文章:

  • Agent 框架最全解析与实战攻略:LangChain / LangGraph、AutoGen、CrewAI... 到底怎么选?
  • AI提示工程:开发者从编码到问题解决的核心能力跃迁
  • 别再手动改简历了!用这6个可验证、可复现、可审计的ChatGPT优化SOP,拿下2024秋招首批Offer(附Prompt审计日志模板)
  • 湖南家庭聚餐餐馆怎么选,有哪些通用的选型标准? - 资讯纵览
  • 【技术应用】邻近连接技术PLA应用实例介绍—第Ⅱ期:蛋白-RNA
  • 天龙八部单机版GM工具终极指南:免费开源的游戏数据管理神器
  • 找设计师花了几千?Coze工作流免费生成电商详情页,3分钟搞定老板再也不催
  • 为什么你记不住自己问过什么?:ChatGPT会话记忆衰减曲线揭示——必须在第7次交互前部署习惯锚点
  • 免费解锁AMD Ryzen隐藏性能:终极硬件调试工具完全指南
  • 一文讲透 RAG:概念、原理、架构、最佳实践全解析
  • 基于FRM的高效信道化接收器设计:窄过渡带与FPGA资源优化
  • 不止甘特图!6个项目管理核心工具,搞定进度、分工与风险管控
  • OpenAI 兼容客户端通用教程:API 地址、密钥与模型名
  • CVPR2021坐标注意力机制:从SE、CBAM到CA的源码演进与实战解析
  • 人机协同进化:从指令执行到互补共创的三种模式与实战
  • 2026年最实用的录音转文字软件!8款主流语音转文字工具深度评测
  • 2026年三亚汽车贴膜合规资质横向深度测评:4家官方授权门店实测对比 - GrowthUME
  • 为ClaudeCode配置Taotoken密钥解决封号与额度焦虑指南
  • 5 分钟快速理解 RAG
  • 别再死记硬背模型了!一张图带你分清P中位、P中心和覆盖问题,附Python代码对比
  • 从实验到实战:基于模糊推理的智能洗衣机控制系统设计与Python/Matlab实现
  • 2026年RAG架构演进:从混合搜索到智能体流程的生产级实践
  • DataAgent实战指南:从架构设计到工程实现,小白也能轻松掌握大模型落地(收藏版)
  • Windows风扇控制终极指南:用FanControl实现完美静音与散热平衡
  • 第5课:变量名与赋值
  • 揭开DDR引脚的神秘面纱:原理图背后的硬件逻辑
  • 40VOUT,3A,XZ5129,升压LED恒流驱动芯片
  • 阿贝云免费云服务器实测
  • 今日算法(带回文问题的回溯)
  • 戴森球计划8000+工厂蓝图终极指南:快速打造高效星际帝国