blob: 624521d5447994c9b738b34ab4f8656a9b465a43 [file] [log] [blame]
/*
* Copyright 2013, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "AndroidBitcodeLinker.h"
#include "Archive.h"
#include "llvm/ADT/SetOperations.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Bitcode/BitcodeWriterPass.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Linker/Linker.h"
#include "llvm/PassManager.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Wrap/BitcodeWrapper.h"
#include <memory>
#include <set>
#include <system_error>
#include <vector>
using namespace llvm;
// Generate current module to std::string
std::string* AndroidBitcodeLinker::GenerateBitcode() {
std::string *BCString = new std::string;
Module *M = linker->getModule();
PassManager PM;
raw_string_ostream Bitcode(*BCString);
PM.add(createVerifierPass());
PM.add(new DataLayoutPass(M));
if (!Config.isDisableOpt())
PassManagerBuilder().populateLTOPassManager(PM,
false /*Internalize*/,
true /*RunInliner*/);
// Doing clean up passes
if (!Config.isDisableOpt())
{
PM.add(createInstructionCombiningPass());
PM.add(createCFGSimplificationPass());
PM.add(createAggressiveDCEPass());
PM.add(createGlobalDCEPass());
}
// Make sure everything is still good
PM.add(createVerifierPass());
// Strip debug info and symbols.
if (Config.isStripAll() || Config.isStripDebug())
PM.add(createStripSymbolsPass(Config.isStripDebug() && !Config.isStripAll()));
PM.add(createBitcodeWriterPass(Bitcode));
PM.run(*M);
Bitcode.flush();
// Re-compute defined and undefined symbols
UpdateSymbolList(M);
delete M;
delete linker;
linker = 0;
return BCString;
}
Module *
AndroidBitcodeLinker::LoadAndroidBitcode(AndroidBitcodeItem &Item) {
const StringRef &FileName = Item.getFile();
ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
MemoryBuffer::getFileOrSTDIN(FileName);
if (!Buffer) {
Error = "Error reading file '" + FileName.str() + "'" + ": " +
Buffer.getError().message();
return nullptr;
}
MemoryBuffer *BufferPtr = Buffer.get().get();
BitcodeWrapper *Wrapper = new BitcodeWrapper(BufferPtr->getBufferStart(),
BufferPtr->getBufferSize());
Item.setWrapper(Wrapper);
assert(Item.getWrapper() != 0);
ErrorOr<Module *> Result = parseBitcodeFile(BufferPtr, Config.getContext());
if (!Result) {
Error = "Bitcode file '" + FileName.str() + "' could not be loaded." +
Result.getError().message();
errs() << Error << '\n';
return nullptr;
}
return Result.get();
}
void
AndroidBitcodeLinker::UpdateSymbolList(Module *M) {
std::set<std::string> UndefinedSymbols;
std::set<std::string> DefinedSymbols;
GetAllSymbols(M, UndefinedSymbols, DefinedSymbols);
// Update global undefined/defined symbols
set_union(GlobalDefinedSymbols, DefinedSymbols);
set_union(GlobalUndefinedSymbols, UndefinedSymbols);
set_subtract(GlobalUndefinedSymbols, GlobalDefinedSymbols);
verbose("Dump global defined symbols:");
for (std::set<std::string>::iterator I = DefinedSymbols.begin();
I != DefinedSymbols.end(); ++I)
verbose("D:" + *I);
verbose("Dump global undefined symbols:");
for (std::set<std::string>::iterator I = GlobalUndefinedSymbols.begin();
I != GlobalUndefinedSymbols.end(); ++I)
verbose("U:" + *I);
}
bool
AndroidBitcodeLinker::LinkInAndroidBitcodes(ABCItemList& Items,
std::vector<std::string*> &BCStrings) {
// Create llvm::Linker
linker = new Linker(new Module(Config.getModuleName(), Config.getContext()));
for (ABCItemList::iterator I = Items.begin(), E = Items.end();
I != E; ++I) {
if (LinkInAndroidBitcode(*I))
return true;
}
if (linker != 0)
BCStrings.push_back(GenerateBitcode());
return false;
}
//
// Link in bitcode relocatables and bitcode archive
//
bool
AndroidBitcodeLinker::LinkInAndroidBitcode(AndroidBitcodeItem &Item) {
const StringRef &File = Item.getFile();
if (File.str() == "-") {
return error("Not supported!");
}
if (!sys::fs::exists(File))
return error("Cannot find linker input '" + File.str() + "'");
sys::fs::file_magic Magic;
if (sys::fs::identify_magic(File, Magic))
return error("Cannot find linker input '" + File.str() + "'");
switch (Magic) {
case sys::fs::file_magic::archive: {
if (Item.isWholeArchive()) {
verbose("Link whole archive" + File.str());
if (LinkInWholeArchive(Item))
return true;
}
else {
verbose("Link no-whole archive" + File.str());
if (LinkInArchive(Item))
return true;
}
break;
}
case sys::fs::file_magic::bitcode: {
verbose("Linking bitcode file '" + File.str() + "'");
std::unique_ptr<Module> M(LoadAndroidBitcode(Item));
int BCFileType = Item.getWrapper()->getBCFileType();
int BitcodeType = -1;
if (BCFileType == BC_RAW)
BitcodeType = BCHeaderField::BC_Relocatable;
else if (BCFileType == BC_WRAPPER)
BitcodeType = Item.getWrapper()->getBitcodeType();
else
return error("Invalid bitcode file type" + File.str());
if (M.get() == 0)
return error("Cannot load file '" + File.str() + "': " + Error);
Triple triple(M.get()->getTargetTriple());
if ((triple.getArch() != Triple::le32 && triple.getArch() != Triple::le64) ||
triple.getOS() != Triple::NDK) {
Item.setNative(true);
return error("Cannot link '" + File.str() + "', triple:" + M.get()->getTargetTriple());
}
switch (BitcodeType) {
default:
return error("Unknown android bitcode type");
case BCHeaderField::BC_Relocatable:
assert(linker != 0);
if (linker->linkInModule(M.get(), &Error))
return error("Cannot link file '" + File.str() + "': " + Error);
break;
case BCHeaderField::BC_SharedObject:
break;
case BCHeaderField::BC_Executable:
return error("Cannot link bitcode executable: " + File.str());
}
break;
}
case sys::fs::file_magic::elf_shared_object: {
Item.setNative(true);
if (!Config.isLinkNativeBinary()) {
return error("Cannot link native binaries with bitcode" + File.str());
}
break;
}
case sys::fs::file_magic::elf_relocatable: {
return error("Cannot link ELF relocatable:" + File.str());
}
case sys::fs::file_magic::elf_executable: {
return error("Cannot link ELF executable:" + File.str());
}
default: {
return error("Ignoring file '" + File.str() +
"' because does not contain bitcode.");
}
}
return false;
}
bool
AndroidBitcodeLinker::LinkInWholeArchive(AndroidBitcodeItem &Item) {
const StringRef &Filename = Item.getFile();
// Open the archive file
verbose("Linking archive file '" + Filename.str() + "'");
std::string ErrMsg;
std::unique_ptr<Archive> AutoArch(
Archive::OpenAndLoad(Filename, Config.getContext(), &ErrMsg));
Archive* arch = AutoArch.get();
// possible empty archive?
if (!arch) {
return false;
}
if (!arch->isBitcodeArchive()) {
Item.setNative(true);
if (Config.isLinkNativeBinary()) {
return false;
}
else {
return error("Cannot link native binaries with bitcode" + Filename.str());
}
}
std::vector<Module*> Modules;
if (arch->getAllModules(Modules, &ErrMsg))
return error("Cannot read modules in '" + Filename.str() + "': " + ErrMsg);
if (Modules.empty()) {
return false;
}
// Loop over all the Modules
for (std::vector<Module*>::iterator I=Modules.begin(), E=Modules.end();
I != E; ++I) {
// Get the module we must link in.
Module* aModule = *I;
if (aModule != NULL) {
if (std::error_code ec = aModule->materializeAll())
return error("Could not load a module: " + ec.message());
verbose(" Linking in module: " + aModule->getModuleIdentifier());
assert(linker != 0);
// Link it in
std::string moduleErrorMsg;
if (linker->linkInModule(aModule, &moduleErrorMsg))
return error("Cannot link in module '" +
aModule->getModuleIdentifier() + "': " + moduleErrorMsg);
delete aModule;
}
}
/* Success! */
return false;
}
void
AndroidBitcodeLinker::GetAllSymbols(Module *M,
std::set<std::string> &UndefinedSymbols,
std::set<std::string> &DefinedSymbols) {
UndefinedSymbols.clear();
DefinedSymbols.clear();
Function *Main = M->getFunction("main");
if (Main == 0 || Main->isDeclaration())
UndefinedSymbols.insert("main");
for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
if (I->hasName()) {
if (I->isDeclaration())
UndefinedSymbols.insert(I->getName());
else if (!I->hasLocalLinkage()) {
assert(!I->hasDLLImportStorageClass()
&& "Found dllimported non-external symbol!");
DefinedSymbols.insert(I->getName());
}
}
for (Module::global_iterator I = M->global_begin(), E = M->global_end();
I != E; ++I)
if (I->hasName()) {
if (I->isDeclaration())
UndefinedSymbols.insert(I->getName());
else if (!I->hasLocalLinkage()) {
assert(!I->hasDLLImportStorageClass()
&& "Found dllimported non-external symbol!");
DefinedSymbols.insert(I->getName());
}
}
for (Module::alias_iterator I = M->alias_begin(), E = M->alias_end();
I != E; ++I)
if (I->hasName())
DefinedSymbols.insert(I->getName());
for (std::set<std::string>::iterator I = UndefinedSymbols.begin();
I != UndefinedSymbols.end(); )
if (DefinedSymbols.count(*I))
UndefinedSymbols.erase(I++);
else
++I;
}
bool
AndroidBitcodeLinker::LinkInArchive(AndroidBitcodeItem &Item) {
const StringRef &Filename = Item.getFile();
verbose("Linking archive file '" + Filename.str() + "'");
std::set<std::string> UndefinedSymbols;
std::set<std::string> DefinedSymbols;
GetAllSymbols(linker->getModule(), UndefinedSymbols, DefinedSymbols);
// Update list
set_union(UndefinedSymbols, GlobalUndefinedSymbols);
set_union(DefinedSymbols, GlobalDefinedSymbols);
set_subtract(UndefinedSymbols, DefinedSymbols);
if (UndefinedSymbols.empty()) {
verbose("No symbols undefined, skipping library '" + Filename.str() + "'");
return false; // No need to link anything in!
}
std::string ErrMsg;
std::unique_ptr<Archive> AutoArch(
Archive::OpenAndLoadSymbols(Filename, Config.getContext(), &ErrMsg));
Archive* arch = AutoArch.get();
// possible empty archive?
if (!arch) {
return false;
}
if (!arch->isBitcodeArchive()) {
Item.setNative(true);
if (Config.isLinkNativeBinary()) {
return false;
}
else {
return error("Cannot link native binaries with bitcode" + Filename.str());
}
}
std::set<std::string> NotDefinedByArchive;
std::set<std::string> CurrentlyUndefinedSymbols;
do {
CurrentlyUndefinedSymbols = UndefinedSymbols;
SmallVector<Module*, 16> Modules;
if (!arch->findModulesDefiningSymbols(UndefinedSymbols, Modules, &ErrMsg))
return error("Cannot find symbols in '" + Filename.str() +
"': " + ErrMsg);
if (Modules.empty())
break;
NotDefinedByArchive.insert(UndefinedSymbols.begin(),
UndefinedSymbols.end());
for (SmallVectorImpl<Module*>::iterator I=Modules.begin(), E=Modules.end();
I != E; ++I) {
Module* aModule = *I;
if (aModule != NULL) {
if (std::error_code ec = aModule->materializeAll())
return error("Could not load a module: " + ec.message());
verbose(" Linking in module: " + aModule->getModuleIdentifier());
// Link it in
std::string moduleErrorMsg;
if (linker->linkInModule(aModule, &moduleErrorMsg))
return error("Cannot link in module '" +
aModule->getModuleIdentifier() + "': " + moduleErrorMsg);
}
}
GetAllSymbols(linker->getModule(), UndefinedSymbols, DefinedSymbols);
set_subtract(UndefinedSymbols, NotDefinedByArchive);
if (UndefinedSymbols.empty())
break;
} while (CurrentlyUndefinedSymbols != UndefinedSymbols);
return false;
}