23、指令的格式及其操作尺寸


上一节:22、进入保护模式
下一节:24、存储器的保护

01、80286的16位保护模式

80286的寄存器:
在这里插入图片描述
80286存储器的段描述符格式:
在这里插入图片描述
80286段寄存器:分为段选择器描述符高速缓存器
在这里插入图片描述
80286保护模式下访问段的步骤:
在这里插入图片描述
在这里插入图片描述
可以看出虽然段最大之后64K字节,但是因为基地址是24位的且可以任意选择,所以不影响80286访问全部的2^24 = 16777216 = 16MB字节内存。

80286在是实模式和保护模式下都只能使用8位或者16位的操作数,而且地址中的偏移量只有16位,所以80286的保护模式又叫做16位的保护模式。

02、16位处理器的指令操作尺寸

指令的操作尺寸:
在这里插入图片描述
8086的指令操作尺寸:8位、16位
在这里插入图片描述
80286的指令操作尺寸:
在这里插入图片描述
其中描述符高速缓存器中的基地址在实模式和保护模式下是不同的:
实模式:是将段地址左移4位得到;
保护模式:来自段描述符,当初将段选择子带入段寄存器中,处理器使用段选择子从描述符表中的对应的描述符中取出的。

在这里插入图片描述

03、32位处理器的指令操作尺寸

指令的操作尺寸,操作数为8位、16位、32位;有效地址为16位、32位。
在这里插入图片描述
其中描述符高速缓存器中的基地址在实模式和保护模式下是不同的:
实模式:是将段地址左移4位得到,其中还有段界限为0xFFFF,保证在实模式下访问正确的内存;
保护模式:来自段描述符,当初将段选择子带入段寄存器中,处理器使用段选择子从描述符表中的对应的描述符中取出的。

04、x86的指令格式–操作码和立即数部分

操作码:
在这里插入图片描述
在这里插入图片描述
操作码相关资料:指令集参考第二卷。
在这里插入图片描述
计算下面3条指令的机器码:
在这里插入图片描述
1、计算指令mov al, 3的机器码B003
在这里插入图片描述
其中:rb表示长度为1个字节的寄存器,在这条指令中只有一个寄存器r8,即rb就是r8,此条指令中r8就是寄存器AL。即B0 + AL的编号AL的编号如下:
在这里插入图片描述
那么这条指令的操作码就是B0 + 0 = B0,立即数是8位的03,即操作码就是B003

2、计算指令mov cx, 3的机器码B90300
在这里插入图片描述
其中:rw表示长度为2个字节的寄存器,在这条指令中只有一个寄存器r16,即rb就是r16,此条指令中r16就是寄存器CX。即B0 + CX的编号CX的编号如下:
在这里插入图片描述
那么这条指令的操作码就是B0 + 1 = B9,立即数是16位的0003,即操作码就是B90300(按照低端字节序存放)。

3、计算指令mov edx, 3的机器码BA0300000
在这里插入图片描述
其中:rd表示长度为4个字节的寄存器,在这条指令中只有一个寄存器r32,即rb就是r32,此条指令中r32就是寄存器EDX。即B0 + EDX的编号EDX的编号如下:
在这里插入图片描述
那么这条指令的操作码就是B0 + 2 = BA,立即数是32位的00000003,即操作码就是BA03000000(按照低端字节序存放)。

05、x86的指令格式–ModR/M和偏移量部分

在这里插入图片描述
ModR/M字段的组成:1个字节。
在这里插入图片描述
16位寻址方式的ModR/M方式,还有32位的。
在这里插入图片描述
计算下面3条指令的机器码:
在这里插入图片描述
1、计算指令mov al, cl的机器码88C8
在这里插入图片描述
其中:操作码是88
其中:/r表示指令中的纯寄存器操作数,在这里就是右操作数r8/是指操作码的扩展,需要将这个/r中的寄存器r的编号添加在ModR/M的中间部分,就是reg/opcode。这条指令的右操作数是CL,编号如下为001reg/opcode001
/r就可以看出只要是操作码的后边有斜杠'/',这条指令一定有ModR/M字段。
在这里插入图片描述
其中:Mod如下为11,对应寄存器寻址,左操作数是ALR/M位是000
在这里插入图片描述
那么这条指令由上述各位组合而成:因此这条指令的机器码就是88C8

操作码modregr/mModR/M
8811001000C8

2、计算指令mov ax, [bx]的机器码8B07
在这里插入图片描述
其中:操作码是8B
其中:/r表示指令中的纯寄存器操作数,在这里就是左操作数r16/是指操作码的扩展,需要将这个/r中的寄存器r的编号添加在ModR/M的中间部分,就是reg/opcode。这条指令的左操作数是AX,编号如下为000reg/opcode000
/r就可以看出只要是操作码的后边有斜杠'/',这条指令一定有ModR/M字段。
在这里插入图片描述
其中:Mod如下为00,对应地址寻址,右操作数是[BX]R/M位是111
在这里插入图片描述
那么这条指令由上述各位组合而成:因此这条指令的机器码就是8B07

操作码modregr/mModR/M
8B0000011107

3、计算指令mov cx, [bx+si]的机器码8B08
在这里插入图片描述
其中:操作码是8B
其中:/r表示指令中的纯寄存器操作数,在这里就是左操作数r16/是指操作码的扩展,需要将这个/r中的寄存器r的编号添加在ModR/M的中间部分,就是reg/opcode。这条指令的左操作数是CX,编号如下为001reg/opcode001
/r就可以看出只要是操作码的后边有斜杠'/',这条指令一定有ModR/M字段。
在这里插入图片描述
其中:Mod如下为00,对应地址寻址,右操作数是[BX+SI]R/M位是000
在这里插入图片描述
那么这条指令由上述各位组合而成:因此这条指令的机器码就是8B08

操作码modregr/mModR/M
8B0000100008

上述计算过程中可通过快速定位计算出ModR/M的数值,如第3条指令mov cx, [bx+si],左操作数CL、右操作数[BX+SI],定位机器码是08,即得到机器码8B08
在这里插入图片描述
ModR/M后面还可以有偏移量和立即数部分。
在这里插入图片描述
计算下面两条指令的机器码:
在这里插入图片描述
4、计算指令mov ax, [bx+3]的机器码8B4703
在这里插入图片描述
其中:操作码是8B
其中:/r表示指令中的纯寄存器操作数,在这里就是左操作数r16/是指操作码的扩展,需要将这个/r中的寄存器r的编号添加在ModR/M的中间部分,就是reg/opcode。这条指令的左操作数是AX,编号如下为000reg/opcode000
/r就可以看出只要是操作码的后边有斜杠'/',这条指令一定有ModR/M字段。
在这里插入图片描述
其中:Mod如下为01,对应地址寻址+偏移量,右操作数是[BX]R/M位是111
在这里插入图片描述
那么这条指令由上述各位组合而成:因此这条指令的机器码就是8B4703

操作码modregr/mModR/M偏移量
8B010001114703

5、计算指令mov word [bx+si+3], 0x55AA的机器码C74003AA55
在这里插入图片描述
其中:操作码是C7
其中:/0表示指令中的纯寄存器操作数,在这里就是左操作数r16/是指操作码的扩展,就是reg/opcode。将这个0扩展成3位既为000reg/opcode000

其中:Mod如下为01,对应地址寻址+偏移量,R/M位是000
在这里插入图片描述
那么这条指令由上述各位组合而成:因此这条指令的机器码就是C74003AA55

操作码modregr/mModR/M偏移量立即数
C7010000004003AA55

06、x86指令格式–SIB部分

在这里插入图片描述
在这里插入图片描述
SIB字段的格式:
在这里插入图片描述
在这里插入图片描述
1、计算指令add edx, [eax+ebx*2]的机器码031458
在这里插入图片描述
其中:操作码是03
其中:/r表示指令中的纯寄存器操作数,在这里就是左操作数r32/是指操作码的扩展,需要将这个/r中的寄存器r的编号添加在ModR/M的中间部分,就是reg/opcode。这条指令的左操作数是EDX,编号如下为010reg/opcode010
/r就可以看出只要是操作码的后边有斜杠'/',这条指令一定有ModR/M字段。
在这里插入图片描述
其中:Mod如下为00,对应地址寻址,R/M位是100
在这里插入图片描述
上面有一个注释1:表示有SIB字段
在这里插入图片描述
其中SIB的基址寄存器(Base)为EAX000
在这里插入图片描述
其中SIB的寻址方式是EBX*2,则SS01Index011
在这里插入图片描述
那么这条指令由上述各位组合而成:因此这条指令的机器码就是031458

操作码modregr/mModR/MssIndexBaseSIB
0300010100140101100058

若指令比较复杂,如:对于32为寻址方式来说偏移量是1、4个字节,即对应8、32位偏移量。
在这里插入图片描述
计算下面这条指令的机器码:
在这里插入图片描述
2、计算指令add word [eax+ebx*8+0x3c00], 0x55AA的机器码8184D8003C0000AA55
在这里插入图片描述
其中:操作码是81
其中:/0表示是操作码的扩展,这个数字0要转换成3位000添加在ModR/M的中间部分,就是reg/opcodereg/opcode010。从/r就可以看出只要是操作码的后边有斜杠'/',这条指令一定有ModR/M字段。
其中:iw(imm word长度为字的立即数),这里就是指令中的右操作数imm16
其中:Mod如下为10,对应地址寻址,R/M位是100
在这里插入图片描述
其中SIB的基址寄存器(Base)为EAX000
在这里插入图片描述
其中SIB的寻址方式是EBX*8,则SS11Index011
在这里插入图片描述
那么这条指令由上述各位组合而成:因此这条指令的机器码就是8184D8003C0000AA55

操作码modregr/mModR/MssIndexBaseSIB偏移量立即数
81100001008411011000D8003C0000AA55

07、x86指令格式–指令前缀部分

指令前缀:段超越前缀、总线封锁前缀、数据传送指令的重复前缀、操作尺寸反转前缀、地址尺寸反转前缀等等。指令最多有4个前缀
在这里插入图片描述
在这里插入图片描述
课后练习:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

08、处理器默认操作尺寸和相关指令前缀

07小节课后习题答案:
在这里插入图片描述
之前讲过的操作尺寸:
在这里插入图片描述
16位、32位操作尺寸:
在这里插入图片描述
默认操作尺寸:
在这里插入图片描述
所以上节习题中:

1、默认操作尺寸16位时:
在这里插入图片描述
2、默认操作尺寸32位时:
在这里插入图片描述
其中前缀66将反转操作数的尺寸,从默认的是16位反转成32位
其中前缀67将反转有效地址的尺寸,从默认的是16位反转成32位

09、使用伪指令bits生成16位和32位模块

相同机器指令对应不同汇编指令
在这里插入图片描述
相同机汇编指令对应不同机器指令
在这里插入图片描述
代码如下:

	bits 16		;也可写为[bits 16],若为第一条[bits 16]指令也可省略;
				;因为默认使用[bits 16]编译程序
	mov ax, [bx+si]
	
	bits 32		;也可写为[bits 32]
	mov ax, [bx+si]

编译器编译之后的机器码:
在这里插入图片描述

10、描述符和段描述符高速缓存器的D位

描述符的D/B位,对于代码段,即S=1、X=1来说,此位为D为0表示16位操作尺寸、为1表示32位操作尺寸。
在这里插入图片描述
如使用CS段选择子选择一个描述符到描述符高速缓存器中,会有一个D位,就是描述符中的D位,处理器就根据这个D位来判断当前的默认操作尺寸。

当程序加电复位时,处理器默认是16位的操作尺寸:
在这里插入图片描述
设置断点b 0x7c00c命令执行到此处,查看CSD位:仍然是0,既16位操作尺寸。
在这里插入图片描述
n/s命令单步执行,进入保护模式,查看CSD位,仍然是0,既16位操作尺寸。
在这里插入图片描述
其中CS的状态:
在这里插入图片描述
其中X=0表示不可执行,即数据段,段类型的检查是在将一个描述符加载到段描述符高速缓存器时进行的,主要是看它的类型是否与段寄存器的类型匹配,因为代码段/数据段寄存器只能加载代码段/数据段描述符。然而在平时读取指令时段的类型是不检查的。

11、进入保护模式并切换到32位模块使用32位默认操作尺寸

安装代码段的描述符:

	;创建#1描述符,保护模式下的代码段描述符
	mov dword [bx+0x08],0x7c0001ff     
	mov dword [bx+0x0c],0x00409800   

在这里插入图片描述

  • 段基地址0x00007C00
  • 段界限0x001FF
  • G位为0表示段界限以字节为单位。所以段大小为0x001FF + 1 = 0x02000 = 512字节
  • S位为1表明是代码段
  • X位为1表明可执行
  • P位为1表明是段是存在的
  • D/B位为1表明是32位的默认操作尺寸

直接绝对远转移指令:

...
	;以下进入保护模式
	jmp 0000000000010_0_00B:flush
	bits 32
	
flush:
	mov cx,00000000000_10_000B		;加载数据段选择子(0x10)
	mov ds,cx
	
	;以下在屏幕上显示"Protect mode OK." 
	mov byte [0x00],'P'  
	mov byte [0x02],'r'
	mov byte [0x04],'o'
...

这时处理器是在16位操作尺寸,所以使用的是IP不是EIP
在这里插入图片描述
在这里插入图片描述
在进入jmp指令之前,有很多指令已经进入了流水线,都是按照之前的16位操作尺寸进行译码的。那么在使用bits 32改变了操作尺寸之后,那些指令都是错误的,但是执行jmp指令会清空流水线,这样程序才不会出错。

调试程序,执行到jmpf指令停下查看寄存器状态:此时操作尺寸都是16位,但是下列汇编中使用了ecx32位寄存器,显然以16位操作尺寸的角度是不正确的。
在这里插入图片描述
执行这条jmpf指令之后,查看寄存器状态:从CS的状态可以看出当前默认操作尺寸是32位的。
在这里插入图片描述
那么再以32位操作尺寸的角度看之后的指令:就和程序中是一样的了。
在这里插入图片描述
上一节:22、进入保护模式
下一节:24、存储器的保护

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

「已注销」

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值