《30天自制操作系统》第二天

79 / 100 SEO Score

汇编语言学习与Makefile入门

这一章的内容如章节标题所示,纯粹对汇编语言以及Makefile基本语法的入门。没有太多关于操作系统方面的知识。学过汇编后直接看代码即可。

接下来要用文本编辑器进行开发。

这里推荐个文本编辑器:Notepad++

继续昨天的内容开发。


汇编语言入门

把 \30天自制操作系统\projects\02_day\helloos3目录复制到 30天自制操作系统\tolset中

源码

; hello-os
; TAB=4

        ORG       0x7c00          ; 指名启动区的装载地址,不能随便指定其他位置

; 以下代码为启动区

; 以下段落为标准FAT12格式软盘专用代码

        JMP       entry
        DB        0x90            ; 此处没有上一节中的0xeb, 0x4e
        DB        "HELLOIPL"      ; 启动区名称,可取任意字符串(8字节)
        DW        512             ; 每个扇区的大小(必须为512字节)
        DB        1               ; 簇大小,(必需为1个扇区)
        DW        1               ; FAT的起始位置(一般是从第一个扇区开始)
        DB        2               ; FAT的个数(必须为2)
        DW        224             ; 根目录大小,(一般设置为224项)
        DW        2880            ; 该硬盘大小(必须为2880扇区)
        DB        0xf0            ; 硬盘种类(必须是0xf0)
        DW        9               ; FAT长度(必须是9个扇区)
        DW        18              ; 1个磁道有几个扇区(必须是18个)
        DW        2               ; 磁头数(软盘必须是2个)
        DD        0               ; 不使用分区,此处为0
        DD        2880            ; 重写一次,硬盘大小
        DB        0,0,0x29        ; 不知道是干什么的,但必要写
        DD        0xffffffff      ; 可能是卷标号码
        DB        "HELLO-OS   "   ; 硬盘名称(11字节)
        DB        "FAT12   "      ; 硬盘文件系统名称(8字节)
        RESB      18              ; 空出18字节

; 程序主体

entry:
        MOV        AX,0            ; 初始化寄存器
        MOV        SS,AX
        MOV        SP,0x7c00
        MOV        DS,AX
        MOV        ES,AX

        MOV        SI,msg          ; 把msg的地址赋值给SI
putloop:
        MOV        AL,[SI]         ; 把SI中地址所指的内存单元中的值赋值给AL
        ADD        SI,1            ; SI的内容+1
        CMP        AL,0            ; AL和0比较
        JE         fin             ; AL等于0时跳转fin
        MOV        AH,0x0e         ; 显示一个文字
        MOV        BX,15           ; 指定字符颜色
        INT        0x10            ; 调用BIOS中的显卡中断
        JMP        putloop         ; 无条件跳转putloop
fin:
        HLT                        ; 让CPU待机,等待指令
        JMP        fin             ; 循环

;到DB 0x55, 0xaa为止,以下代码是要在屏幕上显示的内容。
msg:
        DB        0x0a, 0x0a       ; 2个换行
        DB        "hello, world"
        DB        0x0a             ; 换行
        DB        0

        RESB      0x7dfe-$         ; 当前到0x1fe地址的位置全部填0

        DB        0x55, 0xaa       ; 启动区末尾标识,必须是0x55, 0xaa

; 启动区结束

; 以下是程序以外的输出部分

        DB        0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
        RESB      4600
        DB        0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
        RESB      1469432

8个16位寄存器

  • AX——accumulator,累加寄存器
  • CX——counter,计数寄存器
  • DX——data,数据寄存器
  • BX——base,基址寄存器
  • SP——stack pointer,栈指针寄存器
  • BP——base pointer,基址指针寄存器
  • SI——source index,源变址寄存器
  • DI——destination index,目的变址寄存器

8个8位急寄存器,实际上就是把AX、CX、DX、BX这4个16位寄存器拆成8个8位寄存器。

  • AL——累加寄存器低位(accumulator low)
  • CL——计数寄存器低位(counter low)
  • DL——数据寄存器低位(data low)
  • BL——基址寄存器低位(base low)
  • AH——累加寄存器高位(accumulator high)
  • CH——计数寄存器高位(counter high)
  • DH——数据寄存器高位(data high)
  • BH——基址寄存器高位(base high)

6个16位段寄存器

  • ES——附加段寄存器(extra segment)
  • CS——代码段寄存器(code segment)
  • SS——栈段寄存器(stack segment)
  • DS——数据段寄存器(data segment)
  • FS——没有名称(segment part 2)
  • GS——没有名称(segment part 3)

汇编命令:

  • ORG 指名程序装载到内存中的哪个地址,此时$的含义也变了,变成了内存单元的开始地址
  • JMP 跳转指令,JMP entry指的是跳转到entry标签执行程序
  • ADD 加法指令ADD SI,1 即SI中的值+1
  • CMP 比较指令 CMP AL,0 即AL中的值和0比较
  • JE 条件跳转指令中之一,要和CMP连用,如果比较结果相等,则跳转到指定的地址
  • INT 软件中断指令,后接调用的中断指令
  • HLT 让CPU进入待机状态
  • MOV 基本传送指令MOV AX,0相当于把0送入AX寄存器,MOV SS,AX把AX中的内容送到SS中

MOV指令简单介绍

  • MOV AX,0 相当于把0送入AX寄存器
  • MOV SS,AX 把AX中的值送到SS中
  • MOV AL,[SI] 把SI中的值作为地址,把地址所指的内存单元中的值送到SS中(寄存器间接寻址)

汇编中源操作数和目的操作数位数必须相同,所以MOV中有了BYTE、WORD、DWORD等汇编保留字。BX为16位寄存器,AL为8位寄存器,故无法直接MOV BX, AL。

  • MOV AL, BYTE [BX] 把BX中的值作为地址,送到AL中(寄存器间接寻址)
  • MOV BYTE [678],123 把123送入内存678号单元中,BYTE表示8位
  • MOV WORD [678],123 把123送入内存678号单元中,WORD表示16位,所以678和679号单元都需要用上

BIOS中断介绍

原书中的网址已经打不开了,这里给一个新网址

BIOS中断调用介绍相关的网站,根据其中介绍的中段值和寄存器值来进行BIOS调用

https://wiki.osdev.org/BIOS

https://www.ctyme.com/intr/int.htm

https://www.ctyme.com/intr/int.htm为例

打开网站,随便选择一个值

此处选择10,之后便进入到INT 0x10的中段说明界面,里面包含了需要设置的寄存器的值。以及所代表的功能。

选择AH=0Eh,可见以下代码为完整的BIOS中断调用,以ASCII码的形式输出AL中的值

        MOV        AH,0x0e         ; 显示一个文字
MOV BX,15 ; 指定字符颜色
INT 0x10 ; 调用BIOS中的显卡中断

完整的输出代码如下

代码中这部分为了在屏幕上打印"hello, world"
        MOV        SI,msg          ; 把msg的地址赋值给SI
putloop:
        MOV        AL,[SI]         ; 把SI中地址所指的内存单元中的值赋值给AL
        ADD        SI,1            ; SI的内容+1
        CMP        AL,0            ; AL和0比较
        JE         fin             ; AL等于0时跳转fin
        MOV        AH,0x0e         ; 显示一个文字
        MOV        BX,15           ; 指定字符颜色
        INT        0x10            ; 调用BIOS中的显卡中断
        JMP        putloop         ; 无条件跳转putloop
fin:
        HLT                        ; 让CPU待机,等待指令
        JMP        fin             ; 循环

;到DB 0x55, 0xaa为止,以下代码是要在屏幕上显示的内容。
msg:
        DB        0x0a, 0x0a       ; 2个换行
        DB        "hello, world"
        DB        0x0a             ; 换行
        DB        0

        RESB      0x7dfe-$         ; 当前到0x1fe地址的位置全部填0

        DB        0x55, 0xaa       ; 启动区末尾标识,必须是0x55, 0xaa

详细说明:此段代码把msg的地址赋值给SI——即DB 0x0a, 0x0a 中第一个0x0a在内存中的地址。MOV AL,[SI]采用寄存器间接寻址的方式,把存在内存中的0x0a存入Al中,以BIOS调用的方式显示一个换行(0x0a在ASCII码中表示换行)。之后ADD SI,1,SI中的地址指向了下一个字符——第二个0x0a在内存中的存储单元。以此循环,每循环一次便显示一个字符,直到显示到DB 0x0a为止。因为下一条指令为DB 0,所以AL中的值也为0,会执行跳转指令JE。


内存分布图

硬盘中的程序需要装载到内存中才能运行,所以程序一开始指明了整个程序的装载地址ORG 0x7c00。这个地址不能随便指定,需要符合规范,否则计算机很可能会出错。

原书给的网址依旧打不开

新的内存分布图介绍网站

https://wiki.osdev.org/Memory_Map_(x86)

startendsizedescriptiontype
Real mode address space (the first MiB)
0x000000000x000003FF1 KiBReal Mode IVT (Interrupt Vector Table)unusable in real mode640 KiB RAM (“Low memory”)
0x000004000x000004FF256 bytesBDA (BIOS data area)
0x000005000x00007BFF29.75 KiBConventional memoryusable memory
0x00007C000x00007DFF512 bytesYour OS BootSector
0x00007E000x0007FFFF480.5 KiBConventional memory
0x000800000x0009FFFF128 KiBEBDA (Extended BIOS Data Area)partially used by the EBDA
0x000A00000x000BFFFF128 KiBVideo display memoryhardware mapped384 KiB System / Reserved (“Upper Memory”)
0x000C00000x000C7FFF32 KiB (typically)Video BIOSROM and hardware mapped / Shadow RAM
0x000C80000x000EFFFF160 KiB (typically)BIOS Expansions
0x000F00000x000FFFFF64 KiBMotherboard BIOS

图中明确指出了0x00007C00——0x00007DFF为操作系统引导扇区。


制作启动区

其实就是把今天代码中DB 0x55, 0xaa ; 启动区末尾标识,必须是0x55, 0xaa之前的单独作为一个文件保存而已

把 \30天自制操作系统\projects\02_day\helloos4目录复制到 \30天自制操作系统\tolset中

源码保存为ipl.nas文件,这样启动区便制作完成。

; hello-os
; TAB=4

        ORG       0x7c00          ; 指明程序装载地址,不能随便指定其他位置

; 以下代码为启动区

; 以下段落为标准FAT12格式软盘专用代码

        JMP       entry
        DB        0x90            ; 此处没有上一节中的0xeb, 0x4e
        DB        "HELLOIPL"      ; 启动区名称,可取任意字符串(8字节)
        DW        512             ; 每个扇区的大小(必须为512字节)
        DB        1               ; 簇大小,(必需为1个扇区)
        DW        1               ; FAT的起始位置(一般是从第一个扇区开始)
        DB        2               ; FAT的个数(必须为2)
        DW        224             ; 根目录大小,(一般设置为224项)
        DW        2880            ; 该硬盘大小(必须为2880扇区)
        DB        0xf0            ; 硬盘种类(必须是0xf0)
        DW        9               ; FAT长度(必须是9个扇区)
        DW        18              ; 1个磁道有几个扇区(必须是18个)
        DW        2               ; 磁头数(必须是2个)
        DD        0               ; 不使用分区,此处为0
        DD        2880            ; 重写一次,硬盘大小
        DB        0,0,0x29        ; 不知道是干什么的,但必要写
        DD        0xffffffff      ; 可能是卷标号码
        DB        "HELLO-OS   "   ; 硬盘名称(11字节)
        DB        "FAT12   "      ; 硬盘文件系统名称(8字节)
        RESB      18              ; 空出18字节

; 程序主体

entry:
        MOV        AX,0            ; 初始化寄存器
        MOV        SS,AX
        MOV        SP,0x7c00
        MOV        DS,AX
        MOV        ES,AX

        MOV        SI,msg          ; 把msg的地址赋值给SI
putloop:
        MOV        AL,[SI]         ; 把SI中地址所指的内存单元中的值赋值给AL
        ADD        SI,1            ; SI的内容+1
        CMP        AL,0            ; AL和0比较
        JE         fin             ; AL等于0时跳转fin
        MOV        AH,0x0e         ; 显示一个文字
        MOV        BX,15           ; 指定字符颜色
        INT        0x10            ; 调用BIOS中的显卡中断
        JMP        putloop         ; 无条件跳转putloop
fin:
        HLT                        ; 让CPU待机,等待指令
        JMP        fin             ; 循环

msg:
        DB        0x0a, 0x0a       ; 2个换行
        DB        "hello, world"
        DB        0x0a             ; 换行
        DB        0

        RESB      0x7dfe-$         ; 当前到0x1fe地址的位置全部填0

        DB        0x55, 0xaa       ; 启动区末尾标识,必须是0x55, 0xaa

; 启动区结束

Makefile入门

Makefile算是linux中的某种基本操作了,没什么难的

自定义的命令: 文件1 文件2。。。
<tab>   标准命令

之后保存名为”Makefile“文件,无后缀名

新建记事本,写入以下代码

#请把文件保存在\30天自制操作系统\tolset\helloos4
#自定义命令ipl.bin
#执行后会自动查找ipl.nas、Makefile文件是否存在
#存在的话执行../z_tools/nask.exe ipl.nas ipl.bin ipl.lst命令
ipl.bin : ipl.nas Makefile
	../z_tools/nask.exe ipl.nas ipl.bin ipl.lst

helloos.img : ipl.bin Makefile
	../z_tools/edimg.exe   imgin:../z_tools/fdimg0at.tek \
		wbinimg src:ipl.bin len:512 from:0 to:0   imgout:helloos.img
#保存为Makefile

同时把\30天自制操作系统\tolset\z_new_w中的make.bat复制到\30天自制操作系统\tolset\helloos4中

cmd命令行窗口进入\30天自制操作系统\tolset\helloos4,执行命令make -r ipl.bin

之后ipl.nas便被编译成ipl.bin这一启动区文件。

\30天自制操作系统\projects\02_day\helloos5中仅仅对Makefile文件进行了优化,并添加了其他功能,有兴趣的可自行用文本编辑器查看。

之后的内容想要模拟运行需要cmd进入工作目录(\30天自制操作系统\tolset\xxxxxx),用make命令把代码编译成img文件,再执行make run命令即可。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇