blob: 8c76a788fa2b015e71e35c41613493f1c8d13d18 [file] [log] [blame]
//===- lib/ReaderWriter/ELF/ELFLinkingContext.cpp -------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lld/ReaderWriter/ELFLinkingContext.h"
#include "ELFFile.h"
#include "OrderPass.h"
#include "TargetHandler.h"
#include "lld/Core/Instrumentation.h"
#include "lld/Core/SharedLibraryFile.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Config/config.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#if defined(HAVE_CXXABI_H)
#include <cxxabi.h>
#endif
using llvm::sys::fs::exists;
using llvm::sys::path::is_absolute;
namespace lld {
class CommandLineUndefinedAtom : public SimpleUndefinedAtom {
public:
CommandLineUndefinedAtom(const File &f, StringRef name)
: SimpleUndefinedAtom(f, name) {}
CanBeNull canBeNull() const override {
return CanBeNull::canBeNullAtBuildtime;
}
};
void ELFLinkingContext::addPasses(PassManager &pm) {
pm.add(llvm::make_unique<elf::OrderPass>());
}
uint16_t ELFLinkingContext::getOutputMachine() const {
switch (getTriple().getArch()) {
case llvm::Triple::x86:
return llvm::ELF::EM_386;
case llvm::Triple::x86_64:
return llvm::ELF::EM_X86_64;
case llvm::Triple::hexagon:
return llvm::ELF::EM_HEXAGON;
case llvm::Triple::mips:
case llvm::Triple::mipsel:
case llvm::Triple::mips64:
case llvm::Triple::mips64el:
return llvm::ELF::EM_MIPS;
case llvm::Triple::aarch64:
return llvm::ELF::EM_AARCH64;
case llvm::Triple::arm:
return llvm::ELF::EM_ARM;
default:
llvm_unreachable("Unhandled arch");
}
}
StringRef ELFLinkingContext::entrySymbolName() const {
if (_outputELFType == llvm::ELF::ET_EXEC && _entrySymbolName.empty())
return "_start";
return _entrySymbolName;
}
bool ELFLinkingContext::validateImpl(raw_ostream &diagnostics) {
switch (outputFileType()) {
case LinkingContext::OutputFileType::YAML:
_writer = createWriterYAML(*this);
break;
default:
_writer = createWriterELF(*this);
break;
}
// If -dead_strip, set up initial live symbols.
if (deadStrip())
addDeadStripRoot(entrySymbolName());
return true;
}
bool ELFLinkingContext::isDynamic() const {
switch (_outputELFType) {
case llvm::ELF::ET_EXEC:
return !_isStaticExecutable;
case llvm::ELF::ET_DYN:
return true;
}
return false;
}
bool ELFLinkingContext::isRelativeReloc(const Reference &) const {
return false;
}
Writer &ELFLinkingContext::writer() const { return *_writer; }
static void buildSearchPath(SmallString<128> &path, StringRef dir,
StringRef sysRoot) {
if (dir.startswith("=/")) {
// If a search directory begins with "=", "=" is replaced
// with the sysroot path.
path.assign(sysRoot);
path.append(dir.substr(1));
} else {
path.assign(dir);
}
}
ErrorOr<StringRef> ELFLinkingContext::searchLibrary(StringRef libName) const {
bool hasColonPrefix = libName[0] == ':';
SmallString<128> path;
for (StringRef dir : _inputSearchPaths) {
// Search for dynamic library
if (!_isStaticExecutable) {
buildSearchPath(path, dir, _sysrootPath);
llvm::sys::path::append(path, hasColonPrefix
? libName.drop_front()
: Twine("lib", libName) + ".so");
if (exists(path.str()))
return path.str().copy(_allocator);
}
// Search for static libraries too
buildSearchPath(path, dir, _sysrootPath);
llvm::sys::path::append(path, hasColonPrefix
? libName.drop_front()
: Twine("lib", libName) + ".a");
if (exists(path.str()))
return path.str().copy(_allocator);
}
if (hasColonPrefix && exists(libName.drop_front()))
return libName.drop_front();
return make_error_code(llvm::errc::no_such_file_or_directory);
}
ErrorOr<StringRef> ELFLinkingContext::searchFile(StringRef fileName,
bool isSysRooted) const {
SmallString<128> path;
if (is_absolute(fileName) && isSysRooted) {
path.assign(_sysrootPath);
path.append(fileName);
if (exists(path.str()))
return path.str().copy(_allocator);
} else if (exists(fileName)) {
return fileName;
}
if (is_absolute(fileName))
return make_error_code(llvm::errc::no_such_file_or_directory);
for (StringRef dir : _inputSearchPaths) {
buildSearchPath(path, dir, _sysrootPath);
llvm::sys::path::append(path, fileName);
if (exists(path.str()))
return path.str().copy(_allocator);
}
return make_error_code(llvm::errc::no_such_file_or_directory);
}
void ELFLinkingContext::createInternalFiles(
std::vector<std::unique_ptr<File>> &files) const {
std::unique_ptr<SimpleFile> file(
new SimpleFile("<internal file for --defsym>"));
for (auto &i : getAbsoluteSymbols()) {
StringRef sym = i.first;
uint64_t val = i.second;
file->addAtom(*(new (_allocator) SimpleAbsoluteAtom(
*file, sym, Atom::scopeGlobal, val)));
}
files.push_back(std::move(file));
LinkingContext::createInternalFiles(files);
}
void ELFLinkingContext::finalizeInputFiles() {
// Add virtual archive that resolves undefined symbols.
if (_resolver)
getNodes().push_back(llvm::make_unique<FileNode>(std::move(_resolver)));
}
std::unique_ptr<File> ELFLinkingContext::createUndefinedSymbolFile() const {
if (_initialUndefinedSymbols.empty())
return nullptr;
std::unique_ptr<SimpleFile> undefinedSymFile(
new SimpleFile("command line option -u"));
for (auto undefSymStr : _initialUndefinedSymbols)
undefinedSymFile->addAtom(*(new (_allocator) CommandLineUndefinedAtom(
*undefinedSymFile, undefSymStr)));
return std::move(undefinedSymFile);
}
void ELFLinkingContext::notifySymbolTableCoalesce(const Atom *existingAtom,
const Atom *newAtom,
bool &useNew) {
// First suppose that the `existingAtom` is defined
// and the `newAtom` is undefined.
auto *da = dyn_cast<DefinedAtom>(existingAtom);
auto *ua = dyn_cast<UndefinedAtom>(newAtom);
if (!da && !ua) {
// Then try to reverse the assumption.
da = dyn_cast<DefinedAtom>(newAtom);
ua = dyn_cast<UndefinedAtom>(existingAtom);
}
if (da && ua && da->scope() == Atom::scopeGlobal &&
isa<SharedLibraryFile>(ua->file()))
// If strong defined atom coalesces away an atom declared
// in the shared object the strong atom needs to be dynamically exported.
// Save its name.
_dynamicallyExportedSymbols.insert(ua->name());
}
std::string ELFLinkingContext::demangle(StringRef symbolName) const {
#if defined(HAVE_CXXABI_H)
if (!demangleSymbols())
return symbolName;
// Only try to demangle symbols that look like C++ symbols
if (!symbolName.startswith("_Z"))
return symbolName;
SmallString<256> symBuff;
StringRef nullTermSym = Twine(symbolName).toNullTerminatedStringRef(symBuff);
const char *cstr = nullTermSym.data();
int status;
char *demangled = abi::__cxa_demangle(cstr, nullptr, nullptr, &status);
if (demangled == NULL)
return symbolName;
std::string result(demangled);
// __cxa_demangle() always uses a malloc'ed buffer to return the result.
free(demangled);
return result;
#else
return symbolName;
#endif
}
void ELFLinkingContext::setUndefinesResolver(std::unique_ptr<File> resolver) {
assert(isa<ArchiveLibraryFile>(resolver.get()) && "Wrong resolver type");
_resolver = std::move(resolver);
}
void ELFLinkingContext::notifyInputSectionName(StringRef name) {
// Save sections names which can be represented as a C identifier.
if (name.find_first_not_of("0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"_") == StringRef::npos) {
std::lock_guard<std::mutex> lock(_cidentMutex);
_cidentSections.insert(name);
}
}
} // end namespace lld