gpt4 book ai didi

x86-64 - 如何编写 X86_64 _汇编器_?

转载 作者:行者123 更新时间:2023-12-02 07:06:11 37 4
gpt4 key购买 nike

目标:我想编写一个 X86_64 汇编器。注意:标记为社区维基

背景:我熟悉C语言,以前写过MIPS汇编。我写了一些 x86 程序集。但是,我想编写一个 x86_64 汇编器 - 它应该输出我可以跳转到并开始执行的机器代码(就像在 JIT 中一样)。

问题是:解决这个问题的最佳方法是什么?我意识到这个问题看起来很难解决。我想从一个基本的最低限度开始:

  • 加载到寄存器
  • 寄存器上的算术运算(只需整数就可以了,还不需要搞乱 FPU)
  • 条件
  • 跳跃

只是一个使其图灵完备的基本集合。有人做过这个吗?建议/资源?

最佳答案

与任何其他“编译器”一样,汇编器最好编写为输入到语言语法处理器中的词法分析器。

汇编语言通常比常规编译语言更容易,因为您无需担心构造跨越行边界,并且格式通常是固定的。

大约两年前,出于教育目的,我为(虚构的)CPU 编写了一个汇编程序,它基本上将每一行视为:

  • 可选标签(例如:loop)。
  • 操作(例如,mov)。
  • 操作数(例如,ax,$1)。

最简单的方法是确保 token 易于区分。

这就是为什么我制定了标签必须以 : 开头的规则 - 它使该行的分析变得更加容易。处理一行的过程是:

  • 删除注释(第一个 ; 位于字符串之外到行尾)。
  • 提取标签(如果有)。
  • 第一个词就是操作。
  • 其余部分是操作数。

您可以轻松地坚持不同的操作数也有特殊的标记,以使您的生活更轻松。所有这一切都假设您可以控制输入格式。如果您需要使用 Intel 或 AT&T 格式,那就有点困难了。

我的方法是调用一个简单的每个操作函数(例如,doJmpdoCalldoRet )并且该函数决定操作数中允许的内容。

例如,doCall 只允许使用数字或标签,doRet 不允许任何内容。

例如,以下是来自 encInstr 函数的代码段:

private static MultiRet encInstr(
boolean ignoreVars,
String opcode,
String operands)
{
if (opcode.length() == 0) return hlprNone(ignoreVars);
if (opcode.equals("defb")) return hlprByte(ignoreVars,operands);
if (opcode.equals("defbr")) return hlprByteR(ignoreVars,operands);
if (opcode.equals("defs")) return hlprString(ignoreVars,operands);
if (opcode.equals("defw")) return hlprWord(ignoreVars,operands);
if (opcode.equals("defwr")) return hlprWordR(ignoreVars,operands);
if (opcode.equals("equ")) return hlprNone(ignoreVars);
if (opcode.equals("org")) return hlprNone(ignoreVars);

if (opcode.equals("adc")) return hlprTwoReg(ignoreVars,0x0a,operands);
if (opcode.equals("add")) return hlprTwoReg(ignoreVars,0x09,operands);
if (opcode.equals("and")) return hlprTwoReg(ignoreVars,0x0d,operands);

hlpr... 函数只是获取操作数并返回一个包含指令的字节数组。当许多操作具有类似的操作数要求时,它们非常有用,例如 adcaddand` 在上述情况下都需要两个寄存器操作数(第二个参数控制什么操作码)已返回指令)。

通过使操作数的类型易于区分,您可以检查提供了哪些操作数、它们是否合法以及要生成哪些字节序列。将操作分离到它们自己的函数中提供了一个很好的逻辑结构。

此外,大多数 CPU 都遵循从操作码到操作的合理逻辑转换(以使芯片设计人员的工作更轻松),因此所有操作码上都会有非常相似的计算,例如允许索引寻址。

为了在允许可变长度指令的 CPU 中正确创建代码,最好分两遍完成。

在第一遍中,不生成代码,只生成指令的长度。这允许您在遇到所有标签时为其分配值。第二遍将生成代码并可以填充对这些标签的引用,因为它们的值是已知的。上面代码段中的 ignoreVars 用于此目的(返回代码的字节序列,以便我们可以知道长度,但对符号的任何引用都只使用 0)。

关于x86-64 - 如何编写 X86_64 _汇编器_?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3074004/

37 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com