org 7c00h
segment .text
bits 16
start:
jmp short main
nop
首先两句定义整个代码的运行位置,org 7C00H指示整个代码的其实位置在7C00处,这样可以减少不必要的便宜运算。也就是整个MBR加载到系统之后不存在偏移。而后面的bits 16则是表明整个代码段都是16位对齐,start后面是MBR的开始,这一句通过汇编会生成两字节的调整指令和一跳空操作指令。紧跟三条跳转指令后面的是MBR当中的一些属性值。
OEMName db 'MSWIN4.0' ;厂商标志和OS版本号
BytesPerSector dw 512 ;每扇区的字节数
SectsPerCluster db 1 ;每簇的扇区数
ReservedSectors dw 1 ;第一个FAT开始之前的扇区数,包括引导扇区
NumberOfFats db 2 ;该分区上FAT的副本数
MaxRootEntries dw 0 ; 对FAT32分区而言,本字段必须设置为 0
TotalSectors dw 0 ; 对FAT32分区而言,本字段必须设置为 0
MediaDescriptor db 0f8h ; 媒体被类型信息,值0xF8表示硬盘
SectorsPerFat dw 0 ; 对FAT32分区而言,本字段必须设置为 0
SectorsPerTrack dw 18 ;包含使用INT13h的磁盘的“每道扇区数”几何结构值
NumberOfHeads dw 2 ;使用INT 13h的磁盘的“磁头数”几何结构值
HiddenSectors dd 0 ;分区上引导扇区之前的扇区数
TotalSectorsBig dd 0 ;全部扇区
SectorsPerFatBig dd 0 ;只被FAT32使用,该分区每个FAT所占的扇区数
ExtendedFlags dw 0 ;此域为FAT32特有。Bits0-3: 活动的FAT(active FAT)数目,只在镜像禁止时才效。Bits 4-6: 保留Bits 7: 0 表示FAT实时镜像到所的FAT表中
;1 表示只一个活动的FAT表。这个表就是Bits0-3所指定的那个
;Bits8-15: 保留
FSVersion dw 0 ;此域为FAT32特有
RootDirStartCluster dd 0 ;根目录所在第一个簇的簇号
FSInfoSector dw 0 ;只供FAT32使用, FAT32分区的保留区中的文件系统信息
BackupBootSector dw 6 ;如果不为0,表示在保留区中引导记录的备份数据所占的扇区数,通常为6
Reserved1 times 12 db 0 ;12个字节均为0x00 保留
BootDrive db 80 ;用于BIOS中断0x13得到磁盘驱动器参数,0x00为软盘,0x80为硬盘
Reserved db 0 ;保留
ExtendSig db 29h ;段必须要有能被Windows 2000所识别的值0x28或0x29
SerialNumber dd 00000000h ;在格式化磁盘时所产生的一个随机序号,它有助于区分磁盘
VolumeLabel db 'NO NAME ' ;卷标也作为一个特殊的文件(有文件名无文件内容)保存在根目录中
FileSystem db 'FAT32 ' ;通常设置为“FAT32”
通过后面的注释,还不能对整个属性有一个大概的了解。并且在在上面的属性当中实际有些数值是不正确的,比如BootDrive,实际上MBR有一些信息是在系统安装的时候进行填写,这里只是为了占位符,所以填入的是0,接下来是开头位置的jmp指令的main标号。(具体的FAT分析可以参考FAT手册)
main: 00007C5A 33C9 xor cx,cx 00007C5C 8ED1 mov ss,cx ; 00007C5E BCF47B mov sp,0x7bf4 ; 首先设置段寄存器和相应的堆栈,注意这里的堆栈式向下增长的,所以当sp设置为7c00的时候不会覆盖掉代码段 00007C61 8EC1 mov es,cx 00007C63 8ED9 mov ds,cx 00007C65 BD007C mov bp,0x7c00 ;这里SP不等于BP,其中BP和SP之间的数据用于局部变量 00007C68 884E02 mov [bp+0x2],cl ;这里bp+2实际上是最开头的第三个nop指令 ;********************************************************************** 00007C6B 8A5640 mov dl,[bp+BootDrive] 00007C6E B408 mov ah,0x8 00007C70 CD13 int 0x13 ;获取整个磁盘的参数 00007C72 7305 jnc drive_param_ok ; 这一条跳转应该不陌生了吧,INT13调用会设置进位标志 drive_param_error: 00007C74 B9FFFF mov cx,0xffff ; We couldn't determine the drive parameters 00007C77 8AF1 mov dh,cl ; So just set the CHS to 0xff drive_param_ok: 00007C79 660FB6C6 movzx eax,dh ;将获得的参数数据用于计算整个磁盘的大小,假设没有跳转的话,下面的inc指令将使得整个ax溢出,也就是ax为0,所以整个大小为0 00007C7D 40 inc ax ; BIOS的int 13进行读取磁盘的数据操作,功能08H 功能描述:读取驱动器参数 00007C7E 660FB6D1 movzx edx,cl ; 入口参数:AH=08H,DL=驱动器,00H~7FH:软盘;80H~0FFH:硬盘 00007C82 80E23F and dl,0x3f ; 出口参数:CF=1——操作失败,AH=状态代码,参见功能号01H中的说明,否则, BL=01H — 360K;=02H — 1.2M;=03H — 720K;=04H — 1.44M 00007C85 F7E2 mul dx ; CH=柱面数的低8位 ; CL的位7-6=柱面数的该2位 ;CL的位5-0=扇区数 ;DH=磁头数 ;上面的mul指令执行之后,数据dx:ax存放的是磁头数目*扇区数目
00007C87 86CD xchg cl,ch ; 两个寄存器交换之后,CX向右移动六位就可以得到柱面数 00007C89 C0ED06 shr ch,0x6 ; 00007C8C 41 inc cx ; 00007C8D 660FB7C9 movzx ecx,cx 00007C91 66F7E1 mul ecx ; 柱面数*先前的结果得到最终磁盘驱动器的大小,并保存到局部变量当中 00007C94 668946F8 mov [bp-0x8],eax ; 00007C98 837E1600 cmp word [bp+TotalSectors],byte +0x0 ; 00007C9C 7538 jnz print_ntldr_error_message ; 00007C9E 837E2A00 cmp word [bp&#