引导扇区汇编程序-操作系统
首先先看一个简单的例子,在显示屏上输出字符串。首先一个扇区是512字节。
org 07c00h ; 告诉编译器程序加载到7c00处
mov ax, cs
mov ds, ax
mov es, ax
call DispStr ;调用显示字符串子程序
jmp $ ; 无限循环
DispStr:
mov ax, BootMessage
mov bp, ax ; 将字符串的首地址给堆栈指针bp
mov cx, 16 ; 字符串长度传给cx寄存器
mov ax, 01301h ; AH = 13, AL = 01h
mov bx, 000ch ; 页号为0(BH = 0) 黑底红字(BL = 0Ch,高亮)
mov dl, 0
int 10h ; 10h号中断
ret
BootMessage: db "Hello, OS world!"
times 510-($-$$) db 0 ; 填充剩下的空间,使生成的二进制代码恰好为512字节
dw 0xaa55 ; 结束标志
看上面这个例子,是不是还不是很清楚,我们现在详细的分析一下。
介绍一下代码中存在的寄存器:
十六位的通用寄存器:
AX――累加器(Accumulator),常用于存放算术、逻辑运算中的操作数或结果。另外,所有的I/O指令都要使用累加器与外设接口传道递数据
BX――基址寄存器(Base Register),常用来存放访问内存时的地址
CX――计数器(Count Register),常作为计数器,在循环、串操作指令中用作计数器
DX――数据寄存器(Data Register),存放数据,在寄存器间接寻址中的I/O指令中存放I/O端口的地址
当然AX、BX、CX、DX,都还可以分为高(H:High)、低(L:low)两个独立的8位寄存器,分别取名为AH / AL、BH / BL、CH / CL、DH / DL。
八位的通用寄存器:
SI――源变址寄存器(Source Index),常保存存储单元地址
DI――目的变址寄存器(Destination Index),常保存存储单元地址
BP――基址指针寄存器(Base Pointer),表示堆栈区域中的基地址
SP――堆栈指针寄存器(Stack Pointer),指示堆栈区域的栈顶地址
IP――指令指针寄存器(Instruction Pointer),指示要执行指令所在存储单元的地址。IP寄存器是一个专用寄存器。
然后我们逐句分析:
org 07c00h
org伪指令: org + 数值表达式;即org语句后的指令或数据以数值表达式给出的值作为起始的偏移地址。数值表达式必须是一个可计算得到的正整数,数值范围在0~65535之间。BIOS将相应启动设备的第一个扇区(也就是MBR扇区)读入内存地址为0000:7C00H 处。
mov ax, cs
mov ds, ax
mov es, ax
cs 为代码段寄存器,一般用于存放代码;ds 为数据段寄存器,一般用于存放数据;es 为扩展段寄存器;这一操作使cs=ds=es,令各个段,处于一个相同的 64K 存储器空间,集中在一起,便于处理代码和数据。这等于是写引导程序的初始化阶段。
call DispStr
jmp $
以调用子程序的方式操作。$被称为当前位置计数器,在汇编程序对源程序进行汇编的过程中,使用地址计数器来保证当前正在汇编的指令地址,一直在当前跳转,即在当前无限循环。
接下来看子程序:DispStr
mov ax, BootMessage
mov bp, ax
mov cx, 16
mov ax, 01301h
mov bx, 000ch
mov dl, 0
int 10h
ret
将字符串首地址给ax,然后通过ax将字符串首地址给堆栈指针bp。在汇编中,不能直接将立即数直接传给段寄存器(bp作为堆栈指针在段寄存器ss中–ss是堆栈段寄存器),而这边字符串的首地址即等于立即数。接下来将字符数传给cx(计数器寄存器)。然后就是比较难的几句了,有关于中断,暂时简单理解,从代码中看出是int 10h中断,是由BIOS对显示器和屏幕所提供的服务程序。想要详细了解10h中断的可看:int 10h中断详解
mov ax, 01301h :寄存器ax分为ah,al,在此中ah=13h,查阅可知13h表示写字符串。
以下是我查阅的:
由此可见:al=01h,表示写完字符串后,光标位置。设置好ax,然后设置bx,000ch,由此上表可见,bh=页号,此处为0。bl=0ch,bl表示属性,属性即字符的颜色、背景颜色、是否闪烁、有没有底线等性质。在彩色显示中,通常以第 0~3 位表示文字本身颜色;第 4~6 位表示背景颜色,背景颜色只有上表左栏的 8 种而已;第 7 个位,表示是否闪烁,0 表示不闪烁,1 表示闪烁。查表可知:0c表示黑底红色(实际是淡红色),然后mov dl, 0
由上表可知,dh=行号,dl=列号,所以此处字符串从第0列开始显示。最后设置好这些后,才可以调用int 10h。ret :子程序返回指令,也就是子程序返回。
BootMessage: db "Hello, OS world!"
times 510-($-$$) db 0
dw 0xaa55
最后:BootMessage:伪指令,db “Hello, OS world!”:db定义字节类型变量,一个字节数据占1个字节单元。即占16个字节单元。表示要显示的字符串。times:重复指令或数据,$$:表示一个节(一段代码)的开始处被汇编后的地址。
$-$$:经常被用到,表示本行距离程序开始处的相对距离
times 510-($-$$) db 0
就是将剩下的512剩下的空间用0填充。为什么边是510,是因为最后还有引导扇区结束符代码,占两字节。在hex可查看知中扇区结束标志为0x55aa,由于dw是低端序存放,在汇编代码中为0xaa55。dw定义字类型变量,一个字数据占2个字节单元,读完一个,偏移量加2。
最后,这篇博客我写了很久,基于对汇编语言,寄存器等的不熟,又源于老师上课讲的不够详细,所以我查看了很多博客,资料,才写了这篇博客,也供我自己学习
以下是我参考的一些资料:
汇编代码解释合集
自己动手写操作系统(一)
颜色搭配显示+BIOS功能调用表+INT 10H功能详细列表
int 10中断