首页 文章

如何反汇编LLVM MCJIT编译的结果?

提问于
浏览
5

我有一个我写的程序,它使用LLVM 3.5作为JIT编译器,我正在尝试更新以在LLVM 3.7中使用MCJIT . 我主要使用它,但我很难重现我用LLVM 3.5实现的一个仅调试功能 .

我希望能够看到JIT进程生成的主机代码(例如x86,x64或ARM,而不是LLVM IR);在调试版本中,我在程序运行时将其记录下来 . 使用LLVM 3.5,我可以通过调用ExecutionEngine :: runJITOnFunction()来填充llvm :: MachineCodeInfo对象,它为我提供了生成代码的起始地址 and size . 然后我可以反汇编代码 .

我似乎无法在MCJIT中找到任何等效物 . 我可以得到函数的起始地址(例如通过getPointerToFunction())但不是大小 .

我见过Disassemble Memory但除了在答案中没有那么多细节之外,它似乎更多的是关于如何反汇编一系列字节 . 我知道怎么做,我的问题是:我怎样才能掌握字节序列?

如果它有助于使其更具体,请将此问题重新解释为:“如何扩展示例Kaleidoscope JIT以显示它生成的机器代码(x86,ARM等),而不仅仅是LLVM IR?”

谢谢 .

2 回答

  • 1

    这里至少有两个选项 .

    • 提供您自己的内存管理器 . 这必须有详细记录,并在许多使用MCJIT的项目中完成 . 但为了完整起见,这里是代码:
    class MCJITMemoryManager : public llvm::RTDyldMemoryManager {
    public:
    static std::unique_ptr<MCJITMemoryManager> Create();
    
    MCJITMemoryManager();
    virtual ~MCJITMemoryManager();
    
    // Allocate a memory block of (at least) the given size suitable for
    // executable code. The section_id is a unique identifier assigned by the
    // MCJIT engine, and optionally recorded by the memory manager to access a
    // loaded section.
    byte* allocateCodeSection(uintptr_t size, unsigned alignment,
                              unsigned section_id,
                              llvm::StringRef section_name) override;
    
    // Allocate a memory block of (at least) the given size suitable for data.
    // The SectionID is a unique identifier assigned by the JIT engine, and
    // optionally recorded by the memory manager to access a loaded section.
    byte* allocateDataSection(uintptr_t size, unsigned alignment,
                        unsigned section_id, llvm::StringRef section_name,
                        bool is_readonly) override;
    ...
    }
    

    将内存管理器实例传递给EngineBuilder:

    std::unique_ptr<MCJITMemoryManager> manager = MCJITMemoryManager::Create();
    llvm::ExecutionEngine* raw = lvm::EngineBuilder(std::move(module))
        .setMCJITMemoryManager(std::move(manager))
        ...
        .create();
    

    现在通过这些回调,您可以控制发出代码的内存 . (并且 size 直接传递给您的方法) . 只需记住为代码段分配的缓冲区的地址,并在gdb中停止程序并反汇编内存(或将其转储到某处或甚至使用LLVM的反汇编程序) .

    • 只需在LLVM IR上使用 llc 并使用适当的选项(优化级别等) . 正如我所看到的那样,MCJIT被调用是出于某种原因,原因在于它重用了现有的代码生成模块(与llc相同) .
  • 0

    包括以下 Headers llvm/Object/SymbolSize.h ,并使用函数 llvm::object::computeSymbolSizes(ObjectFile&) . 您需要以某种方式获取 ObjectFile 的实例 .

    要获得该实例,您可以执行以下操作:

    • 声明一个被调用的类,将 Module 转换为 ObjectFile ,类似于: class ModuleToObjectFileCompiler { ... // Compile a Module to an ObjectFile. llvm::object::OwningBinary<llvm::object::ObjectFile> operator() (llvm::Module&); };

    • 要实现 ModuleToObjectFileCompileroperator() ,请查看 llvm/ExecutionEngine/Orc/CompileUtils.h ,其中定义了类 SimpleCompiler .

    • llvm::orc::IRCompileLayer 的实例提供 ModuleToObjectFileCompiler 的实例,例如: new llvm::orc::IRCompileLayer <llvm::orc::ObjectLinkingLayer <llvm::orc::DoNothingOnNotifyLoaded> > (_object_layer, _module_to_object_file);

    • operator() ModuleToObjectFileCompiler 收到 ObjectFile 的实例,您可以将其提供给 computeSymbolSizes() . 然后检查返回的 std::vector 以找出 Module 中定义的所有符号的大小(以字节为单位) . 保存您感兴趣的符号的信息 . 这就是全部 .

相关问题