如何链接两个LLVM bitcode模块?

时间:2017-07-25 10:36:39

标签: c++ linker llvm compiler-optimization static-linking

我有一个简单的LLVM传递,它重命名当前翻译单元中定义的每个函数(即:在所有预处理步骤发生后,所讨论的源文件 - 请参阅here)。我的通行证如下:

#include <vector>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>

#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/TypeFinder.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/IR/Argument.h"
#include "llvm/IR/GlobalValue.h"

using namespace llvm;

namespace {

  struct FunctionRename : public ModulePass {
    static char ID; // Pass identification
    FunctionRename() : ModulePass(ID) {}

    bool runOnModule(Module &M) override {
      // Rename all functions
      for (auto &F : M) {
        StringRef Name = F.getName();
        // Leave library functions alone because their presence or absence
        // could affect the behaviour of other passes.
        if (F.isDeclaration())
          continue;
        F.setLinkage(GlobalValue::LinkOnceAnyLinkage);
        F.setName(Name + "_renamed");
      }
      return true;
    }
  };
}

char FunctionRename::ID = 0;
static RegisterPass<FunctionRename> X("functionrename", "Function Rename Pass");
// ===-------------------------------------------------------==//
//
// Function Renamer - Renames all functions
//

在bitcode文件file.bc上运行传递后,我将结果输出到新文件file_renamed.bc,如下所示

opt -load /path/to/libFunctionRenamePass.so -functionrename < file.bc > file_renamed.bc

然后我尝试按如下方式链接这两个文件

llvm-link file.bc file_renamed.bc -o file_linked.bc

但是,我仍然会遇到C ++源文件(生成初始bitcode文件)的符号冲突,其中涉及构造函数和析构函数。我的期望是该行

F.setLinkage(GlobalValue::LinkOnceAnyLinkage)

可防止file.bcfile_renamed.bc中定义的任何符号发生符号冲突。

我做错了什么?

2 个答案:

答案 0 :(得分:1)

当我尝试在示例bitcode文件上运行代码时,由于全局变量,llvm-link步骤失败:

ERROR: Linking globals named 'my_global': symbol multiply defined!

在RunOnModule例程中添加第二个循环以处理全局变量后,llvm-link成功,然后代码最终链接。

for (auto git = M.global_begin(), get = M.global_end(); git != get; ++git)
{
   GlobalValue* gv = &*git;
   gv->setLinkage(GlobalValue::LinkOnceAnyLinkage);
}

然而,我对带有构造函数的C ++代码的简单测试在有或没有这种改变的情况下都有效。

答案 1 :(得分:0)

我的完整解决方案如下:

#include <vector>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>

#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/TypeFinder.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/IR/Argument.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/Metadata.h"

using namespace llvm;

namespace {

  struct FunctionRename : public ModulePass {
    static char ID; // Pass identification
    FunctionRename() : ModulePass(ID) {}

    bool runOnModule(Module &M) override {

      for (auto it = M.global_begin(); it != M.global_end(); ++it)
      {
        GlobalVariable& gv = *it;
        if (!gv.isDeclaration())
          gv.setLinkage(GlobalValue::LinkerPrivateLinkage);
      }

      for (auto it = M.alias_begin(); it != M.alias_end(); ++it)
      {
        GlobalAlias& ga = *it;
        if (!ga.isDeclaration())
          ga.setLinkage(GlobalValue::LinkerPrivateLinkage);
      }

      // Rename all functions
      for (auto &F : M) {
        StringRef Name = F.getName();
        // Leave library functions alone because their presence or absence
        // could affect the behaviour of other passes.
        if (F.isDeclaration())
          continue;
        F.setLinkage(GlobalValue::WeakAnyLinkage);
        F.setName(Name + "_renamed");
      }
      return true;
    }
  };
}

char FunctionRename::ID = 0;
static RegisterPass<FunctionRename> X("functionrename", "Function Rename Pass");
// ===-------------------------------------------------------==//
//
// Function Renamer - Renames all functions
//

在处理函数for(auto &F : M) { ... }的循环中,由于以下原因,我更倾向于使用WeakAnyLinkage而不是LinkOnceAnyLinkage

具有LinkOnceAnyLinkage的全局 - 顾名思义 - 在链接发生时与其他同名符号合并,并且允许丢弃具有此链接的未引用的全局变量。

WeakAnyLinkage的全局变量与LinkOnceAnyLinkage的全局变量具有相同的语义,但可能不会丢弃带有WeakAnyLinkage的未引用的全局变量。

此外,在处理全局变量和别名的两个循环中,我使用LinkerPrivateLinkage,因为我不希望file_renamed.bc中的全局变量可以被该模块外的任何对象访问。

此外,处理别名的循环是必要的(至少在我的环境中)是为了避免与完整对象构造函数和析构函数相关的符号冲突(即:根据Itanium C ++ ABI的C1和D1析构函数)。