如何处理将冗长的汇编代码转换为 AsmJIT 函数调用?

问题描述 投票:0回答:1

我正在开发一个编译器,项目如下:

↓   . Take a line of Python code;
    . Convert Python code to an IR (Intermediate Language);
    . Convert the intermediate language to assembly;
    . Optimization (After)
    . Use AsmJIT to convert assembly code to machine code;
    . Execution at runtime in memory.

    . Next line                                                                                                         
                                                              ↑

并决定使用AsmJIT来汇编代码。但是,现在我有一个冗长的汇编代码,问题在于将此汇编代码“转换”为 AsmJIT 函数调用,如下所示:

  a.mov(eax, dword_ptr(esp, 4));    // Load the destination pointer.
  a.mov(ecx, dword_ptr(esp, 8));    // Load the first source pointer.
  a.mov(edx, dword_ptr(esp, 12));   // Load the second source pointer.
 
  a.movups(xmm0, ptr(ecx));         // Load 4 floats from [ecx] to XMM0.
  a.movups(xmm1, ptr(edx));         // Load 4 floats from [edx] to XMM1.
  a.addps(xmm0, xmm1);              // Add 4 floats in XMM1 to XMM0.
  a.movups(ptr(eax), xmm0);         // Store the result to [eax].
  a.ret();                          // Return from function.

鉴于我的代码相当大,手动执行此“转换”非常困难。是否可以在汇编代码中使用字符串,我应该如何进行?

assembly compiler-construction asmjit
1个回答
0
投票

如果我正确理解这个问题,你有一个管道,并且你想使用 AsmJit 来编码管道输出的代码(输出是你想要汇编的机器代码)。

这可以通过 AsmJit 实现,下面是一个示例:

#include <asmjit/x86.h>
#include <stdio.h>

using namespace asmjit;

class MyErrorHandler : public ErrorHandler {
public:
  void handleError(Error err,
                   const char* message,
                   BaseEmitter* origin) override {
    printf("AsmJit error: %s\n", message);
  }
};

static x86::Gp createGp32(uint32_t id) noexcept { return x86::gpd(id); }
static x86::Gp createGp64(uint32_t id) noexcept { return x86::gpq(id); }
static x86::Vec createXmm(uint32_t id) noexcept { return x86::xmm(id); }

int main() {
  MyErrorHandler eh;
  FileLogger logger(stdout);

  JitRuntime rt;
  CodeHolder code;

  code.init(rt.environment());
  code.setErrorHandler(&eh);
  code.setLogger(&logger);

  x86::Assembler a(&code);

  // An example of converting instruction name to AsmJit's instruction id.
  const char* instructionName = "vcvtsi2sd";
  InstId instructionId =
    InstAPI::stringToInstId(a.arch(), instructionName, strlen(instructionName));

  // An example of creating operands dynamically, encodes 'vcvtsi2sd xmm0, xmm1, rbx'.
  a.emit(instructionId, createXmm(0), createXmm(1), createGp64(3));

  return 0;
}

基本上,如果您使用

emit()
,您可以根据您自己的管道的输出创建整个指令以进行动态汇编。该方法可以完全由表驱动(将 IR 操作码转换为单个指令),或者转换可能更复杂(将更高级别的 IR 转换为 1 个或多个指令)。

查看 InstId(指令标识符)和 Operand(所有操作数都继承自 Operand,因此您可以在结构中使用 Operand,然后它可以是任何内容 - 标签、寄存器、立即值或内存地址)。

如果您有文本表示作为输出,则可以使用 AsmTK:

这基本上是一个解析器,它使用 AsmJit 的指令 API 将文本输入转换为 AsmJit 理解的形式。

© www.soinside.com 2019 - 2024. All rights reserved.