Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix linking #77

Merged
merged 1 commit into from
Apr 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions include/klee/Core/Interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,15 @@ class Interpreter {
InterpreterHandler *ih);

/// Register the module to be executed.
/// \param modules A list of modules that should form the final
/// \param userModules A list of user modules that should form the final
/// module
/// \param libsModules A list of libs modules that should form the final
/// module
/// \return The final module after it has been optimized, checks
/// inserted, and modified for interpretation.
virtual llvm::Module *
setModule(std::vector<std::unique_ptr<llvm::Module>> &modules,
setModule(std::vector<std::unique_ptr<llvm::Module>> &userModules,
std::vector<std::unique_ptr<llvm::Module>> &libsModules,
const ModuleOptions &opts,
const std::vector<std::string> &mainModuleFunctions) = 0;

Expand Down
2 changes: 1 addition & 1 deletion include/klee/Module/KModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ class KModule {
/// @return true if at least one module has been linked in, false if nothing
/// changed
bool link(std::vector<std::unique_ptr<llvm::Module>> &modules,
const std::string &entryPoint);
const unsigned flag);

void instrument(const Interpreter::ModuleOptions &opts);

Expand Down
29 changes: 24 additions & 5 deletions include/klee/Support/ModuleUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ namespace klee {
/// everything is linked against the first entry.
/// @param entryFunction if set, missing functions of the module containing the
/// entry function will be solved.
/// @return final module or null in this case errorMsg is set
std::unique_ptr<llvm::Module>
linkModules(std::vector<std::unique_ptr<llvm::Module>> &modules,
llvm::StringRef entryFunction, std::string &errorMsg);
/// @return false in this case errorMsg is set
bool linkModules(llvm::Module *composite,
std::vector<std::unique_ptr<llvm::Module>> &modules,
const unsigned Flags, std::string &errorMsg);

#if defined(__x86_64__) || defined(__i386__)
#define addFunctionReplacement(from, to) \
{#from "f", #to "f"}, {#from, #to}, { "" #from "l", #to "l" }
{#from "f", #to "f"}, {#from "", #to ""}, { "" #from "l", #to "l" }

#define addIntrinsicReplacement(from, to) \
{"llvm." #from ".f32", #to "f"}, {"llvm." #from ".f64", #to}, { \
Expand Down Expand Up @@ -119,13 +119,32 @@ bool functionEscapes(const llvm::Function *f);
/// * .a archive containing .bc and .ll files
///
/// @param libraryName library to read
/// @param context module context
/// @param modules contains extracted modules
/// @param errorMsg contains the error description in case the file could not be
/// loaded
/// @return true if successful otherwise false
bool loadFile(const std::string &libraryName, llvm::LLVMContext &context,
std::vector<std::unique_ptr<llvm::Module>> &modules,
std::string &errorMsg);

/// Loads the file libraryName and reads all modules into one.
///
/// Different file types are possible:
/// * .bc binary file
/// * .ll IR file
/// * .a archive containing .bc and .ll files
///
/// @param libraryName library to read
/// @param context module context
/// @param modules contains extracted modules
/// @param errorMsg contains the error description in case the file could not be
/// loaded
/// @return true if successful otherwise false
bool loadFileAsOneModule(const std::string &libraryName,
llvm::LLVMContext &context,
std::vector<std::unique_ptr<llvm::Module>> &modules,
std::string &errorMsg);
} // namespace klee

#endif /* KLEE_MODULEUTIL_H */
38 changes: 22 additions & 16 deletions lib/Core/Executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ typedef unsigned TypeSize;
#include <iomanip>
#include <iosfwd>
#include <limits>
#include <memory>
#include <sstream>
#include <string>
#include <sys/mman.h>
Expand Down Expand Up @@ -542,29 +543,34 @@ Executor::Executor(LLVMContext &ctx, const InterpreterOptions &opts,
}

llvm::Module *
Executor::setModule(std::vector<std::unique_ptr<llvm::Module>> &modules,
Executor::setModule(std::vector<std::unique_ptr<llvm::Module>> &userModules,
std::vector<std::unique_ptr<llvm::Module>> &libsModules,
const ModuleOptions &opts,
const std::vector<std::string> &mainModuleFunctions) {
assert(!kmodule && !modules.empty() &&
assert(!kmodule && !userModules.empty() &&
"can only register one module"); // XXX gross

kmodule = std::unique_ptr<KModule>(new KModule());
kmodule = std::make_unique<KModule>();

// Preparing the final module happens in multiple stages
// 1.) Link the modules together && 2.) Apply different instrumentation
kmodule->link(userModules, 0);
kmodule->instrument(opts);

// Link with KLEE intrinsics library before running any optimizations
SmallString<128> LibPath(opts.LibraryDir);
llvm::sys::path::append(LibPath,
"libkleeRuntimeIntrinsic" + opts.OptSuffix + ".bca");
std::string error;
if (!klee::loadFile(LibPath.c_str(), modules[0]->getContext(), modules,
error)) {
klee_error("Could not load KLEE intrinsic file %s", LibPath.c_str());
}
kmodule->link(libsModules, 2);
kmodule->instrument(opts);

// 1.) Link the modules together
while (kmodule->link(modules, opts.EntryPoint)) {
// 2.) Apply different instrumentation
{
std::vector<std::unique_ptr<llvm::Module>> modules;
// Link with KLEE intrinsics library before running any optimizations
SmallString<128> LibPath(opts.LibraryDir);
llvm::sys::path::append(LibPath, "libkleeRuntimeIntrinsic" +
opts.OptSuffix + ".bca");
std::string error;
if (!klee::loadFileAsOneModule(
LibPath.c_str(), kmodule->module->getContext(), modules, error)) {
klee_error("Could not load KLEE intrinsic file %s", LibPath.c_str());
}
kmodule->link(modules, 2);
kmodule->instrument(opts);
}

Expand Down
3 changes: 2 additions & 1 deletion lib/Core/Executor.h
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,8 @@ class Executor : public Interpreter {
}

llvm::Module *
setModule(std::vector<std::unique_ptr<llvm::Module>> &modules,
setModule(std::vector<std::unique_ptr<llvm::Module>> &userModules,
std::vector<std::unique_ptr<llvm::Module>> &libsModules,
const ModuleOptions &opts,
const std::vector<std::string> &mainModuleFunctions) override;

Expand Down
20 changes: 9 additions & 11 deletions lib/Module/KModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,20 +221,18 @@ void KModule::addInternalFunction(const char *functionName) {
}

bool KModule::link(std::vector<std::unique_ptr<llvm::Module>> &modules,
const std::string &entryPoint) {
auto numRemainingModules = modules.size();
// Add the currently active module to the list of linkables
modules.push_back(std::move(module));
unsigned flags) {
std::string error;
module = std::unique_ptr<llvm::Module>(
klee::linkModules(modules, entryPoint, error));
if (!module)
if (!module) {
module = std::move(modules.front());
}
if (!klee::linkModules(module.get(), modules, flags, error)) {
klee_error("Could not link KLEE files %s", error.c_str());
return false;
}

targetData = std::unique_ptr<llvm::DataLayout>(new DataLayout(module.get()));

// Check if we linked anything
return modules.size() != numRemainingModules;
targetData = std::make_unique<llvm::DataLayout>(module.get());
return true;
}

void KModule::replaceFunction(const std::unique_ptr<llvm::Module> &m,
Expand Down
164 changes: 24 additions & 140 deletions lib/Module/ModuleUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,153 +133,24 @@ static void GetAllUndefinedSymbols(Module *M,
<< "*** Finished computing undefined symbols ***\n");
}

static bool linkTwoModules(llvm::Module *Dest,
std::unique_ptr<llvm::Module> Src,
std::string &errorMsg) {
// Get the potential error message (Src is moved and won't be available later)
errorMsg = "Linking module " + Src->getModuleIdentifier() + " failed";
auto linkResult = Linker::linkModules(*Dest, std::move(Src));

return !linkResult;
}

std::unique_ptr<llvm::Module>
klee::linkModules(std::vector<std::unique_ptr<llvm::Module>> &modules,
llvm::StringRef entryFunction, std::string &errorMsg) {
assert(!modules.empty() && "modules list should not be empty");

if (entryFunction.empty()) {
// If no entry function is provided, link all modules together into one
std::unique_ptr<llvm::Module> composite = std::move(modules.back());
modules.pop_back();

// Just link all modules together
for (auto &module : modules) {
if (linkTwoModules(composite.get(), std::move(module), errorMsg))
continue;

// Linking failed
errorMsg = "Linking archive module with composite failed:" + errorMsg;
return nullptr;
}

// clean up every module as we already linked in every module
modules.clear();
return composite;
}

// Starting from the module containing the entry function, resolve unresolved
// dependencies recursively
bool klee::linkModules(llvm::Module *composite,
std::vector<std::unique_ptr<llvm::Module>> &modules,
const unsigned flags, std::string &errorMsg) {
// assert(composite);

// search for the module containing the entry function
std::unique_ptr<llvm::Module> composite;
Linker linker(*composite);
for (auto &module : modules) {
if (!module || !module->getNamedValue(entryFunction))
if (!module)
continue;
if (composite) {
errorMsg =
"Function " + entryFunction.str() +
" defined in different modules (" + module->getModuleIdentifier() +
" already defined in: " + composite->getModuleIdentifier() + ")";
return nullptr;
}
composite = std::move(module);
}

// fail if not found
if (!composite) {
errorMsg =
"Entry function '" + entryFunction.str() + "' not found in module.";
return nullptr;
}

auto containsUsedSymbols = [](const llvm::Module *module) {
GlobalValue *GV =
dyn_cast_or_null<GlobalValue>(module->getNamedValue("llvm.used"));
if (!GV)
return false;
KLEE_DEBUG_WITH_TYPE("klee_linker", dbgs() << "Used attribute in "
<< module->getModuleIdentifier()
<< '\n');
return true;
};

for (auto &module : modules) {
if (!module || !containsUsedSymbols(module.get()))
continue;

if (!linkTwoModules(composite.get(), std::move(module), errorMsg)) {
errorMsg = "Linking module " + module->getModuleIdentifier() + " failed";
if (linker.linkInModule(std::move(module), flags)) {
// Linking failed
errorMsg = "Linking module containing '__attribute__((used))'"
" symbols with composite failed:" +
errorMsg;
return nullptr;
}
module = nullptr;
}

bool symbolsLinked = true;
while (symbolsLinked) {
symbolsLinked = false;
std::set<std::string> undefinedSymbols;
GetAllUndefinedSymbols(composite.get(), undefinedSymbols);
auto hasRequiredDefinition = [&undefinedSymbols](
const llvm::Module *module) {
for (auto symbol : undefinedSymbols) {
GlobalValue *GV =
dyn_cast_or_null<GlobalValue>(module->getNamedValue(symbol));
if (GV && !GV->isDeclaration()) {
KLEE_DEBUG_WITH_TYPE("klee_linker",
dbgs() << "Found " << GV->getName() << " in "
<< module->getModuleIdentifier() << "\n");
return true;
}
}
errorMsg = "Linking archive module with composite failed:" + errorMsg;
return false;
};

// replace std functions with KLEE internals
for (const auto &p : floatReplacements) {
if (composite->getFunction(p.first)) {
undefinedSymbols.insert(p.second);
}
}
for (const auto &p : feRoundReplacements) {
if (composite->getFunction(p.first)) {
undefinedSymbols.insert(p.second);
}
}

// Stop in nothing is undefined
if (undefinedSymbols.empty())
break;

for (auto &module : modules) {
if (!module)
continue;

if (!hasRequiredDefinition(module.get()))
continue;

if (!linkTwoModules(composite.get(), std::move(module), errorMsg)) {
// Linking failed
errorMsg = "Linking archive module with composite failed:" + errorMsg;
return nullptr;
}
module = nullptr;
symbolsLinked = true;
}
}

// Condense the module array
std::vector<std::unique_ptr<llvm::Module>> LeftoverModules;
for (auto &module : modules) {
if (module)
LeftoverModules.emplace_back(std::move(module));
}

modules.swap(LeftoverModules);
return composite;
modules.clear();
return true;
}

Function *klee::getDirectCallTarget(
Expand Down Expand Up @@ -496,3 +367,16 @@ bool klee::loadFile(const std::string &fileName, LLVMContext &context,
modules.push_back(std::move(module));
return true;
}

bool klee::loadFileAsOneModule(
const std::string &libraryName, LLVMContext &context,
std::vector<std::unique_ptr<llvm::Module>> &modules,
std::string &errorMsg) {
std::vector<std::unique_ptr<llvm::Module>> modules2;
bool res = klee::loadFile(libraryName, context, modules2, errorMsg);
if (res) {
modules.push_back(std::move(modules2.front()));
return linkModules(modules.back().get(), modules2, 0, errorMsg);
}
return res;
}
5 changes: 5 additions & 0 deletions lib/Module/RaiseAsm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ bool RaiseAsmPass::runOnInstruction(Module &M, Instruction *I) {

bool RaiseAsmPass::runOnModule(Module &M) {
bool changed = false;

if (M.empty()) {
return false;
}

std::string Err;

// Use target triple from the module if possible.
Expand Down
Loading