summaryrefslogtreecommitdiff
path: root/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ReaderWriter/ELF/ELFLinkingContext.cpp')
-rw-r--r--lib/ReaderWriter/ELF/ELFLinkingContext.cpp259
1 files changed, 259 insertions, 0 deletions
diff --git a/lib/ReaderWriter/ELF/ELFLinkingContext.cpp b/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
new file mode 100644
index 000000000000..c7dffda8a463
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
@@ -0,0 +1,259 @@
+//===- 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
+
+namespace lld {
+
+class CommandLineUndefinedAtom : public SimpleUndefinedAtom {
+public:
+ CommandLineUndefinedAtom(const File &f, StringRef name)
+ : SimpleUndefinedAtom(f, name) {}
+
+ CanBeNull canBeNull() const override {
+ return CanBeNull::canBeNullAtBuildtime;
+ }
+};
+
+ELFLinkingContext::ELFLinkingContext(
+ llvm::Triple triple, std::unique_ptr<TargetHandlerBase> targetHandler)
+ : _outputELFType(llvm::ELF::ET_EXEC), _triple(triple),
+ _targetHandler(std::move(targetHandler)), _baseAddress(0),
+ _isStaticExecutable(false), _noInhibitExec(false), _exportDynamic(false),
+ _mergeCommonStrings(false), _useShlibUndefines(true),
+ _dynamicLinkerArg(false), _noAllowDynamicLibraries(false),
+ _mergeRODataToTextSegment(true), _demangle(true),
+ _stripSymbols(false), _alignSegments(true), _collectStats(false),
+ _outputMagic(OutputMagic::DEFAULT), _initFunction("_init"),
+ _finiFunction("_fini"), _sysrootPath(""), _linkerScriptSema() {}
+
+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::mipsel:
+ 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;
+ case LinkingContext::OutputFileType::Native:
+ llvm_unreachable("Unimplemented");
+ break;
+ default:
+ _writer = createWriterELF(this->targetHandler());
+ 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("=/"))
+ path.assign(dir);
+ else {
+ path.assign(sysRoot);
+ path.append(dir.substr(1));
+ }
+}
+
+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 (llvm::sys::fs::exists(path.str()))
+ return StringRef(*new (_allocator) std::string(path.str()));
+ }
+ // Search for static libraries too
+ buildSearchPath(path, dir, _sysrootPath);
+ llvm::sys::path::append(path, hasColonPrefix
+ ? libName.drop_front()
+ : Twine("lib", libName) + ".a");
+ if (llvm::sys::fs::exists(path.str()))
+ return StringRef(*new (_allocator) std::string(path.str()));
+ }
+ if (hasColonPrefix && llvm::sys::fs::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 (llvm::sys::path::is_absolute(fileName) && isSysRooted) {
+ path.assign(_sysrootPath);
+ path.append(fileName);
+ if (llvm::sys::fs::exists(path.str()))
+ return StringRef(*new (_allocator) std::string(path.str()));
+ } else if (llvm::sys::fs::exists(fileName))
+ return fileName;
+
+ if (llvm::sys::path::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 (llvm::sys::fs::exists(path.str()))
+ return StringRef(*new (_allocator) std::string(path.str()));
+ }
+ 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 (!demangleSymbols())
+ return symbolName;
+
+ // Only try to demangle symbols that look like C++ symbols
+ if (!symbolName.startswith("_Z"))
+ return symbolName;
+
+#if defined(HAVE_CXXABI_H)
+ 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) {
+ std::string result(demangled);
+ // __cxa_demangle() always uses a malloc'ed buffer to return the result.
+ free(demangled);
+ return result;
+ }
+#endif
+
+ return symbolName;
+}
+
+void ELFLinkingContext::setUndefinesResolver(std::unique_ptr<File> resolver) {
+ assert(isa<ArchiveLibraryFile>(resolver.get()) && "Wrong resolver type");
+ _resolver = std::move(resolver);
+}
+
+} // end namespace lld