8. immediate 值
immediate 部分为指令提供一个 immediate operand。
immediate 寻址分为两种:需要 ModRM 字节引导和直接嵌在 opcode 中。
但是: ModRM 字节本身是不提供 immediate 寻址的,这个 ModRM 字节除了提供 register 和 memory 寻址外,只是起了对 Opcode 进行补充的作用,即:这个 Opcode 是一个 Group Opcode 而 immediate 实际上还是嵌在 Opcode 中。 |
1、使用 immediate 的方式
上面已经说了,提供 immediate 的方式为:
(1)operand 寻址在 opcode 中嵌入,即:encode 中直接提供 immediate 值
这一类指令很多,也很常用,如:call/jmp,mov/push 等等..
例:指令 mov al, 1
它的 encode 是:b0 01 这种就是典型的指令,operand 寻址方式是嵌在 opcode 中的。
(2)operand 寻址需要 ModRM 引导
基于这种寻址方式,可肯定这个 opcode 是 Group 属性的 opcode
★ ModRM.reg 对 opcode 进行补充确定,而 ModRM.r/m 是提供 register 或者 memory 寻址。
例: 指令 mov dword ptr [eax], 1
这条指令的 opcode 就是典型的 Group 属性的 opcode,它的 目的操作数(first operand)是 memory,源操作数(second operand) 是 immediate。
它的最终 encode 是: c7 00 01 00 00 00
它的 ModRM 字节中:ModRM.reg = 000 是确定 C7 opcode,ModRM.r/m 提供对 [eax] 的寻址,immediate 部分是 01 00 00 00
同样 immediate 也分 singed(符号数) 与 unsigned(无符号数)情况
(1)immediate 是 signed(符号数)
★ immediate 用于算术运算时:它是 signed(符号数),当 immediate 小于 operand size 时,它被 sign-extended(符号扩展)到 operand size 大小。
★ immediate 是基于 rip 寄存器的偏移时:它是 signed(符号数)。同样会被做 sign-extended(符号扩展)处理。
★ immediate 被 push 入 stack 时:它是 signed(符号数)。同样会被做 sign-extended(符号扩展)处理。
add rax, 0xf3 |
这条指令的 immediate 是 8 位,它的其中一种编码是: 48 83 c0 f3
它的 immediate 是 0xf3 只有 1 byte,因此 0xf3 会被符号扩展到 64位数 0xffffffff_fffffff3 然后与 rax 相加。
jmp $ |
指令中 $ 代表当前指令的位置,这条指令会产生死循环。
它是其中一种编码是: eb fe
它的 immediate 是 0xfe,只有 1 byte 因此,它也会被 sign-extended 为 64 位 0xffffffff_fffffffe(假设当前为 64 位),然后与 rip 相加得出新的 rip 值。
push 0xf3 |
这是一条 push 指令,immediate 是 0xf3,它的编码为:6a f3
同样 immediate 0xf3 会被符号扩展为 64 位 0xffffffff_fffffff3(假设当前为 64 位),然后入栈。
3、immediate 的长度
在 64 位下:immediate 可为 8 位、16 位、32 位以及 64 位
与 displacement 情形一样,immediate 只有少数指令才能使用 64 位的 immediate
关于 displacement 这方面的论述,详见:displacement 的长度
指令 |
编码 |
说明 |
mov al, 1 |
b0 01 |
8 位 immediate |
mov ax, 1 |
66 b8 01 00 |
使用 operand size override 达到 16 位 immediate |
mov eax, 1 |
b8 01 00 00 00 |
32 位 immediate |
mov rax, 1 |
48 b8 01 00 00 00 00 00 00 00 |
使用 REX prefix 达到 64 位 immediate |
上表是在 64 位模式下,使用 4 种 immediate 长度的示例
3.1 使用 64 位的 immediate 值
只有当 immediate 操作数的属性是 Iv 的情形下,immediate 才可能有 64 位。
x64 体系中规定,只有在将 immediate 赋给 GPRs 时,才能使用 64 位的 immediate
这种情况下,immediate operand 的属性是 Iv,表示可以使用 64 位的 effective operand size
mov rax, 0x1122334455667788 |
这条指令是正确的,它的 encode 是:48 b8 88 77 66 55 44 33 22 11
这条指令形式是:MOV rAX, Iv,因此,immediate 是可以使用 64 位的 immediate 值
而像这条指令: mov qword ptr [rax], 0x112233445566778 是不正确的,编译器要么将 immediate 截断为 32 位,要么提示出错。
3.2 使用 64 位的 immediate 值的本质(具有 Iv 属性的本质)
immediate operand 只有具有 Iv 属性时,才可以使用 64 位的 immediate 值,与 displacement 情形一样,同样须有两个前提:
★ operand 不依赖于 ModRM 寻址,换句说说:operand 是嵌在 Opcode 里的。
★ 使用 64 位 displacement 第 2 个前提条件是:指令长度不能超过 15 bytes
例子: mov qword ptr [rax + rcx * 8 + 0x11223344], 0x12345678
这个例子是前面多次提到过,它的 encode 是:48 c7 84 c8 44 33 22 11 78 56 34 12 (共 12 个 bytes)
同样,如果使用 64 位 immediate 指令长度超过了 15 bytes。
实际上,这条指令中,opcode 指示它的 immediate operand 属性是 Iz 也就是:immediate 要 signed-extended 到 64 位
关于 64 位的限制,参见:x64 体系 64 位下的 displacement
mik(deng zhi)写于 2008-11-26 15:40