主引导程序中如何进行字符串打印?
汇编中的常量定义
Const equ 0x7c00 == c语言 #define Const 0x7c00
主引导程序
org 0x7c00 ; IP = 0x7c00 jmp short start ;占用两字节 nop ;占用一字节 define: ;自己定义栈空间 BaseOfStack equ 0x7c00 ;#define BaseOfStack 0x7c00 栈从高地址向低地址增长,与代码段无影响 ;主引导区(0扇区)的必要信息 header: BS_OEMName db "D.T.Soft" BPB_BytsPerSec dw 512 BPB_SecPerClus db 1 BPB_RsvdSecCnt dw 1 BPB_NumFATs db 2 BPB_RootEntCnt dw 224 BPB_TotSec16 dw 2880 BPB_Media db 0xF0 BPB_FATSz16 dw 9 BPB_SecPerTrk dw 18 BPB_NumHeads dw 2 BPB_HiddSec dd 0 BPB_TotSec32 dd 0 BS_DrvNum db 0 BS_Reserved1 db 0 BS_BootSig db 0x29 BS_VolID dd 0 BS_VolLab db "D.T.OS-0.01" BS_FileSysType db "FAT12 " ;开始就跳转到这里执行 start: mov ax, cs mov ss, ax mov ds, ax mov es, ax mov sp, BaseOfStack ;指定栈顶指针 mov bp, MsgStr ;指定字符串地址 mov cx, MsgLen ;指定字符串长度 call Print last: hlt jmp last ;打印字符串函数 ; es:bp --> string address ; cx --> string length Print: mov ax, 0x1301 ;指定打印参数 mov bx, 0x0007 ;指定打印参数 int 0x10 ;执行0x10号中断 ret MsgStr db "Hello, DTOS!" MsgLen equ ($-MsgStr) Buf: times 510-($-$$) db 0x00 db 0x55, 0xaa
org 0x7c00 jmp short start //短跳转 跳转到start 占用了两个字节(jmp占一个字节,目标占一个字节) nop //空指令 一个字节填充 (三个字的跳转指令) define: BaseOfStack equ 0x7c00 header: BS_OEMName db "D.T.Soft" BPB_BytsPerSec dw 512 BPB_SecPerClus db 1 BPB_RsvdSecCnt dw 1 BPB_NumFATs db 2 BPB_RootEntCnt dw 224 BPB_TotSec16 dw 2880 BPB_Media db 0xF0 BPB_FATSz16 dw 9 BPB_SecPerTrk dw 18 BPB_NumHeads dw 2 BPB_HiddSec dd 0 BPB_TotSec32 dd 0 BS_DrvNum db 0 BS_Reserved1 db 0 BS_BootSig db 0x29 BS_VolID dd 0 BS_VolLab db "D.T.OS-0.01" BS_FileSysType db "FAT12 " start: mov ax, cs mov ss, ax mov ds, ax mov es, ax mov sp, BaseOfStack mov ax, 34 mov cx, 1 mov bx, Buf call ReadSector mov bp, Buf mov cx, 29 call Print last: hlt jmp last ; es:bp --> string address ; cx --> string length Print: mov ax, 0x1301 mov bx, 0x0007 int 0x10 ret ; no parameter ResetFloppy: push ax push dx mov ah, 0x00 mov dl, [BS_DrvNum] int 0x13 pop dx pop ax ret ; ax --> logic sector number ; cx --> number of sector ; es:bx --> target address ReadSector: push bx push cx push dx push ax call ResetFloppy push bx push cx mov bl, [BPB_SecPerTrk] div bl mov cl, ah add cl, 1 mov ch, al shr ch, 1 mov dh, al and dh, 1 mov dl, [BS_DrvNum] pop ax pop bx mov ah, 0x02 read: int 0x13 jc read pop ax pop dx pop cx pop bx ret MsgStr db "Hello, DTOS!" MsgLen equ ($-MsgStr) Buf: times 510-($-$$) db 0x00 db 0x55, 0xaa
调用print
mov bp, MsgStr mov cx, 29 call Print
有函数调用,就要考虑栈
define: BaseOfStack equ 0x7c00 //定义栈空间起始地址
start:
mov ax, cs
mov ss, ax
mov ds, ax
mov es, ax
mov sp, BaseOfStack ;将sp指针指向栈的起始地址处
0x7c00作为栈的地址是可以的
3.5寸软盘
我们通常说的扇区号是逻辑扇区号,然而在真正的软盘物理结构上面,不是线性编号的
将逻辑扇区号进行拆分
使用BIOS中断
读取数据流程
mov ch, al
shr ch, 1 将商右移一位
read:
int 0x13
jc read 出错之后就跳转重读
这里的进栈操作是为了保存寄存器原有的值
org 0x7c00 jmp short start nop define: BaseOfStack equ 0x7c00 header: BS_OEMName db "D.T.Soft" BPB_BytsPerSec dw 512 BPB_SecPerClus db 1 BPB_RsvdSecCnt dw 1 BPB_NumFATs db 2 BPB_RootEntCnt dw 224 BPB_TotSec16 dw 2880 BPB_Media db 0xF0 BPB_FATSz16 dw 9 BPB_SecPerTrk dw 18 BPB_NumHeads dw 2 BPB_HiddSec dd 0 BPB_TotSec32 dd 0 BS_DrvNum db 0 BS_Reserved1 db 0 BS_BootSig db 0x29 BS_VolID dd 0 BS_VolLab db "D.T.OS-0.01" BS_FileSysType db "FAT12 " start: mov ax, cs mov ss, ax mov ds, ax mov es, ax mov sp, BaseOfStack mov ax, 34 mov cx, 1 mov bx, Buf call ReadSector mov bp, Buf mov cx, 29 call Print last: hlt jmp last ; es:bp --> string address ; cx --> string length Print: mov ax, 0x1301 mov bx, 0x0007 int 0x10 ret ; no parameter ResetFloppy: push ax push dx mov ah, 0x00 mov dl, [BS_DrvNum] int 0x13 pop dx pop ax ret ; ax --> logic sector number ; cx --> number of sector ; es:bx --> target address ReadSector: push bx push cx push dx push ax call ResetFloppy push bx push cx mov bl, [BPB_SecPerTrk] ;改动了这些寄存器的值,因此要将这些寄存器的初始状态保留 div bl mov cl, ah add cl, 1 mov ch, al shr ch, 1 mov dh, al and dh, 1 mov dl, [BS_DrvNum] pop ax pop bx mov ah, 0x02 read: int 0x13 jc read pop ax pop dx pop cx pop bx ret MsgStr db "Hello, DTOS!" MsgLen equ ($-MsgStr) Buf: times 510-($-$$) db 0x00 db 0x55, 0xaa