如何 link 两个 LLVM 位码模块?
How to link two LLVM bitcode modules?
我有一个简单的 LLVM pass,它重命名当前翻译单元中定义的每个函数(即:在所有预处理步骤发生之后的相关源文件 - 参见 here)。我的pass如下:
#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
然后我尝试link两个文件如下
llvm-link file.bc file_renamed.bc -o file_linked.bc
但是,对于涉及构造函数和析构函数的 C++ 源文件(从中生成初始位码文件),我仍然遇到符号冲突。我的期望是这条线
F.setLinkage(GlobalValue::LinkOnceAnyLinkage)
将防止 file.bc
和 file_renamed.bc
中定义的任何符号发生符号冲突。
我做错了什么?
当我尝试 运行 您的代码示例位码文件时,llvm-link 步骤因全局变量而失败:
ERROR: Linking globals named 'my_global': symbol multiply defined!
在向 RunOnModule 例程添加第二个循环以处理全局变量后,llvm-link 成功,然后代码最终 linked.
for (auto git = M.global_begin(), get = M.global_end(); git != get; ++git)
{
GlobalValue* gv = &*git;
gv->setLinkage(GlobalValue::LinkOnceAnyLinkage);
}
但是,我对带有构造函数的 C++ 代码的简单测试在有和没有这种变化的情况下都有效。
我的完整解决方案如下:
#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 析构函数)。
我有一个简单的 LLVM pass,它重命名当前翻译单元中定义的每个函数(即:在所有预处理步骤发生之后的相关源文件 - 参见 here)。我的pass如下:
#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
然后我尝试link两个文件如下
llvm-link file.bc file_renamed.bc -o file_linked.bc
但是,对于涉及构造函数和析构函数的 C++ 源文件(从中生成初始位码文件),我仍然遇到符号冲突。我的期望是这条线
F.setLinkage(GlobalValue::LinkOnceAnyLinkage)
将防止 file.bc
和 file_renamed.bc
中定义的任何符号发生符号冲突。
我做错了什么?
当我尝试 运行 您的代码示例位码文件时,llvm-link 步骤因全局变量而失败:
ERROR: Linking globals named 'my_global': symbol multiply defined!
在向 RunOnModule 例程添加第二个循环以处理全局变量后,llvm-link 成功,然后代码最终 linked.
for (auto git = M.global_begin(), get = M.global_end(); git != get; ++git)
{
GlobalValue* gv = &*git;
gv->setLinkage(GlobalValue::LinkOnceAnyLinkage);
}
但是,我对带有构造函数的 C++ 代码的简单测试在有和没有这种变化的情况下都有效。
我的完整解决方案如下:
#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 析构函数)。