不对请指正,欢迎交流
单位换算:
1 Byte = 8 bit
1 KB = 1024 Byte
1 MB = 1024 KB
1 GB = 1024 MB
8位寄存器可以容纳8比特(bit), 或者说1个字节 1byte=8bit,8个二进制数 1111 1111 -> 0xFF
16位寄存器可以存放2个字节,也就是1个字, 从右到左数,其中0~7是低字节,8~15是高字节
32位寄存器可以放4个字节也就是一个双字,其中0~15是低字,16~31是高位
8086内部有8个16位的通用寄存器,分别被命名为AX,BX,CX,DX,SI,DI,BP,SP
其中前四个AX,BX,CX,DX可以各自拆分成两个8位寄存器,总共是8个8为寄存器,分别是AH,AL,BH,BL,CH,CL,DH,DL
高低位关系是
15 8 7 0
---------------------
| AH | AL | AX, AH位于高字节,AL位于底字节
---------------------
8086内部有4个段寄存器,CS是段代码寄存器,DS是数据段寄存器,ES是附加寄存器,SS是栈段寄存器
IP是指令指针寄存器他只和CS一起使用,而且只有处理器才能直接改变他的内容。当一段代码开始执行时,CS指向代码段的起始地址,IP则指向段内偏移,这样CS和IP共同形成的逻辑地址是处理器要执行指令的地址,并且由总线接口部件转换成物理地址来取得指令,然后处理器自动根据当前指令的长度来改变IP的值,使它指向下一条指令的地址偏移。
我们把内存地址在逻辑上进行分段,便于操作,然后在使用"段地址:偏移地址"的方式还对内存进行访问,为了在硬件上提供对"段地址:编译地址"内存访问模式的支持,处理器提供了两个段寄存器,分别是代码段寄存器CS,数据段寄存器DS
CS中存储的段地址是处理器开始执行指令的段地址
DS中存储的段地址是处理器在访问内存是默认的地址,例如,处理器要访问内存地址0001H中的内容,会默认把0001H当作DS段中的偏移地址,如果DS是00FFH,那处理器要访问的物理地址是00FFH:0001H
由于8086处理器提供里20根地址总线,地址范围是 00000H ~ FFFFFH, 但是16位段地址加上16位的偏移地址只能表示16位的物理地址
为了解决这个问题,8086在形成物理地址前,把段地址左移四位,形成20位的段地址,然后加上16位的偏移地址,这样能够表示20位的物理地址了
因为偏移地址是16位的,所以在保证段与段值之间不重叠的情况下,可以分成16个段(因为地址范围最大F FFFFH,一个段偏移最大FFFFH,FFFFFH/FFFFH=FH 也就是10进制的16)
物理地址是82255H,如果段的划分是在段之间不重叠的情况下的,他的内存地址可以表示为是 8000H:2255H
0x1234 ----> 立即数,字面值
[0x1234] ----> 这个是获取地址 "段地址:0x1234"的内容
mov 目的操作数, 源操作数
注意事项:
目的操作数与源操作数的的位数要一致
在目的操作数是段寄存器时,源操作数不能是立即数,但是可以先把立即数放到通用寄存器中,然把通用寄存器的值传送给段寄存器
mov ax, 0x1234
mov ds, ax
如果不想使用默认的ds寄存器,可以指定寄存器进行偏移,例子中指定的是ex段寄存器,这种用法叫做段超越前缀
mov [es:0x00], 0x4c
但是如果只是这么运行还是会出错,因为处理器不知道要操作空间的大小,因为两边都没有指定这条指令是8位的还是16位的,所以要加一个前缀byte
mov byte [es:0x00], 0x4c
关键词byte是用来修饰操作数的,指出本次传送是以字节的方式进行的,还有关键词word,指定是以字进行传输的
汇编地址 tag db 0, 1, 2, 3
在当前汇编地址声明了4个字节的空间,并且进行初始化,其中四个字节里的内容依次是0,1,2,3 ,并且在其他地方使用的时候可是使用tag这个标识代替当前的汇编地址
例如把第二个字节中的内容从1变成2
mov byte [tag+1], 0x02
首先指定本次传送的数的大小byte,指定传送的位置tag+1,然后需要传送的数0x02
db的意思是声明字节,所以他后面的操作数都会占一个字节的长度,如果要声明多个,各个操作数之间必须以逗号隔开
dw用于声明字数据,dd用于声明双字数据(两个字),dq用于声明4字数据
16位的二进制数除以8位的二进制数
被除数必须事前传送到寄存器AX中,指令执行后,商在寄存器AL中,余数在寄存器AH中
mov ax, 0x0023
div byte [0x1234]
32位的二进制数除以16进制的二进制数
被除数的高16位放在DX中,低16位放到AX中,指令执行后,商在AX中,余数在DX中
1 1 ---> 0
1 0 ---> 1
0 0 ---> 0
xr 目的操作数, 源操作数
目的操作数可以是通用寄存器和内存单元,一把来说两个操作数应当具有相同的数据宽度,两个操作数不能同时为内存单元
两种形式,第一个后面跟绝对地址
jmp 0x5000:0xf0c0 ;段地址加偏移地址
直接跳到0x5500:0xf0c0继续执行
jmp near tag ; 相对位置
跳到tag标识处,
两条指令都是跳转,但编译完成的机器码是不一样的,第一条是绝对地址跳转,第二条是相对位置跳转,指令的机器码也不一样
time 100 db 0
重复db 0 指令100次
movsb 传送是以字节为单位的
movsw 传送是以字为单位的
源地址: 段地址+偏移地址 DS是段地址,SI是偏移地址 DS:SI
目的地址:段地址+偏移地址 ES是段地址,DI是偏移地址 ES:DI
传送的颗粒:由使用的movsb(字节)还是movsw(字)决定
传送的次数:CX寄存器中存储传送的次数,每传送一次自动减1
传送方向: 由标志寄存器FLAGS中的DF位来决定,DF为0时,正向传送;DF为1时,反向传送
正向传送:从内存地址的低地址开始传送,低地址端到高地址端,每次传送SI和DI加1或加2(由传送的颗粒决定)
反向传送:从内存的地址高地址开始传送,高地址端到低地址段,每次传送SI和DI减1或减2
设置DF位: cld可以将DF位清零---> 正向传送
std可以将DF位置1----> 反向传送
提示: movsb/movsw执行之前就要把DS,SI,ES,DI,CX,DF位等寄存器和位中的内容设置好,然后直接执行movsb或者movsw,但是单纯的movsb/movsw只是传送一次,如果想需要希望反复执行,请加rep指令前缀
rep指令前缀:如果CX不为0,则重复执行
执行命令 rep movsb/ rep movsw
loop 目的地址
重复执行一段相同代码
将寄存器CX中的内容减一
如果CX的内容不为0,转移到指定的位置处执行,否则顺序执行后面的指令
老样子:CX里的内容提前设置好
inc 目的操作数 ; 将目的操作数加一
dec 目的操作数 ; 将目的操作数减一
用0减去指令中指定的操作数,如果目的操作数不能明确操作的大小可以使用byte或word指定
neg [byte] 目的操作数
cbw:将寄存器AL中的有符号数扩展到整个AX, AL中的数提前设置 8位-->16位
11110001 ----> 11111111 11110001
cwd :将寄存器AX中的有符号数扩展到DX:AX 16位--->32位
sub:减法指令,用法参考add
idiv: 有符号除法,用法参考div