//===- 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 #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 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()); } 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 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 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> &files) const { std::unique_ptr file( new SimpleFile("")); 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(std::move(_resolver))); } std::unique_ptr ELFLinkingContext::createUndefinedSymbolFile() const { if (_initialUndefinedSymbols.empty()) return nullptr; std::unique_ptr 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(existingAtom); auto *ua = dyn_cast(newAtom); if (!da && !ua) { // Then try to reverse the assumption. da = dyn_cast(newAtom); ua = dyn_cast(existingAtom); } if (da && ua && da->scope() == Atom::scopeGlobal && isa(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 resolver) { assert(isa(resolver.get()) && "Wrong resolver type"); _resolver = std::move(resolver); } } // end namespace lld