最近在阅读linux早起内核的源码,可惜全是AT&T汇编,和以前学的大不一样,我们何不用AT&T汇编从一个HelloWorld开始实现一个小型操作系统,记得以前有本书叫<<一个操作系统的实现>>是用nasm汇编从一个HelloWorld开始实现了作者自己的操作系统。这其实是一个引导程序,因为PC机启动时ROM BIOS中的程序会把默认启动驱动器上的引导扇区代码和数据读入内存。好吧,那就从HelloWorld开始。
我们先来熟悉一下int10的13功能号,一会我们用的着
功能号:13H
功能:在Teletype模式下显示字符串
入口参数:AH=13H
BH=页码
BL=属性(若AL=00H或01H)
CX=显示字符串长度
(DH、DL)=坐标(行、列)
ES:BP=显示字符串的地址 AL= 显示输出方式
0—字符串中只含显示字符,其显示属性在BL中。显示后,光标位置不变
1—字符串中只含显示字符,其显示属性在BL中。显示后,光标位置改变
2—字符串中含显示字符和显示属性。显示后,光标位置不变
3—字符串中含显示字符和显示属性。显示后,光标位置改变
当AL=00H或01H时,BL中各位含义如下:
7 6 5 4 3 2 1 0
BL R G B I R G B
闪烁 背景 高亮 前景
下面是AT&T汇编代码的myboot.s:
.text .globl start/*程序从start处开始运行*/ .code16 start: jmpl $0x0, $code msg: .string "Hello world!" code: mov %cs,%ax mov %ax,%ds mov %ax,%es mov %ax,%ss mov $0x400,%sp call DispStr/*调用显示字符串函数*/ loop0:/*无限循环*/ jmp loop0 DispStr: mov $msg ,%ax mov %ax ,%bp/*es:bp = 串地址*/ mov $12 ,%cx/*cs = 串长度*/ mov $0x1301,%ax/*ah=13是功能号表示显示字符串 ,al=01是显示输出方式*/ mov $0x000c,%bx/*bh=0是0页,bl=0ch高亮 黑底红字*/ mov $0 ,%dl/*0行0列*/ int $0x10 ret .org 0x1fe, 0x90 .word 0xaa55
编译方法:
as -o myboot.o -a myboot.s
ld --oformat binary -N -e start -Ttext 0x7c00 -o myboot myboot.o
dd bs=512 if=myboot of=Image count=1 conv=notrunc
下面是nasm汇编代码myboot.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 ; 结束标志
nasm myboot.asm -o myboot
dd bs=512 if=myboot of=Image count=1 conv=notrunc
bochs运行效果如下: