| //===- 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 |