x86汇编-01编写MBR,看完后用脚都能写出的教程

一. 编写MBR

1 实模式下显示字符的基本工作原理

显卡都有自己的存储器,因为它位于显卡上,故称显示存储器(Video RAM: VRAM),简称显存,要显示的内容都预先写入显存。和其他半导体存储器一样,显存并没有 什么特殊的地方,也是一个按字节访问的存储器件

1.1 图形模式 原理

显卡的工作是周期性地从显存中取这些比特,并把它们按顺序显示在屏幕上。如果是比特“0”,则像素保持原来的状态不变,因为屏幕本来就是黑的;如果是比特“1”,则点亮对应的像素。

在这里插入图片描述

图形模式的问题

操作显存里的比特,使得屏幕上能显示出字符的形状,是非常麻烦、非常繁重的工作, 因为你必须计算该字符所对应的比特位于显存里的什么位置。

1.2 文本模式 原理

就像一个二进制数既可以是一个普通的数,也可以代表 一条处理器指令一样,他们认为每个字符也可以表示成一个数。比如,数字 0x4C 就代表字符“L”, 这个数被称为是字符“L”的 ASCII 代码

可以将字符的代码存放到显存里,第 1 个代码对应着屏幕左上角第 1 个字符, 第 2 个代码对应着屏幕左上角第 2 个字符,后面的依次类推。剩下的工作是如何用代码来控制屏幕 上的像素,使它们或明或暗以构成字符的轮廓,这是字符发生器和控制电路的事情

1.2.1 文本模式 为什么需要引入内存映射

处理器需要访问显存,把字符的 ASCII 码写进去,

显存是位于显卡上的,CPU访问显存需要和显卡这个外围设备打交道。同时,多一道手续自然是不好的,这当中最重要的考量是速度和效率

计算机系统的设计者们,这些拥有聪明脑瓜子的人,决定把显存映射到处理器可以直接访问的 地址空间里,也就是内存空间里

在这里插入图片描述

1.2.2 显存映射至内存的分布

F0000~FFFFF:属于ROM-BIOS 64kb

A0000~BFFFF:这段内存空间由特定的外围设备提供

​ B8000~BFFFF:显存映射至内存的空间

计算空间:

let biosMem=0xFFFFF-0xF0000+1;
let peripheralMem=0xEFFFF-0xA0000+1;
let videoMem=0xBFFFF-0xB8000+1;
console.log(`每个内存单元1Byte,BIOS占:${biosMem}个`)
console.log("BIOS:",biosMem/1024,"KB")
console.log("外围设备:",peripheralMem/1024,"KB")
console.log("外围设备显存映射:",videoMem/1024,"KB")

输出结果:

let biosMem=0xFFFFF-0xF0000+1;
let peripheralMem=0xEFFFF-0xA0000+1;
let videoMem=0xBFFFF-0xB8000+1;
console.log(`每个内存单元1Byte,BIOS占:${biosMem}个`)
console.log("BIOS:",biosMem/1024,"KB")
console.log("外围设备:",peripheralMem/1024,"KB")
console.log("外围设备显存映射:",videoMem/1024,"KB")
1.2.3 显卡加电自检后的文本模式
在加电自检之后都会把自己初始化到 80×25 的文本模式。在这种模式下,屏幕上可以显示 25 行,每行 80 个字符,每屏总共 2000 个 字符

这里应该是指的每屏显示2000个字符,而不是说的总共,根据计算:

//32kb的显存映射空间
console.log(32*1024/2)

最多显示字符:
16384个
1.2.4字符显示属性

字符的显示属性(1 字节)分为两部分,
低 4 位定义的是前景色,
高 4 位定 义的是背景色。

色彩主要由 R、G、B 这 3 位决定,

可以由红®、绿(G)、蓝 (B)三原色来配出其他所有颜色。

K 是闪烁位,为 0 时不闪烁,为 1 时闪烁;

I 是亮度位,为 0时正常亮度,为 1 时呈高亮

在这里插入图片描述

2. 代码 MBR Master Boot Record

        
         
;------------------------------- 显示字符 XXOS MBR Hi: ----------------------------
         ;访问内存可以使用段寄存器 DS,但这不是强制性的,也可以使用 ES。
         ;因为 DS 还有别的用处, 所以在这里我们使用 ES 来指向显存所在的段
  			 ;DS: Data Segment
  			 ;ES: Extend Segment
  			 
         mov ax,0xb800                 ;指向文本模式的显示缓冲区   
         mov es,ax										 ;设置附加段寄存器 ES为0xb800
         
         ; ?:为什么不直接mov es,0xb800

         ;以下显示字符串"Label offset:"
         ; ?:为什么要声明 byte
         ; ?:为什么是[es:0x00]而不是[0x00]
         mov byte [es:0x00],'X'				 ;1.设置字符显示内容 		  
         mov byte [es:0x01],0x07			 ;2.设备字符显示属性			 
         mov byte [es:0x02],'X'				 
         mov byte [es:0x03],0x07			 
         mov byte [es:0x04],'O'				 
         mov byte [es:0x05],0x07			 
         mov byte [es:0x06],'S'			  
         mov byte [es:0x07],0x07		   
         mov byte [es:0x08],' '				 
         mov byte [es:0x09],0x07			
         mov byte [es:0x0a],'M'
         mov byte [es:0x0b],0x07
         mov byte [es:0x0c],'B'
         mov byte [es:0x0d],0x07
         mov byte [es:0x0e],'R'
         mov byte [es:0x0f],0x07
         mov byte [es:0x10],''
         mov byte [es:0x11],0x07
         mov byte [es:0x12],'H'
         mov byte [es:0x13],0x07
         mov byte [es:0x14],'i'
         mov byte [es:0x15],0x07
         mov byte [es:0x16],'!'
         mov byte [es:0x17],0x07
         mov byte [es:0x18],''
         mov byte [es:0x19],0x07
;-------------------------------显示字符 除法运算 显示结果--------------------------------
;被除数 ÷ 除数= 商 and 余数
         mov ax,number                 ;取得标号number的偏移地址
         mov bx,10										 ;除数

         ;设置数据段的基地址
         mov cx,cs										 ;?: mov cx,cs mov ds,cx这里的含义是什么?
         mov ds,cx

         ;求个位上的数字
         mov dx,0
         div bx												 
         mov [0x7c00+number+0x00],dl   ;保存个位上的数字  ;?:为什么是mov [0x7c00+number+0x00],dl

         ;求十位上的数字
         xor dx,dx										 ;?:xor dx,dx 这里的含义是什么?
         div bx
         mov [0x7c00+number+0x01],dl   ;保存十位上的数字

         ;求百位上的数字
         xor dx,dx
         div bx
         mov [0x7c00+number+0x02],dl   ;保存百位上的数字

         ;求千位上的数字
         xor dx,dx
         div bx
         mov [0x7c00+number+0x03],dl   ;保存千位上的数字

         ;求万位上的数字 
         xor dx,dx
         div bx
         mov [0x7c00+number+0x04],dl   ;保存万位上的数字

         ;以下用十进制显示标号的偏移地址
         mov al,[0x7c00+number+0x04]
         add al,0x30								   ;:? 为什么需要 add al,0x30
         mov [es:0x1a],al							 ;:? 为什么是  mov [es:0x1a],al	
         mov byte [es:0x1b],0x04
         
         mov al,[0x7c00+number+0x03]
         add al,0x30
         mov [es:0x1c],al
         mov byte [es:0x1d],0x04
         
         mov al,[0x7c00+number+0x02]
         add al,0x30
         mov [es:0x1e],al
         mov byte [es:0x1f],0x04

         mov al,[0x7c00+number+0x01]
         add al,0x30
         mov [es:0x20],al
         mov byte [es:0x21],0x04

         mov al,[0x7c00+number+0x00]
         add al,0x30
         mov [es:0x22],al
         mov byte [es:0x23],0x04
         
         mov byte [es:0x24],'D'
         mov byte [es:0x25],0x07
          
   infi: jmp near infi                 ;无限循环 ;: infi: jmp near infi 为什么这里是无限循环
      
  number db 0,0,0,0,0									 ;?:number是什么意思 db是什么意思
  
  times 203 db 0											 ;times是什么意思
            db 0x55,0xaa							 ;db 0x55,0xaa

3.CPU的特性

以下是总结的防坑指南,其实也就是CPU的一些规定,或者是一些小白容易犯错的地方,共勉

3.1 段寄存器赋值

Intel 的处理器不允许将一个立即数传送到段寄存器

错误:

mov ex,0xb800

正确:

 mov 段寄存器,通用寄存器 
 mov 段寄存器,内存单元
3.3 为什么需要声明byte?
mov byte [es:0x01],0x07

因为在16bit的处理器下,0x07,即可以表示8位的立即数,也可以表示为16bit中的0x0007,因此需要指明传输的是byte

 mov [0x00],AL ;按字节操作 
 mov AX,[0x02] ;按字操作
 
 ;这里就不用指明,byte还是word,因为AL为8bit,AX为16bit
3.4 为什么需要申明[es:0x01]?
mov byte [es:0x01],0x07

因为默认访问内存使用 DS 寄存器

访问内存可以使用段寄存器 DS,但这不是强制性的,也可以使用 ES。因为 DS 还有别的用处, 所以在这里我们使用 ES 来指向显存所在的段

mov [0x00],AL ;这种写法表明,使用DS段基址寄存器,DS:0000

3.5 为什么mov cx,cs mov ds,cx这里的含义是什么?

电脑开机-BIOS开机自检-加载MBR-跳转至0x0000:7c00处开始执行MBR代码

mov cx,cs

mov ds,cx

这里表示代码段基址和数据段基址为同一个段地址 0x0000

但代码段和数据段的偏移地址却不同,一个是0x00000000,一个是0x0000012E

3.6 为什么是mov [0x7c00+number+0x00],dl 为什么加0x7c00

nasm编译后,编译是从0x0000000开始编译的,可以理解为汇编地址/偏移地址,BIOS把MBR是加载到物理地址0x0000:7c000处的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d8hCcDpe-1624030116069)(/Users/software/Library/Application Support/typora-user-images/image-20210618224630428.png)]

ds为数据段0x0000:偏移地址0x7c00+0x012E+0x00,因此这里要加上物理地址

3.7 xor dx,dx 这里的含义是什么?

xor为异或,也就是 在 或运算的基础上(有一个输入为真则为真),还要保证两个输入不同

这里表示把dx置为0,(可忽略部分–>:同时也表示被除数为32位的二进制,往下看)

in in  out
0  0 = 0
1  0 = 1
0  1 = 1
1  1 = 0

3.8 汇编中的除法

16位二进制除法: ax ÷ cl =al…ah 除数可以由 8 位的通用寄存器或者内存单元􏰀供 div byte [0x0230]

32位二进制除法:dx:ax ÷ cx = ax…dx 除数可以由 8 位的通用寄存器或者内存单元􏰀供 div word [0x0230]

3.9 :? 为什么需要 add al,0x30

因为比如数字1+0x30,刚好对应ASCALL码 “1”:0x31

3.10 为什么是 mov [es:0x1a],al

为了接着XXOS MBR Hi: 继续填充显存映射内存的地址

3.11 infi: jmp near infi 为什么这里是无限循环

数字显示完成后,原则上整个程序就结束了,但对处理器来说,它并不知道。对它来说,取指令、执行是永无止境的

jmp 是转移指令,用于使处理器脱离当前的执行序列,转移到指定的地方执行,关键字 near 表 示目标位置依然在当前代码段内

也就是说,它将会不停地重复执行自己

如果这里不让CPU无限循环的话,CPU会继续执行到number db 0,0,0,0,0,CPU把数据当成指令执行,那么悲剧就发生了

3.12 number是什么意思

number为标号number db 0,0,0,0,0 代表 db 0,0,0,0,0的汇编地址,在nasm编译阶段会被替换为具体的汇编地址/偏移地址

3.13 db是什么意思

db—>Declare Byte:声明

在程序中声明并初始化数据, 为数据区

3.14 times是什么意思

times为伪指令,告诉nasm,在汇编器nasm编译阶段发生,填充剩余空间为0

重复执行次数,填充0

3.15 db 0x55,0xaa

根据规定512Byte,最后两个字节必须为0x55,0xaa,这样才能被识别被MBR程序

4 编译运行

nasm c05_mbr.asm -l c05_mbr.lst -o c05_mbr.bin

dd if=c05.bin of=a.img bs=512 count=1 conv=notrunc

bochs -f bochsout.txt

爽了一下,说明一下mac下的bochs,感觉有点不友好,在显存映射内存区域填充了其他信息,改天把它清除,看着确实不爽

在这里插入图片描述

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第Ο章 写在前面...................................................................................................................2 第一章汇编语言简介.............................................................................................................3 第二章认识处理器.................................................................................................................4 2.1 寄存器........................................................................................................................4 2.2 使用寄存器................................................................................................................6 第三章操作内存...................................................................................................................12 3.1 实模式......................................................................................................................12 3.2 保护模式..................................................................................................................16 3.3 操作内存..................................................................................................................19 3.4 串操作......................................................................................................................21 3.5 关于保护模式中内存操作的一点说明.................................................................22 3.6 堆栈.........................................................................................................................23 本章小结.........................................................................................................................25 第四章利用子程序与中断...................................................................................................25 4.1 子程序......................................................................................................................25 4.2 中断..........................................................................................................................31 第五章编译优化概述...........................................................................................................34 5.1 循环优化:强度削减和代码外提.........................................................................36 5.2 局部优化:表达式预计算和子表达式提取.........................................................37 5.3 全局寄存器优化.....................................................................................................38 5.4 x86体系结构上的并行最大化和指令封包..........................................................40 5.5 存储优化..................................................................................................................42 第六章 Linux X86汇编程序设计........................................................................................46 6.1编译和链接...............................................................................................................46 6.2基本示例...................................................................................................................46 第七章 X86汇编指令集汇总...............................................................................................47 一.数据传输指令............................................................................................................47 二、算术运算指令.........................................................................................................49 三、逻辑运算指令.........................................................................................................49 四、串指令.....................................................................................................................50 五、程序转移指令.........................................................................................................50 六、伪指令.....................................................................................................................52 七、寄存器.....................................................................................................................52 八、位操作指令,处理器控制指令.............................................................................52 九、FPU instructions......................................................................................................54 第八章 GCC内联汇编基础..................................................................................................54 1. GCC汇编格式...........................................................................................................55 2.内联汇编基本形式......................................................................................................56 3. 扩展形式内联汇编....................................................................................................56 4. 深入constra................................................................................................................59 5.结束语..........................................................................................................................63

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值