--------------------------------------------------------------------------------
具体的 *** 作过程在下边的 load.c 文件注释中有比较详细的说明。
目的:写一个引导程序和一个超简单的内核,引导成功后能在键盘上输入字符并显示
工具:masm5.0编译器,tc2.0,一个电脑(如果有virtual pc的话更可以,在上面做实验不损机子)。
所需知识:
我简单地说说电脑开机的过程吧,电脑开机后经过很复杂的过程,包括什么自检呀,bios驻入内存呀.... 最后bios把引导盘的0磁道1扇区的512字节放入内存0000:7c00开始的地方,然后把控制权交给引导程序,那一瞬间CS=0000,IP=7c00.(我想应该是这样),然后一切就可以进入你的掌握之中了。
我们现在用汇编要写的就是7c00之后的程序,把这个程序放在第一个扇区,叫做boot,这个程序的作用是把放在第二个扇区的kernel调入内存8000:0000处并跳到那里执行。
文件:boot.asm
file:boot.asm
load.exe 程序将下边代码生成的二进制文件写入A盘
的0磁道1扇区
开机时BIOS引导程序会自动将这个扇区的内容加载进入内存
的07c0H处并执行它
code segment
assume cs:code
start: cs=0000,ip=7c00
mov ax,offset start
add ax,07c0h ax加上07c0h送给ds,
mov ds,ax设置数据段寄存器ds,
使得ds:0000为内存地址的0000:7c00
mov si,offset msgmsg偏移送si
call display 显示
初始化 int 13h 的各寄存器,加载内核(kernel)
(具体设置信息请查阅BIOS中断手册)
mov ax, 8000hkernel将要存放的内存的段地址
mov es, ax 传递给ES
mov bx, 0kernel偏移地址为0
mov dl, 0驱动器号为0h,即A盘
mov dh, 0磁头号为0
mov ch, 0磁道号为0
mov cl, 2扇区号为2
mov al, 1要读的扇区数为1
mov ah, 2调用读磁盘的中断程序
int 13h
内核加载完毕
mov si,offset ok 显示ok
call display
mov bx,offset kerkernel 存放的是地址 8000:0000
根据前边(es:bx)的设定。
跳去执行内核(kernel)程序。
jmp dword ptr [bx] 跳到bx这个指针指向的地址处。
display:
lodsb装入一个字节到al
or al,al al=0则表明这个字符串结束
jz disend跳到最后返回
mov ah, 0eh 0eh是显示功能号
mov bx, 7颜色
int 10h
jmp display
disend:
ret
msg db 'My Os is loading...',0 显示信息
ok db 'OK',13,10,0
ker dw 0,8000h kernel的内存地址8000:0000
code ends
end start
文件:kernel.asm
file:kernel.asm
load.exe 程序将下边代码生成的二进制文件写入了A盘
的0磁道2扇区
在0磁道1扇区的boot代码会将此代码加载到内存中并跳
转到对应地址去执行这段代码.
代码功能:不断从键盘接收输入,并将其顺序显示出来.
kernel segment
assume cs:kernel
start:
mov ah,0 从键盘读入字符的功能
int 16h
mov ah,0eh显示功能
int 10h
cmp al,13如果是回车则换行
jnz start
mov al,10
int 10h
jmp start 无穷循环
kernel ends
end start
文件:load.c
/* file: load.c */
/*这个程序如此简单,功能只有两个,接受字符和显示,又编译连接吧。
现在我们生成了两个文件boot.exe,kernel.exe。其中boot.exe不要执行,你可以在dos
下运行的是kernel.exe,可以看看写对没有。
现在就差把这两个文件写入软盘的1,2扇区了。可是你会发现很怪的问题,boot有603字
节,kernel有522字节,但是一个扇区只有512字节,怎么写得下?这个问题我最先也迷
惑,后来把两个exe文件反汇编才知道真正我们写的代码出现在exe文件的513字节处,
exe文件的前512字节是mircosoft定义的exe文件的前缀,其中有exe文件标识,大小,
段定位指针等东西,这512字节我们不需要我们就只要后面的,那么我们就来写个程序
把boot.exe 和kernel.exe 写入软盘吧,(注意写入引导扇区的时候最后两个字节必须
是55aa这是规定的引导扇区的标识。)我这里选的是用tc2.0了,当然也可以用汇编写,
下面是writebt.c
*/
#include<stdio.h>
#include<dos.h>
union REGS inreg,outreg
struct SREGS segreg
main()
{
int i
char boot_buf[512] /*暂存放boot.exe的内容*/
char kernel_buf[512] /*暂存放kernel.exe的内容*/
FILE *fp
for(i=0i<512i++)
{ /*先把这两个缓冲区清0*/
boot_buf[i]=0
kernel_buf[i]=0
}
if((fp=fopen("boot.exe","rb"))==NULL)
{
printf("cannot find boot.exe")exit(0)
} /*打开boot.exe*/
fseek(fp,512L,0) /*直接定位到文件第513个字节处,即512L*/
i=0
while(1)
{
fread(&boot_buf[i],1,1,fp) /*读入后面的所有内容直到结束*/
i++
if(feof(fp))
{
fclose(fp)
break
}
}
boot_buf[510] = 0x55 /*最后两个字节必须为55aa*/
boot_buf[511] = 0xaa
/* 设置:将boot中的引导程序写入A盘的第0磁道1扇区*/
inreg.h.ah=0x03/*调用bios13h的3号写盘功能*/
inreg.h.al=0x1 /*要读的扇区数为1*/
inreg.h.ch=0 /*磁道号为0*/
inreg.h.cl=1 /*扇区号为1*/
inreg.h.dh=0 /*磁头号为0*/
inreg.h.dl=0 /*驱动器号为0,即a盘*/
inreg.x.bx=FP_OFF(boot_buf)/*bx中写boot_buf的内存偏移地址*/
segreg.es=FP_SEG(boot_buf) /*es中写它的内存段地址*/
int86x(0x13,&inreg,&outreg,&segreg)/*调中断写盘*/
if (_AH!=0) /*ah为0刚写盘成功,否则退出*/
{
printf("error writing")exit(0)
}
else
{
printf("ok")
}
if((fp=fopen("kernel.exe","rb"))==NULL)/*打开kernel.exe*/
{
printf("cannot find kernel.exe")exit(0)
}
fseek(fp,512L,0) /*直接定位到文件第513个字节处,即512L*/
i=0
while(1)
{
fread(&kernel_buf[i],1,1,fp) /*读入后面的所有内容直到结束*/
i++
if(feof(fp))
{
fclose(fp)
break
}
}
/* 设置:将kernel中的程序写入A盘的第0磁道2扇区*/
inreg.h.ah=0x03
inreg.h.al=0x1
inreg.h.ch=0
inreg.h.cl=2/*扇区号为2*/
inreg.h.dh=0
inreg.h.dl=0
inreg.x.bx=FP_OFF(kernel_buf)
segreg.es=FP_SEG(kernel_buf)
int86x(0x13,&inreg,&outreg,&segreg)
if (_AH!=0)
{
printf("error writing")exit(0)
}
else
{
printf("ok")
}
}
/*
同样地编译连接,现在我们有boot.exe,kernel.exe和writebt.exe,拷贝他们到同一个目录下,然后手
插入软盘,执行writebt.exe,如果出现error writing则表明写盘出错,你多运行几次,直到出现okok
时就写成功了,但你不要马上切换到a盘按dir,这样系统会出现未格式化的信息,要你格式化。因为刚
才我们所做的把微软定义的软盘的一些信息给修改了,dos自然识别不了。现在你可以重起,从软盘起
动,你会看到你的成果了。
假设你的 masm.exe 在下列路径 C:\abc\def\masm.exe那么 在 开始-->运行 中输入 cmd
打开cmd.exe, 在命令行中输入 :C:\abc\def\masm.exe
回车 确定即可打开 masm
1.先用汇编工具如masm对源文件汇编,链接,生成.exe文件masm 下载地址:http://dl1.csdn.net/down3/20070416/16194756234.rar
例如,假设汇编工具在d:\masm,源文件名为1.asm,也在该目录下,可以如下 *** 作:
开始--运行--cmd--d: --cd masm--masm 1--回车3下--link 1--回车3下
此时在d:\masm下生成1.obj,1.exe
在命令行(cmd)下输入debug 1.exe开始调试。
2.在开始调试之前先介绍一下debug的常用命令
-A 地址 从指定地址开始编写小汇编程序,按两个回车键结束编辑
-U 地址 从指定地址开始反汇编32字节的机器指令,缺省地址则从上一U命令继续
-D 始址 终址 以16进制/Asc字符对照方式显示指定内存范围的数据,每行显示10H个字节
-E 地址 值表 用给出的值表(空格分隔)替换指定地址开始的内存单元,例:-E 100 'v' 1F 'hello'
-N 文件名 为后续的L/W命令约定所 *** 作的文件名
-L 地址 将N命令所指定文件的内容读入到指定内存位置。另,逻辑卷扇区直接读:-L 地址 逻卷号 起始逻扇号 扇数
-W 地址 将BX-CX个字节的内存数据写入N命令指定的文件中。另,逻辑卷扇区直接写:-W 地址 逻卷号 起始逻扇号 扇数
-R 寄存器名 显示并允许修改指定寄存器的值
-G=始址 终址 执行指定内存中的机器指令程序
-T=地址 单步执行机器指令,缺省地址则从上一T命令继续。另,继续跟踪m条指令:-T m
读取c:卷的引导扇区,并保存到Boot.1文件中,并简单分析引导程序的前面几条指令:
-L 1000 2 0 1
-N boot.1
-R bx输入0000
-R cx输入0200
-W 1000
-U 1000
读取第一个硬盘上的主引导扇区,并保存到MB.1文件中,在屏幕上显示硬盘分区表数据:
-A 100
yyyy:0100 mov dx,0080
yyyy:01xx mov cx,0001
yyyy:01xx mov ax,yyyy
yyyy:01xx mov es,ax
yyyy:01xx mov bx,1000
yyyy:01xx mov ax,0201
yyyy:01xx int 13
yyyy:01zz nop
-G=yyyy:0100 01zz
-N mb.1
-R bx 输入0000
-R cx 输入0200
-W 1000
-D 11be 11ff
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)