在机器代码中引用寄存器
Referencing registers in machine code
我正在查看一些汇编代码和相应的内存转储,但我无法理解发生了什么。我正在使用 this as reference for opcodes for x86 and this as reference for registers in x86。我 运行 进入了这些命令,我意识到我仍然遗漏了一大块拼图。
8B 45 F8 - mov eax,[ebp-08]
8B 80 78040000 - mov eax,[eax+00000478]
8B 00 - mov eax,[eax]
基本上我不明白操作码后面的两个字节是什么意思,我找不到任何地方可以给出命令的逐位格式(如果任何人都可以指出我将不胜感激)。
CPU如何知道这些命令的长度?
根据我的参考资料,这个 8B mov 命令允许使用 32b 或 16b 寄存器,这意味着有 16 个可能的寄存器(AX、CX、DX、BX、SP、BP、SI、DI 及其扩展等效项).这意味着你需要一个完整的字节来指定在每个操作中使用哪个寄存器运行d.
到目前为止还可以,操作码后面的两个字节可以指定使用哪些寄存器。然后我注意到这些命令在内存中逐字节堆叠,并且所有三个命令都使用不同的字节数来指定在取消引用第二个 ope运行d.
时要使用的偏移量
我想你可以将寄存器限制为只能将 16b 与 16b 一起使用,将 32b 与 32b 一起使用,但这只会释放一个位,不足以告诉 CPU 有多少字节偏移量是。
哪些值对应哪些寄存器?
第二件困扰我的事情是,尽管我的引用明确地对寄存器进行了编号,但我没有看到与这些命令中操作码之后的字节有任何关联。这些命令似乎连自己都不一致。第二个和第三个命令都是从 eax 到 eax,但是第一个字节的中途有一点不同。
根据我的参考,我假设 0 是 EAX,1 是 ECX,2 是 EDX,依此类推。但是,这并没有让我深入了解如何在 RAX、EAX、AX、AL 和 AH 之间指定。有些命令似乎只接受 8b 寄存器,而其他命令接受 16b 或 32b,而在 x86_64 上,有些命令似乎接受 16b、32b 或 64b 寄存器。那么你会做一些像 0-7 是 R,8-15 是 E,16-23 是非扩展,24-31 是 H 和 L 吗?即使是类似的东西,看起来应该更容易找到手册或指定的东西。
操作码后的第一个字节是ModR/M字节。您链接的第一个参考包含页面末尾 ModR/M 字节的 tables。对于诸如此类的内存访问指令,ModR/M 字节表示正在加载或存储的寄存器以及用于内存访问的寻址模式。
ModR/M 字节之后的字节取决于 ModR/M 字节的值。
在"mov eax, [ebp-8]"指令中,ModR/M字节为45。从table为32位ModR/M字节,这意味着Reg为eax和Effective Address是 [EBP]+disp8。指令的下一个字节 F8 是 8 位有符号偏移量。
指令的操作数大小可以隐含在指令中,也可以由指令前缀指定。例如,66 前缀表示 16 位操作数,对于您的示例中的 mov 指令。如果您使用的是 64 位模式,则 48 前缀表示 64 位操作数。
8位操作数通常由指令的低位表示。如果您将示例中的指令从 8B 更改为 8A,它将变为 8 位移动到 al.
我正在查看一些汇编代码和相应的内存转储,但我无法理解发生了什么。我正在使用 this as reference for opcodes for x86 and this as reference for registers in x86。我 运行 进入了这些命令,我意识到我仍然遗漏了一大块拼图。
8B 45 F8 - mov eax,[ebp-08]
8B 80 78040000 - mov eax,[eax+00000478]
8B 00 - mov eax,[eax]
基本上我不明白操作码后面的两个字节是什么意思,我找不到任何地方可以给出命令的逐位格式(如果任何人都可以指出我将不胜感激)。
CPU如何知道这些命令的长度?
根据我的参考资料,这个 8B mov 命令允许使用 32b 或 16b 寄存器,这意味着有 16 个可能的寄存器(AX、CX、DX、BX、SP、BP、SI、DI 及其扩展等效项).这意味着你需要一个完整的字节来指定在每个操作中使用哪个寄存器运行d.
到目前为止还可以,操作码后面的两个字节可以指定使用哪些寄存器。然后我注意到这些命令在内存中逐字节堆叠,并且所有三个命令都使用不同的字节数来指定在取消引用第二个 ope运行d.
时要使用的偏移量我想你可以将寄存器限制为只能将 16b 与 16b 一起使用,将 32b 与 32b 一起使用,但这只会释放一个位,不足以告诉 CPU 有多少字节偏移量是。
哪些值对应哪些寄存器?
第二件困扰我的事情是,尽管我的引用明确地对寄存器进行了编号,但我没有看到与这些命令中操作码之后的字节有任何关联。这些命令似乎连自己都不一致。第二个和第三个命令都是从 eax 到 eax,但是第一个字节的中途有一点不同。
根据我的参考,我假设 0 是 EAX,1 是 ECX,2 是 EDX,依此类推。但是,这并没有让我深入了解如何在 RAX、EAX、AX、AL 和 AH 之间指定。有些命令似乎只接受 8b 寄存器,而其他命令接受 16b 或 32b,而在 x86_64 上,有些命令似乎接受 16b、32b 或 64b 寄存器。那么你会做一些像 0-7 是 R,8-15 是 E,16-23 是非扩展,24-31 是 H 和 L 吗?即使是类似的东西,看起来应该更容易找到手册或指定的东西。
操作码后的第一个字节是ModR/M字节。您链接的第一个参考包含页面末尾 ModR/M 字节的 tables。对于诸如此类的内存访问指令,ModR/M 字节表示正在加载或存储的寄存器以及用于内存访问的寻址模式。
ModR/M 字节之后的字节取决于 ModR/M 字节的值。
在"mov eax, [ebp-8]"指令中,ModR/M字节为45。从table为32位ModR/M字节,这意味着Reg为eax和Effective Address是 [EBP]+disp8。指令的下一个字节 F8 是 8 位有符号偏移量。
指令的操作数大小可以隐含在指令中,也可以由指令前缀指定。例如,66 前缀表示 16 位操作数,对于您的示例中的 mov 指令。如果您使用的是 64 位模式,则 48 前缀表示 64 位操作数。
8位操作数通常由指令的低位表示。如果您将示例中的指令从 8B 更改为 8A,它将变为 8 位移动到 al.