【问题标题】:Assembly Language to Machine Code汇编语言到机器码
【发布时间】:2017-10-25 00:16:22
【问题描述】:

我用以下代码创建了一个简单的 c++ 源文件。

int main() {
int a = 1;
int b = 2;
if(a < b) {
    return 1;
}
else if(a > b) {
    return 2;
}
else {
    return 3;
}

}

我使用 objdump 命令来获取上述源代码的汇编代码。 还有那一行

int b = 2;被转换为 mov DWORD PTR [rbp-0x4],0x2

其对应的机器码(十六进制格式)为c7 45 fc 02 00 00 00

我想知道如何将汇编代码转换为二进制代码。我浏览了 x86-64 的英特尔参考手册,但我无法理解,因为我是低级编程的新手。

【问题讨论】:

  • “转换”是什么意思?使用程序?手动操作?
  • 手动转换。
  • int b = 2; 不是汇编语言。不同之处在于,C 是编译语言,因此 int b = 2; 行可以以多种不同的方式实现(甚至被优化器完全删除),这取决于编译器将决定什么,如何生成机器代码来产生定义的结果C 语言标准。汇编语言在某种程度上是不同的,Assembler 不是这种编译器,当你用 Assembly add rax,rbx 编写时,它将被编译为那样,不改变指令,或者被某种优化器删除,所以更像“1:1 转换”。

标签: assembly binary x86-64


【解决方案1】:

您应该阅读英特尔手册,它解释了如何做到这一点。如需更简单的参考,请read this。 x86 指令的编码方式相当简单,但可能性的数量可能有点多。

简而言之,一条 x86 指令由以下部分组成,其中除了操作码之外的所有部分都可能丢失:

prefix opcode operands immediate

prefix 字段可能会修改指令的行为,这不适用于您的用例。您可以在引用中查找opcode(我喜欢this one),例如,mov r/m32, imm32C7 /0,这意味着:操作码是C7,两个操作数之一作为扩展操作数为零.该指令采用 32 位立即数,因此指令形式为

C7 operand/0 imm32

操作数/扩展操作码被编码为 modr/m 字节,带有用于某些寻址模式的可选 sib(标度索引基)字节和可选的 8 位或 32 位位移。您可以查找您需要的值in the reference。因此,在您的情况下,您希望使用一个字节位移和一个寄存器操作数 0 对内存操作数 [rbp] 进行编码,从而导致 modr/m 字节 45。所以编码是:

C7 45 disp8 imm32

现在我们将 8 位位移编码为二进制补码。 -4 对应于FC,所以这是

C7 45 FC imm32

最后,我们将 32 位立即数编码为 2。请注意,它是小端:

C7 45 FC 02 00 00 00

这就是指令的编码方式。

【讨论】:

  • 所以在你提供的link 中,我去了C7 1 Byte Opcode,它是用于MOV 指令的。但是 Evqp 和 Ivds 这两个操作数是什么意思,它们是否对应于 rm32 寻址和立即数?感谢您的帮助
  • 请参阅this page 了解字段的含义。我链接的参考资料高度浓缩,但更难阅读。
  • 好的,很好。另一个问题是,当我看到 MOD r/m 表时,您说“我想用 1 字节位移(8 位)[DWORD PTR [rbp-0x4]] 对 rbp 寄存器进行编码”在link 中,我还看到了 32 位位移的版本,你能给我举个例子吗?
  • @AbhisheykDeb 对于 32 位位移,编码将是 C7 85 FC FF FF FF 02 00 00 00,其中 modr/m 字节是 85 而不是 45,位移是 FC FF FF FF
  • @AbhisheykDeb 48 前缀是 REX.W 前缀。表示操作数大小是 64 位而不是 32 位。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-16
  • 2010-11-18
  • 2011-04-02
  • 1970-01-01
  • 2012-04-05
  • 2017-06-17
相关资源
最近更新 更多