x86汇编语言学习笔记
以李忠老师的《x86汇编语言:从实模式到保护模式》为学习教材!
第一章 十六进制计数法
学习二进制,十进制,十六进制,以及他们之间的相互转换(太简单了,省略不记)
第二章 处理器,内存和指令
- Intel处理器用的是小端格式 0000H(5D)0001H(00) —> 0x 005D
- 一个处理器能识别的指令的集合,称之为该处理器的指令集
一般指令组成:操作码+操作数(有些没有操作数)
- 比如:B8005D,B8是一个字节的操作码(有些是两个字节),005D是操作数
- 可以立即在指令里面取得的操作数称之为立即数
- 因为操作码和操作数都是2进制数,为了区分,所以要分开存放在代码区和数据区
Intel8086处理器:
- 有8个16bit的通用寄存器:
AX,BX,CX,DX,SI,DI,BP,SP - 前四个又可以分成8个8bit的寄存器:
AH,AL,BH,BL…
处理器是自动化的,给出一个首地址,就会自动执行下去,因此一个工作他的所有代码应该集中起来,处于内存的某一段位置,称之为代码段.
数据同理,有数据段.
- 因为程序在内存中的位置是随机的,因此我们不能使用绝对内存地址.
- 所以处理器使用了内存分段机制:通过
段:偏移地址的方式找到真实地址 - 在开始前,CS(代码段寄存器)和DS(数据段寄存器)指向程序代码段和数据段的开始位置,然后处理器将指令里面的地址都视作偏移地址.
8086的内存分段机制
CS指向代码段起始位置,IP指向偏移地址,共同组成逻辑地址,由总线接口转成物理地址
还有6字节的指令预取队列
有四个段寄存器(CS,DS,ES附加段寄存器,SS栈寄存器)
8086的总线有20根,而寄存器却是16位的,最经典的情况,段:偏移地址中将段左移4bit
第三章 汇编语言和汇编软件
略
其实就是编译器+编辑器+16进制文件查看器
第四章 虚拟机的安装和使用
VirtualBox…
前四章,预备知识到这里就结束了,因为太容易所以写的很简略
第5章 编写主引导扇区代码
第一个扇区叫主引导扇区,有512字节,开机后被加载到内存地址0x07c00处,然后判断是否有效(扇区最后两个字节为0x55,0xAA,则有效),然后跳到内存0x07c00处开始执行.
显卡和显存
- 有两种显示模式:图形模式,文本模式
- 显卡在加电自检后初始化到80*25的文本模式
8086有1M的地址数,00000H~FFFFFH
- 00000H~9FFFFH:给常规内存(内存条)
- A0000HBFFFF固定给显卡)
- F0000H~FFFFFH:给ROM-BIOS
传送指令MOV
mov 目的操作数,源操作数
- mov只改变目的操作数的值,不改变源操作数的值
- Intel不允许直接将立即数传送到段寄存器,于是只能
- mov 段寄存器,通用寄存器
- mov 段寄存器,内存单元
mov byte [es:0x00],'L'
- byte/word:16bit字节/8bit字,修饰目的操作数,如果目的操作数明确位数,则无需修饰符
- []:取内存地址的值
- es:代表使用ES段寄存器,而不是默认的DS
- ‘’,使用字符需要用’’
每条指令都可以有标号
flag:mov byte [es:0x00],'L'
和C语言的Goto的使用方式一样
显示十进制数
- 需要通过除余操作来获取各位的数
- 加上0x30为ASCII上对应数字的值
声明数据命令
- 声明字节命令db
- 声明字命令dw
- 声明四字命令dq
除法命令div(两种使用方法)
16位/8位
- 被除数必须在AX中,执行后,商在AL中,余数在AH中
32位/16位
- 被除数高位在DX中,低位在AX中,执行后,商在AX中,余数在DX中
位异或命令xor
还有跳转命令jmp
全部代码:
;代码清单5-1;文件名:c05_mbr.asm;文件说明:硬盘主引导扇区代码;创建日期:2011-3-31 21:15mov ax,0xb800 ;指向文本模式的显示缓冲区mov es,ax ;因为立即数不能字节传入段寄存器;以下显示字符串"Label offset:"mov byte [es:0x00],'L'mov byte [es:0x01],0x07mov byte [es:0x02],'a'mov byte [es:0x03],0x07mov byte [es:0x04],'b'mov byte [es:0x05],0x07mov byte [es:0x06],'e'mov byte [es:0x07],0x07mov byte [es:0x08],'l'mov byte [es:0x09],0x07mov byte [es:0x0a],' 'mov byte [es:0x0b],0x07mov byte [es:0x0c],"o"mov byte [es:0x0d],0x07mov byte [es:0x0e],'f'mov byte [es:0x0f],0x07mov byte [es:0x10],'f'mov byte [es:0x11],0x07mov byte [es:0x12],'s'mov byte [es:0x13],0x07mov byte [es:0x14],'e'mov byte [es:0x15],0x07mov byte [es:0x16],'t'mov byte [es:0x17],0x07mov byte [es:0x18],':'mov byte [es:0x19],0x07;这前面的代码显示"Label offset:";下面的代码是以十进制显示number的偏移地址mov ax,number ;取得标号number的偏移地址mov bx,10 ;用来进行运算,取各位的数;设置数据段的基地址mov cx,cs ;将代码段的地址传入数据段mov ds,cx;求个位上的数字mov dx,0 ;dx=0,表示是32位/16位的情况div bx ;标号number的偏移地址除以10mov [0x7c00+number+0x00],dl ;保存个位上的数字;求十位上的数字xor dx,dxdiv bxmov [0x7c00+number+0x01],dl ;保存十位上的数字;求百位上的数字xor dx,dxdiv bxmov [0x7c00+number+0x02],dl ;保存百位上的数字;求千位上的数字xor dx,dxdiv bxmov [0x7c00+number+0x03],dl ;保存千位上的数字;求万位上的数字xor dx,dxdiv bxmov [0x7c00+number+0x04],dl ;保存万位上的数字;以下用十进制显示标号的偏移地址mov al,[0x7c00+number+0x04]add al,0x30mov [es:0x1a],almov byte [es:0x1b],0x04mov al,[0x7c00+number+0x03]add al,0x30mov [es:0x1c],almov byte [es:0x1d],0x04mov al,[0x7c00+number+0x02]add al,0x30mov [es:0x1e],almov byte [es:0x1f],0x04mov al,[0x7c00+number+0x01]add al,0x30mov [es:0x20],almov byte [es:0x21],0x04mov al,[0x7c00+number+0x00]add al,0x30mov [es:0x22],almov byte [es:0x23],0x04mov byte [es:0x24],'D'mov byte [es:0x25],0x07infi: jmp near infi ;无限循环,jum跳转命令,后面接偏移地址,直接跳转,如果有near,跳转到相对于当前命令地址的偏移地址number db 0,0,0,0,0 ;用于占位(5个字节),位置用来保存各位的值times 203 db 0 ;把第一扇区空闲位填0db 0x55,0xaa ;检查的扇区的标志位
第六章 相同的功能,不同的代码
数据区数据写在前面,用跳转命令跳转到真正的执行代码处
数据声明时使用字面值
div是无符号数除法指令,有符号的应该用idiv
用idiv时需要注意不能溢出,如果需要把被除数扩展成32bit,用cwd命令
