LLVMCreateDisasm返回NULL

Bab*_*yan 9 c llvm disassembly

我试图使用LLVM的C接口反汇编一些字节.但是LLVMCreateDisasm()返回NULL.

#include <stdio.h> // printf()
#include <stdlib.h> // EXIT_FAILURE, EXIT_SUCCESS

#define __STDC_CONSTANT_MACROS // llvm complains otherwise
#define __STDC_LIMIT_MACROS
#include <llvm-c/Disassembler.h>

int main()
{
    LLVMDisasmContextRef dc = LLVMCreateDisasm (
        "testname",
        NULL,
        0,
        NULL,
        NULL
    );
    if (dc == NULL) {
        printf("Could not create disassembler");
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)

我在x64 Linux上.查看文档似乎我正在做的一切正确.

LLVMDisasmContextRef LLVMCreateDisasm   (
    const char *             TripleName,
    void *                   DisInfo,
    int                      TagType,
    LLVMOpInfoCallback       GetOpInfo,
    LLVMSymbolLookupCallback SymbolLookUp 
)
Run Code Online (Sandbox Code Playgroud)

为TripleName创建反汇编程序.通过在DisInfo参数中传递信息块并指定TagType和回调函数来支持符号反汇编,如上所述.这些都可以作为NULL传递.如果成功,则返回反汇编程序上下文.如果不是,则返回NULL.

更新

  1. 我的llvm版本是3.4
  2. 我尝试了所有可能的三重/目标,仍然是相同的.
  3. printflib/MC/MCDisassembler/Disassembler.cpp:LLVMCreateDisasmCPU()中插入,并在首次if检查时失败.Error那一点的字符串是"Unable to find target for this triple (no targets are registered)"

    LLVMDisasmContextRef LLVMCreateDisasmCPU(const char *Triple, const char *CPU,
                                         void *DisInfo, int TagType,
                                         LLVMOpInfoCallback GetOpInfo,
                                         LLVMSymbolLookupCallback SymbolLookUp){
        std::cout << ">>> Triplename: " << Triple << std::endl;
        // Get the target.
        std::string Error;
        const Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error);
        if (!TheTarget) {
            std::cout << "Failed 1: " << Error << std::endl;
            return 0;
        }
        ...
    
    Run Code Online (Sandbox Code Playgroud)

    所以它在lookupTarget通话中失败了.

  4. 查看lib/Support/TargetRegistry.cpp:lookupTarget()在第一次if检查时失败.那里的评论提供了一些线索:

    const Target *TargetRegistry::lookupTarget(const std::string &TT,
                                               std::string &Error) {
        // Provide special warning when no targets are initialized.
        if (begin() == end()) {
            Error = "Unable to find target for this triple (no targets are registered)";
            return 0;
        }
        ...
    
    Run Code Online (Sandbox Code Playgroud)

    所以事实证明我必须首先初始化目标.

  5. 在我的代码中,我首先LLVMInitializeAllTargetInfos();llvm-c/Target.h标题中调用.现在它ifDisassembler.cpp中的第二次检查失败:LLVMCreateDisasmCPU()

    const MCRegisterInfo *MRI = TheTarget->createMCRegInfo(Triple);
    if (!MRI) {
        std::cout << "Failed 2: " << Error << std::endl;
        return 0;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    用这个Error字符串:Could not create disassembler

终于解决了!

我刚打电话LLVMInitializeAllTargetInfos();,LLVMInitializeAllTargetMCs();,LLVMInitializeAllDisassemblers();创造DISASM上下文之前:

#include <stdio.h> // printf()
#include <stdlib.h> // EXIT_FAILURE, EXIT_SUCCESS

#define __STDC_CONSTANT_MACROS // llvm complains otherwise
#define __STDC_LIMIT_MACROS
#include <llvm-c/Disassembler.h>
#include <llvm-c/Target.h>

int main()
{
    LLVMInitializeAllTargetInfos();
    LLVMInitializeAllTargetMCs();
    LLVMInitializeAllDisassemblers();

    LLVMDisasmContextRef dc = LLVMCreateDisasm (
        "x86_64-unknown-linux-gnu",
        NULL,
        0,
        NULL,
        NULL
    );
    if (dc == NULL) {
        printf("Could not create disassembler");
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)

osg*_*sgx 6

第一个论点LLVMCreateDisasm,

"testname"
Run Code Online (Sandbox Code Playgroud)

是无效的TripleName.TripleName将指示LLVM您的目标是什么,这是必需的,因为LLVM在单个安装中包含对多个目标的支持.

您可以通过运行命令列出支持的目标体系结构

llc  -version
Run Code Online (Sandbox Code Playgroud)

并且有x86和x86_64的目标

x86      - 32-bit X86: Pentium-Pro and above
x86-64   - 64-bit X86: EM64T and AMD64
Run Code Online (Sandbox Code Playgroud)

要构建正确的TripleName,您应该为您的目标找到一些好的子shell(i486或x86_64),然后添加供应商和操作系统:

http://llvm.org/docs/doxygen/html/Triple_8h_source.html

00022 /// Triple - Helper class for working with autoconf configuration names. For
00023 /// historical reasons, we also call these 'triples' (they used to contain
00024 /// exactly three fields).
00025 ///
00026 /// Configuration names are strings in the canonical form:
00027 ///   ARCHITECTURE-VENDOR-OPERATING_SYSTEM
00028 /// or
00029 ///   ARCHITECTURE-VENDOR-OPERATING_SYSTEM-ENVIRONMENT
Run Code Online (Sandbox Code Playgroud)

这里有ArchType枚举,注释中已识别的Arch列表(实际的解析器是lib/Support/Triple.cpp - parseArch),就像

arm,     // ARM: arm, armv.*, xscale
aarch64, // AArch64: aarch64
....
x86,     // X86: i[3-9]86
x86_64,  // X86-64: amd64, x86_64
Run Code Online (Sandbox Code Playgroud)

在同一个文件中有有效的vendor(enum VendorType),OS types(enum OSType)和Envronments(enum EnvironmentType).在大多数情况下,您可以为vendor和os使用"unknown",但通常使用"-unknown-linux-gnu".

一些有效TripleName的例子:

x86_64--linux-gnu
x86_64-unknown-linux-gnu
i486--linux-gnu
Run Code Online (Sandbox Code Playgroud)

这里有更多关于clang的有效三元组的描述:http://clang.llvm.org/docs/CrossCompilation.html以及/sf/answers/1300345231/中列出的一些有效名称

另一个限制 LLVMCreateDisasm是并非所有目标都已MCDisassembler实施.例如,在LLVM-2.9中,只有X86,X86_64,ARM和MBlaze有MCDissasemblers; 最近(2014年2月1日), Sparc,PPC,MIPS,SystemZ,XCore和AArch64.

如果即使使用正确的三元组也无法创建MCDisassembler,有几个选项可以LLVMCreateDisasmCPU从MC/MCDisassembler/Disassembler.cpp文件调试该函数.您可以使用gdb进入,然后执行"下一步" - 执行直到出现错误(使用LLVM的调试版本,这将更加美观和简单); 或者你可以LLVMCreateDisasmCPU从普通的NULL信息中添加一些调试printf到临时更改返回值,每个错误都有一些不同.

更新:似乎您的LLVM在通话时未初始化.当前LLVM(~3.4或更新版本)中的llvm-c/Target.h头中有许多LLVM初始值设定项:

LLVMInitializeAllTargetInfos() - 如果主程序想要访问LLVM配置为支持的所有可用目标,则应调用此函数.

LLVMInitializeAllTargets() - 如果主程序要链接LLVM配置为支持的所有可用目标,则应调用此函数.

LLVMInitializeAllTargetMCs() - 如果主程序要访问LLVM配置为支持的所有可用目标MC,则应调用此函数.

LLVMInitializeAllDisassemblers() - 主程序应该调用此函数,如果它想要LLVM配置为支持的所有反汇编程序,则通过TargetRegistry使它们可用.

LLVMInitializeAllAsmPrinters() - 主程序应该调用此函数,如果它想要LLVM配置为支持的所有asm打印机,则通过TargetRegistry使它们可用.

依此类推(https://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm-c/Target.h?logsort=rev&diff_format=h&r1=192697&r2=192696&pathrev=192697).

甚至还有LLVMInitializeNativeTarget初始化本机目标的函数:

LLVMInitializeNativeTarget() - 主程序应调用此函数来初始化与主机对应的本机目标.这对于JIT应用程序非常有用,可以确保正确链接目标.