1.代码
boot.asm
org 07c00h ;告诉编译器程序加载到7c00处
mov ax,cs
mov ds,ax
mov es,ax
call DispStr ;调用显示字符串例程
jmp $ ;无限循环
DispStr:
mov ax,BootMessage
mov bp,ax ;ES: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 ;结束标志
bochsrc //没有后缀,bochsrc文件和a.img以及boot.bin放在同一目录下
display_library:sdl
floppya:1_44=a.img,status=inserted
boot:floppy
2.编译连接
> nasm boot.asm -o boot.bin
> bximage
> fd
> 1.44
> a.img
> dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc
3.启动bochs
> bochs -f bochsrc
4.代码解释
org:orihin缩写,表示起始地址,源。在汇编语言源程序的开始通常都用一条ORG伪指令来实现规定程序的起始地址。如果不用ORG规定则汇编得到的目标程序将从0000H开始。
mov:数据传送指令,把源位置一个字节、字或双字的操作数复制到目的位置。可以是立即数到通用寄存器,也可以是通用寄存器和通用寄存器、主存、段寄存器之间的互相传送。
e.g mov eax,050ah; 把十六进制数050a传送到通用寄存器eax中。
call:call指令不能实现短转移,除此之外与jmp指令实现转移的原理相同。
CPU执行call指令时,进行两步操作:
1.将当前的IP或CS和IP压入栈中;
2.转移;
jmp:无条件转移指令。
$:地址计数器的值——记录正在被汇编程序翻译的语句地址。每个段均分配一个计数器,段内定义的所有标号和变量的偏移地址就是当前汇编地址计数器的值。
int 10h:显示中断,用它可以随意控制屏幕,显示字符、画图等。
ES:BP:bp是基址寻址寄存器,默认的段是堆栈段。在不是默认段的情况下,称为:段超越。段超越情况下的寻址,必须要加上段超越前缀。ES:BP就是段超越的应用事例之一。
ret:用栈中的数据修改IP值,实现近转移。不带任何参数时,用在子程序的结束位置,被调用的子程序必须有ret指令,否则调用没有ret指令的子程序会导致自陷,子程序执行完后处于完全失控状态。带参数ret n表示子程序返回主程序的同时,堆栈弹出n个字节。
db:伪指令——定义字节。其后的每个操作数占用一个字节。若是字符串, 必须用引号' '括起来,字符串不能超过 255个字符,字符串自左至右以字符的ASCII码按地址递增的顺序依次存放。
dw:伪指令——定义字。其后的每个操作数占用一个字(低字节在前,高字节在后)。DW可以给两个字符组成的字符串(用' '括起来) 分配两个字节的存储单元(前一个字符在高字节)。DW还可以把其后的变量或标号的偏移地址存入存储器的指定单元(即DW前的变量)。
times:重复汇编,在times后跟着的表达式会被重复汇编指定次数。
bximage:启动bochs创建镜像的程序。
fd:选择镜像类型为fd(floppy disk,软盘)。
1.44:选择镜像的大小。
a.img:为镜像命名。
dd:将操作系统写入软盘。
if:输入文件
of:输出设备
bs:一个扇区大小
count:扇区数
conv:不作其他处理
-------//bochsrc,配置bochs的文件。
display_library:bochs使用的GUI库,在Ubuntu下是sdl。
megs:虚拟机内存大小。
floppya:虚拟机外设,软盘为a.img文件。
boot:虚拟机启动方式,从软盘启动。
-------//关于转移
短转移(short):偏移量在[-128,127]范围内(段内转移,改变指令指针寄存器IP的值)
近转移(near):偏移量在[-32K,32K]范围内(段内转移,改变指令指针寄存器IP的值)
远转移(far):在不同的代码段之间转移(段间转移,改变指令指针寄存器IP的值和代码段寄存器CS的值)
短转移包含在近转移内,但这种包含是以浪费为代价的,短转移指令占的字节少于近转移指令。
-------//关于通用寄存器
8086有14个16位寄存器:8个通用寄存器、1个指令指针寄存器、1个标志寄存器和4个段寄存器。它们都有名称,编程时使用其名称代表其保存的内容。* AX――累加器(Accumulator),使用频度最高
* BX――基址寄存器(Base Register),常存放存储器地址
* CX――计数器(Count Register),常作为计数器
* DX――数据寄存器(Data Register),存放数据
8086的4个16位数据寄存器:AX、BX、CX、DX,都还可以分为高(H:High)、低(L:low)两个独立的8位寄存器,分别取名为AH / AL、BH / BL、CH / CL、DH / DL;对其中某8位的操作,并不影响另外对应8位的数据。
所以,我们说8086有8个通用的16位寄存器,还有8个通用的8位寄存器。
* SI――源变址寄存器(Source Index),常保存存储单元地址
* DI――目的变址寄存器(Destination Index),常保存存储单元地址
* BP――基址指针寄存器(Base Pointer),表示堆栈区域中的基地址
* SP――堆栈指针寄存器(Stack Pointer),指示堆栈区域的栈顶地址
* IP――指令指针寄存器(Instruction Pointer),指示要执行指令所在存储单元的地址。IP寄存器是一个专用寄存器。
-------//命令行
-o:指定输出文件的文件名
-f:指定输出文件格式
-d:预定义一个宏。e.g. -dF00=100 → %define F00 100