1 x86 assembly machine-code opcode instruction-encoding
我正在编写一个 x86-64 汇编程序。我正在浏览 Intel x86 手册第 2 卷,试图了解如何从程序集中生成正确的指令。我主要了解它是如何工作的,但一直在组装和拆卸说明以检查我是否正确。
在 ADD 参考表(第 2A 卷,3.31)中:
opcode | Instruction
04 ib | ADD AL, imm8
05 iw | ADD AX, imm16
05 id | ADD EAX, imm32
REX.W + 05 id | ADD RAX, imm32
Run Code Online (Sandbox Code Playgroud)
集合:
;add.s
add al, 1
add ax, 1
add eax, 1
add rax, 1
Run Code Online (Sandbox Code Playgroud)
拆卸:
.text:
0: 04 01 add al, 1
2: 66 83 c0 01 add ax, 1
6: 83 c0 01 add eax, 1
9: 48 83 c0 01 add rax, 1
Run Code Online (Sandbox Code Playgroud)
所以第一个是正确的,就像手册所说的那样,但是汇编器使用 ADD 参考表下面的指令,比如 REX 前缀,为什么要使用这些指令而不是我之前列出的指令呢?
现在是第二个ADD ax, 1;搜索后,我发现这66是操作数大小覆盖前缀,但未在 ADD 参考表中列出,因此我何时选择添加此前缀,我似乎无法找到有关它或 Intel 中其他旧前缀的太多信息手动的?
我尝试按照手册中所示反汇编 05 01,但它没有将其识别为操作码,而只是数字。英特尔手册是一个很好的资源,我认为它只是缺少一些额外的解释和结构,仍然试图让我了解 ModRM 的内容。
| 操作码 | 操作说明 | 描述 |
|---|---|---|
REX.W + 05 id |
ADD RAX, imm32 |
将 imm32 符号扩展为 64 位添加到 RAX。 |
REX.W + 81 /0 id |
ADD r/m64, imm32 |
将 imm32 符号扩展为 64 位添加到 r/m64。 |
REX.W + 83 /0 ib |
ADD r/m64, imm8 |
将符号扩展 imm8 添加到 r/m64。 |
因为01适合一个字节,所以汇编器使用操作码83来节省指令长度。如果您尝试add rax, 100000000或类似的操作,您将获得操作码05
现在,要强制进行另一种解码而不是更有效的解码,您需要在汇编器中定义一些语法。例如 nasm 使用strict关键字
Run Code Online (Sandbox Code Playgroud)mov eax, 1 ; 5 bytes to encode (B8 imm32) mov rax, strict dword 1 ; 7 bytes: REX mov r/m64, sign-extended-imm32. NASM optimizes mov rax,1 to the 5B version, but dword or strict dword stops it for some reason mov rax, strict qword 1 ; 10 bytes
现在,如果你仔细观察表格,你可能会发现一些“奇怪”的东西
| 操作码 | 操作说明 | 描述 |
|---|---|---|
05 iw |
ADD AX, imm16 |
将 imm16 添加到 AX。 |
05 id |
ADD EAX, imm32 |
将 imm32 添加到 EAX。 |
81 /0 iw |
ADD r/m16, imm16 |
将 imm16 添加到 r/m16。 |
81 /0 id |
ADD r/m32, imm32 |
将 imm32 添加到 r/m32。 |
01 /r |
ADD r/m16, r16 |
将 r16 添加到 r/m16。 |
01 /r |
ADD r/m32, r32 |
将 r32 添加到 r/m32。 |
03 /r |
ADD r16, r/m16 |
将 r/m16 添加到 r16。 |
03 /r |
ADD r32, r/m32 |
将 r/m32 添加到 r32。 |
为什么同一条指令的所有 16 位和 32 位版本都具有相同的操作码?
答案是当前模式将定义指令类型。如果您在 16 位模式下运行,则默认情况下将使用 16 位寄存器,如果您在 32 或 64 位模式下运行,则默认大小将为 32 位。如果您想使用其他大小,则必须使用66h (操作数大小覆盖)前缀。这意味着在 16 位模式下,您将得到以下输出,而不是上面看到的输出
83 c0 01 add ax, 1
66 83 c0 01 add eax, 1
Run Code Online (Sandbox Code Playgroud)
我尝试按照手册中所示反汇编 05 01,但它没有将其识别为操作码,只是数字
因为05后面必须跟一个 4 字节立即数(id/imm32如手册中所示)或 2 字节立即数 ( iw/imm16),具体取决于默认操作数大小。只有 的指令imm8/ib才能有单字节立即数。例如,在线反汇编程序给出以下输出:
0: 05 01 02 03 04 add eax,0x4030201
5: 66 05 01 02 add ax,0x201
Run Code Online (Sandbox Code Playgroud)
出于与上面相同的原因,选择操作码 83h 是因为 0x01 适合一个字节,使得长度相同,并且汇编器可以选择它喜欢的任何内容
0: 66 83 c0 01 add ax,0x1
4: 66 05 01 00 add ax,0x1
Run Code Online (Sandbox Code Playgroud)
您可能想阅读此内容
| 归档时间: |
|
| 查看次数: |
1372 次 |
| 最近记录: |