4_地址计算指令与其它-1

地址计算指令与其他-1

刚才说了两种寻址方式, 现在讲第三种方式

变址寻址

常见形式

D(RB, Ri, S) Mem[Reg[Rb] + S*Reg[Ri] + D]

D : Displacement 常量 (地址偏移量)
Rb : 基址寄存器 : 8 个通用寄存器之一
Ri : 索引寄存器 : %esp 不作为索引寄存器, 一般 %ebp 也不用作这个用途
S : Scale 比例因子 1, 2, 4, or 8

我把这个基址, 加上你的索引*scale, 这个 scale 是 1 2 4 8, 这个算出来之后, 再加上一个常量的地址偏移.

这个实际上很像 C 里面访问的数组. 数组可以想象, 数组应该有一个开始的一个地址, 可以把它放在寄存器里面, 访问的时候是用 index, 可以想象把这个 index 放到 index 寄存器里面去, 然后再乘上 sizeof(每个数组元素的宽度, 一般来说 1 2 4 8 够用了), 最后加一个总的偏移量.

变址寻址模式, 用的时候可以漏掉一些, 可以两个要素, 甚至一个要素 :

其他变形 :
(Rb, Ri) Mem[Reg[Rb] + Reg[Ri]]
D(Rb, Ri) Mem[Reg[Rb] + Reg[Ri] + D]
(Rb, Ri, S) Mem[Reg[Rb] + S*Reg[Ri]]

反正总的算法是 index 乘上你的 scale, 再加上基址, 再加上 displacement

寻址模式实例

初始值 : %edx = 0xF000; %ecx = 0x100

Expression 表达式 Computation 运算 Address 最终地址
0x8(%edx) 0xF000 + 0x8 0xF008
(%edx, %ecx) 0xF000 + 0x100 0xF100
(%edx, %ecx, 4) 0xF000 + 4 * 0x100 0xF400
0x80 (, %edx, 2) 2 * 0xF000 + 0x80 0x1E080

第一行 0x8 括号里面是个 edx, 就是把 edx 的值取出来, 加上 displacement.

第二个是括号里面是两个寄存器, 那反正是把这两个寄存器加起来的和作为地址.

第三个括号里面三个参数, 就是 edx 作为基址, ecx 是作为 index 乘上 4 (就是 Scale), 乘完之后再加 edx

最后一个, 括号里面第一个漏掉了, 没有基址这是可以的, 然后就是 edx 乘 2, 再加上括号外面的 D 0x80

地址计算指令

讲完了 mov 指令, 接下来就是地址计算指令

leal Src, Dest

计算出来的地址赋给 Dest

l 后缀就是, 我算的目的操作数是双字类型

注意, Src 是地址计算表达式. 地址计算表达式就是刚才变址寻址的式子.

Destination 一般来说是个寄存器.

它和 mov 很像, 但是有本质的不同. mov 指令如果你的 Src 是地址表达式的话, 它是把这个算出来地址, 这个地址里面的内容取出来再移动过去. 而 leal 很简单, 我算出来的这个地址, 就是我所需要的东西, 算完之后这个地址本身, 给挪到 Destination 里面去.

它的一大用途就是地址计算, 但是不访问内存

它还可以完成 x + k * y 这一种类型的整数计算. 这里面 x 和 y 可以是寄存器, 也就是说 x y 是可变的. 如果你能把一个整数计算表达成这种形式的话, 那么可以用 leal 指令很方便地进行计算. 这个比你单独地用加减乘除指令计算要快.

整数计算指令

  • 双操作数指令

加减乘

指令格式 计算过程
addl Src, Dest Dest = Dest + Src
subl Src, Dest Dest = Dest - Src
imull Src, Dest Dest = Dest * Src

稍微说下 32 位乘法, 注意看, 这里面加减乘, 乘法是只取 32 位结果的, 因为它是 l 没有说取到 64 位结果.

在这种情况下, 加减乘实际上不区分它们操作数的类型是带符号或者不带符号.

指令格式 计算过程
sall Src, Dest Dest = Dest << Src 与 shll 等价, 数据左移
sarl Src, Dest Dest = Dest >> Src 数据的算术右移
shrl Src, Dest Dest = Dest >> Src 数据的逻辑右移

算术右移与逻辑右移不一样的地方在于, 因为你数据整个往右挪动了, 你高位得把别的数据补充进来. 补什么呢, 逻辑右移就是单纯地补充 0, 算术右移就是补充被移动数据的最高位, 就是符号位.

指令格式 计算过程
xorl Src, Dest Dest = Dest ^ Src
andl Src, Dest Dest = Dest & Src
orl Src, Dest Dest = Dest | Src

这些就是一些逻辑操作了

  • 单操作数指令
指令格式 计算过程
incl Dest Dest = Dest + 1 加
decl Dest Dest = Dest -1 减
negl Dest Dest = - Dest 取非
notl Dest Dest = ~ Dest 取反