汇编语言:基于x86处理器-学习笔记-第七章

《汇编语言:基于x86处理器(原书第7版)》
第七章学习笔记

移位和循环移位指令

《汇编语言:基于x86处理器(原书第7版)》Page 192

移动操作数的位有两种方法。

  • 第一种是逻辑移位 (logic shift),空出来的位用 0 填充。如下图所示,一个字节的数据向右移动一位。也就是说,每一位都被移动到其旁边的低位上。
  • 另一种移位的方法是算术移位 (arithmetic shift),空出来的位用原数据的符号位填充。

SHL 指令

逻辑左移。SHL 的第一个操作数是目的操作数,第二个操作数是移位次数:

$$ SHL \space \space destination,count $$ 该指令可用的操作数类型如下所示:
1
2
3
4
SHL reg, imm8
SHL mem, imm8
SHL reg, CL
SHL mem, CL

x86处理器允许 imm8 为 0~255 中的任何整数。另外,CL 寄存器包含的是移位计数。上述格式同样适用于 SHR、SAL、SAR、ROR、ROL、RCR 和 RCL 指令。

SHR 指令

逻辑右移。SHR 的指令格式与 SHL 相同。

SAL 和 SAR 指令

SAL(算术左移)指令的操作与SHL指令一样。

每次移动时,SAL 都将目的操作数中的每一位移动到下一个最高位上。最低位用0填充;最高位移入进位标志位,该标志位原来的值被丢弃:

SAR 指令为算术右移,指令格式与 SHL 相同。

ROL 指令

以循环方式来移位即为位元循环 (Bitwise Rotation)。一些操作中,从数的一端移出的位立即复制到该数的另一端。还有一种类型则是把进位标志位当作移动位的中间点。

ROL(循环左移)指令把所有位都向左移。最高位复制到进位标志位和最低位。该指令格式与 SHL 指令相同:

image-20230102212019795

位循环不会丢弃位。从数的一端循环出去的位会出现在该数的另一端。

特点

  1. 当循环计数值大于 1 时,进位标志位保存的是最后循环移出 MSB 的位。
  2. 位组交换利用 ROL 可以交换一个字节的高四位(位 4~7)和低四位(位 0~3)。例如,26h 向任何方向循环移动 4 位就变为 62h。当多字节整数以四位为单位进行循环移位时,其效果相当于一次向右或向左移动一个十六进制位。例如,将 6A4Bh 反复循环左移四位,最后就会回到初始值。

ROR 指令

ROR(循环右移)指令把所有位都向右移,最低位复制到进位标志位和最高位。该指令格式与 SHL 指令相同。

当循环计数值大于 1 时,进位标志位保存的是最后循环移出 LSB 的位。

RCL 和 RCR 指令

RCL(带进位循环左移)指令把每一位都向左移,进位标志位复制到 LSB,而 MSB 复制到进位标志位:

RCR(带进位循环右移)指令把每一位都向右移,进位标志位复制到 MSB,而 LSB 复制到进位标志位:

SHLD 和 SHRD 指令

SHLD(双精度左移)指令将目的操作数向左移动指定位数。移动形成的空位由源操作数的高位填充。源操作数不变,但是符号标志位、零标志位、辅助进位标志位、奇偶标志位和进位标志位会受影响:
$$
SHLD \space \space dest, source, count
$$
下图展示的是 SHLD 执行移动一位的过程。源操作数的最高位复制到目的操作数的最低位上。目的操作数的所有位都向左移动:

SHRD(双精度右移)指令将目的操作数向右移动指定位数。移动形成的空位由源操作数的低位填充:

SHLD 和 SHRD 的指令格式中,目标操作数可以是寄存器或内存操作数;源操作数必须是寄存器;移位次数可以是 CL 寄存器或者 8 位立即数。

程序示例

《汇编语言:基于x86处理器(原书第7版)》Page 200


乘法和除法指令

《汇编语言:基于x86处理器(原书第7版)》Page 201

MUL 指令

32位模式下,MUL(无符号数乘法)指令有三种类型:

  • 第一种执行 8 位操作数与 AL 寄存器的乘法
  • 第二种执行16位操作数与 AX 寄存器的乘法
  • 第三种执行 32 位操作数与 EAX 寄存器的乘法

乘数和被乘数的大小必须保持一致,乘积的大小则是它们的一倍。这三种类型都可以使用寄存器和内存操作数,但不能使用立即数。

1
2
3
MUL reg/mem8
MUL reg/mem16
MUL reg/mem32

MUL 指令中的单操作数是乘数。下图按照乘数的大小,列出了默认的被乘数和乘积。

由于目的操作数是被乘数和乘数大小的两倍,因此不会发生溢出

如果乘积的高半部分不为零,则 MUL 会把进位标志位和溢出标志位置 1。因为进位标志位常常用于无符号数的算术运算。

例如,当 AX 乘以一个 16 位操作数时,乘积存放在 DX 和 AX 寄存器对中。其中,乘积的高 16 位存放在 DX,低 16 位存放在 AX。如果 DX 不等于零,则进位标志位置 1,这就意味着隐含的目的操作数的低半部分容纳不了整个乘积。

IMUL 指令

IMUL(有符号数乘法)指令执行有符号整数乘法。与 MUL 指令不同,IMUL 会保留乘积的符号,实现的方法是,将乘积低半部分的最高位符号扩展到高半部分。x86指令集支持三种格式的 IMUL 指令:单操作数、双操作数和三操作数。

单操作数格式

单操作数格式中,乘数和被乘数大小相同,而乘积的大小是它们的两倍。单操作数格式将乘积存放在 AX、DX:AX 或 EDX: EAX 中:

和 MUL 指令一样,其乘积的存储大小使得溢出不会发生。同时,如果乘积的高半部分不是其低半部分的符号扩展,则进位标志位和溢出标志位置1。利用这个特点可以决定是否忽略乘积的高半部分。

双操作数格式(32位模式)

32 位模式中的双操作数 IMUL 指令把乘积存放在第一个操作数中,这个操作数必须是寄存器。第二个操作数(乘数)可以是寄存器、内存操作数和立即数。
$$
IMUL \space \space reg, \space reg/mem/imm
$$
双操作数格式会按照目的操作数的大小来截取乘积。如果被丢弃的是有效位则溢出标志位和进位标志位置 1。因此,在执行了有两个操作数的 IMUL 操作后,必须检查这些标志位中的一个。

三操作数格式

32 位模式下的三操作数格式将乘积保存在第一个操作数中。第二个操作数可以是16位寄存器或内存操作数,它与第三个操作数相乘,该操作数是一个8位或16位立即数。
$$
IMUL \space \space reg, \space reg/mem, \space imm
$$
IMUL 执行时,若乘积有效位被丢弃,则溢出标志位和进位标志位置 1。因此,在执行了有三个操作数的 IMUL 操作后,必须检查这些标志位中的一个。

DIV 指令

32 位模式下,DIV(无符号除法)指令执行 8 位、16 位和 32 位无符号数除法。其中,单寄存器或内存操作数是除数。格式如下:
$$
DIV\space\space reg/mem
$$
下图给出了被除数、除数、商和余数之间的关系:

64 位模式下,DIV 指令用 RDX:RAX 作被除数,用 64 位寄存器和内存操作数作除数商存放到 RAX,余数存放在 RDX 中。

IDIV 指令

IDIV(有符号除法)指令执行有符号整数除法,其操作数与 DIV 指令相同。执行 8 位除法之前,被除数 (AX) 必须完成符号扩展。余数的符号总是与被除数相同。


扩展加减法

《汇编语言:基于x86处理器(原书第7版)》Page 212

ADC 指令

ADC(带进位加法)指令将源操作数和进位标志位的值都与目的操作数相加。该指令格式与 ADD 指令一样,且操作数大小必须相同:

1
2
3
4
5
ADC reg, reg
ADC mem, reg
ADC reg, mem
ADC mem, imm
ADC reg, imm

程序示例

下面的代码示例调用 Extended_Add,并向其传递两个 8 字节的整数。要注意为和数多分配一个字节:

上述程序的输出,加法产生了一个进位:0122C32B0674BB5736

SBB 指令

SBB(带借位减法)指令从目的操作数中减去源操作数和进位标志位的值。允许使用的操作数与 ADC 指令相同。


汇编语言:基于x86处理器-学习笔记-第七章
https://luoyuy.top/posts/68212001d88c/
作者
LuoYu-Ying
发布于
2023年1月2日
许可协议