diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:48:50 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:48:50 +0000 |
commit | 1c98619801a5705c688e683be3ef9d70169a0686 (patch) | |
tree | 8422105cd1a94c368315f2db16b9ac746cf7c000 /lib | |
parent | f4f3ce4613680903220815690ad79fc7ba0a2e26 (diff) | |
download | src-1c98619801a5705c688e683be3ef9d70169a0686.tar.gz src-1c98619801a5705c688e683be3ef9d70169a0686.zip |
Vendor import of lld release_39 branch r276489:vendor/lld/lld-release_39-r276489
Notes
Notes:
svn path=/vendor/lld/dist/; revision=303239
svn path=/vendor/lld/lld-release_39-r276489/; revision=303240; tag=vendor/lld/lld-release_39-r276489
Diffstat (limited to 'lib')
174 files changed, 2828 insertions, 27087 deletions
diff --git a/lib/Config/Version.cpp b/lib/Config/Version.cpp index b64ccef12c7b..60687b9d8940 100644 --- a/lib/Config/Version.cpp +++ b/lib/Config/Version.cpp @@ -13,8 +13,6 @@ #include "lld/Config/Version.h" #include "llvm/Support/raw_ostream.h" -#include <cstdlib> -#include <cstring> using namespace llvm; @@ -37,22 +35,15 @@ StringRef getLLDRevision() { } std::string getLLDRepositoryVersion() { - std::string buf; - llvm::raw_string_ostream OS(buf); - std::string Path = getLLDRepositoryPath(); - std::string Revision = getLLDRevision(); - if (!Path.empty() || !Revision.empty()) { - OS << '('; - if (!Path.empty()) - OS << Path; - if (!Revision.empty()) { - if (!Path.empty()) - OS << ' '; - OS << Revision; - } - OS << ')'; - } - return OS.str(); + std::string S = getLLDRepositoryPath(); + std::string T = getLLDRevision(); + if (S.empty() && T.empty()) + return ""; + if (!S.empty() && !T.empty()) + return "(" + S + " " + T + ")"; + if (!S.empty()) + return "(" + S + ")"; + return "(" + T + ")"; } StringRef getLLDVersion() { diff --git a/lib/Core/DefinedAtom.cpp b/lib/Core/DefinedAtom.cpp index f1d308088ed4..8dc4d4a16f96 100644 --- a/lib/Core/DefinedAtom.cpp +++ b/lib/Core/DefinedAtom.cpp @@ -41,8 +41,8 @@ DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) { case typeDTraceDOF: case typeCompactUnwindInfo: case typeProcessedUnwindInfo: - case typeRONote: - case typeNoAlloc: + case typeObjCImageInfo: + case typeObjCMethodList: return permR__; case typeData: @@ -52,8 +52,8 @@ DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) { case typeObjC1Class: case typeLazyPointer: case typeLazyDylibPointer: + case typeNonLazyPointer: case typeThunkTLV: - case typeRWNote: return permRW_; case typeGOT: @@ -68,15 +68,12 @@ DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) { case typeTLVInitialData: case typeTLVInitialZeroFill: case typeTLVInitializerPtr: - case typeThreadData: - case typeThreadZeroFill: return permRW_L; - case typeGroupComdat: - case typeGnuLinkOnce: case typeUnknown: case typeTempLTO: case typeSectCreate: + case typeDSOHandle: return permUnknown; } llvm_unreachable("unknown content type"); diff --git a/lib/Core/Error.cpp b/lib/Core/Error.cpp index 3b7733746dcd..4df1ce120bd9 100644 --- a/lib/Core/Error.cpp +++ b/lib/Core/Error.cpp @@ -39,42 +39,6 @@ const std::error_category &lld::YamlReaderCategory() { return o; } -class _LinkerScriptReaderErrorCategory : public std::error_category { -public: - const char *name() const LLVM_NOEXCEPT override { - return "lld.linker-script.reader"; - } - - std::string message(int ev) const override { - switch (static_cast<LinkerScriptReaderError>(ev)) { - case LinkerScriptReaderError::success: - return "Success"; - case LinkerScriptReaderError::parse_error: - return "Error parsing linker script"; - case LinkerScriptReaderError::unknown_symbol_in_expr: - return "Unknown symbol found when evaluating linker script expression"; - case LinkerScriptReaderError::unrecognized_function_in_expr: - return "Unrecognized function call when evaluating linker script " - "expression"; - case LinkerScriptReaderError::unknown_phdr_ids: - return "Unknown header identifiers (missing in PHDRS command) are used"; - case LinkerScriptReaderError::extra_program_phdr: - return "Extra program header is found"; - case LinkerScriptReaderError::misplaced_program_phdr: - return "Program header must precede load segments"; - case LinkerScriptReaderError::program_phdr_wrong_phdrs: - return "Program header has invalid PHDRS attribute"; - } - llvm_unreachable("An enumerator of LinkerScriptReaderError does not have a " - "message defined."); - } -}; - -const std::error_category &lld::LinkerScriptReaderCategory() { - static _LinkerScriptReaderErrorCategory o; - return o; -} - namespace lld { /// Temporary class to enable make_dynamic_error_code() until @@ -112,16 +76,16 @@ private: static dynamic_error_category categorySingleton; -std::error_code make_dynamic_error_code(const char *msg) { - return make_dynamic_error_code(StringRef(msg)); -} - std::error_code make_dynamic_error_code(StringRef msg) { return std::error_code(categorySingleton.add(msg), categorySingleton); } -std::error_code make_dynamic_error_code(const Twine &msg) { - return std::error_code(categorySingleton.add(msg.str()), categorySingleton); +char GenericError::ID = 0; + +GenericError::GenericError(Twine Msg) : Msg(Msg.str()) { } + +void GenericError::log(raw_ostream &OS) const { + OS << Msg; } } // namespace lld diff --git a/lib/Core/File.cpp b/lib/Core/File.cpp index ac95f1016797..b84132bfecd5 100644 --- a/lib/Core/File.cpp +++ b/lib/Core/File.cpp @@ -13,7 +13,7 @@ namespace lld { -File::~File() {} +File::~File() { } File::AtomVector<DefinedAtom> File::_noDefinedAtoms; File::AtomVector<UndefinedAtom> File::_noUndefinedAtoms; diff --git a/lib/Core/LinkingContext.cpp b/lib/Core/LinkingContext.cpp index cbcf25c17df2..2732543d306e 100644 --- a/lib/Core/LinkingContext.cpp +++ b/lib/Core/LinkingContext.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lld/Core/Alias.h" #include "lld/Core/LinkingContext.h" #include "lld/Core/Resolver.h" #include "lld/Core/Simple.h" @@ -16,16 +15,7 @@ namespace lld { -LinkingContext::LinkingContext() - : _deadStrip(false), _allowDuplicates(false), - _globalsAreDeadStripRoots(false), - _searchArchivesToOverrideTentativeDefinitions(false), - _searchSharedLibrariesToOverrideTentativeDefinitions(false), - _warnIfCoalesableAtomsHaveDifferentCanBeNull(false), - _warnIfCoalesableAtomsHaveDifferentLoadName(false), - _printRemainingUndefines(true), _allowRemainingUndefines(false), - _logInputFiles(false), _allowShlibUndefines(true), - _outputFileType(OutputFileType::Default), _nextOrdinal(0) {} +LinkingContext::LinkingContext() {} LinkingContext::~LinkingContext() {} @@ -33,15 +23,10 @@ bool LinkingContext::validate(raw_ostream &diagnostics) { return validateImpl(diagnostics); } -std::error_code LinkingContext::writeFile(const File &linkedFile) const { +llvm::Error LinkingContext::writeFile(const File &linkedFile) const { return this->writer().writeFile(linkedFile, _outputPath); } -void LinkingContext::createImplicitFiles( - std::vector<std::unique_ptr<File>> &result) { - this->writer().createImplicitFiles(result); -} - std::unique_ptr<File> LinkingContext::createEntrySymbolFile() const { return createEntrySymbolFile("<command line option -e>"); } @@ -50,7 +35,8 @@ std::unique_ptr<File> LinkingContext::createEntrySymbolFile(StringRef filename) const { if (entrySymbolName().empty()) return nullptr; - std::unique_ptr<SimpleFile> entryFile(new SimpleFile(filename)); + std::unique_ptr<SimpleFile> entryFile(new SimpleFile(filename, + File::kindEntryObject)); entryFile->addAtom( *(new (_allocator) SimpleUndefinedAtom(*entryFile, entrySymbolName()))); return std::move(entryFile); @@ -64,41 +50,20 @@ std::unique_ptr<File> LinkingContext::createUndefinedSymbolFile(StringRef filename) const { if (_initialUndefinedSymbols.empty()) return nullptr; - std::unique_ptr<SimpleFile> undefinedSymFile(new SimpleFile(filename)); + std::unique_ptr<SimpleFile> undefinedSymFile( + new SimpleFile(filename, File::kindUndefinedSymsObject)); for (StringRef undefSym : _initialUndefinedSymbols) undefinedSymFile->addAtom(*(new (_allocator) SimpleUndefinedAtom( *undefinedSymFile, undefSym))); return std::move(undefinedSymFile); } -std::unique_ptr<File> LinkingContext::createAliasSymbolFile() const { - if (getAliases().empty()) - return nullptr; - std::unique_ptr<SimpleFile> file(new SimpleFile("<alias>")); - for (const auto &i : getAliases()) { - StringRef from = i.first; - StringRef to = i.second; - SimpleDefinedAtom *fromAtom = new (_allocator) AliasAtom(*file, from); - UndefinedAtom *toAtom = new (_allocator) SimpleUndefinedAtom(*file, to); - fromAtom->addReference(Reference::KindNamespace::all, - Reference::KindArch::all, Reference::kindLayoutAfter, - 0, toAtom, 0); - file->addAtom(*fromAtom); - file->addAtom(*toAtom); - } - return std::move(file); -} - void LinkingContext::createInternalFiles( std::vector<std::unique_ptr<File> > &result) const { if (std::unique_ptr<File> file = createEntrySymbolFile()) result.push_back(std::move(file)); if (std::unique_ptr<File> file = createUndefinedSymbolFile()) result.push_back(std::move(file)); - if (std::unique_ptr<File> file = createAliasSymbolFile()) - result.push_back(std::move(file)); } -void LinkingContext::addPasses(PassManager &pm) {} - } // end namespace lld diff --git a/lib/Core/Reader.cpp b/lib/Core/Reader.cpp index 6069093d211e..107db07891da 100644 --- a/lib/Core/Reader.cpp +++ b/lib/Core/Reader.cpp @@ -47,7 +47,6 @@ Registry::loadFile(std::unique_ptr<MemoryBuffer> mb) const { static const Registry::KindStrings kindStrings[] = { {Reference::kindLayoutAfter, "layout-after"}, - {Reference::kindGroupChild, "group-child"}, {Reference::kindAssociate, "associate"}, LLD_KIND_STRING_END}; diff --git a/lib/Core/Resolver.cpp b/lib/Core/Resolver.cpp index 8f89856c4a47..ef694fd972fc 100644 --- a/lib/Core/Resolver.cpp +++ b/lib/Core/Resolver.cpp @@ -19,6 +19,7 @@ #include "lld/Core/UndefinedAtom.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" @@ -29,26 +30,27 @@ namespace lld { -bool Resolver::handleFile(File &file) { +llvm::Expected<bool> Resolver::handleFile(File &file) { + if (auto ec = _ctx.handleLoadedFile(file)) + return std::move(ec); bool undefAdded = false; - for (const DefinedAtom *atom : file.defined()) - doDefinedAtom(*atom); - for (const UndefinedAtom *atom : file.undefined()) { - if (doUndefinedAtom(*atom)) { + for (auto &atom : file.defined().owning_ptrs()) + doDefinedAtom(std::move(atom)); + for (auto &atom : file.undefined().owning_ptrs()) { + if (doUndefinedAtom(std::move(atom))) undefAdded = true; - maybePreloadArchiveMember(atom->name()); - } } - for (const SharedLibraryAtom *atom : file.sharedLibrary()) - doSharedLibraryAtom(*atom); - for (const AbsoluteAtom *atom : file.absolute()) - doAbsoluteAtom(*atom); + for (auto &atom : file.sharedLibrary().owning_ptrs()) + doSharedLibraryAtom(std::move(atom)); + for (auto &atom : file.absolute().owning_ptrs()) + doAbsoluteAtom(std::move(atom)); return undefAdded; } -void Resolver::forEachUndefines(File &file, bool searchForOverrides, - UndefCallback callback) { +llvm::Expected<bool> Resolver::forEachUndefines(File &file, + UndefCallback callback) { size_t i = _undefineIndex[&file]; + bool undefAdded = false; do { for (; i < _undefines.size(); ++i) { StringRef undefName = _undefines[i]; @@ -60,190 +62,120 @@ void Resolver::forEachUndefines(File &file, bool searchForOverrides, _undefines[i] = ""; continue; } - callback(undefName, false); - } - if (!searchForOverrides) - continue; - for (StringRef tentDefName : _symbolTable.tentativeDefinitions()) { - // Load for previous tentative may also have loaded - // something that overrode this tentative, so always check. - const Atom *curAtom = _symbolTable.findByName(tentDefName); - assert(curAtom != nullptr); - if (const DefinedAtom *curDefAtom = dyn_cast<DefinedAtom>(curAtom)) - if (curDefAtom->merge() == DefinedAtom::mergeAsTentative) - callback(tentDefName, true); + auto undefAddedOrError = callback(undefName); + if (auto ec = undefAddedOrError.takeError()) + return std::move(ec); + undefAdded |= undefAddedOrError.get(); } } while (i < _undefines.size()); _undefineIndex[&file] = i; + return undefAdded; } -bool Resolver::handleArchiveFile(File &file) { +llvm::Expected<bool> Resolver::handleArchiveFile(File &file) { ArchiveLibraryFile *archiveFile = cast<ArchiveLibraryFile>(&file); - bool searchForOverrides = - _ctx.searchArchivesToOverrideTentativeDefinitions(); - bool undefAdded = false; - forEachUndefines(file, searchForOverrides, - [&](StringRef undefName, bool dataSymbolOnly) { - if (File *member = archiveFile->find(undefName, dataSymbolOnly)) { + return forEachUndefines(file, + [&](StringRef undefName) -> llvm::Expected<bool> { + if (File *member = archiveFile->find(undefName)) { member->setOrdinal(_ctx.getNextOrdinalAndIncrement()); - member->beforeLink(); - updatePreloadArchiveMap(); - undefAdded = handleFile(*member) || undefAdded; + return handleFile(*member); } + return false; }); - return undefAdded; } -void Resolver::handleSharedLibrary(File &file) { +llvm::Error Resolver::handleSharedLibrary(File &file) { // Add all the atoms from the shared library SharedLibraryFile *sharedLibrary = cast<SharedLibraryFile>(&file); - handleFile(*sharedLibrary); - bool searchForOverrides = - _ctx.searchSharedLibrariesToOverrideTentativeDefinitions(); - forEachUndefines(file, searchForOverrides, - [&](StringRef undefName, bool dataSymbolOnly) { - if (const SharedLibraryAtom *atom = - sharedLibrary->exports(undefName, dataSymbolOnly)) - doSharedLibraryAtom(*atom); - }); + auto undefAddedOrError = handleFile(*sharedLibrary); + if (auto ec = undefAddedOrError.takeError()) + return ec; + undefAddedOrError = + forEachUndefines(file, [&](StringRef undefName) -> llvm::Expected<bool> { + auto atom = sharedLibrary->exports(undefName); + if (atom.get()) + doSharedLibraryAtom(std::move(atom)); + return false; + }); + + if (auto ec = undefAddedOrError.takeError()) + return ec; + return llvm::Error(); } -bool Resolver::doUndefinedAtom(const UndefinedAtom &atom) { +bool Resolver::doUndefinedAtom(OwningAtomPtr<UndefinedAtom> atom) { DEBUG_WITH_TYPE("resolver", llvm::dbgs() << " UndefinedAtom: " - << llvm::format("0x%09lX", &atom) - << ", name=" << atom.name() << "\n"); - - // add to list of known atoms - _atoms.push_back(&atom); + << llvm::format("0x%09lX", atom.get()) + << ", name=" << atom.get()->name() << "\n"); // tell symbol table - bool newUndefAdded = _symbolTable.add(atom); + bool newUndefAdded = _symbolTable.add(*atom.get()); if (newUndefAdded) - _undefines.push_back(atom.name()); - - // If the undefined symbol has an alternative name, try to resolve the - // symbol with the name to give it a second chance. This feature is used - // for COFF "weak external" symbol. - if (newUndefAdded || !_symbolTable.isDefined(atom.name())) { - if (const UndefinedAtom *fallbackAtom = atom.fallback()) { - doUndefinedAtom(*fallbackAtom); - _symbolTable.addReplacement(&atom, fallbackAtom); - } - } - return newUndefAdded; -} + _undefines.push_back(atom.get()->name()); -/// \brief Add the section group and the group-child reference members. -void Resolver::maybeAddSectionGroupOrGnuLinkOnce(const DefinedAtom &atom) { - // First time adding a group? - bool isFirstTime = _symbolTable.addGroup(atom); - - if (!isFirstTime) { - // If duplicate symbols are allowed, select the first group. - if (_ctx.getAllowDuplicates()) - return; - auto *prevGroup = dyn_cast<DefinedAtom>(_symbolTable.findGroup(atom.name())); - assert(prevGroup && - "Internal Error: The group atom could only be a defined atom"); - // The atoms should be of the same content type, reject invalid group - // resolution behaviors. - if (atom.contentType() == prevGroup->contentType()) - return; - llvm::errs() << "SymbolTable: error while merging " << atom.name() - << "\n"; - llvm::report_fatal_error("duplicate symbol error"); - } + // add to list of known atoms + _atoms.push_back(OwningAtomPtr<Atom>(atom.release())); - for (const Reference *r : atom) { - if (r->kindNamespace() == lld::Reference::KindNamespace::all && - r->kindValue() == lld::Reference::kindGroupChild) { - const DefinedAtom *target = dyn_cast<DefinedAtom>(r->target()); - assert(target && "Internal Error: kindGroupChild references need to " - "be associated with Defined Atoms only"); - _atoms.push_back(target); - _symbolTable.add(*target); - } - } + return newUndefAdded; } // Called on each atom when a file is added. Returns true if a given // atom is added to the symbol table. -void Resolver::doDefinedAtom(const DefinedAtom &atom) { +void Resolver::doDefinedAtom(OwningAtomPtr<DefinedAtom> atom) { DEBUG_WITH_TYPE("resolver", llvm::dbgs() << " DefinedAtom: " - << llvm::format("0x%09lX", &atom) + << llvm::format("0x%09lX", atom.get()) << ", file=#" - << atom.file().ordinal() + << atom.get()->file().ordinal() << ", atom=#" - << atom.ordinal() + << atom.get()->ordinal() << ", name=" - << atom.name() + << atom.get()->name() << ", type=" - << atom.contentType() + << atom.get()->contentType() << "\n"); - // add to list of known atoms - _atoms.push_back(&atom); - - if (atom.isGroupParent()) { - maybeAddSectionGroupOrGnuLinkOnce(atom); - } else { - _symbolTable.add(atom); - } - // An atom that should never be dead-stripped is a dead-strip root. - if (_ctx.deadStrip() && atom.deadStrip() == DefinedAtom::deadStripNever) { - _deadStripRoots.insert(&atom); + if (_ctx.deadStrip() && + atom.get()->deadStrip() == DefinedAtom::deadStripNever) { + _deadStripRoots.insert(atom.get()); } + + // add to list of known atoms + _symbolTable.add(*atom.get()); + _atoms.push_back(OwningAtomPtr<Atom>(atom.release())); } -void Resolver::doSharedLibraryAtom(const SharedLibraryAtom &atom) { +void Resolver::doSharedLibraryAtom(OwningAtomPtr<SharedLibraryAtom> atom) { DEBUG_WITH_TYPE("resolver", llvm::dbgs() << " SharedLibraryAtom: " - << llvm::format("0x%09lX", &atom) + << llvm::format("0x%09lX", atom.get()) << ", name=" - << atom.name() + << atom.get()->name() << "\n"); - // add to list of known atoms - _atoms.push_back(&atom); - // tell symbol table - _symbolTable.add(atom); + _symbolTable.add(*atom.get()); + + // add to list of known atoms + _atoms.push_back(OwningAtomPtr<Atom>(atom.release())); } -void Resolver::doAbsoluteAtom(const AbsoluteAtom &atom) { +void Resolver::doAbsoluteAtom(OwningAtomPtr<AbsoluteAtom> atom) { DEBUG_WITH_TYPE("resolver", llvm::dbgs() << " AbsoluteAtom: " - << llvm::format("0x%09lX", &atom) + << llvm::format("0x%09lX", atom.get()) << ", name=" - << atom.name() + << atom.get()->name() << "\n"); - // add to list of known atoms - _atoms.push_back(&atom); - // tell symbol table - if (atom.scope() != Atom::scopeTranslationUnit) - _symbolTable.add(atom); -} + if (atom.get()->scope() != Atom::scopeTranslationUnit) + _symbolTable.add(*atom.get()); -// utility to add a vector of atoms -void Resolver::addAtoms(const std::vector<const DefinedAtom *> &newAtoms) { - for (const DefinedAtom *newAtom : newAtoms) - doDefinedAtom(*newAtom); -} - -// Instantiate an archive file member if there's a file containing a -// defined symbol for a given symbol name. Instantiation is done in a -// different worker thread and has no visible side effect. -void Resolver::maybePreloadArchiveMember(StringRef sym) { - auto it = _archiveMap.find(sym); - if (it == _archiveMap.end()) - return; - ArchiveLibraryFile *archive = it->second; - archive->preload(_ctx.getTaskGroup(), sym); + // add to list of known atoms + _atoms.push_back(OwningAtomPtr<Atom>(atom.release())); } // Returns true if at least one of N previous files has created an @@ -276,23 +208,6 @@ File *Resolver::getFile(int &index) { return cast<FileNode>(inputs[index++].get())->getFile(); } -// Update a map of Symbol -> ArchiveFile. The map is used for speculative -// file loading. -void Resolver::updatePreloadArchiveMap() { - std::vector<std::unique_ptr<Node>> &nodes = _ctx.getNodes(); - for (int i = nodes.size() - 1; i >= 0; --i) { - auto *fnode = dyn_cast<FileNode>(nodes[i].get()); - if (!fnode) - continue; - auto *archive = dyn_cast<ArchiveLibraryFile>(fnode->getFile()); - if (!archive || _archiveSeen.count(archive)) - continue; - _archiveSeen.insert(archive); - for (StringRef sym : archive->getDefinedSymbols()) - _archiveMap[sym] = archive; - } -} - // Keep adding atoms until _ctx.getNextFile() returns an error. This // function is where undefined atoms are resolved. bool Resolver::resolveUndefines() { @@ -315,10 +230,17 @@ bool Resolver::resolveUndefines() { } DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Loaded file: " << file->path() << "\n"); - file->beforeLink(); - updatePreloadArchiveMap(); switch (file->kind()) { - case File::kindObject: + case File::kindErrorObject: + case File::kindNormalizedObject: + case File::kindMachObject: + case File::kindCEntryObject: + case File::kindHeaderObject: + case File::kindEntryObject: + case File::kindUndefinedSymsObject: + case File::kindStubHelperObject: + case File::kindResolverMergedObject: + case File::kindSectCreateObject: { // The same file may be visited more than once if the file is // in --start-group and --end-group. Only library files should // be processed more than once. @@ -327,17 +249,41 @@ bool Resolver::resolveUndefines() { seen.insert(file); assert(!file->hasOrdinal()); file->setOrdinal(_ctx.getNextOrdinalAndIncrement()); - undefAdded = handleFile(*file); + auto undefAddedOrError = handleFile(*file); + if (auto EC = undefAddedOrError.takeError()) { + // FIXME: This should be passed to logAllUnhandledErrors but it needs + // to be passed a Twine instead of a string. + llvm::errs() << "Error in " + file->path() << ": "; + logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string()); + return false; + } + undefAdded = undefAddedOrError.get(); break; - case File::kindArchiveLibrary: + } + case File::kindArchiveLibrary: { if (!file->hasOrdinal()) file->setOrdinal(_ctx.getNextOrdinalAndIncrement()); - undefAdded = handleArchiveFile(*file); + auto undefAddedOrError = handleArchiveFile(*file); + if (auto EC = undefAddedOrError.takeError()) { + // FIXME: This should be passed to logAllUnhandledErrors but it needs + // to be passed a Twine instead of a string. + llvm::errs() << "Error in " + file->path() << ": "; + logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string()); + return false; + } + undefAdded = undefAddedOrError.get(); break; + } case File::kindSharedLibrary: if (!file->hasOrdinal()) file->setOrdinal(_ctx.getNextOrdinalAndIncrement()); - handleSharedLibrary(*file); + if (auto EC = handleSharedLibrary(*file)) { + // FIXME: This should be passed to logAllUnhandledErrors but it needs + // to be passed a Twine instead of a string. + llvm::errs() << "Error in " + file->path() << ": "; + logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string()); + return false; + } break; } _newUndefinesAdded[file] = undefAdded; @@ -350,8 +296,8 @@ void Resolver::updateReferences() { DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "******** Updating references:\n"); ScopedTask task(getDefaultDomain(), "updateReferences"); - for (const Atom *atom : _atoms) { - if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) { + for (const OwningAtomPtr<Atom> &atom : _atoms) { + if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom.get())) { for (const Reference *ref : *defAtom) { // A reference of type kindAssociate should't be updated. // Instead, an atom having such reference will be removed @@ -359,7 +305,7 @@ void Resolver::updateReferences() { // go away as a group. if (ref->kindNamespace() == lld::Reference::KindNamespace::all && ref->kindValue() == lld::Reference::kindAssociate) { - if (_symbolTable.isCoalescedAway(atom)) + if (_symbolTable.isCoalescedAway(atom.get())) _deadAtoms.insert(ref->target()); continue; } @@ -391,8 +337,7 @@ void Resolver::markLive(const Atom *atom) { static bool isBackref(const Reference *ref) { if (ref->kindNamespace() != lld::Reference::KindNamespace::all) return false; - return (ref->kindValue() == lld::Reference::kindLayoutAfter || - ref->kindValue() == lld::Reference::kindGroupChild); + return (ref->kindValue() == lld::Reference::kindLayoutAfter); } // remove all atoms not actually used @@ -408,19 +353,19 @@ void Resolver::deadStripOptimize() { // Make a reverse map of such references before traversing the graph. // While traversing the list of atoms, mark AbsoluteAtoms as live // in order to avoid reclaim. - for (const Atom *atom : _atoms) { - if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) + for (const OwningAtomPtr<Atom> &atom : _atoms) { + if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom.get())) for (const Reference *ref : *defAtom) if (isBackref(ref)) - _reverseRef.insert(std::make_pair(ref->target(), atom)); - if (const AbsoluteAtom *absAtom = dyn_cast<AbsoluteAtom>(atom)) + _reverseRef.insert(std::make_pair(ref->target(), atom.get())); + if (const AbsoluteAtom *absAtom = dyn_cast<AbsoluteAtom>(atom.get())) markLive(absAtom); } // By default, shared libraries are built with all globals as dead strip roots if (_ctx.globalsAreDeadStripRoots()) - for (const Atom *atom : _atoms) - if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) + for (const OwningAtomPtr<Atom> &atom : _atoms) + if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom.get())) if (defAtom->scope() == DefinedAtom::scopeGlobal) _deadStripRoots.insert(defAtom); @@ -436,8 +381,9 @@ void Resolver::deadStripOptimize() { markLive(dsrAtom); // now remove all non-live atoms from _atoms - _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), [&](const Atom *a) { - return _liveAtoms.count(a) == 0; + _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), + [&](OwningAtomPtr<Atom> &a) { + return _liveAtoms.count(a.get()) == 0; }), _atoms.end()); } @@ -496,8 +442,10 @@ void Resolver::removeCoalescedAwayAtoms() { DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "******** Removing coalesced away atoms:\n"); ScopedTask task(getDefaultDomain(), "removeCoalescedAwayAtoms"); - _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), [&](const Atom *a) { - return _symbolTable.isCoalescedAway(a) || _deadAtoms.count(a); + _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), + [&](OwningAtomPtr<Atom> &a) { + return _symbolTable.isCoalescedAway(a.get()) || + _deadAtoms.count(a.get()); }), _atoms.end()); } @@ -505,7 +453,6 @@ void Resolver::removeCoalescedAwayAtoms() { bool Resolver::resolve() { DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "******** Resolving atom references:\n"); - updatePreloadArchiveMap(); if (!resolveUndefines()) return false; updateReferences(); @@ -524,15 +471,16 @@ bool Resolver::resolve() { return true; } -void Resolver::MergedFile::addAtoms(std::vector<const Atom *> &all) { +void Resolver::MergedFile::addAtoms( + llvm::MutableArrayRef<OwningAtomPtr<Atom>> all) { ScopedTask task(getDefaultDomain(), "addAtoms"); DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Resolver final atom list:\n"); - for (const Atom *atom : all) { + for (OwningAtomPtr<Atom> &atom : all) { #ifndef NDEBUG - if (auto *definedAtom = dyn_cast<DefinedAtom>(atom)) { + if (auto *definedAtom = dyn_cast<DefinedAtom>(atom.get())) { DEBUG_WITH_TYPE("resolver", llvm::dbgs() - << llvm::format(" 0x%09lX", atom) + << llvm::format(" 0x%09lX", definedAtom) << ", file=#" << definedAtom->file().ordinal() << ", atom=#" @@ -544,13 +492,13 @@ void Resolver::MergedFile::addAtoms(std::vector<const Atom *> &all) { << "\n"); } else { DEBUG_WITH_TYPE("resolver", llvm::dbgs() - << llvm::format(" 0x%09lX", atom) + << llvm::format(" 0x%09lX", atom.get()) << ", name=" - << atom->name() + << atom.get()->name() << "\n"); } #endif - addAtom(*atom); + addAtom(*atom.release()); } } diff --git a/lib/Core/SymbolTable.cpp b/lib/Core/SymbolTable.cpp index b85a83ffbfe6..44631a5d40dc 100644 --- a/lib/Core/SymbolTable.cpp +++ b/lib/Core/SymbolTable.cpp @@ -28,8 +28,6 @@ #include <vector> namespace lld { -SymbolTable::SymbolTable(LinkingContext &context) : _ctx(context) {} - bool SymbolTable::add(const UndefinedAtom &atom) { return addByName(atom); } bool SymbolTable::add(const SharedLibraryAtom &atom) { return addByName(atom); } @@ -55,25 +53,6 @@ bool SymbolTable::add(const DefinedAtom &atom) { return false; } -const Atom *SymbolTable::findGroup(StringRef sym) { - NameToAtom::iterator pos = _groupTable.find(sym); - if (pos == _groupTable.end()) - return nullptr; - return pos->second; -} - -bool SymbolTable::addGroup(const DefinedAtom &da) { - StringRef name = da.name(); - assert(!name.empty()); - const Atom *existing = findGroup(name); - if (existing == nullptr) { - _groupTable[name] = &da; - return true; - } - _replacedAtoms[&da] = existing; - return false; -} - enum NameCollisionResolution { NCR_First, NCR_Second, @@ -185,19 +164,16 @@ bool SymbolTable::addByName(const Atom &newAtom) { // fallthrough } case MCR_Error: - if (!_ctx.getAllowDuplicates()) { - llvm::errs() << "Duplicate symbols: " - << existing->name() - << ":" - << existing->file().path() - << " and " - << newAtom.name() - << ":" - << newAtom.file().path() - << "\n"; - llvm::report_fatal_error("duplicate symbol error"); - } - useNew = false; + llvm::errs() << "Duplicate symbols: " + << existing->name() + << ":" + << existing->file().path() + << " and " + << newAtom.name() + << ":" + << newAtom.file().path() + << "\n"; + llvm::report_fatal_error("duplicate symbol error"); break; } break; @@ -207,56 +183,13 @@ bool SymbolTable::addByName(const Atom &newAtom) { const UndefinedAtom* newUndef = cast<UndefinedAtom>(&newAtom); bool sameCanBeNull = (existingUndef->canBeNull() == newUndef->canBeNull()); - if (!sameCanBeNull && _ctx.warnIfCoalesableAtomsHaveDifferentCanBeNull()) { - llvm::errs() << "lld warning: undefined symbol " - << existingUndef->name() - << " has different weakness in " - << existingUndef->file().path() - << " and in " << newUndef->file().path() << "\n"; - } - - const UndefinedAtom *existingFallback = existingUndef->fallback(); - const UndefinedAtom *newFallback = newUndef->fallback(); - bool hasDifferentFallback = - (existingFallback && newFallback && - existingFallback->name() != newFallback->name()); - if (hasDifferentFallback) { - llvm::errs() << "lld warning: undefined symbol " - << existingUndef->name() << " has different fallback: " - << existingFallback->name() << " in " - << existingUndef->file().path() << " and " - << newFallback->name() << " in " - << newUndef->file().path() << "\n"; - } - - bool hasNewFallback = newUndef->fallback(); if (sameCanBeNull) - useNew = hasNewFallback; + useNew = false; else useNew = (newUndef->canBeNull() < existingUndef->canBeNull()); break; } case NCR_DupShLib: { - const SharedLibraryAtom *curShLib = cast<SharedLibraryAtom>(existing); - const SharedLibraryAtom *newShLib = cast<SharedLibraryAtom>(&newAtom); - bool sameNullness = - (curShLib->canBeNullAtRuntime() == newShLib->canBeNullAtRuntime()); - bool sameName = curShLib->loadName().equals(newShLib->loadName()); - if (sameName && !sameNullness && - _ctx.warnIfCoalesableAtomsHaveDifferentCanBeNull()) { - // FIXME: need diagonstics interface for writing warning messages - llvm::errs() << "lld warning: shared library symbol " - << curShLib->name() << " has different weakness in " - << curShLib->file().path() << " and in " - << newShLib->file().path(); - } - if (!sameName && _ctx.warnIfCoalesableAtomsHaveDifferentLoadName()) { - // FIXME: need diagonstics interface for writing warning messages - llvm::errs() << "lld warning: shared library symbol " - << curShLib->name() << " has different load path in " - << curShLib->file().path() << " and in " - << newShLib->file().path(); - } useNew = false; break; } @@ -266,9 +199,6 @@ bool SymbolTable::addByName(const Atom &newAtom) { break; } - // Give context a chance to change which is kept. - _ctx.notifySymbolTableCoalesce(existing, &newAtom, useNew); - if (useNew) { // Update name table to use new atom. _nameTable[name] = &newAtom; diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt index 840ccce50ab3..1bd1f2125816 100644 --- a/lib/Driver/CMakeLists.txt +++ b/lib/Driver/CMakeLists.txt @@ -1,19 +1,9 @@ -set(LLVM_TARGET_DEFINITIONS UniversalDriverOptions.td) -tablegen(LLVM UniversalDriverOptions.inc -gen-opt-parser-defs) -set(LLVM_TARGET_DEFINITIONS GnuLdOptions.td) -tablegen(LLVM GnuLdOptions.inc -gen-opt-parser-defs) -set(LLVM_TARGET_DEFINITIONS CoreOptions.td) -tablegen(LLVM CoreOptions.inc -gen-opt-parser-defs) set(LLVM_TARGET_DEFINITIONS DarwinLdOptions.td) tablegen(LLVM DarwinLdOptions.inc -gen-opt-parser-defs) add_public_tablegen_target(DriverOptionsTableGen) add_lld_library(lldDriver - CoreDriver.cpp DarwinLdDriver.cpp - Driver.cpp - GnuLdDriver.cpp - UniversalDriver.cpp ADDITIONAL_HEADER_DIRS ${LLD_INCLUDE_DIR}/lld/Driver @@ -21,16 +11,6 @@ add_lld_library(lldDriver LINK_LIBS lldConfig lldMachO - lldCOFF - lldELF - lldELF2 - lldAArch64ELFTarget - lldARMELFTarget - lldHexagonELFTarget - lldMipsELFTarget - lldX86ELFTarget - lldExampleSubTarget - lldX86_64ELFTarget lldCore lldReaderWriter lldYAML @@ -40,4 +20,3 @@ add_lld_library(lldDriver ) add_dependencies(lldDriver DriverOptionsTableGen) - diff --git a/lib/Driver/CoreDriver.cpp b/lib/Driver/CoreDriver.cpp deleted file mode 100644 index ce8648595109..000000000000 --- a/lib/Driver/CoreDriver.cpp +++ /dev/null @@ -1,173 +0,0 @@ -//===- lib/Driver/CoreDriver.cpp ------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lld/Core/Reader.h" -#include "lld/Driver/Driver.h" -#include "lld/ReaderWriter/CoreLinkingContext.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/Triple.h" -#include "llvm/Option/Arg.h" -#include "llvm/Option/Option.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Signals.h" -#include "llvm/Support/raw_ostream.h" - -using namespace lld; - -namespace { - -// Create enum with OPT_xxx values for each option in CoreOptions.td -enum { - OPT_INVALID = 0, -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELP, META) \ - OPT_##ID, -#include "CoreOptions.inc" -#undef OPTION -}; - -// Create prefix string literals used in CoreOptions.td -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; -#include "CoreOptions.inc" -#undef PREFIX - -// Create table mapping all options defined in CoreOptions.td -static const llvm::opt::OptTable::Info infoTable[] = { -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR) \ - { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ - PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS }, -#include "CoreOptions.inc" -#undef OPTION -}; - -// Create OptTable class for parsing actual command line arguments -class CoreOptTable : public llvm::opt::OptTable { -public: - CoreOptTable() : OptTable(infoTable) {} -}; - -} // namespace anonymous - - -namespace lld { - -static const Registry::KindStrings coreKindStrings[] = { - { CoreLinkingContext::TEST_RELOC_CALL32, "call32" }, - { CoreLinkingContext::TEST_RELOC_PCREL32, "pcrel32" }, - { CoreLinkingContext::TEST_RELOC_GOT_LOAD32, "gotLoad32" }, - { CoreLinkingContext::TEST_RELOC_GOT_USE32, "gotUse32" }, - { CoreLinkingContext::TEST_RELOC_LEA32_WAS_GOT, "lea32wasGot" }, - LLD_KIND_STRING_END -}; - -bool CoreDriver::link(llvm::ArrayRef<const char *> args, - raw_ostream &diagnostics) { - CoreLinkingContext ctx; - - // Register possible input file parsers. - ctx.registry().addSupportYamlFiles(); - ctx.registry().addKindTable(Reference::KindNamespace::testing, - Reference::KindArch::all, coreKindStrings); - - if (!parse(args, ctx)) - return false; - return Driver::link(ctx); -} - -bool CoreDriver::parse(llvm::ArrayRef<const char *> args, - CoreLinkingContext &ctx, raw_ostream &diagnostics) { - // Parse command line options using CoreOptions.td - CoreOptTable table; - unsigned missingIndex; - unsigned missingCount; - llvm::opt::InputArgList parsedArgs = - table.ParseArgs(args.slice(1), missingIndex, missingCount); - if (missingCount) { - diagnostics << "error: missing arg value for '" - << parsedArgs.getArgString(missingIndex) << "' expected " - << missingCount << " argument(s).\n"; - return false; - } - - // Set default options - ctx.setOutputPath("-"); - ctx.setDeadStripping(false); - ctx.setGlobalsAreDeadStripRoots(false); - ctx.setPrintRemainingUndefines(false); - ctx.setAllowRemainingUndefines(true); - ctx.setSearchArchivesToOverrideTentativeDefinitions(false); - - // Process all the arguments and create input files. - for (auto inputArg : parsedArgs) { - switch (inputArg->getOption().getID()) { - case OPT_mllvm: - ctx.appendLLVMOption(inputArg->getValue()); - break; - - case OPT_entry: - ctx.setEntrySymbolName(inputArg->getValue()); - break; - - case OPT_output: - ctx.setOutputPath(inputArg->getValue()); - break; - - case OPT_dead_strip: - ctx.setDeadStripping(true); - break; - - case OPT_keep_globals: - ctx.setGlobalsAreDeadStripRoots(true); - break; - - case OPT_undefines_are_errors: - ctx.setPrintRemainingUndefines(true); - ctx.setAllowRemainingUndefines(false); - break; - - case OPT_commons_search_archives: - ctx.setSearchArchivesToOverrideTentativeDefinitions(true); - break; - - case OPT_add_pass: - ctx.addPassNamed(inputArg->getValue()); - break; - - case OPT_INPUT: { - std::vector<std::unique_ptr<File>> files - = loadFile(ctx, inputArg->getValue(), false); - for (std::unique_ptr<File> &file : files) - ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file))); - break; - } - - default: - break; - } - } - - parseLLVMOptions(ctx); - - if (ctx.getNodes().empty()) { - diagnostics << "No input files\n"; - return false; - } - - // Validate the combination of options used. - return ctx.validate(diagnostics); -} - -} // namespace lld diff --git a/lib/Driver/CoreOptions.td b/lib/Driver/CoreOptions.td deleted file mode 100644 index df7cb41737d2..000000000000 --- a/lib/Driver/CoreOptions.td +++ /dev/null @@ -1,15 +0,0 @@ -include "llvm/Option/OptParser.td" - -def output : Separate<["-"], "o">; -def entry : Separate<["-"], "e">; - -def dead_strip : Flag<["--"], "dead-strip">; -def undefines_are_errors : Flag<["--"], "undefines-are-errors">; -def keep_globals : Flag<["--"], "keep-globals">; -def commons_search_archives : Flag<["--"], "commons-search-archives">; - -def add_pass : Separate<["--"], "add-pass">; - -def target : Separate<["-"], "target">, HelpText<"Target triple to link for">; -def mllvm : Separate<["-"], "mllvm">, HelpText<"Options to pass to LLVM">; - diff --git a/lib/Driver/DarwinLdDriver.cpp b/lib/Driver/DarwinLdDriver.cpp index 40fad74c9529..496b651bab4f 100644 --- a/lib/Driver/DarwinLdDriver.cpp +++ b/lib/Driver/DarwinLdDriver.cpp @@ -13,8 +13,11 @@ /// //===----------------------------------------------------------------------===// -#include "lld/Core/File.h" #include "lld/Core/ArchiveLibraryFile.h" +#include "lld/Core/File.h" +#include "lld/Core/Instrumentation.h" +#include "lld/Core/PassManager.h" +#include "lld/Core/Resolver.h" #include "lld/Core/SharedLibraryFile.h" #include "lld/Driver/Driver.h" #include "lld/ReaderWriter/MachOLinkingContext.h" @@ -25,17 +28,10 @@ #include "llvm/Option/Arg.h" #include "llvm/Option/Option.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Error.h" #include "llvm/Support/Format.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/MachO.h" -#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Path.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" -#include <algorithm> using namespace lld; @@ -72,6 +68,25 @@ public: DarwinLdOptTable() : OptTable(infoTable) {} }; +static std::vector<std::unique_ptr<File>> +makeErrorFile(StringRef path, std::error_code ec) { + std::vector<std::unique_ptr<File>> result; + result.push_back(llvm::make_unique<ErrorFile>(path, ec)); + return result; +} + +static std::vector<std::unique_ptr<File>> +parseMemberFiles(std::unique_ptr<File> file) { + std::vector<std::unique_ptr<File>> members; + if (auto *archive = dyn_cast<ArchiveLibraryFile>(file.get())) { + if (std::error_code ec = archive->parseAllMembers(members)) + return makeErrorFile(file->path(), ec); + } else { + members.push_back(std::move(file)); + } + return members; +} + std::vector<std::unique_ptr<File>> loadFile(MachOLinkingContext &ctx, StringRef path, raw_ostream &diag, bool wholeArchive, bool upwardDylib) { @@ -215,9 +230,9 @@ static std::error_code parseOrderFile(StringRef orderFilePath, // In this variant, the path is to a text file which contains a partial path // per line. The <dir> prefix is prepended to each partial path. // -static std::error_code loadFileList(StringRef fileListPath, - MachOLinkingContext &ctx, bool forceLoad, - raw_ostream &diagnostics) { +static llvm::Error loadFileList(StringRef fileListPath, + MachOLinkingContext &ctx, bool forceLoad, + raw_ostream &diagnostics) { // If there is a comma, split off <dir>. std::pair<StringRef, StringRef> opt = fileListPath.split(','); StringRef filePath = opt.first; @@ -227,7 +242,7 @@ static std::error_code loadFileList(StringRef fileListPath, ErrorOr<std::unique_ptr<MemoryBuffer>> mb = MemoryBuffer::getFileOrSTDIN(filePath); if (std::error_code ec = mb.getError()) - return ec; + return llvm::errorCodeToError(ec); StringRef buffer = mb->get()->getBuffer(); while (!buffer.empty()) { // Split off each line in the file. @@ -245,9 +260,9 @@ static std::error_code loadFileList(StringRef fileListPath, path = ctx.copy(line); } if (!ctx.pathExists(path)) { - return make_dynamic_error_code(Twine("File not found '") - + path - + "'"); + return llvm::make_error<GenericError>(Twine("File not found '") + + path + + "'"); } if (ctx.testingFileUsage()) { diagnostics << "Found filelist entry " << canonicalizePath(path) << '\n'; @@ -255,7 +270,7 @@ static std::error_code loadFileList(StringRef fileListPath, addFile(path, ctx, forceLoad, false, diagnostics); buffer = lineAndRest.second; } - return std::error_code(); + return llvm::Error(); } /// Parse number assuming it is base 16, but allow 0x prefix. @@ -265,20 +280,24 @@ static bool parseNumberBase16(StringRef numStr, uint64_t &baseAddress) { return numStr.getAsInteger(16, baseAddress); } -namespace lld { - -bool DarwinLdDriver::linkMachO(llvm::ArrayRef<const char *> args, - raw_ostream &diagnostics) { - MachOLinkingContext ctx; - if (!parse(args, ctx, diagnostics)) - return false; - if (ctx.doNothing()) - return true; - return link(ctx, diagnostics); +static void parseLLVMOptions(const LinkingContext &ctx) { + // Honor -mllvm + if (!ctx.llvmOptions().empty()) { + unsigned numArgs = ctx.llvmOptions().size(); + auto **args = new const char *[numArgs + 2]; + args[0] = "lld (LLVM option parsing)"; + for (unsigned i = 0; i != numArgs; ++i) + args[i + 1] = ctx.llvmOptions()[i]; + args[numArgs + 1] = nullptr; + llvm::cl::ParseCommandLineOptions(numArgs + 1, args); + } } -bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, - MachOLinkingContext &ctx, raw_ostream &diagnostics) { +namespace lld { +namespace mach_o { + +bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, + raw_ostream &diagnostics) { // Parse command line options using DarwinLdOptions.td DarwinLdOptTable table; unsigned missingIndex; @@ -299,6 +318,7 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, // Figure out output kind ( -dylib, -r, -bundle, -preload, or -static ) llvm::MachO::HeaderFileType fileType = llvm::MachO::MH_EXECUTE; + bool isStaticExecutable = false; if (llvm::opt::Arg *kind = parsedArgs.getLastArg( OPT_dylib, OPT_relocatable, OPT_bundle, OPT_static, OPT_preload)) { switch (kind->getOption().getID()) { @@ -313,6 +333,7 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, break; case OPT_static: fileType = llvm::MachO::MH_EXECUTE; + isStaticExecutable = true; break; case OPT_preload: fileType = llvm::MachO::MH_PRELOAD; @@ -350,7 +371,7 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, } // Handle -macosx_version_min or -ios_version_min - MachOLinkingContext::OS os = MachOLinkingContext::OS::macOSX; + MachOLinkingContext::OS os = MachOLinkingContext::OS::unknown; uint32_t minOSVersion = 0; if (llvm::opt::Arg *minOS = parsedArgs.getLastArg(OPT_macosx_version_min, OPT_ios_version_min, @@ -385,9 +406,16 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, // No min-os version on command line, check environment variables } + // Handle export_dynamic + // FIXME: Should we warn when this applies to something other than a static + // executable or dylib? Those are the only cases where this has an effect. + // Note, this has to come before ctx.configure() so that we get the correct + // value for _globalsAreDeadStripRoots. + bool exportDynamicSymbols = parsedArgs.hasArg(OPT_export_dynamic); + // Now that there's enough information parsed in, let the linking context // set up default values. - ctx.configure(fileType, arch, os, minOSVersion); + ctx.configure(fileType, arch, os, minOSVersion, exportDynamicSymbols); // Handle -e xxx if (llvm::opt::Arg *entry = parsedArgs.getLastArg(OPT_entry)) @@ -673,6 +701,22 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, } } + // Handle obsolete ObjC options: -objc_gc_compaction, -objc_gc, -objc_gc_only + if (parsedArgs.getLastArg(OPT_objc_gc_compaction)) { + diagnostics << "error: -objc_gc_compaction is not supported\n"; + return false; + } + + if (parsedArgs.getLastArg(OPT_objc_gc)) { + diagnostics << "error: -objc_gc is not supported\n"; + return false; + } + + if (parsedArgs.getLastArg(OPT_objc_gc_only)) { + diagnostics << "error: -objc_gc_only is not supported\n"; + return false; + } + // Handle -pie or -no_pie if (llvm::opt::Arg *pie = parsedArgs.getLastArg(OPT_pie, OPT_no_pie)) { switch (ctx.outputMachOType()) { @@ -719,6 +763,182 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, } } + // Handle -version_load_command or -no_version_load_command + { + bool flagOn = false; + bool flagOff = false; + if (auto *arg = parsedArgs.getLastArg(OPT_version_load_command, + OPT_no_version_load_command)) { + flagOn = arg->getOption().getID() == OPT_version_load_command; + flagOff = arg->getOption().getID() == OPT_no_version_load_command; + } + + // default to adding version load command for dynamic code, + // static code must opt-in + switch (ctx.outputMachOType()) { + case llvm::MachO::MH_OBJECT: + ctx.setGenerateVersionLoadCommand(false); + break; + case llvm::MachO::MH_EXECUTE: + // dynamic executables default to generating a version load command, + // while static exectuables only generate it if required. + if (isStaticExecutable) { + if (flagOn) + ctx.setGenerateVersionLoadCommand(true); + } else { + if (!flagOff) + ctx.setGenerateVersionLoadCommand(true); + } + break; + case llvm::MachO::MH_PRELOAD: + case llvm::MachO::MH_KEXT_BUNDLE: + if (flagOn) + ctx.setGenerateVersionLoadCommand(true); + break; + case llvm::MachO::MH_DYLINKER: + case llvm::MachO::MH_DYLIB: + case llvm::MachO::MH_BUNDLE: + if (!flagOff) + ctx.setGenerateVersionLoadCommand(true); + break; + case llvm::MachO::MH_FVMLIB: + case llvm::MachO::MH_DYLDLINK: + case llvm::MachO::MH_DYLIB_STUB: + case llvm::MachO::MH_DSYM: + // We don't generate load commands for these file types, even if + // forced on. + break; + } + } + + // Handle -function_starts or -no_function_starts + { + bool flagOn = false; + bool flagOff = false; + if (auto *arg = parsedArgs.getLastArg(OPT_function_starts, + OPT_no_function_starts)) { + flagOn = arg->getOption().getID() == OPT_function_starts; + flagOff = arg->getOption().getID() == OPT_no_function_starts; + } + + // default to adding functions start for dynamic code, static code must + // opt-in + switch (ctx.outputMachOType()) { + case llvm::MachO::MH_OBJECT: + ctx.setGenerateFunctionStartsLoadCommand(false); + break; + case llvm::MachO::MH_EXECUTE: + // dynamic executables default to generating a version load command, + // while static exectuables only generate it if required. + if (isStaticExecutable) { + if (flagOn) + ctx.setGenerateFunctionStartsLoadCommand(true); + } else { + if (!flagOff) + ctx.setGenerateFunctionStartsLoadCommand(true); + } + break; + case llvm::MachO::MH_PRELOAD: + case llvm::MachO::MH_KEXT_BUNDLE: + if (flagOn) + ctx.setGenerateFunctionStartsLoadCommand(true); + break; + case llvm::MachO::MH_DYLINKER: + case llvm::MachO::MH_DYLIB: + case llvm::MachO::MH_BUNDLE: + if (!flagOff) + ctx.setGenerateFunctionStartsLoadCommand(true); + break; + case llvm::MachO::MH_FVMLIB: + case llvm::MachO::MH_DYLDLINK: + case llvm::MachO::MH_DYLIB_STUB: + case llvm::MachO::MH_DSYM: + // We don't generate load commands for these file types, even if + // forced on. + break; + } + } + + // Handle -data_in_code_info or -no_data_in_code_info + { + bool flagOn = false; + bool flagOff = false; + if (auto *arg = parsedArgs.getLastArg(OPT_data_in_code_info, + OPT_no_data_in_code_info)) { + flagOn = arg->getOption().getID() == OPT_data_in_code_info; + flagOff = arg->getOption().getID() == OPT_no_data_in_code_info; + } + + // default to adding data in code for dynamic code, static code must + // opt-in + switch (ctx.outputMachOType()) { + case llvm::MachO::MH_OBJECT: + if (!flagOff) + ctx.setGenerateDataInCodeLoadCommand(true); + break; + case llvm::MachO::MH_EXECUTE: + // dynamic executables default to generating a version load command, + // while static exectuables only generate it if required. + if (isStaticExecutable) { + if (flagOn) + ctx.setGenerateDataInCodeLoadCommand(true); + } else { + if (!flagOff) + ctx.setGenerateDataInCodeLoadCommand(true); + } + break; + case llvm::MachO::MH_PRELOAD: + case llvm::MachO::MH_KEXT_BUNDLE: + if (flagOn) + ctx.setGenerateDataInCodeLoadCommand(true); + break; + case llvm::MachO::MH_DYLINKER: + case llvm::MachO::MH_DYLIB: + case llvm::MachO::MH_BUNDLE: + if (!flagOff) + ctx.setGenerateDataInCodeLoadCommand(true); + break; + case llvm::MachO::MH_FVMLIB: + case llvm::MachO::MH_DYLDLINK: + case llvm::MachO::MH_DYLIB_STUB: + case llvm::MachO::MH_DSYM: + // We don't generate load commands for these file types, even if + // forced on. + break; + } + } + + // Handle sdk_version + if (llvm::opt::Arg *arg = parsedArgs.getLastArg(OPT_sdk_version)) { + uint32_t sdkVersion = 0; + if (MachOLinkingContext::parsePackedVersion(arg->getValue(), + sdkVersion)) { + diagnostics << "error: malformed sdkVersion value\n"; + return false; + } + ctx.setSdkVersion(sdkVersion); + } else if (ctx.generateVersionLoadCommand()) { + // If we don't have an sdk version, but were going to emit a load command + // with min_version, then we need to give an warning as we have no sdk + // version to put in that command. + // FIXME: We need to decide whether to make this an error. + diagnostics << "warning: -sdk_version is required when emitting " + "min version load command. " + "Setting sdk version to match provided min version\n"; + ctx.setSdkVersion(ctx.osMinVersion()); + } + + // Handle source_version + if (llvm::opt::Arg *arg = parsedArgs.getLastArg(OPT_source_version)) { + uint64_t version = 0; + if (MachOLinkingContext::parsePackedVersion(arg->getValue(), + version)) { + diagnostics << "error: malformed source_version value\n"; + return false; + } + ctx.setSourceVersion(version); + } + // Handle stack_size if (llvm::opt::Arg *stackSize = parsedArgs.getLastArg(OPT_stack_size)) { uint64_t stackSizeVal; @@ -794,6 +1014,10 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, ctx.setUndefinedMode(UndefMode); } + // Handle -no_objc_category_merging. + if (parsedArgs.getLastArg(OPT_no_objc_category_merging)) + ctx.setMergeObjCCategories(false); + // Handle -rpath <path> if (parsedArgs.hasArg(OPT_rpath)) { switch (ctx.outputMachOType()) { @@ -829,7 +1053,7 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, // Handle input files and sectcreate. for (auto &arg : parsedArgs) { bool upward; - ErrorOr<StringRef> resolvedPath = StringRef(); + llvm::Optional<StringRef> resolvedPath; switch (arg->getOption().getID()) { default: continue; @@ -852,9 +1076,10 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, return false; } else if (ctx.testingFileUsage()) { diagnostics << "Found " << (upward ? "upward " : " ") << "library " - << canonicalizePath(resolvedPath.get()) << '\n'; + << canonicalizePath(resolvedPath.getValue()) << '\n'; } - addFile(resolvedPath.get(), ctx, globalWholeArchive, upward, diagnostics); + addFile(resolvedPath.getValue(), ctx, globalWholeArchive, + upward, diagnostics); break; case OPT_framework: case OPT_upward_framework: @@ -866,17 +1091,20 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, return false; } else if (ctx.testingFileUsage()) { diagnostics << "Found " << (upward ? "upward " : " ") << "framework " - << canonicalizePath(resolvedPath.get()) << '\n'; + << canonicalizePath(resolvedPath.getValue()) << '\n'; } - addFile(resolvedPath.get(), ctx, globalWholeArchive, upward, diagnostics); + addFile(resolvedPath.getValue(), ctx, globalWholeArchive, + upward, diagnostics); break; case OPT_filelist: - if (std::error_code ec = loadFileList(arg->getValue(), - ctx, globalWholeArchive, - diagnostics)) { - diagnostics << "error: " << ec.message() - << ", processing '-filelist " << arg->getValue() - << "'\n"; + if (auto ec = loadFileList(arg->getValue(), + ctx, globalWholeArchive, + diagnostics)) { + handleAllErrors(std::move(ec), [&](const llvm::ErrorInfoBase &EI) { + diagnostics << "error: "; + EI.log(diagnostics); + diagnostics << ", processing '-filelist " << arg->getValue() << "'\n"; + }); return false; } break; @@ -908,5 +1136,80 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, return ctx.validate(diagnostics); } +/// This is where the link is actually performed. +bool link(llvm::ArrayRef<const char *> args, raw_ostream &diagnostics) { + MachOLinkingContext ctx; + if (!parse(args, ctx, diagnostics)) + return false; + if (ctx.doNothing()) + return true; + if (ctx.getNodes().empty()) + return false; + + for (std::unique_ptr<Node> &ie : ctx.getNodes()) + if (FileNode *node = dyn_cast<FileNode>(ie.get())) + node->getFile()->parse(); + + std::vector<std::unique_ptr<File>> internalFiles; + ctx.createInternalFiles(internalFiles); + for (auto i = internalFiles.rbegin(), e = internalFiles.rend(); i != e; ++i) { + auto &members = ctx.getNodes(); + members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i))); + } + + // Give target a chance to add files. + std::vector<std::unique_ptr<File>> implicitFiles; + ctx.createImplicitFiles(implicitFiles); + for (auto i = implicitFiles.rbegin(), e = implicitFiles.rend(); i != e; ++i) { + auto &members = ctx.getNodes(); + members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i))); + } + + // Give target a chance to postprocess input files. + // Mach-O uses this chance to move all object files before library files. + ctx.finalizeInputFiles(); + // Do core linking. + ScopedTask resolveTask(getDefaultDomain(), "Resolve"); + Resolver resolver(ctx); + if (!resolver.resolve()) + return false; + SimpleFile *merged = nullptr; + { + std::unique_ptr<SimpleFile> mergedFile = resolver.resultFile(); + merged = mergedFile.get(); + auto &members = ctx.getNodes(); + members.insert(members.begin(), + llvm::make_unique<FileNode>(std::move(mergedFile))); + } + resolveTask.end(); + + // Run passes on linked atoms. + ScopedTask passTask(getDefaultDomain(), "Passes"); + PassManager pm; + ctx.addPasses(pm); + if (auto ec = pm.runOnFile(*merged)) { + // FIXME: This should be passed to logAllUnhandledErrors but it needs + // to be passed a Twine instead of a string. + diagnostics << "Failed to run passes on file '" << ctx.outputPath() + << "': "; + logAllUnhandledErrors(std::move(ec), diagnostics, std::string()); + return false; + } + + passTask.end(); + + // Give linked atoms to Writer to generate output file. + ScopedTask writeTask(getDefaultDomain(), "Write"); + if (auto ec = ctx.writeFile(*merged)) { + // FIXME: This should be passed to logAllUnhandledErrors but it needs + // to be passed a Twine instead of a string. + diagnostics << "Failed to write file '" << ctx.outputPath() << "': "; + logAllUnhandledErrors(std::move(ec), diagnostics, std::string()); + return false; + } + + return true; +} +} // namespace mach_o } // namespace lld diff --git a/lib/Driver/DarwinLdOptions.td b/lib/Driver/DarwinLdOptions.td index cbf6ac1d4a4b..fa07f33646e7 100644 --- a/lib/Driver/DarwinLdOptions.td +++ b/lib/Driver/DarwinLdOptions.td @@ -33,6 +33,28 @@ def iphoneos_version_min : Separate<["-"], "iphoneos_version_min">, def ios_simulator_version_min : Separate<["-"], "ios_simulator_version_min">, MetaVarName<"<version>">, HelpText<"Minimum iOS simulator version">, Group<grp_opts>; +def sdk_version : Separate<["-"], "sdk_version">, + MetaVarName<"<version>">, + HelpText<"SDK version">, Group<grp_opts>; +def source_version : Separate<["-"], "source_version">, + MetaVarName<"<version>">, + HelpText<"Source version">, Group<grp_opts>; +def version_load_command : Flag<["-"], "version_load_command">, + HelpText<"Force generation of a version load command">, Group<grp_opts>; +def no_version_load_command : Flag<["-"], "no_version_load_command">, + HelpText<"Disable generation of a version load command">, Group<grp_opts>; +def function_starts : Flag<["-"], "function_starts">, + HelpText<"Force generation of a function starts load command">, + Group<grp_opts>; +def no_function_starts : Flag<["-"], "no_function_starts">, + HelpText<"Disable generation of a function starts load command">, + Group<grp_opts>; +def data_in_code_info : Flag<["-"], "data_in_code_info">, + HelpText<"Force generation of a data in code load command">, + Group<grp_opts>; +def no_data_in_code_info : Flag<["-"], "no_data_in_code_info">, + HelpText<"Disable generation of a data in code load command">, + Group<grp_opts>; def mllvm : Separate<["-"], "mllvm">, MetaVarName<"<option>">, HelpText<"Options to pass to LLVM during LTO">, Group<grp_opts>; @@ -68,6 +90,10 @@ def undefined : Separate<["-"], "undefined">, MetaVarName<"<undefined>">, HelpText<"Determines how undefined symbols are handled.">, Group<grp_opts>; +def no_objc_category_merging : Flag<["-"], "no_objc_category_merging">, + HelpText<"Disables the optimisation which merges Objective-C categories " + "on a class in to the class itself.">, + Group<grp_opts>; // main executable options def grp_main : OptionGroup<"opts">, HelpText<"MAIN EXECUTABLE OPTIONS">; @@ -84,6 +110,9 @@ def stack_size : Separate<["-"], "stack_size">, HelpText<"Specifies the maximum stack size for the main thread in a program. " "Must be a page-size multiple. (default=8Mb)">, Group<grp_main>; +def export_dynamic : Flag<["-"], "export_dynamic">, + HelpText<"Preserves all global symbols in main executables during LTO">, + Group<grp_main>; // dylib executable options def grp_dylib : OptionGroup<"opts">, HelpText<"DYLIB EXECUTABLE OPTIONS">; @@ -205,3 +234,9 @@ def single_module : Flag<["-"], "single_module">, HelpText<"Default for dylibs">, Group<grp_obsolete>; def multi_module : Flag<["-"], "multi_module">, HelpText<"Unsupported way to build dylibs">, Group<grp_obsolete>; +def objc_gc_compaction : Flag<["-"], "objc_gc_compaction">, + HelpText<"Unsupported ObjC GC option">, Group<grp_obsolete>; +def objc_gc : Flag<["-"], "objc_gc">, + HelpText<"Unsupported ObjC GC option">, Group<grp_obsolete>; +def objc_gc_only : Flag<["-"], "objc_gc_only">, + HelpText<"Unsupported ObjC GC option">, Group<grp_obsolete>; diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp deleted file mode 100644 index 6a7a26b3b0f6..000000000000 --- a/lib/Driver/Driver.cpp +++ /dev/null @@ -1,142 +0,0 @@ -//===- lib/Driver/Driver.cpp - Linker Driver Emulator -----------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lld/Core/ArchiveLibraryFile.h" -#include "lld/Core/File.h" -#include "lld/Core/Instrumentation.h" -#include "lld/Core/LLVM.h" -#include "lld/Core/Parallel.h" -#include "lld/Core/PassManager.h" -#include "lld/Core/Reader.h" -#include "lld/Core/Resolver.h" -#include "lld/Core/Writer.h" -#include "lld/Driver/Driver.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Option/Arg.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/Process.h" -#include "llvm/Support/raw_ostream.h" -#include <mutex> - -namespace lld { - -FileVector makeErrorFile(StringRef path, std::error_code ec) { - std::vector<std::unique_ptr<File>> result; - result.push_back(llvm::make_unique<ErrorFile>(path, ec)); - return result; -} - -FileVector parseMemberFiles(std::unique_ptr<File> file) { - std::vector<std::unique_ptr<File>> members; - if (auto *archive = dyn_cast<ArchiveLibraryFile>(file.get())) { - if (std::error_code ec = archive->parseAllMembers(members)) - return makeErrorFile(file->path(), ec); - } else { - members.push_back(std::move(file)); - } - return members; -} - -FileVector loadFile(LinkingContext &ctx, StringRef path, bool wholeArchive) { - ErrorOr<std::unique_ptr<MemoryBuffer>> mb - = MemoryBuffer::getFileOrSTDIN(path); - if (std::error_code ec = mb.getError()) - return makeErrorFile(path, ec); - ErrorOr<std::unique_ptr<File>> fileOrErr = - ctx.registry().loadFile(std::move(mb.get())); - if (std::error_code ec = fileOrErr.getError()) - return makeErrorFile(path, ec); - std::unique_ptr<File> &file = fileOrErr.get(); - if (wholeArchive) - return parseMemberFiles(std::move(file)); - std::vector<std::unique_ptr<File>> files; - files.push_back(std::move(file)); - return files; -} - -void Driver::parseLLVMOptions(const LinkingContext &ctx) { - // Honor -mllvm - if (!ctx.llvmOptions().empty()) { - unsigned numArgs = ctx.llvmOptions().size(); - auto **args = new const char *[numArgs + 2]; - args[0] = "lld (LLVM option parsing)"; - for (unsigned i = 0; i != numArgs; ++i) - args[i + 1] = ctx.llvmOptions()[i]; - args[numArgs + 1] = nullptr; - llvm::cl::ParseCommandLineOptions(numArgs + 1, args); - } -} - -/// This is where the link is actually performed. -bool Driver::link(LinkingContext &ctx, raw_ostream &diagnostics) { - if (ctx.getNodes().empty()) - return false; - - for (std::unique_ptr<Node> &ie : ctx.getNodes()) - if (FileNode *node = dyn_cast<FileNode>(ie.get())) - ctx.getTaskGroup().spawn([node] { node->getFile()->parse(); }); - - std::vector<std::unique_ptr<File>> internalFiles; - ctx.createInternalFiles(internalFiles); - for (auto i = internalFiles.rbegin(), e = internalFiles.rend(); i != e; ++i) { - auto &members = ctx.getNodes(); - members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i))); - } - - // Give target a chance to add files. - std::vector<std::unique_ptr<File>> implicitFiles; - ctx.createImplicitFiles(implicitFiles); - for (auto i = implicitFiles.rbegin(), e = implicitFiles.rend(); i != e; ++i) { - auto &members = ctx.getNodes(); - members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i))); - } - - // Give target a chance to postprocess input files. - // Mach-O uses this chance to move all object files before library files. - // ELF adds specific undefined symbols resolver. - ctx.finalizeInputFiles(); - - // Do core linking. - ScopedTask resolveTask(getDefaultDomain(), "Resolve"); - Resolver resolver(ctx); - if (!resolver.resolve()) { - ctx.getTaskGroup().sync(); - return false; - } - std::unique_ptr<SimpleFile> merged = resolver.resultFile(); - resolveTask.end(); - - // Run passes on linked atoms. - ScopedTask passTask(getDefaultDomain(), "Passes"); - PassManager pm; - ctx.addPasses(pm); - if (std::error_code ec = pm.runOnFile(*merged)) { - diagnostics << "Failed to write file '" << ctx.outputPath() - << "': " << ec.message() << "\n"; - return false; - } - - passTask.end(); - - // Give linked atoms to Writer to generate output file. - ScopedTask writeTask(getDefaultDomain(), "Write"); - if (std::error_code ec = ctx.writeFile(*merged)) { - diagnostics << "Failed to write file '" << ctx.outputPath() - << "': " << ec.message() << "\n"; - return false; - } - - return true; -} - -} // namespace lld diff --git a/lib/Driver/GnuLdDriver.cpp b/lib/Driver/GnuLdDriver.cpp deleted file mode 100644 index 1cff481dd8d7..000000000000 --- a/lib/Driver/GnuLdDriver.cpp +++ /dev/null @@ -1,782 +0,0 @@ -//===- lib/Driver/GnuLdDriver.cpp -----------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// -/// Concrete instance of the Driver for GNU's ld. -/// -//===----------------------------------------------------------------------===// - -#include "lld/Driver/Driver.h" -#include "lld/ReaderWriter/ELFLinkingContext.h" -#include "lld/ReaderWriter/LinkerScript.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/Triple.h" -#include "llvm/Option/Arg.h" -#include "llvm/Option/Option.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Signals.h" -#include "llvm/Support/StringSaver.h" -#include "llvm/Support/Timer.h" -#include "llvm/Support/raw_ostream.h" -#include <cstring> -#include <tuple> - -using namespace lld; - -using llvm::BumpPtrAllocator; - -namespace { - -// Create enum with OPT_xxx values for each option in GnuLdOptions.td -enum { - OPT_INVALID = 0, -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELP, META) \ - OPT_##ID, -#include "GnuLdOptions.inc" -#undef OPTION -}; - -// Create prefix string literals used in GnuLdOptions.td -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; -#include "GnuLdOptions.inc" -#undef PREFIX - -// Create table mapping all options defined in GnuLdOptions.td -static const llvm::opt::OptTable::Info infoTable[] = { -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR) \ - { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ - PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS }, -#include "GnuLdOptions.inc" -#undef OPTION -}; - - -// Create OptTable class for parsing actual command line arguments -class GnuLdOptTable : public llvm::opt::OptTable { -public: - GnuLdOptTable() : OptTable(infoTable){} -}; - -} // anonymous namespace - -// If a command line option starts with "@", the driver reads its suffix as a -// file, parse its contents as a list of command line options, and insert them -// at the original @file position. If file cannot be read, @file is not expanded -// and left unmodified. @file can appear in a response file, so it's a recursive -// process. -static llvm::ArrayRef<const char *> -maybeExpandResponseFiles(llvm::ArrayRef<const char *> args, - BumpPtrAllocator &alloc) { - // Expand response files. - SmallVector<const char *, 256> smallvec; - for (const char *arg : args) - smallvec.push_back(arg); - llvm::StringSaver saver(alloc); - llvm::cl::ExpandResponseFiles(saver, llvm::cl::TokenizeGNUCommandLine, smallvec); - - // Pack the results to a C-array and return it. - const char **copy = alloc.Allocate<const char *>(smallvec.size() + 1); - std::copy(smallvec.begin(), smallvec.end(), copy); - copy[smallvec.size()] = nullptr; - return llvm::makeArrayRef(copy, smallvec.size() + 1); -} - -// Parses an argument of --defsym=<sym>=<number> -static bool parseDefsymAsAbsolute(StringRef opt, StringRef &sym, - uint64_t &addr) { - size_t equalPos = opt.find('='); - if (equalPos == 0 || equalPos == StringRef::npos) - return false; - sym = opt.substr(0, equalPos); - if (opt.substr(equalPos + 1).getAsInteger(0, addr)) - return false; - return true; -} - -// Parses an argument of --defsym=<sym>=<sym> -static bool parseDefsymAsAlias(StringRef opt, StringRef &sym, - StringRef &target) { - size_t equalPos = opt.find('='); - if (equalPos == 0 || equalPos == StringRef::npos) - return false; - sym = opt.substr(0, equalPos); - target = opt.substr(equalPos + 1); - return !target.empty(); -} - -// Parses -z max-page-size=<value> -static bool parseMaxPageSize(StringRef opt, uint64_t &val) { - size_t equalPos = opt.find('='); - if (equalPos == 0 || equalPos == StringRef::npos) - return false; - StringRef value = opt.substr(equalPos + 1); - val = 0; - if (value.getAsInteger(0, val) || !val) - return false; - return true; -} - -bool GnuLdDriver::linkELF(llvm::ArrayRef<const char *> args, - raw_ostream &diag) { - BumpPtrAllocator alloc; - args = maybeExpandResponseFiles(args, alloc); - std::unique_ptr<ELFLinkingContext> options; - if (!parse(args, options, diag)) - return false; - if (!options) - return true; - bool linked = link(*options, diag); - - // Handle --stats. - if (options->collectStats()) { - llvm::TimeRecord t = llvm::TimeRecord::getCurrentTime(true); - diag << "total time in link " << t.getProcessTime() << "\n"; - diag << "data size " << t.getMemUsed() << "\n"; - } - return linked; -} - -static llvm::Optional<llvm::Triple::ArchType> -getArchType(const llvm::Triple &triple, StringRef value) { - switch (triple.getArch()) { - case llvm::Triple::x86: - case llvm::Triple::x86_64: - if (value == "elf_i386") - return llvm::Triple::x86; - if (value == "elf_x86_64") - return llvm::Triple::x86_64; - return llvm::None; - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - return llvm::StringSwitch<llvm::Optional<llvm::Triple::ArchType>>(value) - .Cases("elf32btsmip", "elf32btsmipn32", llvm::Triple::mips) - .Cases("elf32ltsmip", "elf32ltsmipn32", llvm::Triple::mipsel) - .Case("elf64btsmip", llvm::Triple::mips64) - .Case("elf64ltsmip", llvm::Triple::mips64el) - .Default(llvm::None); - case llvm::Triple::aarch64: - if (value == "aarch64linux") - return llvm::Triple::aarch64; - return llvm::None; - case llvm::Triple::arm: - if (value == "armelf_linux_eabi") - return llvm::Triple::arm; - return llvm::None; - default: - return llvm::None; - } -} - -static bool isLinkerScript(StringRef path, raw_ostream &diag) { - llvm::sys::fs::file_magic magic = llvm::sys::fs::file_magic::unknown; - if (std::error_code ec = llvm::sys::fs::identify_magic(path, magic)) { - diag << "unknown input file format: " << path << ": " - << ec.message() << "\n"; - return false; - } - return magic == llvm::sys::fs::file_magic::unknown; -} - -static ErrorOr<StringRef> -findFile(ELFLinkingContext &ctx, StringRef path, bool dashL) { - // If the path was referred to by using a -l argument, let's search - // for the file in the search path. - if (dashL) { - ErrorOr<StringRef> pathOrErr = ctx.searchLibrary(path); - if (std::error_code ec = pathOrErr.getError()) - return make_dynamic_error_code( - Twine("Unable to find library -l") + path + ": " + ec.message()); - path = pathOrErr.get(); - } - if (!llvm::sys::fs::exists(path)) - return make_dynamic_error_code( - Twine("lld: cannot find file ") + path); - return path; -} - -static bool isPathUnderSysroot(StringRef sysroot, StringRef path) { - if (sysroot.empty()) - return false; - while (!path.empty() && !llvm::sys::fs::equivalent(sysroot, path)) - path = llvm::sys::path::parent_path(path); - return !path.empty(); -} - -static std::error_code -addFilesFromLinkerScript(ELFLinkingContext &ctx, StringRef scriptPath, - const std::vector<script::Path> &inputPaths, - raw_ostream &diag) { - bool sysroot = (!ctx.getSysroot().empty() - && isPathUnderSysroot(ctx.getSysroot(), scriptPath)); - for (const script::Path &path : inputPaths) { - ErrorOr<StringRef> pathOrErr = path._isDashlPrefix - ? ctx.searchLibrary(path._path) : ctx.searchFile(path._path, sysroot); - if (std::error_code ec = pathOrErr.getError()) { - auto file = llvm::make_unique<ErrorFile>(path._path, ec); - ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file))); - continue; - } - - std::vector<std::unique_ptr<File>> files - = loadFile(ctx, pathOrErr.get(), false); - for (std::unique_ptr<File> &file : files) { - if (ctx.logInputFiles()) - diag << file->path() << "\n"; - ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file))); - } - } - return std::error_code(); -} - -std::error_code GnuLdDriver::evalLinkerScript(ELFLinkingContext &ctx, - std::unique_ptr<MemoryBuffer> mb, - raw_ostream &diag, - bool nostdlib) { - // Read the script file from disk and parse. - StringRef path = mb->getBufferIdentifier(); - auto parser = llvm::make_unique<script::Parser>(std::move(mb)); - if (std::error_code ec = parser->parse()) - return ec; - script::LinkerScript *script = parser->get(); - if (!script) - return LinkerScriptReaderError::parse_error; - // Evaluate script commands. - // Currently we only recognize this subset of linker script commands. - for (const script::Command *c : script->_commands) { - if (auto *input = dyn_cast<script::Input>(c)) - if (std::error_code ec = addFilesFromLinkerScript( - ctx, path, input->getPaths(), diag)) - return ec; - if (auto *group = dyn_cast<script::Group>(c)) { - int origSize = ctx.getNodes().size(); - if (std::error_code ec = addFilesFromLinkerScript( - ctx, path, group->getPaths(), diag)) - return ec; - size_t groupSize = ctx.getNodes().size() - origSize; - ctx.getNodes().push_back(llvm::make_unique<GroupEnd>(groupSize)); - } - if (auto *searchDir = dyn_cast<script::SearchDir>(c)) - if (!nostdlib) - ctx.addSearchPath(searchDir->getSearchPath()); - if (auto *entry = dyn_cast<script::Entry>(c)) - ctx.setEntrySymbolName(entry->getEntryName()); - if (auto *output = dyn_cast<script::Output>(c)) - ctx.setOutputPath(output->getOutputFileName()); - if (auto *externs = dyn_cast<script::Extern>(c)) { - for (auto symbol : *externs) { - ctx.addInitialUndefinedSymbol(symbol); - } - } - } - // Transfer ownership of the script to the linking context - ctx.linkerScriptSema().addLinkerScript(std::move(parser)); - return std::error_code(); -} - -bool GnuLdDriver::applyEmulation(llvm::Triple &triple, - llvm::opt::InputArgList &args, - raw_ostream &diag) { - llvm::opt::Arg *arg = args.getLastArg(OPT_m); - if (!arg) - return true; - llvm::Optional<llvm::Triple::ArchType> arch = - getArchType(triple, arg->getValue()); - if (!arch) { - diag << "error: unsupported emulation '" << arg->getValue() << "'.\n"; - return false; - } - triple.setArch(*arch); - return true; -} - -void GnuLdDriver::addPlatformSearchDirs(ELFLinkingContext &ctx, - llvm::Triple &triple, - llvm::Triple &baseTriple) { - if (triple.getOS() == llvm::Triple::NetBSD && - triple.getArch() == llvm::Triple::x86 && - baseTriple.getArch() == llvm::Triple::x86_64) { - ctx.addSearchPath("=/usr/lib/i386"); - return; - } - ctx.addSearchPath("=/usr/lib"); -} - -std::unique_ptr<ELFLinkingContext> -GnuLdDriver::createELFLinkingContext(llvm::Triple triple) { - std::unique_ptr<ELFLinkingContext> p; - if ((p = elf::createAArch64LinkingContext(triple))) return p; - if ((p = elf::createARMLinkingContext(triple))) return p; - if ((p = elf::createExampleLinkingContext(triple))) return p; - if ((p = elf::createHexagonLinkingContext(triple))) return p; - if ((p = elf::createMipsLinkingContext(triple))) return p; - if ((p = elf::createX86LinkingContext(triple))) return p; - if ((p = elf::createX86_64LinkingContext(triple))) return p; - return nullptr; -} - -static llvm::Optional<bool> -getBool(const llvm::opt::InputArgList &parsedArgs, - unsigned yesFlag, unsigned noFlag) { - if (auto *arg = parsedArgs.getLastArg(yesFlag, noFlag)) - return arg->getOption().getID() == yesFlag; - return llvm::None; -} - -bool GnuLdDriver::parse(llvm::ArrayRef<const char *> args, - std::unique_ptr<ELFLinkingContext> &context, - raw_ostream &diag) { - // Parse command line options using GnuLdOptions.td - GnuLdOptTable table; - unsigned missingIndex; - unsigned missingCount; - - llvm::opt::InputArgList parsedArgs = - table.ParseArgs(args.slice(1), missingIndex, missingCount); - if (missingCount) { - diag << "error: missing arg value for '" - << parsedArgs.getArgString(missingIndex) << "' expected " - << missingCount << " argument(s).\n"; - return false; - } - - // Handle --help - if (parsedArgs.hasArg(OPT_help)) { - table.PrintHelp(llvm::outs(), args[0], "LLVM Linker", false); - return true; - } - - // Use -target or use default target triple to instantiate LinkingContext - llvm::Triple baseTriple; - if (auto *arg = parsedArgs.getLastArg(OPT_target)) { - baseTriple = llvm::Triple(arg->getValue()); - } else { - baseTriple = getDefaultTarget(args[0]); - } - llvm::Triple triple(baseTriple); - - if (!applyEmulation(triple, parsedArgs, diag)) - return false; - - std::unique_ptr<ELFLinkingContext> ctx(createELFLinkingContext(triple)); - - if (!ctx) { - diag << "unknown target triple\n"; - return false; - } - - // Copy mllvm - for (auto *arg : parsedArgs.filtered(OPT_mllvm)) - ctx->appendLLVMOption(arg->getValue()); - - // Ignore unknown arguments. - for (auto unknownArg : parsedArgs.filtered(OPT_UNKNOWN)) - diag << "warning: ignoring unknown argument: " - << unknownArg->getValue() << "\n"; - - // Set sys root path. - if (auto *arg = parsedArgs.getLastArg(OPT_sysroot)) - ctx->setSysroot(arg->getValue()); - - // Handle --demangle option(For compatibility) - if (parsedArgs.hasArg(OPT_demangle)) - ctx->setDemangleSymbols(true); - - // Handle --no-demangle option. - if (parsedArgs.hasArg(OPT_no_demangle)) - ctx->setDemangleSymbols(false); - - // Figure out output kind (-r, -static, -shared) - if (parsedArgs.hasArg(OPT_relocatable)) { - ctx->setOutputELFType(llvm::ELF::ET_REL); - ctx->setPrintRemainingUndefines(false); - ctx->setAllowRemainingUndefines(true); - } - - if (parsedArgs.hasArg(OPT_static)) { - ctx->setOutputELFType(llvm::ELF::ET_EXEC); - ctx->setIsStaticExecutable(true); - } - - if (parsedArgs.hasArg(OPT_shared)) { - ctx->setOutputELFType(llvm::ELF::ET_DYN); - ctx->setAllowShlibUndefines(true); - ctx->setUseShlibUndefines(false); - ctx->setPrintRemainingUndefines(false); - ctx->setAllowRemainingUndefines(true); - } - - // Handle --stats. - if (parsedArgs.hasArg(OPT_stats)) { - ctx->setCollectStats(true); - } - - // Figure out if the output type is nmagic/omagic - if (auto *arg = - parsedArgs.getLastArg(OPT_nmagic, OPT_omagic, OPT_no_omagic)) { - switch (arg->getOption().getID()) { - case OPT_nmagic: - ctx->setOutputMagic(ELFLinkingContext::OutputMagic::NMAGIC); - ctx->setIsStaticExecutable(true); - break; - case OPT_omagic: - ctx->setOutputMagic(ELFLinkingContext::OutputMagic::OMAGIC); - ctx->setIsStaticExecutable(true); - break; - case OPT_no_omagic: - ctx->setOutputMagic(ELFLinkingContext::OutputMagic::DEFAULT); - ctx->setNoAllowDynamicLibraries(); - break; - } - } - - if (parsedArgs.hasArg(OPT_discard_loc)) - ctx->setDiscardLocals(true); - - if (parsedArgs.hasArg(OPT_discard_temp_loc)) - ctx->setDiscardTempLocals(true); - - if (parsedArgs.hasArg(OPT_strip_all)) - ctx->setStripSymbols(true); - - if (auto *arg = parsedArgs.getLastArg(OPT_soname)) - ctx->setSharedObjectName(arg->getValue()); - - if (parsedArgs.hasArg(OPT_rosegment)) - ctx->setCreateSeparateROSegment(); - - if (parsedArgs.hasArg(OPT_no_align_segments)) - ctx->setAlignSegments(false); - - if (auto *arg = parsedArgs.getLastArg(OPT_image_base)) { - uint64_t baseAddress = 0; - StringRef inputValue = arg->getValue(); - if (inputValue.getAsInteger(0, baseAddress) || !baseAddress) { - diag << "invalid value for image base " << inputValue << "\n"; - return false; - } - ctx->setBaseAddress(baseAddress); - } - - if (parsedArgs.hasArg(OPT_merge_strings)) - ctx->setMergeCommonStrings(true); - - if (parsedArgs.hasArg(OPT_t)) - ctx->setLogInputFiles(true); - - if (parsedArgs.hasArg(OPT_use_shlib_undefs)) - ctx->setUseShlibUndefines(true); - - if (auto val = getBool(parsedArgs, OPT_allow_shlib_undefs, - OPT_no_allow_shlib_undefs)) - ctx->setAllowShlibUndefines(*val); - - if (auto *arg = parsedArgs.getLastArg(OPT_e)) - ctx->setEntrySymbolName(arg->getValue()); - - if (auto *arg = parsedArgs.getLastArg(OPT_output)) - ctx->setOutputPath(arg->getValue()); - - if (parsedArgs.hasArg(OPT_noinhibit_exec)) - ctx->setAllowRemainingUndefines(true); - - if (auto val = getBool(parsedArgs, OPT_export_dynamic, OPT_no_export_dynamic)) - ctx->setExportDynamic(*val); - - if (parsedArgs.hasArg(OPT_allow_multiple_definition)) - ctx->setAllowDuplicates(true); - - if (auto *arg = parsedArgs.getLastArg(OPT_dynamic_linker)) - ctx->setInterpreter(arg->getValue()); - - if (auto *arg = parsedArgs.getLastArg(OPT_init)) - ctx->setInitFunction(arg->getValue()); - - if (auto *arg = parsedArgs.getLastArg(OPT_fini)) - ctx->setFiniFunction(arg->getValue()); - - if (auto *arg = parsedArgs.getLastArg(OPT_output_filetype)) - ctx->setOutputFileType(arg->getValue()); - - // Process ELF/ARM specific options - bool hasArmTarget1Rel = parsedArgs.hasArg(OPT_target1_rel); - bool hasArmTarget1Abs = parsedArgs.hasArg(OPT_target1_abs); - if (triple.getArch() == llvm::Triple::arm) { - if (hasArmTarget1Rel && hasArmTarget1Abs) { - diag << "error: options --target1-rel and --target1-abs" - " can't be used together.\n"; - return false; - } else if (hasArmTarget1Rel || hasArmTarget1Abs) { - ctx->setArmTarget1Rel(hasArmTarget1Rel && !hasArmTarget1Abs); - } - } else { - for (const auto *arg : parsedArgs.filtered(OPT_grp_arm_targetopts)) { - diag << "warning: ignoring unsupported ARM/ELF specific argument: " - << arg->getSpelling() << "\n"; - } - } - - // Process MIPS specific options. - if (triple.getArch() == llvm::Triple::mips || - triple.getArch() == llvm::Triple::mipsel || - triple.getArch() == llvm::Triple::mips64 || - triple.getArch() == llvm::Triple::mips64el) { - ctx->setMipsPcRelEhRel(parsedArgs.hasArg(OPT_pcrel_eh_reloc)); - auto *hashArg = parsedArgs.getLastArg(OPT_hash_style); - if (hashArg && hashArg->getValue() != StringRef("sysv")) { - diag << "error: .gnu.hash is incompatible with the MIPS ABI\n"; - return false; - } - } - else { - for (const auto *arg : parsedArgs.filtered(OPT_grp_mips_targetopts)) { - diag << "warning: ignoring unsupported MIPS specific argument: " - << arg->getSpelling() << "\n"; - } - } - - for (auto *arg : parsedArgs.filtered(OPT_L)) - ctx->addSearchPath(arg->getValue()); - - // Add the default search directory specific to the target. - if (!parsedArgs.hasArg(OPT_nostdlib)) - addPlatformSearchDirs(*ctx, triple, baseTriple); - - for (auto *arg : parsedArgs.filtered(OPT_u)) - ctx->addInitialUndefinedSymbol(arg->getValue()); - - for (auto *arg : parsedArgs.filtered(OPT_defsym)) { - StringRef sym, target; - uint64_t addr; - if (parseDefsymAsAbsolute(arg->getValue(), sym, addr)) { - ctx->addInitialAbsoluteSymbol(sym, addr); - } else if (parseDefsymAsAlias(arg->getValue(), sym, target)) { - ctx->addAlias(sym, target); - } else { - diag << "invalid --defsym: " << arg->getValue() << "\n"; - return false; - } - } - - for (auto *arg : parsedArgs.filtered(OPT_z)) { - StringRef opt = arg->getValue(); - if (opt == "muldefs") - ctx->setAllowDuplicates(true); - else if (opt == "now") - ctx->setDTFlag(ELFLinkingContext::DTFlag::DT_NOW); - else if (opt == "origin") - ctx->setDTFlag(ELFLinkingContext::DTFlag::DT_ORIGIN); - else if (opt.startswith("max-page-size")) { - // Parse -z max-page-size option. - // The default page size is considered the minimum page size the user - // can set, check the user input if its atleast the minimum page size - // and does not exceed the maximum page size allowed for the target. - uint64_t maxPageSize = 0; - - // Error if the page size user set is less than the maximum page size - // and greather than the default page size and the user page size is a - // modulo of the default page size. - if ((!parseMaxPageSize(opt, maxPageSize)) || - (maxPageSize < ctx->getPageSize()) || - (maxPageSize % ctx->getPageSize())) { - diag << "invalid option: " << opt << "\n"; - return false; - } - ctx->setMaxPageSize(maxPageSize); - } else { - diag << "warning: ignoring unknown argument for -z: " << opt << "\n"; - } - } - - for (auto *arg : parsedArgs.filtered(OPT_rpath)) { - SmallVector<StringRef, 2> rpaths; - StringRef(arg->getValue()).split(rpaths, ":"); - for (auto path : rpaths) - ctx->addRpath(path); - } - - for (auto *arg : parsedArgs.filtered(OPT_rpath_link)) { - SmallVector<StringRef, 2> rpaths; - StringRef(arg->getValue()).split(rpaths, ":"); - for (auto path : rpaths) - ctx->addRpathLink(path); - } - - // Enable new dynamic tags. - if (parsedArgs.hasArg(OPT_enable_newdtags)) - ctx->setEnableNewDtags(true); - - // Support --wrap option. - for (auto *arg : parsedArgs.filtered(OPT_wrap)) - ctx->addWrapForSymbol(arg->getValue()); - - // Register possible input file parsers. - ctx->registry().addSupportELFObjects(*ctx); - ctx->registry().addSupportArchives(ctx->logInputFiles()); - ctx->registry().addSupportYamlFiles(); - if (ctx->allowLinkWithDynamicLibraries()) - ctx->registry().addSupportELFDynamicSharedObjects(*ctx); - - // Parse the LLVM options before we process files in case the file handling - // makes use of things like DEBUG(). - parseLLVMOptions(*ctx); - - std::stack<int> groupStack; - int numfiles = 0; - bool asNeeded = false; - bool wholeArchive = false; - - // Process files - for (auto arg : parsedArgs) { - switch (arg->getOption().getID()) { - case OPT_no_whole_archive: - wholeArchive = false; - break; - - case OPT_whole_archive: - wholeArchive = true; - break; - - case OPT_as_needed: - asNeeded = true; - break; - - case OPT_no_as_needed: - asNeeded = false; - break; - - case OPT_start_group: - groupStack.push(numfiles); - break; - - case OPT_end_group: { - if (groupStack.empty()) { - diag << "stray --end-group\n"; - return false; - } - int startGroupPos = groupStack.top(); - ctx->getNodes().push_back( - llvm::make_unique<GroupEnd>(numfiles - startGroupPos)); - groupStack.pop(); - break; - } - - case OPT_INPUT: - case OPT_l: - case OPT_T: { - bool dashL = (arg->getOption().getID() == OPT_l); - StringRef path = arg->getValue(); - - ErrorOr<StringRef> pathOrErr = findFile(*ctx, path, dashL); - if (std::error_code ec = pathOrErr.getError()) { - auto file = llvm::make_unique<ErrorFile>(path, ec); - auto node = llvm::make_unique<FileNode>(std::move(file)); - node->setAsNeeded(asNeeded); - ctx->getNodes().push_back(std::move(node)); - break; - } - StringRef realpath = pathOrErr.get(); - - bool isScript = - (!path.endswith(".objtxt") && isLinkerScript(realpath, diag)); - if (isScript) { - if (ctx->logInputFiles()) - diag << path << "\n"; - ErrorOr<std::unique_ptr<MemoryBuffer>> mb = - MemoryBuffer::getFileOrSTDIN(realpath); - if (std::error_code ec = mb.getError()) { - diag << "Cannot open " << path << ": " << ec.message() << "\n"; - return false; - } - bool nostdlib = parsedArgs.hasArg(OPT_nostdlib); - std::error_code ec = - evalLinkerScript(*ctx, std::move(mb.get()), diag, nostdlib); - if (ec) { - diag << path << ": Error parsing linker script: " - << ec.message() << "\n"; - return false; - } - break; - } - std::vector<std::unique_ptr<File>> files - = loadFile(*ctx, realpath, wholeArchive); - for (std::unique_ptr<File> &file : files) { - if (ctx->logInputFiles()) - diag << file->path() << "\n"; - auto node = llvm::make_unique<FileNode>(std::move(file)); - node->setAsNeeded(asNeeded); - ctx->getNodes().push_back(std::move(node)); - } - numfiles += files.size(); - break; - } - } - } - - if (ctx->getNodes().empty()) { - diag << "No input files\n"; - return false; - } - - // Set default output file name if the output file was not specified. - if (ctx->outputPath().empty()) { - switch (ctx->outputFileType()) { - case LinkingContext::OutputFileType::YAML: - ctx->setOutputPath("-"); - break; - default: - ctx->setOutputPath("a.out"); - break; - } - } - - // Validate the combination of options used. - if (!ctx->validate(diag)) - return false; - - // Perform linker script semantic actions - if (auto ec = ctx->linkerScriptSema().perform()) { - diag << "Error in the linker script's semantics: " << ec.message() << "\n"; - return false; - } - - context.swap(ctx); - return true; -} - -/// Get the default target triple based on either the program name -/// (e.g. "x86-ibm-linux-lld") or the primary target llvm was configured for. -llvm::Triple GnuLdDriver::getDefaultTarget(const char *progName) { - SmallVector<StringRef, 4> components; - llvm::SplitString(llvm::sys::path::stem(progName), components, "-"); - // If has enough parts to be start with a triple. - if (components.size() >= 4) { - llvm::Triple triple(components[0], components[1], components[2], - components[3]); - // If first component looks like an arch. - if (triple.getArch() != llvm::Triple::UnknownArch) - return triple; - } - - // Fallback to use whatever default triple llvm was configured for. - return llvm::Triple(llvm::sys::getDefaultTargetTriple()); -} diff --git a/lib/Driver/GnuLdOptions.td b/lib/Driver/GnuLdOptions.td deleted file mode 100644 index 7d850d4d002e..000000000000 --- a/lib/Driver/GnuLdOptions.td +++ /dev/null @@ -1,378 +0,0 @@ -include "llvm/Option/OptParser.td" - -//===----------------------------------------------------------------------===// -/// Utility Functions -//===----------------------------------------------------------------------===// -// Single and multiple dash options combined -multiclass smDash<string opt1, string opt2, string help> { - // Option - def "" : Separate<["-"], opt1>, HelpText<help>; - def opt1_eq : Joined<["-"], opt1#"=">, - Alias<!cast<Option>(opt1)>; - // Compatibility aliases - def opt2_dashdash : Separate<["--"], opt2>, - Alias<!cast<Option>(opt1)>; - def opt2_dashdash_eq : Joined<["--"], opt2#"=">, - Alias<!cast<Option>(opt1)>; -} - -// Support -<option>,-<option>= -multiclass dashEq<string opt1, string opt2, string help> { - // Option - def "" : Separate<["-"], opt1>, HelpText<help>; - // Compatibility aliases - def opt2_eq : Joined<["-"], opt2#"=">, - Alias<!cast<Option>(opt1)>; -} - -// Support --<option>,--<option>= -multiclass mDashEq<string opt1, string help> { - // Option - def "" : Separate<["--"], opt1>, HelpText<help>; - // Compatibility aliases - def opt2_eq : Joined<["--"], opt1#"=">, - Alias<!cast<Option>(opt1)>; -} - -//===----------------------------------------------------------------------===// -/// LLVM and Target options -//===----------------------------------------------------------------------===// -def grp_llvmtarget : OptionGroup<"opts">, - HelpText<"LLVM and Target Options">; -def mllvm : Separate<["-"], "mllvm">, - HelpText<"Options to pass to LLVM">, Group<grp_llvmtarget>; -def target : Separate<["-"], "target">, MetaVarName<"<triple>">, - HelpText<"Target triple to link for">, - Group<grp_llvmtarget>; - -//===----------------------------------------------------------------------===// -/// Output Kinds -//===----------------------------------------------------------------------===// -def grp_kind : OptionGroup<"outs">, - HelpText<"OUTPUT KIND">; -def relocatable : Flag<["-"], "r">, - HelpText<"Create relocatable object file">, Group<grp_kind>; -def static : Flag<["-"], "static">, - HelpText<"Create static executable">, Group<grp_kind>; -def dynamic : Flag<["-"], "dynamic">, - HelpText<"Create dynamic executable (default)">,Group<grp_kind>; -def shared : Flag<["-"], "shared">, - HelpText<"Create dynamic library">, Group<grp_kind>; - -// output kinds - compatibility aliases -def Bstatic : Flag<["-"], "Bstatic">, Alias<static>; -def Bshareable : Flag<["-"], "Bshareable">, Alias<shared>; - -//===----------------------------------------------------------------------===// -/// General Options -//===----------------------------------------------------------------------===// -def grp_general : OptionGroup<"opts">, - HelpText<"GENERAL OPTIONS">; -def output : Separate<["-"], "o">, MetaVarName<"<path>">, - HelpText<"Path to file to write output">, - Group<grp_general>; -def m : JoinedOrSeparate<["-"], "m">, MetaVarName<"<emulation>">, - HelpText<"Select target emulation">, - Group<grp_general>; -def build_id : Flag<["--"], "build-id">, - HelpText<"Request creation of \".note.gnu.build-id\" ELF note section">, - Group<grp_general>; -def sysroot : Joined<["--"], "sysroot=">, - HelpText<"Set the system root">, - Group<grp_general>; - - -//===----------------------------------------------------------------------===// -/// Executable Options -//===----------------------------------------------------------------------===// -def grp_main : OptionGroup<"opts">, - HelpText<"EXECUTABLE OPTIONS">; -def L : Joined<["-"], "L">, MetaVarName<"<dir>">, - HelpText<"Directory to search for libraries">, - Group<grp_main>; -def l : Joined<["-"], "l">, MetaVarName<"<libName>">, - HelpText<"Root name of library to use">, - Group<grp_main>; -def noinhibit_exec : Flag<["--"], "noinhibit-exec">, - HelpText<"Retain the executable output file whenever" - " it is still usable">, - Group<grp_main>; -defm e : smDash<"e", "entry", - "Name of entry point symbol">, - Group<grp_main>; -defm init: dashEq<"init", "init", - "Specify an initializer function">, - Group<grp_main>; -defm fini: dashEq<"fini", "fini", - "Specify a finalizer function">, - Group<grp_main>; -def whole_archive: Flag<["--"], "whole-archive">, - HelpText<"Force load of all members in a static library">, - Group<grp_main>; -def no_whole_archive: Flag<["--"], "no-whole-archive">, - HelpText<"Restores the default behavior of loading archive members">, - Group<grp_main>; -def nostdlib : Flag<["-"], "nostdlib">, - HelpText<"Disable default search path for libraries">, - Group<grp_main>; -def image_base : Separate<["--"], "image-base">, - HelpText<"Set the base address">, - Group<grp_main>; - -//===----------------------------------------------------------------------===// -/// Static Executable Options -//===----------------------------------------------------------------------===// -def grp_staticexec : OptionGroup<"opts">, - HelpText<"STATIC EXECUTABLE OPTIONS">; -def nmagic : Flag<["--"], "nmagic">, - HelpText<"Turn off page alignment of sections," - " and disable linking against shared libraries">, - Group<grp_staticexec>; -def omagic : Flag<["--"], "omagic">, - HelpText<"Set the text and data sections to be readable and writable." - " Also, do not page-align the data segment, and" - " disable linking against shared libraries.">, - Group<grp_staticexec>; -def no_omagic : Flag<["--"], "no-omagic">, - HelpText<"This option negates most of the effects of the -N option." - "Disable linking with shared libraries">, - Group<grp_staticexec>; -// Compatible Aliases -def nmagic_alias : Flag<["-"], "n">, - Alias<nmagic>; -def omagic_alias : Flag<["-"], "N">, - Alias<omagic>; - -//===----------------------------------------------------------------------===// -/// Dynamic Library/Executable Options -//===----------------------------------------------------------------------===// -def grp_dynlibexec : OptionGroup<"opts">, - HelpText<"DYNAMIC LIBRARY/EXECUTABLE OPTIONS">; -def dynamic_linker : Joined<["--"], "dynamic-linker=">, - HelpText<"Set the path to the dynamic linker">, Group<grp_dynlibexec>; -// Executable options - compatibility aliases -def dynamic_linker_alias : Separate<["-", "--"], "dynamic-linker">, - Alias<dynamic_linker>; -defm rpath : dashEq<"rpath", "rpath", - "Add a directory to the runtime library search path">, - Group<grp_dynlibexec>; -def rpath_link : Separate<["-"], "rpath-link">, - HelpText<"Specifies the first set of directories to search">, - Group<grp_dynlibexec>; -def export_dynamic : Flag<["-", "--"], "export-dynamic">, - HelpText<"Add all symbols to the dynamic symbol table" - " when creating executables">, - Group<grp_main>; -def alias_export_dynamic: Flag<["-"], "E">, - Alias<export_dynamic>; -def no_export_dynamic : Flag<["--"], "no-export-dynamic">, - Group<grp_main>; - -//===----------------------------------------------------------------------===// -/// Dynamic Library Options -//===----------------------------------------------------------------------===// -def grp_dynlib : OptionGroup<"opts">, - HelpText<"DYNAMIC LIBRARY OPTIONS">; -def soname : Joined<["-", "--"], "soname=">, - HelpText<"Set the internal DT_SONAME field to the specified name">, - Group<grp_dynlib>; -def soname_separate : Separate<["-", "--"], "soname">, Alias<soname>; -def soname_h : Separate<["-"], "h">, Alias<soname>; - -//===----------------------------------------------------------------------===// -/// Resolver Options -//===----------------------------------------------------------------------===// -def grp_resolveropt : OptionGroup<"opts">, - HelpText<"SYMBOL RESOLUTION OPTIONS">; -defm u : smDash<"u", "undefined", - "Force symbol to be entered in the output file" - " as an undefined symbol">, - Group<grp_resolveropt>; -def start_group : Flag<["--"], "start-group">, - HelpText<"Start a group">, - Group<grp_resolveropt>; -def alias_start_group: Flag<["-"], "(">, - Alias<start_group>; -def end_group : Flag<["--"], "end-group">, - HelpText<"End a group">, - Group<grp_resolveropt>; -def alias_end_group: Flag<["-"], ")">, - Alias<end_group>; -def as_needed : Flag<["--"], "as-needed">, - HelpText<"This option affects ELF DT_NEEDED tags for " - "dynamic libraries mentioned on the command line">, - Group<grp_resolveropt>; -def no_as_needed : Flag<["--"], "no-as-needed">, - HelpText<"This option restores the default behavior" - " of adding DT_NEEDED entries">, - Group<grp_resolveropt>; -def no_allow_shlib_undefs : Flag<["--"], "no-allow-shlib-undefined">, - HelpText<"Do not allow undefined symbols from dynamic" - " library when creating executables">, - Group<grp_resolveropt>; -def allow_shlib_undefs : Flag<["-", "--"], "allow-shlib-undefined">, - HelpText<"Allow undefined symbols from dynamic" - " library when creating executables">, - Group<grp_resolveropt>; -def use_shlib_undefs: Flag<["--"], "use-shlib-undefines">, - HelpText<"Resolve undefined symbols from dynamic libraries">, - Group<grp_resolveropt>; -def allow_multiple_definition: Flag<["--"], "allow-multiple-definition">, - HelpText<"Allow multiple definitions">, - Group<grp_resolveropt>; -defm defsym : mDashEq<"defsym", - "Create a global symbol in the output file " - "containing the absolute address given by expression">, - MetaVarName<"symbol=<expression>">, - Group<grp_resolveropt>; - -//===----------------------------------------------------------------------===// -/// Custom Options -//===----------------------------------------------------------------------===// -def grp_customopts : OptionGroup<"opts">, - HelpText<"CUSTOM OPTIONS">; -def disable_newdtags: Flag<["--"], "disable-new-dtags">, - HelpText<"Disable new dynamic tags">, - Group<grp_customopts>; -def enable_newdtags: Flag<["--"], "enable-new-dtags">, - HelpText<"Enable new dynamic tags">, - Group<grp_customopts>; -def rosegment: Flag<["--"], "rosegment">, - HelpText<"Put read-only non-executable sections in their own segment">, - Group<grp_customopts>; -def z : Separate<["-"], "z">, - HelpText<"Linker Option extensions">, - Group<grp_customopts>; -def no_align_segments: Flag<["--"], "no-align-segments">, - HelpText<"Don't align ELF segments(virtualaddress/fileoffset) to page boundaries">, - Group<grp_customopts>; - -//===----------------------------------------------------------------------===// -/// Symbol options -//===----------------------------------------------------------------------===// -def grp_symbolopts : OptionGroup<"opts">, - HelpText<"SYMBOL OPTIONS">; -def demangle : Flag<["--"], "demangle">, - HelpText<"Demangle C++ symbols">, - Group<grp_symbolopts>; -def discard_loc : Flag<["--"], "discard-all">, - HelpText<"Discard all local symbols">, - Group<grp_symbolopts>; -def alias_discard_loc: Flag<["-"], "x">, - Alias<discard_loc>; -def discard_temp_loc : Flag<["--"], "discard-locals">, - HelpText<"Discard temporary local symbols">, - Group<grp_symbolopts>; -def alias_discard_temp_loc : Flag<["-"], "X">, - Alias<discard_temp_loc>; -def no_demangle : Flag<["--"], "no-demangle">, - HelpText<"Dont demangle C++ symbols">, - Group<grp_symbolopts>; -def strip_all : Flag<["--"], "strip-all">, - HelpText<"Omit all symbol informations from output">, - Group<grp_symbolopts>; -def alias_strip_all : Flag<["-"], "s">, - Alias<strip_all>; -defm wrap : smDash<"wrap", "wrap", - "Use a wrapper function for symbol. Any " - " undefined reference to symbol will be resolved to " - "\"__wrap_symbol\". Any undefined reference to \"__real_symbol\"" - " will be resolved to symbol.">, - MetaVarName<"<symbol>">, - Group<grp_symbolopts>; - -//===----------------------------------------------------------------------===// -/// Script Options -//===----------------------------------------------------------------------===// -def grp_scriptopts : OptionGroup<"opts">, - HelpText<"SCRIPT OPTIONS">; -defm T : smDash<"T", "script", - "Use the given linker script in place of the default script.">, - Group<grp_scriptopts>; - -//===----------------------------------------------------------------------===// -/// Optimization Options -//===----------------------------------------------------------------------===// -def grp_opts : OptionGroup<"opts">, - HelpText<"OPTIMIZATIONS">; -def hash_style : Joined <["--"], "hash-style=">, - HelpText<"Set the type of linker's hash table(s)">, - Group<grp_opts>; -def merge_strings : Flag<["--"], "merge-strings">, - HelpText<"Merge common strings across mergeable sections">, - Group<grp_opts>; -def eh_frame_hdr : Flag<["--"], "eh-frame-hdr">, - HelpText<"Request creation of .eh_frame_hdr section and ELF " - " PT_GNU_EH_FRAME segment header">, - Group<grp_opts>; - -//===----------------------------------------------------------------------===// -/// Tracing Options -//===----------------------------------------------------------------------===// -def grp_tracingopts : OptionGroup<"opts">, - HelpText<"TRACING OPTIONS">; -def t : Flag<["-"], "t">, - HelpText<"Print the names of the input files as ld processes them">, - Group<grp_tracingopts>; -def stats : Flag<["--"], "stats">, - HelpText<"Print time and memory usage stats">, Group<grp_tracingopts>; - -//===----------------------------------------------------------------------===// -/// Extensions -//===----------------------------------------------------------------------===// -def grp_extns : OptionGroup<"opts">, - HelpText<"Extensions">; -def output_filetype: Separate<["--"], "output-filetype">, - HelpText<"Specify yaml to create an output in YAML format">, - Group<grp_extns>; -def alias_output_filetype: Joined<["--"], "output-filetype=">, - Alias<output_filetype>; - -//===----------------------------------------------------------------------===// -/// Target Specific Options -//===----------------------------------------------------------------------===// -def grp_targetopts : OptionGroup<"opts">, - HelpText<"ARCH SPECIFIC OPTIONS">; - -//===----------------------------------------------------------------------===// -/// ARM Target Specific Options -//===----------------------------------------------------------------------===// -def grp_arm_targetopts : OptionGroup<"ARM SPECIFIC OPTIONS">, - Group<grp_targetopts>; -def target1_rel : Flag<["--"], "target1-rel">, - Group<grp_arm_targetopts>, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_REL32">; -def target1_abs : Flag<["--"], "target1-abs">, - Group<grp_arm_targetopts>, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_ABS32">; - -//===----------------------------------------------------------------------===// -/// MIPS Target Specific Options -//===----------------------------------------------------------------------===// -def grp_mips_targetopts : OptionGroup<"MIPS SPECIFIC OPTIONS">, - Group<grp_targetopts>; -def pcrel_eh_reloc : Flag<["-", "--"], "pcrel-eh-reloc">, - Group<grp_mips_targetopts>, - HelpText<"Interpret R_MIPS_EH as R_MIPS_PC32">; - -//===----------------------------------------------------------------------===// -/// Ignored options -//===----------------------------------------------------------------------===// -def grp_ignored: OptionGroup<"ignored">, - HelpText<"GNU Options ignored for Compatibility ">; -def dashg : Flag<["-"], "g">, - HelpText<"Ignored.">, - Group<grp_ignored>; -def Qy : Flag<["-"], "Qy">, - HelpText<"Ignored for SVR4 Compatibility">, - Group<grp_ignored>; -def qmagic : Flag<["-"], "qmagic">, - HelpText<"Ignored for Linux Compatibility">, - Group<grp_ignored>; -def G : Separate<["-"], "G">, - HelpText<"Ignored for MIPS GNU Linker Compatibility">, - Group<grp_ignored>; - -//===----------------------------------------------------------------------===// -/// Help -//===----------------------------------------------------------------------===// -def help : Flag<["--"], "help">, - HelpText<"Display this help message">; diff --git a/lib/Driver/TODO.rst b/lib/Driver/TODO.rst deleted file mode 100644 index 868eaf02290c..000000000000 --- a/lib/Driver/TODO.rst +++ /dev/null @@ -1,99 +0,0 @@ -GNU ld Driver -~~~~~~~~~~~~~ - -Missing Options -############### - -* --audit -* -A,--architecture -* -b,--format -* -d,-dc,-dp -* -P,--depaudit -* --exclude-libs -* --exclude-modules-for-implib -* -E,--export-dynamic,--no-export-dynamic -* -EB (We probably shouldn't support this) -* -EL (We probably shouldn't support this) -* -f,--auxiliary -* -F,--filter -* -G,--gpsize -* -h -* -i -* --library -* -M -* --print-map -* -output -* -O -* -q,--emit-relocs -* --force-dynamic -* --relocatable -* -R,--just-symbols -* -s,--strip-all -* -S,--strip-debug -* --trace -* -dT,--default-script -* -Ur -* --unique -* -v,--version,-V -* -y,--trace-symbol -* -z (keywords need to be implemented) -* --accept-unknown-input-arch,--no-accept-unknown-input-arch -* -Bdynamic,-dy,-call_shared -* -Bgroup -* -dn,-non_shared -* -Bsymbolic -* -Bsymbolic-functions -* --dynamic-list -* --dynamic-list-data -* --dynamic-list-cpp-new -* --dynamic-list-cpp-typeinfo -* --check-sections,--no-check-sections -* --copy-dt-needed-entries,--no-copy-dt-needed-entires -* --cref -* --no-define-common -* --defsym (only absolute value supported now) -* --demangle,--no-demangle -* -I -* --fatal-warnings,--no-fatal-warnings -* --force-exe-suffix -* --gc-sections,--no-gc-sections -* --print-gc-sections,--no-print-gc-sections -* --print-output-format -* --target-help -* -Map -* --no-keep-memory -* --no-undefined,-z defs -* --allow-shlib-undefined,--no-alow-shlib-undefined -* --no-undefined-version -* --default-symver -* --default-imported-symver -* --no-warn-mismatch -* --no-warn-search-mismatch -* --oformat -* -pie,--pic-executable -* --relax,--no-relax -* --retain-symbols-file -* --sort-common -* --sort-section={name,alignment} -* --split-by-file -* --split-by-reloc -* --stats -* --section-start -* -T{bss,data,text,{text,rodata,data}-segment} -* --unresolved-symbols -* -dll-verbose,--verbose -* --version-script -* --warn-common -* --warn-constructors -* --warn-multiple-gp -* --warn-once -* --warn-section-align -* --warn-shared-textrel -* --warn-alternate-em -* --warn-unresolved-symbols -* --error-unresolved-symbols -* --wrap -* --no-ld-generated-unwind-info -* --hash-size -* --reduce-memory-overheads -* --build-id diff --git a/lib/Driver/UniversalDriver.cpp b/lib/Driver/UniversalDriver.cpp deleted file mode 100644 index 3dea7ebfae89..000000000000 --- a/lib/Driver/UniversalDriver.cpp +++ /dev/null @@ -1,225 +0,0 @@ -//===- lib/Driver/UniversalDriver.cpp -------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// -/// Driver for "universal" lld tool which can mimic any linker command line -/// parsing once it figures out which command line flavor to use. -/// -//===----------------------------------------------------------------------===// - -#include "lld/Driver/Driver.h" -#include "lld/Config/Version.h" -#include "lld/Core/LLVM.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Option/Arg.h" -#include "llvm/Option/Option.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" - -using namespace lld; - -namespace { - -// Create enum with OPT_xxx values for each option in GnuLdOptions.td -enum { - OPT_INVALID = 0, -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELP, META) \ - OPT_##ID, -#include "UniversalDriverOptions.inc" -#undef OPTION -}; - -// Create prefix string literals used in GnuLdOptions.td -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; -#include "UniversalDriverOptions.inc" -#undef PREFIX - -// Create table mapping all options defined in GnuLdOptions.td -static const llvm::opt::OptTable::Info infoTable[] = { -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR) \ - { \ - PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ - PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS \ - } \ - , -#include "UniversalDriverOptions.inc" -#undef OPTION -}; - -// Create OptTable class for parsing actual command line arguments -class UniversalDriverOptTable : public llvm::opt::OptTable { -public: - UniversalDriverOptTable() - : OptTable(infoTable) {} -}; - -enum class Flavor { - invalid, - old_gnu_ld, // -flavor old-gnu - gnu_ld, // -flavor gnu - win_link, // -flavor link - darwin_ld, // -flavor darwin - core // -flavor core OR -core -}; - -struct ProgramNameParts { - StringRef _target; - StringRef _flavor; -}; - -} // anonymous namespace - -static Flavor strToFlavor(StringRef str) { - return llvm::StringSwitch<Flavor>(str) - .Case("old-gnu", Flavor::old_gnu_ld) - .Case("gnu", Flavor::gnu_ld) - .Case("ld.lld", Flavor::gnu_ld) - .Case("link", Flavor::win_link) - .Case("lld-link", Flavor::win_link) - .Case("darwin", Flavor::darwin_ld) - .Case("core", Flavor::core) - .Case("ld", Flavor::gnu_ld) - .Default(Flavor::invalid); -} - -static ProgramNameParts parseProgramName(StringRef programName) { - SmallVector<StringRef, 3> components; - llvm::SplitString(programName, components, "-"); - ProgramNameParts ret; - - using std::begin; - using std::end; - - // Erase any lld components. - components.erase(std::remove(components.begin(), components.end(), "lld"), - components.end()); - - // Find the flavor component. - auto flIter = std::find_if(components.begin(), components.end(), - [](StringRef str) -> bool { - return strToFlavor(str) != Flavor::invalid; - }); - - if (flIter != components.end()) { - ret._flavor = *flIter; - components.erase(flIter); - } - - // Any remaining component must be the target. - if (components.size() == 1) - ret._target = components[0]; - - return ret; -} - -// Removes the argument from argv along with its value, if exists, and updates -// argc. -static void removeArg(llvm::opt::Arg *arg, - llvm::MutableArrayRef<const char *> &args) { - unsigned int numToRemove = arg->getNumValues() + 1; - auto sub = args.slice(arg->getIndex() + 1); - std::rotate(sub.begin(), sub.begin() + numToRemove, sub.end()); - args = args.drop_back(numToRemove); -} - -static Flavor getFlavor(llvm::MutableArrayRef<const char *> &args, - const llvm::opt::InputArgList &parsedArgs) { - if (llvm::opt::Arg *argCore = parsedArgs.getLastArg(OPT_core)) { - removeArg(argCore, args); - return Flavor::core; - } - if (llvm::opt::Arg *argFlavor = parsedArgs.getLastArg(OPT_flavor)) { - removeArg(argFlavor, args); - return strToFlavor(argFlavor->getValue()); - } - -#if LLVM_ON_UNIX - if (llvm::sys::path::filename(args[0]).equals("ld")) { -#if __APPLE__ - // On a Darwin systems, if linker binary is named "ld", use Darwin driver. - return Flavor::darwin_ld; -#endif - // On a ELF based systems, if linker binary is named "ld", use gnu driver. - return Flavor::gnu_ld; - } -#endif - - StringRef name = llvm::sys::path::filename(args[0]); - if (name.endswith_lower(".exe")) - name = llvm::sys::path::stem(name); - return strToFlavor(parseProgramName(name)._flavor); -} - -namespace lld { - -bool UniversalDriver::link(llvm::MutableArrayRef<const char *> args, - raw_ostream &diagnostics) { - // Parse command line options using GnuLdOptions.td - UniversalDriverOptTable table; - unsigned missingIndex; - unsigned missingCount; - - // Program name - StringRef programName = llvm::sys::path::stem(args[0]); - - llvm::opt::InputArgList parsedArgs = - table.ParseArgs(args.slice(1), missingIndex, missingCount); - - if (missingCount) { - diagnostics << "error: missing arg value for '" - << parsedArgs.getArgString(missingIndex) << "' expected " - << missingCount << " argument(s).\n"; - return false; - } - - // Handle -help - if (parsedArgs.getLastArg(OPT_help)) { - table.PrintHelp(llvm::outs(), programName.data(), "LLVM Linker", false); - return true; - } - - // Handle -version - if (parsedArgs.getLastArg(OPT_version)) { - diagnostics << "LLVM Linker Version: " << getLLDVersion() - << getLLDRepositoryVersion() << "\n"; - return true; - } - - Flavor flavor = getFlavor(args, parsedArgs); - - // Switch to appropriate driver. - switch (flavor) { - case Flavor::old_gnu_ld: - return GnuLdDriver::linkELF(args, diagnostics); - case Flavor::gnu_ld: - elf2::link(args); - return true; - case Flavor::darwin_ld: - return DarwinLdDriver::linkMachO(args, diagnostics); - case Flavor::win_link: - coff::link(args); - return true; - case Flavor::core: - return CoreDriver::link(args, diagnostics); - case Flavor::invalid: - diagnostics << "Select the appropriate flavor\n"; - table.PrintHelp(llvm::outs(), programName.data(), "LLVM Linker", false); - return false; - } - llvm_unreachable("Unrecognised flavor"); -} - -} // end namespace lld diff --git a/lib/Driver/UniversalDriverOptions.td b/lib/Driver/UniversalDriverOptions.td deleted file mode 100644 index 14abc9ce9911..000000000000 --- a/lib/Driver/UniversalDriverOptions.td +++ /dev/null @@ -1,19 +0,0 @@ -include "llvm/Option/OptParser.td" - -// Select an optional flavor -def flavor: Separate<["-"], "flavor">, - HelpText<"Flavor for linking, options are gnu/darwin/link">; - -// Select the core flavor -def core : Flag<["-"], "core">, - HelpText<"CORE linking">; - -def target: Separate<["-"], "target">, - HelpText<"Select the target">; - -def version: Flag<["-"], "version">, - HelpText<"Display the version">; - -// Help message -def help : Flag<["-"], "help">, - HelpText<"Display this help message">; diff --git a/lib/ReaderWriter/CMakeLists.txt b/lib/ReaderWriter/CMakeLists.txt index 2bb5655b9e35..4408d9c18b8b 100644 --- a/lib/ReaderWriter/CMakeLists.txt +++ b/lib/ReaderWriter/CMakeLists.txt @@ -1,4 +1,3 @@ -add_subdirectory(ELF) add_subdirectory(MachO) add_subdirectory(YAML) @@ -7,9 +6,7 @@ if (MSVC) endif() add_lld_library(lldReaderWriter - CoreLinkingContext.cpp FileArchive.cpp - LinkerScript.cpp ADDITIONAL_HEADER_DIRS ${LLD_INCLUDE_DIR}/lld/ReaderWriter diff --git a/lib/ReaderWriter/CoreLinkingContext.cpp b/lib/ReaderWriter/CoreLinkingContext.cpp deleted file mode 100644 index 02f6263c0c3f..000000000000 --- a/lib/ReaderWriter/CoreLinkingContext.cpp +++ /dev/null @@ -1,50 +0,0 @@ -//===- lib/ReaderWriter/CoreLinkingContext.cpp ----------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lld/Core/DefinedAtom.h" -#include "lld/Core/File.h" -#include "lld/Core/Pass.h" -#include "lld/Core/PassManager.h" -#include "lld/Core/Simple.h" -#include "lld/ReaderWriter/CoreLinkingContext.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/STLExtras.h" - -using namespace lld; - -namespace { - -class OrderPass : public Pass { -public: - /// Sorts atoms by position - std::error_code perform(SimpleFile &file) override { - SimpleFile::DefinedAtomRange defined = file.definedAtoms(); - std::sort(defined.begin(), defined.end(), DefinedAtom::compareByPosition); - return std::error_code(); - } -}; - -} // anonymous namespace - -CoreLinkingContext::CoreLinkingContext() {} - -bool CoreLinkingContext::validateImpl(raw_ostream &) { - _writer = createWriterYAML(*this); - return true; -} - -void CoreLinkingContext::addPasses(PassManager &pm) { - for (StringRef name : _passNames) { - (void)name; - assert(name == "order" && "bad pass name"); - pm.add(llvm::make_unique<OrderPass>()); - } -} - -Writer &CoreLinkingContext::writer() const { return *_writer; } diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h b/lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h deleted file mode 100644 index 73864d2b4c38..000000000000 --- a/lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h +++ /dev/null @@ -1,45 +0,0 @@ -//===- lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h ---------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef AARCH64_DYNAMIC_LIBRARY_WRITER_H -#define AARCH64_DYNAMIC_LIBRARY_WRITER_H - -#include "AArch64LinkingContext.h" -#include "AArch64TargetHandler.h" -#include "DynamicLibraryWriter.h" - -namespace lld { -namespace elf { - -class AArch64DynamicLibraryWriter : public DynamicLibraryWriter<ELF64LE> { -public: - AArch64DynamicLibraryWriter(AArch64LinkingContext &ctx, - TargetLayout<ELF64LE> &layout); - -protected: - // Add any runtime files and their atoms to the output - void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override; -}; - -AArch64DynamicLibraryWriter::AArch64DynamicLibraryWriter( - AArch64LinkingContext &ctx, TargetLayout<ELF64LE> &layout) - : DynamicLibraryWriter(ctx, layout) {} - -void AArch64DynamicLibraryWriter::createImplicitFiles( - std::vector<std::unique_ptr<File>> &result) { - DynamicLibraryWriter::createImplicitFiles(result); - auto gotFile = llvm::make_unique<SimpleFile>("GOTFile"); - gotFile->addAtom(*new (gotFile->allocator()) GlobalOffsetTableAtom(*gotFile)); - gotFile->addAtom(*new (gotFile->allocator()) DynamicAtom(*gotFile)); - result.push_back(std::move(gotFile)); -} - -} // namespace elf -} // namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.cpp deleted file mode 100644 index 9a9ec6cba12b..000000000000 --- a/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.cpp +++ /dev/null @@ -1,52 +0,0 @@ -//===- lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.cpp -------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "AArch64LinkingContext.h" -#include "AArch64ExecutableWriter.h" -#include "AArch64TargetHandler.h" -#include "AArch64SectionChunks.h" - -namespace lld { -namespace elf { - -AArch64ExecutableWriter::AArch64ExecutableWriter(AArch64LinkingContext &ctx, - AArch64TargetLayout &layout) - : ExecutableWriter(ctx, layout), _targetLayout(layout) {} - -void AArch64ExecutableWriter::createImplicitFiles( - std::vector<std::unique_ptr<File>> &result) { - ExecutableWriter::createImplicitFiles(result); - auto gotFile = llvm::make_unique<SimpleFile>("GOTFile"); - gotFile->addAtom(*new (gotFile->allocator()) GlobalOffsetTableAtom(*gotFile)); - if (this->_ctx.isDynamic()) - gotFile->addAtom(*new (gotFile->allocator()) DynamicAtom(*gotFile)); - result.push_back(std::move(gotFile)); -} - -void AArch64ExecutableWriter::buildDynamicSymbolTable(const File &file) { - for (auto sec : this->_layout.sections()) { - if (auto section = dyn_cast<AtomSection<ELF64LE>>(sec)) { - for (const auto &atom : section->atoms()) { - // Add all globals GOT symbols (in both .got and .got.plt sections) - // on dynamic symbol table. - for (const auto §ion : _targetLayout.getGOTSections()) { - if (section->hasGlobalGOTEntry(atom->_atom)) - _dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(), - atom->_virtualAddr, atom); - } - } - } - } - - ExecutableWriter<ELF64LE>::buildDynamicSymbolTable(file); -} - -} // namespace elf -} // namespace lld - diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h b/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h deleted file mode 100644 index eef825040ffa..000000000000 --- a/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h +++ /dev/null @@ -1,38 +0,0 @@ -//===- lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h -------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef AARCH64_EXECUTABLE_WRITER_H -#define AARCH64_EXECUTABLE_WRITER_H - -#include "ExecutableWriter.h" - -namespace lld { -namespace elf { - -class AArch64TargetLayout; -class AArch64LinkingContext; - -class AArch64ExecutableWriter : public ExecutableWriter<ELF64LE> { -public: - AArch64ExecutableWriter(AArch64LinkingContext &ctx, - AArch64TargetLayout &layout); - -protected: - // Add any runtime files and their atoms to the output - void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override; - - void buildDynamicSymbolTable(const File &file) override; - -private: - AArch64TargetLayout &_targetLayout; -}; - -} // namespace elf -} // namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp deleted file mode 100644 index ba883f7f59db..000000000000 --- a/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp +++ /dev/null @@ -1,45 +0,0 @@ -//===- lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp -------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "AArch64LinkingContext.h" -#include "AArch64RelocationPass.h" -#include "AArch64TargetHandler.h" - -using namespace lld; -using namespace lld::elf; - -std::unique_ptr<ELFLinkingContext> -elf::createAArch64LinkingContext(llvm::Triple triple) { - if (triple.getArch() == llvm::Triple::aarch64) - return llvm::make_unique<AArch64LinkingContext>(triple); - return nullptr; -} - -AArch64LinkingContext::AArch64LinkingContext(llvm::Triple triple) - : ELFLinkingContext(triple, std::unique_ptr<TargetHandler>( - new AArch64TargetHandler(*this))) {} - -void AArch64LinkingContext::addPasses(PassManager &pm) { - auto pass = createAArch64RelocationPass(*this); - if (pass) - pm.add(std::move(pass)); - ELFLinkingContext::addPasses(pm); -} - -static const Registry::KindStrings kindStrings[] = { -#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name), -#include "llvm/Support/ELFRelocs/AArch64.def" -#undef ELF_RELOC - LLD_KIND_STRING_END -}; - -void AArch64LinkingContext::registerRelocationNames(Registry ®istry) { - registry.addKindTable(Reference::KindNamespace::ELF, - Reference::KindArch::AArch64, kindStrings); -} diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.h b/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.h deleted file mode 100644 index 25a173158318..000000000000 --- a/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.h +++ /dev/null @@ -1,101 +0,0 @@ -//===- lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.h ---------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_AARCH64_AARCH64_LINKING_CONTEXT_H -#define LLD_READER_WRITER_ELF_AARCH64_AARCH64_LINKING_CONTEXT_H - -#include "lld/ReaderWriter/ELFLinkingContext.h" -#include "llvm/Object/ELF.h" -#include "llvm/Support/ELF.h" - -namespace lld { -namespace elf { - -enum { - /// \brief The offset to add operation for a R_AARCH64_ADR_GOT_PAGE - ADD_AARCH64_GOTRELINDEX = 0xE000, -}; - -class AArch64LinkingContext final : public ELFLinkingContext { -public: - int getMachineType() const override { return llvm::ELF::EM_AARCH64; } - AArch64LinkingContext(llvm::Triple); - - void addPasses(PassManager &) override; - void registerRelocationNames(Registry &r) override; - - uint64_t getBaseAddress() const override { - if (_baseAddress == 0) - return 0x400000; - return _baseAddress; - } - - bool isDynamicRelocation(const Reference &r) const override { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - assert(r.kindArch() == Reference::KindArch::AArch64); - switch (r.kindValue()) { - case llvm::ELF::R_AARCH64_COPY: - case llvm::ELF::R_AARCH64_GLOB_DAT: - case llvm::ELF::R_AARCH64_RELATIVE: - case llvm::ELF::R_AARCH64_TLS_DTPREL64: - case llvm::ELF::R_AARCH64_TLS_DTPMOD64: - case llvm::ELF::R_AARCH64_TLS_TPREL64: - case llvm::ELF::R_AARCH64_TLSDESC: - case llvm::ELF::R_AARCH64_IRELATIVE: - return true; - default: - return false; - } - } - - bool isCopyRelocation(const Reference &r) const override { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - assert(r.kindArch() == Reference::KindArch::AArch64); - if (r.kindValue() == llvm::ELF::R_AARCH64_COPY) - return true; - return false; - } - - bool isPLTRelocation(const Reference &r) const override { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - assert(r.kindArch() == Reference::KindArch::AArch64); - switch (r.kindValue()) { - case llvm::ELF::R_AARCH64_JUMP_SLOT: - case llvm::ELF::R_AARCH64_IRELATIVE: - return true; - default: - return false; - } - } - - bool isRelativeReloc(const Reference &r) const override { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - assert(r.kindArch() == Reference::KindArch::AArch64); - switch (r.kindValue()) { - case llvm::ELF::R_AARCH64_IRELATIVE: - case llvm::ELF::R_AARCH64_RELATIVE: - return true; - default: - return false; - } - } - - /// \brief The path to the dynamic interpreter - StringRef getDefaultInterpreter() const override { - return "/lib/ld-linux-aarch64.so.1"; - } -}; -} // end namespace elf -} // end namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp deleted file mode 100644 index ac7c769ec26d..000000000000 --- a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp +++ /dev/null @@ -1,556 +0,0 @@ -//===- lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp ----------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "AArch64TargetHandler.h" -#include "AArch64LinkingContext.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/MathExtras.h" - -#define DEBUG_TYPE "AArch64" - -using namespace lld; -using namespace lld::elf; -using namespace llvm; -using namespace llvm::support::endian; - -static int64_t page(int64_t v) { return v & ~int64_t(0xFFF); } - -/// \brief Check X is in the interval (-2^(bits-1), 2^bits] -static bool withinSignedUnsignedRange(int64_t X, int bits) { - return isIntN(bits - 1, X) || isUIntN(bits, X); -} - -/// \brief R_AARCH64_ABS64 - word64: S + A -static void relocR_AARCH64_ABS64(uint8_t *location, uint64_t P, uint64_t S, - int64_t A) { - int64_t result = (int64_t)S + A; - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - write64le(location, result | read64le(location)); -} - -/// \brief R_AARCH64_ABS32 - word32: S + A -static std::error_code relocR_AARCH64_ABS32(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - int64_t result = S + A; - if (!withinSignedUnsignedRange(result, 32)) - return make_out_of_range_reloc_error(); - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - write32le(location, result | read32le(location)); - return std::error_code(); -} - -/// \brief R_AARCH64_ABS16 - word16: S + A -static std::error_code relocR_AARCH64_ABS16(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - int64_t result = S + A; - if (!withinSignedUnsignedRange(result, 16)) - return make_out_of_range_reloc_error(); - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - write16le(location, result | read16le(location)); - return std::error_code(); -} - -/// \brief R_AARCH64_PREL64 - word64: S + A - P -static void relocR_AARCH64_PREL64(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - int64_t result = S + A - P; - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - write64le(location, result + read64le(location)); -} - -/// \brief R_AARCH64_PREL32 - word32: S + A - P -static std::error_code relocR_AARCH64_PREL32(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - int64_t result = S + A - P; - // ELF for the ARM 64-bit architecture manual states the overflow - // for R_AARCH64_PREL32 to be -2^(-31) <= X < 2^32 - if (!withinSignedUnsignedRange(result, 32)) - return make_out_of_range_reloc_error(); - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - write32le(location, result + read32le(location)); - return std::error_code(); -} - -/// \brief R_AARCH64_PREL16 - word16: S + A - P -static std::error_code relocR_AARCH64_PREL16(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - int64_t result = S + A - P; - if (!withinSignedUnsignedRange(result, 16)) - return make_out_of_range_reloc_error(); - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - write16le(location, result + read16le(location)); - return std::error_code(); -} - -/// \brief R_AARCH64_ADR_PREL_PG_HI21 - Page(S+A) - Page(P) -static std::error_code relocR_AARCH64_ADR_PREL_PG_HI21(uint8_t *location, - uint64_t P, uint64_t S, - int64_t A) { - int64_t result = page(S + A) - page(P); - if (!isInt<32>(result)) - return make_out_of_range_reloc_error(); - result = result >> 12; - uint32_t immlo = result & 0x3; - uint32_t immhi = result & 0x1FFFFC; - immlo = immlo << 29; - immhi = immhi << 3; - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: " << Twine::utohexstr(S); - llvm::dbgs() << " A: " << Twine::utohexstr(A); - llvm::dbgs() << " P: " << Twine::utohexstr(P); - llvm::dbgs() << " immhi: " << Twine::utohexstr(immhi); - llvm::dbgs() << " immlo: " << Twine::utohexstr(immlo); - llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n"); - write32le(location, immlo | immhi | read32le(location)); - return std::error_code(); -} - -/// \brief R_AARCH64_ADR_PREL_LO21 - S + A - P -static std::error_code relocR_AARCH64_ADR_PREL_LO21(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - uint64_t result = S + A - P; - if (!isInt<20>(result)) - return make_out_of_range_reloc_error(); - uint32_t immlo = result & 0x3; - uint32_t immhi = result & 0x1FFFFC; - immlo = immlo << 29; - immhi = immhi << 3; - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: " << Twine::utohexstr(S); - llvm::dbgs() << " A: " << Twine::utohexstr(A); - llvm::dbgs() << " P: " << Twine::utohexstr(P); - llvm::dbgs() << " immhi: " << Twine::utohexstr(immhi); - llvm::dbgs() << " immlo: " << Twine::utohexstr(immlo); - llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n"); - write32le(location, immlo | immhi | read32le(location)); - return std::error_code(); -} - -/// \brief R_AARCH64_ADD_ABS_LO12_NC -static void relocR_AARCH64_ADD_ABS_LO12_NC(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - int32_t result = (int32_t)((S + A) & 0xFFF); - result <<= 10; - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: " << Twine::utohexstr(S); - llvm::dbgs() << " A: " << Twine::utohexstr(A); - llvm::dbgs() << " P: " << Twine::utohexstr(P); - llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n"); - write32le(location, result | read32le(location)); -} - -/// \brief R_AARCH64_CALL26 and R_AARCH64_JUMP26 -static std::error_code relocJump26(uint8_t *location, uint64_t P, uint64_t S, - int64_t A) { - int64_t result = S + A - P; - if (!isInt<27>(result)) - return make_out_of_range_reloc_error(); - result &= 0x0FFFFFFC; - result >>= 2; - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: " << Twine::utohexstr(S); - llvm::dbgs() << " A: " << Twine::utohexstr(A); - llvm::dbgs() << " P: " << Twine::utohexstr(P); - llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n"); - write32le(location, result | read32le(location)); - return std::error_code(); -} - -/// \brief R_AARCH64_CONDBR19 -static std::error_code relocR_AARCH64_CONDBR19(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - int64_t result = S + A - P; - if (!isInt<20>(result)) - return make_out_of_range_reloc_error(); - result &= 0x01FFFFC; - result <<= 3; - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: " << Twine::utohexstr(S); - llvm::dbgs() << " A: " << Twine::utohexstr(A); - llvm::dbgs() << " P: " << Twine::utohexstr(P); - llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n"); - write32le(location, result | read32le(location)); - return std::error_code(); -} - -/// \brief R_AARCH64_LDST8_ABS_LO12_NC - S + A -static void relocR_AARCH64_LDST8_ABS_LO12_NC(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - int32_t result = (int32_t)((S + A) & 0xFFF); - result <<= 10; - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: " << Twine::utohexstr(S); - llvm::dbgs() << " A: " << Twine::utohexstr(A); - llvm::dbgs() << " P: " << Twine::utohexstr(P); - llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n"); - write32le(location, result | read32le(location)); -} - -/// \brief R_AARCH64_LDST16_ABS_LO12_NC -static void relocR_AARCH64_LDST16_ABS_LO12_NC(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - int32_t result = (int32_t)(S + A); - result &= 0x0FFC; - result <<= 9; - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: " << Twine::utohexstr(S); - llvm::dbgs() << " A: " << Twine::utohexstr(A); - llvm::dbgs() << " P: " << Twine::utohexstr(P); - llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n"); - write32le(location, result | read32le(location)); -} - -/// \brief R_AARCH64_LDST32_ABS_LO12_NC -static void relocR_AARCH64_LDST32_ABS_LO12_NC(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - int32_t result = (int32_t)(S + A); - result &= 0x0FFC; - result <<= 8; - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: " << Twine::utohexstr(S); - llvm::dbgs() << " A: " << Twine::utohexstr(A); - llvm::dbgs() << " P: " << Twine::utohexstr(P); - llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n"); - write32le(location, result | read32le(location)); -} - -/// \brief R_AARCH64_LDST64_ABS_LO12_NC -static void relocR_AARCH64_LDST64_ABS_LO12_NC(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - int32_t result = (int32_t)(S + A); - result &= 0x0FF8; - result <<= 7; - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: " << Twine::utohexstr(S); - llvm::dbgs() << " A: " << Twine::utohexstr(A); - llvm::dbgs() << " P: " << Twine::utohexstr(P); - llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n"); - write32le(location, result | read32le(location)); -} - -/// \brief R_AARCH64_LDST128_ABS_LO12_NC -static void relocR_AARCH64_LDST128_ABS_LO12_NC(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - int32_t result = (int32_t)(S + A); - result &= 0x0FF8; - result <<= 6; - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: " << Twine::utohexstr(S); - llvm::dbgs() << " A: " << Twine::utohexstr(A); - llvm::dbgs() << " P: " << Twine::utohexstr(P); - llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n"); - write32le(location, result | read32le(location)); -} - -static std::error_code relocR_AARCH64_ADR_GOT_PAGE(uint8_t *location, - uint64_t P, uint64_t S, - int64_t A) { - uint64_t result = page(S + A) - page(P); - if (!isInt<32>(result)) - return make_out_of_range_reloc_error(); - result = (result >> 12) & 0x3FFFF; - uint32_t immlo = result & 0x3; - uint32_t immhi = result & 0x1FFFFC; - immlo = immlo << 29; - immhi = immhi << 3; - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: " << Twine::utohexstr(S); - llvm::dbgs() << " A: " << Twine::utohexstr(A); - llvm::dbgs() << " P: " << Twine::utohexstr(P); - llvm::dbgs() << " immhi: " << Twine::utohexstr(immhi); - llvm::dbgs() << " immlo: " << Twine::utohexstr(immlo); - llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n"); - write32le(location, immlo | immhi | read32le(location)); - return std::error_code(); -} - -// R_AARCH64_LD64_GOT_LO12_NC -static std::error_code relocR_AARCH64_LD64_GOT_LO12_NC(uint8_t *location, - uint64_t P, uint64_t S, - int64_t A) { - int32_t result = S + A; - DEBUG(llvm::dbgs() << " S: " << Twine::utohexstr(S); - llvm::dbgs() << " A: " << Twine::utohexstr(A); - llvm::dbgs() << " P: " << Twine::utohexstr(P); - llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n"); - if ((result & 0x7) != 0) - return make_unaligned_range_reloc_error(); - result &= 0xFF8; - result <<= 7; - write32le(location, result | read32le(location)); - return std::error_code(); -} - -// ADD_AARCH64_GOTRELINDEX -static void relocADD_AARCH64_GOTRELINDEX(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - int32_t result = S + A; - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: " << Twine::utohexstr(S); - llvm::dbgs() << " A: " << Twine::utohexstr(A); - llvm::dbgs() << " P: " << Twine::utohexstr(P); - llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n"); - result &= 0xFFF; - result <<= 10; - write32le(location, result | read32le(location)); -} - -// R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 -static std::error_code relocR_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21(uint8_t *location, - uint64_t P, - uint64_t S, - int64_t A) { - int64_t result = page(S + A) - page(P); - if (!isInt<32>(result)) - return make_out_of_range_reloc_error(); - result >>= 12; - uint32_t immlo = result & 0x3; - uint32_t immhi = result & 0x1FFFFC; - immlo = immlo << 29; - immhi = immhi << 3; - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: " << Twine::utohexstr(S); - llvm::dbgs() << " A: " << Twine::utohexstr(A); - llvm::dbgs() << " P: " << Twine::utohexstr(P); - llvm::dbgs() << " immhi: " << Twine::utohexstr(immhi); - llvm::dbgs() << " immlo: " << Twine::utohexstr(immlo); - llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n"); - write32le(location, immlo | immhi | read32le(location)); - return std::error_code(); -} - -// R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC -static void relocR_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC(uint8_t *location, - uint64_t P, uint64_t S, - int64_t A) { - int32_t result = S + A; - result &= 0xFF8; - result <<= 7; - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: " << Twine::utohexstr(S); - llvm::dbgs() << " A: " << Twine::utohexstr(A); - llvm::dbgs() << " P: " << Twine::utohexstr(P); - llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n"); - write32le(location, result | read32le(location)); -} - -/// \brief R_AARCH64_TLSLE_ADD_TPREL_HI12 -static std::error_code relocR_AARCH64_TLSLE_ADD_TPREL_HI12(uint8_t *location, - uint64_t P, - uint64_t S, - int64_t A) { - int64_t result = S + A; - if (!isUInt<24>(result)) - return make_out_of_range_reloc_error(); - result &= 0x0FFF000; - result >>= 2; - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: " << Twine::utohexstr(S); - llvm::dbgs() << " A: " << Twine::utohexstr(A); - llvm::dbgs() << " P: " << Twine::utohexstr(P); - llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n"); - write32le(location, result | read32le(location)); - return std::error_code(); -} - -/// \brief R_AARCH64_TLSLE_ADD_TPREL_LO12_NC -static void relocR_AARCH64_TLSLE_ADD_TPREL_LO12_NC(uint8_t *location, - uint64_t P, uint64_t S, - int64_t A) { - int32_t result = S + A; - result &= 0x0FFF; - result <<= 10; - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: " << Twine::utohexstr(S); - llvm::dbgs() << " A: " << Twine::utohexstr(A); - llvm::dbgs() << " P: " << Twine::utohexstr(P); - llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n"); - write32le(location, result | read32le(location)); -} - -/// \brief R_AARCH64_TLSDESC_ADR_PAGE21 - Page(G(GTLSDESC(S+A))) - Page(P) -static std::error_code relocR_AARCH64_TLSDESC_ADR_PAGE21(uint8_t *location, - uint64_t P, uint64_t S, - int64_t A) { - int64_t result = page(S + A) - page(P); - if (!isInt<32>(result)) - return make_out_of_range_reloc_error(); - result = result >> 12; - uint32_t immlo = result & 0x3; - uint32_t immhi = result & 0x1FFFFC; - immlo = immlo << 29; - immhi = immhi << 3; - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: " << Twine::utohexstr(S); - llvm::dbgs() << " A: " << Twine::utohexstr(A); - llvm::dbgs() << " P: " << Twine::utohexstr(P); - llvm::dbgs() << " immhi: " << Twine::utohexstr(immhi); - llvm::dbgs() << " immlo: " << Twine::utohexstr(immlo); - llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n"); - write32le(location, immlo | immhi | read32le(location)); - return std::error_code(); -} - -/// \brief R_AARCH64_TLSDESC_LD64_LO12_NC - G(GTLSDESC(S+A)) -> S + A -static std::error_code relocR_AARCH64_TLSDESC_LD64_LO12_NC(uint8_t *location, - uint64_t P, - uint64_t S, - int64_t A) { - int32_t result = S + A; - DEBUG(llvm::dbgs() << " S: " << Twine::utohexstr(S); - llvm::dbgs() << " A: " << Twine::utohexstr(A); - llvm::dbgs() << " P: " << Twine::utohexstr(P); - llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n"); - if ((result & 0x7) != 0) - return make_unaligned_range_reloc_error(); - result &= 0xFF8; - result <<= 7; - write32le(location, result | read32le(location)); - return std::error_code(); -} - -/// \brief R_AARCH64_TLSDESC_ADD_LO12_NC - G(GTLSDESC(S+A)) -> S + A -static void relocR_AARCH64_TLSDESC_ADD_LO12_NC(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - int32_t result = (int32_t)((S + A) & 0xFFF); - result <<= 10; - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: " << Twine::utohexstr(S); - llvm::dbgs() << " A: " << Twine::utohexstr(A); - llvm::dbgs() << " P: " << Twine::utohexstr(P); - llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n"); - write32le(location, result | read32le(location)); -} - -std::error_code AArch64TargetRelocationHandler::applyRelocation( - ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom, - const Reference &ref) const { - uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset; - uint8_t *loc = atomContent + ref.offsetInAtom(); - uint64_t target = writer.addressOfAtom(ref.target()); - uint64_t reloc = atom._virtualAddr + ref.offsetInAtom(); - int64_t addend = ref.addend(); - - if (ref.kindNamespace() != Reference::KindNamespace::ELF) - return std::error_code(); - assert(ref.kindArch() == Reference::KindArch::AArch64); - switch (ref.kindValue()) { - case R_AARCH64_NONE: - break; - case R_AARCH64_ABS64: - relocR_AARCH64_ABS64(loc, reloc, target, addend); - break; - case R_AARCH64_ABS32: - return relocR_AARCH64_ABS32(loc, reloc, target, addend); - case R_AARCH64_ABS16: - return relocR_AARCH64_ABS16(loc, reloc, target, addend); - case R_AARCH64_PREL64: - relocR_AARCH64_PREL64(loc, reloc, target, addend); - break; - case R_AARCH64_PREL32: - return relocR_AARCH64_PREL32(loc, reloc, target, addend); - case R_AARCH64_PREL16: - return relocR_AARCH64_PREL16(loc, reloc, target, addend); - case R_AARCH64_ADR_PREL_PG_HI21: - return relocR_AARCH64_ADR_PREL_PG_HI21(loc, reloc, target, addend); - case R_AARCH64_ADR_PREL_LO21: - return relocR_AARCH64_ADR_PREL_LO21(loc, reloc, target, addend); - case R_AARCH64_ADD_ABS_LO12_NC: - relocR_AARCH64_ADD_ABS_LO12_NC(loc, reloc, target, addend); - break; - case R_AARCH64_CALL26: - case R_AARCH64_JUMP26: - return relocJump26(loc, reloc, target, addend); - case R_AARCH64_CONDBR19: - return relocR_AARCH64_CONDBR19(loc, reloc, target, addend); - case R_AARCH64_ADR_GOT_PAGE: - return relocR_AARCH64_ADR_GOT_PAGE(loc, reloc, target, addend); - case R_AARCH64_LD64_GOT_LO12_NC: - return relocR_AARCH64_LD64_GOT_LO12_NC(loc, reloc, target, addend); - case R_AARCH64_LDST8_ABS_LO12_NC: - relocR_AARCH64_LDST8_ABS_LO12_NC(loc, reloc, target, addend); - break; - case R_AARCH64_LDST16_ABS_LO12_NC: - relocR_AARCH64_LDST16_ABS_LO12_NC(loc, reloc, target, addend); - break; - case R_AARCH64_LDST32_ABS_LO12_NC: - relocR_AARCH64_LDST32_ABS_LO12_NC(loc, reloc, target, addend); - break; - case R_AARCH64_LDST64_ABS_LO12_NC: - relocR_AARCH64_LDST64_ABS_LO12_NC(loc, reloc, target, addend); - break; - case R_AARCH64_LDST128_ABS_LO12_NC: - relocR_AARCH64_LDST128_ABS_LO12_NC(loc, reloc, target, addend); - break; - case ADD_AARCH64_GOTRELINDEX: - relocADD_AARCH64_GOTRELINDEX(loc, reloc, target, addend); - break; - case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: - return relocR_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21(loc, reloc, target, addend); - case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: - relocR_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC(loc, reloc, target, addend); - break; - case R_AARCH64_TLSLE_ADD_TPREL_HI12: - case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: { - auto tpoffset = _layout.getTPOffset(); - if (ref.kindValue() == R_AARCH64_TLSLE_ADD_TPREL_HI12) - return relocR_AARCH64_TLSLE_ADD_TPREL_HI12(loc, reloc, target + tpoffset, - addend); - else - relocR_AARCH64_TLSLE_ADD_TPREL_LO12_NC(loc, reloc, target + tpoffset, - addend); - } break; - case R_AARCH64_TLSDESC_ADR_PAGE21: - return relocR_AARCH64_TLSDESC_ADR_PAGE21(loc, reloc, target, addend); - case R_AARCH64_TLSDESC_LD64_LO12_NC: - return relocR_AARCH64_TLSDESC_LD64_LO12_NC(loc, reloc, target, addend); - case R_AARCH64_TLSDESC_ADD_LO12_NC: - relocR_AARCH64_TLSDESC_ADD_LO12_NC(loc, reloc, target, addend); - break; - case R_AARCH64_TLSDESC_CALL: - // Relaxation only to optimize TLS access. Ignore for now. - break; - // Runtime only relocations. Ignore here. - case R_AARCH64_RELATIVE: - case R_AARCH64_IRELATIVE: - case R_AARCH64_JUMP_SLOT: - case R_AARCH64_GLOB_DAT: - case R_AARCH64_TLS_TPREL64: - case R_AARCH64_TLSDESC: - break; - default: - return make_unhandled_reloc_error(); - } - return std::error_code(); -} diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.h b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.h deleted file mode 100644 index 8cde7a03e51a..000000000000 --- a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.h +++ /dev/null @@ -1,36 +0,0 @@ -//===- lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.h ------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef AARCH64_RELOCATION_HANDLER_H -#define AARCH64_RELOCATION_HANDLER_H - -#include "lld/ReaderWriter/ELFLinkingContext.h" - -namespace lld { -namespace elf { - -class AArch64TargetLayout; - -class AArch64TargetRelocationHandler final : public TargetRelocationHandler { -public: - AArch64TargetRelocationHandler(AArch64TargetLayout &layout) - : _layout(layout) {} - - std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &, - const AtomLayout &, - const Reference &) const override; - -private: - AArch64TargetLayout &_layout; -}; - -} // end namespace elf -} // end namespace lld - -#endif // AArch64_RELOCATION_HANDLER_H diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp deleted file mode 100644 index 4d94a793665c..000000000000 --- a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp +++ /dev/null @@ -1,612 +0,0 @@ -//===- lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp -------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Defines the relocation processing pass for AArch64. This includes -/// GOT and PLT entries, TLS, COPY, and ifunc. -/// -/// This also includes additional behavior that gnu-ld and gold implement but -/// which is not specified anywhere. -/// -//===----------------------------------------------------------------------===// - -#include "AArch64RelocationPass.h" -#include "AArch64LinkingContext.h" -#include "Atoms.h" -#include "lld/Core/Simple.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/Support/Debug.h" - -using namespace lld; -using namespace lld::elf; -using namespace llvm::ELF; - -// .got values -static const uint8_t AArch64GotAtomContent[8] = {0}; - -// tls descriptor .got values, the layout is: -// struct tlsdesc { -// ptrdiff_t (*entry) (struct tlsdesc *); -// void *arg; -// }; -static const uint8_t AArch64TlsdescGotAtomContent[16] = {0}; - -// .plt value (entry 0) -static const uint8_t AArch64Plt0AtomContent[32] = { - 0xf0, 0x7b, 0xbf, 0xa9, // stp x16, x30, [sp,#-16]! - 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(eh_frame) - 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16,#offset] - 0x10, 0x02, 0x00, 0x91, // add x16, x16, #offset - 0x20, 0x02, 0x1f, 0xd6, // br x17 - 0x1f, 0x20, 0x03, 0xd5, // nop - 0x1f, 0x20, 0x03, 0xd5, // nop - 0x1f, 0x20, 0x03, 0xd5 // nop -}; - -// .plt values (other entries) -static const uint8_t AArch64PltAtomContent[16] = { - 0x10, 0x00, 0x00, 0x90, // adrp x16, PAGE(<GLOBAL_OFFSET_TABLE>) - 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16,#offset] - 0x10, 0x02, 0x00, 0x91, // add x16, x16, #offset - 0x20, 0x02, 0x1f, 0xd6 // br x17 -}; - -// .plt tlsdesc values -static const uint8_t AArch64PltTlsdescAtomContent[32] = { - 0xe2, 0x0f, 0xbf, 0xa9, // stp x2, x3, [sp, #-16] - 0x02, 0x00, 0x00, 0x90, // adpr x2, 0 - 0x03, 0x00, 0x00, 0x90, // adpr x3, 0 - 0x42, 0x00, 0x40, 0xf9, // ldr x2, [x2, #0] - 0x63, 0x00, 0x00, 0x91, // add x3, x3, 0 - 0x40, 0x00, 0x1f, 0xd6, // br x2 - 0x1f, 0x20, 0x03, 0xd5, // nop - 0x1f, 0x20, 0x03, 0xd5 // nop -}; - -namespace { - -/// \brief Atoms that are used by AArch64 dynamic linking -class AArch64GOTAtom : public GOTAtom { -public: - AArch64GOTAtom(const File &f) : GOTAtom(f, ".got") {} - - ArrayRef<uint8_t> rawContent() const override { - return ArrayRef<uint8_t>(AArch64GotAtomContent, 8); - } - -protected: - // Constructor for AArch64GOTAtom - AArch64GOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {} -}; - -class AArch64GOTPLTAtom : public AArch64GOTAtom { -public: - AArch64GOTPLTAtom(const File &f) : AArch64GOTAtom(f, ".got.plt") {} -}; - -class AArch64TLSDESCGOTAtom : public AArch64GOTPLTAtom { -public: - AArch64TLSDESCGOTAtom(const File &f) : AArch64GOTPLTAtom(f) {} - - ArrayRef<uint8_t> rawContent() const override { - return ArrayRef<uint8_t>(AArch64TlsdescGotAtomContent, 16); - } -}; - - -class AArch64PLT0Atom : public PLT0Atom { -public: - AArch64PLT0Atom(const File &f) : PLT0Atom(f) {} - ArrayRef<uint8_t> rawContent() const override { - return ArrayRef<uint8_t>(AArch64Plt0AtomContent, 32); - } -}; - -class AArch64PLTAtom : public PLTAtom { -public: - AArch64PLTAtom(const File &f) : PLTAtom(f, ".plt") {} - - ArrayRef<uint8_t> rawContent() const override { - return ArrayRef<uint8_t>(AArch64PltAtomContent, 16); - } -}; - -class AArch64PLTTLSDESCAtom : public PLTAtom { -public: - AArch64PLTTLSDESCAtom(const File &f) : PLTAtom(f, ".plt") {} - - ArrayRef<uint8_t> rawContent() const override { - return ArrayRef<uint8_t>(AArch64PltTlsdescAtomContent, 32); - } -}; - -class ELFPassFile : public SimpleFile { -public: - ELFPassFile(const ELFLinkingContext &eti) : SimpleFile("ELFPassFile") { - setOrdinal(eti.getNextOrdinalAndIncrement()); - } - - llvm::BumpPtrAllocator _alloc; -}; - -/// \brief CRTP base for handling relocations. -template <class Derived> class AArch64RelocationPass : public Pass { - /// \brief Handle a specific reference. - void handleReference(const DefinedAtom &atom, const Reference &ref) { - DEBUG_WITH_TYPE( - "AArch64", llvm::dbgs() - << "\t" << LLVM_FUNCTION_NAME << "()" - << ": Name of Defined Atom: " << atom.name().str(); - llvm::dbgs() << " kindValue: " << ref.kindValue() << "\n"); - if (ref.kindNamespace() != Reference::KindNamespace::ELF) - return; - assert(ref.kindArch() == Reference::KindArch::AArch64); - switch (ref.kindValue()) { - case R_AARCH64_ABS32: - case R_AARCH64_ABS16: - case R_AARCH64_ABS64: - case R_AARCH64_PREL16: - case R_AARCH64_PREL32: - case R_AARCH64_PREL64: - static_cast<Derived *>(this)->handlePlain(ref); - break; - case R_AARCH64_GOTREL32: - case R_AARCH64_GOTREL64: - static_cast<Derived *>(this)->handleGOT(ref); - break; - case R_AARCH64_ADR_PREL_PG_HI21: - static_cast<Derived *>(this)->handlePlain(ref); - break; - case R_AARCH64_LDST8_ABS_LO12_NC: - case R_AARCH64_LDST16_ABS_LO12_NC: - case R_AARCH64_LDST32_ABS_LO12_NC: - case R_AARCH64_LDST64_ABS_LO12_NC: - case R_AARCH64_LDST128_ABS_LO12_NC: - static_cast<Derived *>(this)->handlePlain(ref); - break; - case R_AARCH64_ADD_ABS_LO12_NC: - static_cast<Derived *>(this)->handlePlain(ref); - break; - case R_AARCH64_CALL26: - case R_AARCH64_JUMP26: - case R_AARCH64_CONDBR19: - static_cast<Derived *>(this)->handlePlain(ref); - break; - case R_AARCH64_TLSLE_ADD_TPREL_HI12: - case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: - static_cast<Derived *>(this)->handlePlain(ref); - break; - case R_AARCH64_ADR_GOT_PAGE: - case R_AARCH64_LD64_GOT_LO12_NC: - static_cast<Derived *>(this)->handleGOT(ref); - break; - case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: - case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: - static_cast<Derived *>(this)->handleGOTTPREL(ref); - break; - case R_AARCH64_TLSDESC_ADR_PAGE21: - case R_AARCH64_TLSDESC_LD64_LO12_NC: - case R_AARCH64_TLSDESC_ADD_LO12_NC: - static_cast<Derived *>(this)->handleTLSDESC(ref); - break; - } - } - -protected: - /// \brief get the PLT entry for a given IFUNC Atom. - /// - /// If the entry does not exist. Both the GOT and PLT entry is created. - const PLTAtom *getIFUNCPLTEntry(const DefinedAtom *da) { - auto plt = _pltMap.find(da); - if (plt != _pltMap.end()) - return plt->second; - auto ga = new (_file._alloc) AArch64GOTPLTAtom(_file); - ga->addReferenceELF_AArch64(R_AARCH64_IRELATIVE, 0, da, 0); - auto pa = new (_file._alloc) AArch64PLTAtom(_file); - pa->addReferenceELF_AArch64(R_AARCH64_PREL32, 2, ga, -4); -#ifndef NDEBUG - ga->_name = "__got_ifunc_"; - ga->_name += da->name(); - pa->_name = "__plt_ifunc_"; - pa->_name += da->name(); -#endif - _gotMap[da] = ga; - _pltMap[da] = pa; - _gotVector.push_back(ga); - _pltVector.push_back(pa); - return pa; - } - - /// \brief Redirect the call to the PLT stub for the target IFUNC. - /// - /// This create a PLT and GOT entry for the IFUNC if one does not exist. The - /// GOT entry and a IRELATIVE relocation to the original target resolver. - std::error_code handleIFUNC(const Reference &ref) { - auto target = dyn_cast_or_null<const DefinedAtom>(ref.target()); - if (target && target->contentType() == DefinedAtom::typeResolver) - const_cast<Reference &>(ref).setTarget(getIFUNCPLTEntry(target)); - return std::error_code(); - } - - /// \brief Create a GOT entry for the TP offset of a TLS atom. - const GOTAtom *getGOTTPREL(const Atom *atom) { - auto got = _gotMap.find(atom); - if (got == _gotMap.end()) { - auto g = new (_file._alloc) AArch64GOTAtom(_file); - g->addReferenceELF_AArch64(R_AARCH64_TLS_TPREL64, 0, atom, 0); -#ifndef NDEBUG - g->_name = "__got_tls_"; - g->_name += atom->name(); -#endif - _gotMap[atom] = g; - _gotVector.push_back(g); - return g; - } - return got->second; - } - - /// \brief Create a GOT TPREL entry to local or external TLS variable. - std::error_code handleGOTTPREL(const Reference &ref) { - if (isa<DefinedAtom>(ref.target()) || - isa<SharedLibraryAtom>(ref.target())) - const_cast<Reference &>(ref).setTarget(getGOTTPREL(ref.target())); - return std::error_code(); - } - - /// \brief Generates a double GOT entry with R_AARCH64_TLSDESC dynamic - /// relocation reference. Since the dynamic relocation is resolved - /// lazily so the GOT associated should be in .got.plt. - const GOTAtom *getTLSDESCPLTEntry(const Atom *da) { - auto got = _gotMap.find(da); - if (got != _gotMap.end()) - return got->second; - auto ga = new (_file._alloc) AArch64TLSDESCGOTAtom(_file); - ga->addReferenceELF_AArch64(R_AARCH64_TLSDESC, 0, da, 0); - auto pa = new (_file._alloc) AArch64PLTTLSDESCAtom(_file); - pa->addReferenceELF_AArch64(R_AARCH64_ADR_PREL_PG_HI21, 4, ga, 0); - pa->addReferenceELF_AArch64(R_AARCH64_ADR_PREL_PG_HI21, 8, ga, 0); - pa->addReferenceELF_AArch64(R_AARCH64_LDST64_ABS_LO12_NC, 12, ga, 0); - pa->addReferenceELF_AArch64(R_AARCH64_ADD_ABS_LO12_NC, 16, ga, 0); -#ifndef NDEBUG - ga->_name = "__got_tlsdesc_"; - ga->_name += da->name(); - pa->_name = "__plt_tlsdesc_"; - pa->_name += da->name(); -#endif - _gotMap[da] = ga; - _pltMap[da] = pa; - _tlsdescVector.push_back(ga); - _pltVector.push_back(pa); - return ga; - } - - std::error_code handleTLSDESC(const Reference &ref) { - if (isa<DefinedAtom>(ref.target()) || - isa<SharedLibraryAtom>(ref.target())) { - const_cast<Reference &>(ref).setTarget(getTLSDESCPLTEntry(ref.target())); - } - return std::error_code(); - } - - /// \brief Create a GOT entry containing 0. - const GOTAtom *getNullGOT() { - if (!_null) { - _null = new (_file._alloc) AArch64GOTPLTAtom(_file); -#ifndef NDEBUG - _null->_name = "__got_null"; -#endif - } - return _null; - } - - const GOTAtom *getGOT(const DefinedAtom *da) { - auto got = _gotMap.find(da); - if (got == _gotMap.end()) { - auto g = new (_file._alloc) AArch64GOTAtom(_file); - g->addReferenceELF_AArch64(R_AARCH64_ABS64, 0, da, 0); -#ifndef NDEBUG - g->_name = "__got_"; - g->_name += da->name(); -#endif - _gotMap[da] = g; - _gotVector.push_back(g); - return g; - } - return got->second; - } - -public: - AArch64RelocationPass(const ELFLinkingContext &ctx) : _file(ctx), _ctx(ctx) {} - - /// \brief Do the pass. - /// - /// The goal here is to first process each reference individually. Each call - /// to handleReference may modify the reference itself and/or create new - /// atoms which must be stored in one of the maps below. - /// - /// After all references are handled, the atoms created during that are all - /// added to mf. - std::error_code perform(SimpleFile &mf) override { - ScopedTask task(getDefaultDomain(), "AArch64 GOT/PLT Pass"); - DEBUG_WITH_TYPE( - "AArch64", llvm::dbgs() << "Undefined Atoms" - << "\n"; - for (const auto &atom - : mf.undefined()) { - llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n"; - } llvm::dbgs() - << "Shared Library Atoms" - << "\n"; - for (const auto &atom - : mf.sharedLibrary()) { - llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n"; - } llvm::dbgs() - << "Absolute Atoms" - << "\n"; - for (const auto &atom - : mf.absolute()) { - llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n"; - } - // Process all references. - llvm::dbgs() - << "Defined Atoms" - << "\n"); - for (const auto &atom : mf.defined()) { - for (const auto &ref : *atom) { - handleReference(*atom, *ref); - } - } - - // Add all created atoms to the link. - uint64_t ordinal = 0; - if (_plt0) { - _plt0->setOrdinal(ordinal++); - mf.addAtom(*_plt0); - } - for (auto &plt : _pltVector) { - plt->setOrdinal(ordinal++); - mf.addAtom(*plt); - } - if (_null) { - _null->setOrdinal(ordinal++); - mf.addAtom(*_null); - } - if (_plt0) { - _got0->setOrdinal(ordinal++); - _got1->setOrdinal(ordinal++); - mf.addAtom(*_got0); - mf.addAtom(*_got1); - } - for (auto &got : _gotVector) { - got->setOrdinal(ordinal++); - mf.addAtom(*got); - } - // Add any tlsdesc GOT relocation after default PLT and iFUNC entries. - for (auto &tlsdesc : _tlsdescVector) { - tlsdesc->setOrdinal(ordinal++); - mf.addAtom(*tlsdesc); - } - for (auto obj : _objectVector) { - obj->setOrdinal(ordinal++); - mf.addAtom(*obj); - } - - return std::error_code(); - } - -protected: - /// \brief Owner of all the Atoms created by this pass. - ELFPassFile _file; - const ELFLinkingContext &_ctx; - - /// \brief Map Atoms to their GOT entries. - llvm::DenseMap<const Atom *, GOTAtom *> _gotMap; - - /// \brief Map Atoms to their PLT entries. - llvm::DenseMap<const Atom *, PLTAtom *> _pltMap; - - /// \brief Map Atoms to their Object entries. - llvm::DenseMap<const Atom *, ObjectAtom *> _objectMap; - - /// \brief the list of GOT/PLT atoms - std::vector<GOTAtom *> _gotVector; - std::vector<GOTAtom *> _tlsdescVector; - std::vector<PLTAtom *> _pltVector; - std::vector<ObjectAtom *> _objectVector; - - /// \brief GOT entry that is always 0. Used for undefined weaks. - GOTAtom *_null = nullptr; - - /// \brief The got and plt entries for .PLT0. This is used to call into the - /// dynamic linker for symbol resolution. - /// @{ - PLT0Atom *_plt0 = nullptr; - GOTAtom *_got0 = nullptr; - GOTAtom *_got1 = nullptr; - /// @} -}; - -/// This implements the static relocation model. Meaning GOT and PLT entries are -/// not created for references that can be directly resolved. These are -/// converted to a direct relocation. For entries that do require a GOT or PLT -/// entry, that entry is statically bound. -/// -/// TLS always assumes module 1 and attempts to remove indirection. -class AArch64StaticRelocationPass final - : public AArch64RelocationPass<AArch64StaticRelocationPass> { -public: - AArch64StaticRelocationPass(const elf::AArch64LinkingContext &ctx) - : AArch64RelocationPass(ctx) {} - - std::error_code handlePlain(const Reference &ref) { return handleIFUNC(ref); } - - std::error_code handlePLT32(const Reference &ref) { - // __tls_get_addr is handled elsewhere. - if (ref.target() && ref.target()->name() == "__tls_get_addr") { - const_cast<Reference &>(ref).setKindValue(R_AARCH64_NONE); - return std::error_code(); - } - // Static code doesn't need PLTs. - const_cast<Reference &>(ref).setKindValue(R_AARCH64_PREL32); - // Handle IFUNC. - if (const DefinedAtom *da = - dyn_cast_or_null<const DefinedAtom>(ref.target())) - if (da->contentType() == DefinedAtom::typeResolver) - return handleIFUNC(ref); - return std::error_code(); - } - - std::error_code handleGOT(const Reference &ref) { - if (isa<UndefinedAtom>(ref.target())) - const_cast<Reference &>(ref).setTarget(getNullGOT()); - else if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(ref.target())) - const_cast<Reference &>(ref).setTarget(getGOT(da)); - return std::error_code(); - } -}; - -class AArch64DynamicRelocationPass final - : public AArch64RelocationPass<AArch64DynamicRelocationPass> { -public: - AArch64DynamicRelocationPass(const elf::AArch64LinkingContext &ctx) - : AArch64RelocationPass(ctx) {} - - const PLT0Atom *getPLT0() { - if (_plt0) - return _plt0; - // Fill in the null entry. - getNullGOT(); - _plt0 = new (_file._alloc) AArch64PLT0Atom(_file); - _got0 = new (_file._alloc) AArch64GOTPLTAtom(_file); - _got1 = new (_file._alloc) AArch64GOTPLTAtom(_file); - _plt0->addReferenceELF_AArch64(R_AARCH64_ADR_GOT_PAGE, 4, _got0, 0); - _plt0->addReferenceELF_AArch64(R_AARCH64_LD64_GOT_LO12_NC, 8, _got1, 0); - _plt0->addReferenceELF_AArch64(ADD_AARCH64_GOTRELINDEX, 12, _got1, 0); -#ifndef NDEBUG - _plt0->_name = "__PLT0"; - _got0->_name = "__got0"; - _got1->_name = "__got1"; -#endif - return _plt0; - } - - const PLTAtom *getPLTEntry(const Atom *a) { - auto plt = _pltMap.find(a); - if (plt != _pltMap.end()) - return plt->second; - auto ga = new (_file._alloc) AArch64GOTPLTAtom(_file); - ga->addReferenceELF_AArch64(R_AARCH64_JUMP_SLOT, 0, a, 0); - auto pa = new (_file._alloc) AArch64PLTAtom(_file); - pa->addReferenceELF_AArch64(R_AARCH64_ADR_GOT_PAGE, 0, ga, 0); - pa->addReferenceELF_AArch64(R_AARCH64_LD64_GOT_LO12_NC, 4, ga, 0); - pa->addReferenceELF_AArch64(ADD_AARCH64_GOTRELINDEX, 8, ga, 0); - pa->addReferenceELF_AArch64(R_AARCH64_NONE, 12, getPLT0(), 0); - // Set the starting address of the got entry to the first instruction in - // the plt0 entry. - ga->addReferenceELF_AArch64(R_AARCH64_ABS32, 0, getPLT0(), 0); -#ifndef NDEBUG - ga->_name = "__got_"; - ga->_name += a->name(); - pa->_name = "__plt_"; - pa->_name += a->name(); -#endif - _gotMap[a] = ga; - _pltMap[a] = pa; - _gotVector.push_back(ga); - _pltVector.push_back(pa); - return pa; - } - - const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a) { - auto obj = _objectMap.find(a); - if (obj != _objectMap.end()) - return obj->second; - - auto oa = new (_file._alloc) ObjectAtom(_file); - // This needs to point to the atom that we just created. - oa->addReferenceELF_AArch64(R_AARCH64_COPY, 0, oa, 0); - - oa->_name = a->name(); - oa->_size = a->size(); - - _objectMap[a] = oa; - _objectVector.push_back(oa); - return oa; - } - - std::error_code handlePlain(const Reference &ref) { - if (!ref.target()) - return std::error_code(); - if (auto sla = dyn_cast<SharedLibraryAtom>(ref.target())) { - if (sla->type() == SharedLibraryAtom::Type::Data) - const_cast<Reference &>(ref).setTarget(getObjectEntry(sla)); - else if (sla->type() == SharedLibraryAtom::Type::Code) - const_cast<Reference &>(ref).setTarget(getPLTEntry(sla)); - } else - return handleIFUNC(ref); - return std::error_code(); - } - - std::error_code handlePLT32(const Reference &ref) { - // Turn this into a PC32 to the PLT entry. - const_cast<Reference &>(ref).setKindValue(R_AARCH64_PREL32); - // Handle IFUNC. - if (const DefinedAtom *da = - dyn_cast_or_null<const DefinedAtom>(ref.target())) - if (da->contentType() == DefinedAtom::typeResolver) - return handleIFUNC(ref); - if (isa<const SharedLibraryAtom>(ref.target())) - const_cast<Reference &>(ref).setTarget(getPLTEntry(ref.target())); - return std::error_code(); - } - - const GOTAtom *getSharedGOT(const SharedLibraryAtom *sla) { - auto got = _gotMap.find(sla); - if (got == _gotMap.end()) { - auto g = new (_file._alloc) AArch64GOTAtom(_file); - g->addReferenceELF_AArch64(R_AARCH64_GLOB_DAT, 0, sla, 0); -#ifndef NDEBUG - g->_name = "__got_"; - g->_name += sla->name(); -#endif - _gotMap[sla] = g; - _gotVector.push_back(g); - return g; - } - return got->second; - } - - std::error_code handleGOT(const Reference &ref) { - if (isa<UndefinedAtom>(ref.target())) - const_cast<Reference &>(ref).setTarget(getNullGOT()); - else if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(ref.target())) - const_cast<Reference &>(ref).setTarget(getGOT(da)); - else if (const auto sla = dyn_cast<const SharedLibraryAtom>(ref.target())) - const_cast<Reference &>(ref).setTarget(getSharedGOT(sla)); - return std::error_code(); - } -}; -} // end anon namespace - -std::unique_ptr<Pass> -lld::elf::createAArch64RelocationPass(const AArch64LinkingContext &ctx) { - switch (ctx.getOutputELFType()) { - case llvm::ELF::ET_EXEC: - if (ctx.isDynamic()) - return llvm::make_unique<AArch64DynamicRelocationPass>(ctx); - return llvm::make_unique<AArch64StaticRelocationPass>(ctx); - case llvm::ELF::ET_DYN: - return llvm::make_unique<AArch64DynamicRelocationPass>(ctx); - case llvm::ELF::ET_REL: - return nullptr; - default: - llvm_unreachable("Unhandled output file type"); - } -} diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.h b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.h deleted file mode 100644 index 73d784e3b52d..000000000000 --- a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.h +++ /dev/null @@ -1,32 +0,0 @@ -//===- lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.h ---------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Declares the relocation processing pass for AArch64. This includes -/// GOT and PLT entries, TLS, COPY, and ifunc. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_AARCH64_AARCH64_RELOCATION_PASS_H -#define LLD_READER_WRITER_ELF_AARCH64_AARCH64_RELOCATION_PASS_H - -#include <memory> - -namespace lld { -class Pass; -namespace elf { -class AArch64LinkingContext; - -/// \brief Create AArch64 relocation pass for the given linking context. -std::unique_ptr<Pass> -createAArch64RelocationPass(const AArch64LinkingContext &); -} -} - -#endif diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.cpp deleted file mode 100644 index 2734bcdbda5f..000000000000 --- a/lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.cpp +++ /dev/null @@ -1,39 +0,0 @@ -//===- lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.cpp --------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "AArch64SectionChunks.h" -#include "TargetLayout.h" - -namespace lld { -namespace elf { - -AArch64GOTSection::AArch64GOTSection(const ELFLinkingContext &ctx, - StringRef name, int32_t order) - : AtomSection<ELF64LE>(ctx, name, DefinedAtom::typeGOT, DefinedAtom::permRW_, - order) { - _alignment = 8; -} - -const AtomLayout *AArch64GOTSection::appendAtom(const Atom *atom) { - const DefinedAtom *da = dyn_cast<DefinedAtom>(atom); - - for (const auto &r : *da) { - if (r->kindNamespace() != Reference::KindNamespace::ELF) - continue; - assert(r->kindArch() == Reference::KindArch::AArch64); - if ((r->kindValue() == R_AARCH64_TLS_TPREL64) || - (r->kindValue() == R_AARCH64_TLSDESC)) - _tlsMap[r->target()] = _tlsMap.size(); - } - - return AtomSection<ELF64LE>::appendAtom(atom); -} - -} // elf -} // lld diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.h b/lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.h deleted file mode 100644 index 2b7594c2db84..000000000000 --- a/lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.h +++ /dev/null @@ -1,37 +0,0 @@ -//===- lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.h ----------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_AARCH64_AARCH64_SECTION_CHUNKS_H -#define LLD_READER_WRITER_ELF_AARCH64_AARCH64_SECTION_CHUNKS_H - -#include "TargetLayout.h" - -namespace lld { -namespace elf { - -class AArch64GOTSection : public AtomSection<ELF64LE> { -public: - AArch64GOTSection(const ELFLinkingContext &ctx, StringRef name, - int32_t order); - - bool hasGlobalGOTEntry(const Atom *a) const { - return _tlsMap.count(a); - } - - const AtomLayout *appendAtom(const Atom *atom) override; - -private: - /// \brief Map TLS Atoms to their GOT entry index. - llvm::DenseMap<const Atom *, std::size_t> _tlsMap; -}; - -} // elf -} // lld - -#endif diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.cpp deleted file mode 100644 index 083b492c1607..000000000000 --- a/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.cpp +++ /dev/null @@ -1,51 +0,0 @@ -//===- lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.cpp --------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Atoms.h" -#include "AArch64DynamicLibraryWriter.h" -#include "AArch64ExecutableWriter.h" -#include "AArch64LinkingContext.h" -#include "AArch64TargetHandler.h" -#include "AArch64SectionChunks.h" - -using namespace lld; -using namespace elf; - -AArch64TargetLayout::AArch64TargetLayout(ELFLinkingContext &ctx) : - TargetLayout(ctx) {} - -AtomSection<ELF64LE> *AArch64TargetLayout::createSection( - StringRef name, int32_t type, DefinedAtom::ContentPermissions permissions, - TargetLayout<ELF64LE>::SectionOrder order) { - if (type == DefinedAtom::typeGOT && (name == ".got" || name == ".got.plt")) { - auto section = new (this->_allocator) AArch64GOTSection(this->_ctx, name, - order); - _gotSections.push_back(section); - return section; - } - return TargetLayout<ELF64LE>::createSection(name, type, permissions, order); -} - - -AArch64TargetHandler::AArch64TargetHandler(AArch64LinkingContext &ctx) - : _ctx(ctx), _targetLayout(new AArch64TargetLayout(ctx)), - _relocationHandler(new AArch64TargetRelocationHandler(*_targetLayout)) {} - -std::unique_ptr<Writer> AArch64TargetHandler::getWriter() { - switch (this->_ctx.getOutputELFType()) { - case llvm::ELF::ET_EXEC: - return llvm::make_unique<AArch64ExecutableWriter>(_ctx, *_targetLayout); - case llvm::ELF::ET_DYN: - return llvm::make_unique<AArch64DynamicLibraryWriter>(_ctx, *_targetLayout); - case llvm::ELF::ET_REL: - llvm_unreachable("TODO: support -r mode"); - default: - llvm_unreachable("unsupported output type"); - } -} diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h b/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h deleted file mode 100644 index c0ecbfa9e44b..000000000000 --- a/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h +++ /dev/null @@ -1,90 +0,0 @@ -//===- lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h ----------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_AARCH64_AARCH64_TARGET_HANDLER_H -#define LLD_READER_WRITER_ELF_AARCH64_AARCH64_TARGET_HANDLER_H - -#include "AArch64RelocationHandler.h" -#include "ELFReader.h" -#include "TargetLayout.h" -#include "lld/Core/Simple.h" - -namespace lld { -namespace elf { - -class AArch64LinkingContext; -class AArch64GOTSection; - -class AArch64TargetLayout final : public TargetLayout<ELF64LE> { - typedef llvm::object::Elf_Shdr_Impl<ELF64LE> Elf_Shdr; - -public: - AArch64TargetLayout(ELFLinkingContext &ctx); - - AtomSection<ELF64LE> * - createSection(StringRef name, int32_t type, - DefinedAtom::ContentPermissions permissions, - TargetLayout<ELF64LE>::SectionOrder order) override; - - const std::vector<AArch64GOTSection *> &getGOTSections() const { - return _gotSections; - } - - uint64_t getTPOffset() { - std::call_once(_tpOffOnce, [this]() { - for (const auto &phdr : *_programHeader) { - if (phdr->p_type == llvm::ELF::PT_TLS) { - _tpOff = llvm::RoundUpToAlignment(TCB_SIZE, phdr->p_align); - break; - } - } - assert(_tpOff != 0 && "TLS segment not found"); - }); - return _tpOff; - } - -private: - enum { - TCB_SIZE = 16, - }; - -private: - std::vector<AArch64GOTSection *> _gotSections; - uint64_t _tpOff = 0; - std::once_flag _tpOffOnce; -}; - -class AArch64TargetHandler final : public TargetHandler { -public: - AArch64TargetHandler(AArch64LinkingContext &ctx); - - const TargetRelocationHandler &getRelocationHandler() const override { - return *_relocationHandler; - } - - std::unique_ptr<Reader> getObjReader() override { - return llvm::make_unique<ELFReader<ELFFile<ELF64LE>>>(_ctx); - } - - std::unique_ptr<Reader> getDSOReader() override { - return llvm::make_unique<ELFReader<DynamicFile<ELF64LE>>>(_ctx); - } - - std::unique_ptr<Writer> getWriter() override; - -private: - AArch64LinkingContext &_ctx; - std::unique_ptr<AArch64TargetLayout> _targetLayout; - std::unique_ptr<AArch64TargetRelocationHandler> _relocationHandler; -}; - -} // end namespace elf -} // end namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/AArch64/CMakeLists.txt b/lib/ReaderWriter/ELF/AArch64/CMakeLists.txt deleted file mode 100644 index aae6420008a4..000000000000 --- a/lib/ReaderWriter/ELF/AArch64/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -add_lld_library(lldAArch64ELFTarget - AArch64LinkingContext.cpp - AArch64TargetHandler.cpp - AArch64RelocationHandler.cpp - AArch64RelocationPass.cpp - AArch64ExecutableWriter.cpp - AArch64SectionChunks.cpp - LINK_LIBS - lldELF - lldReaderWriter - lldCore - LLVMObject - LLVMSupport - ) diff --git a/lib/ReaderWriter/ELF/AArch64/TODO.rst b/lib/ReaderWriter/ELF/AArch64/TODO.rst deleted file mode 100644 index aa6f616ff33f..000000000000 --- a/lib/ReaderWriter/ELF/AArch64/TODO.rst +++ /dev/null @@ -1,15 +0,0 @@ -ELF AArch64 -~~~~~~~~~~~ - -Unimplemented Features -###################### - -* Just about everything! - -Unimplemented Relocations -######################### - -All of these relocations are defined in: -http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf - - diff --git a/lib/ReaderWriter/ELF/ARM/ARMDynamicLibraryWriter.h b/lib/ReaderWriter/ELF/ARM/ARMDynamicLibraryWriter.h deleted file mode 100644 index da843b97abc0..000000000000 --- a/lib/ReaderWriter/ELF/ARM/ARMDynamicLibraryWriter.h +++ /dev/null @@ -1,49 +0,0 @@ -//===- lib/ReaderWriter/ELF/ARM/ARMDynamicLibraryWriter.h -----------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef LLD_READER_WRITER_ELF_ARM_ARM_DYNAMIC_LIBRARY_WRITER_H -#define LLD_READER_WRITER_ELF_ARM_ARM_DYNAMIC_LIBRARY_WRITER_H - -#include "DynamicLibraryWriter.h" -#include "ARMELFWriters.h" -#include "ARMLinkingContext.h" -#include "ARMTargetHandler.h" - -namespace lld { -namespace elf { - -class ARMDynamicLibraryWriter - : public ARMELFWriter<DynamicLibraryWriter<ELF32LE>> { -public: - ARMDynamicLibraryWriter(ARMLinkingContext &ctx, ARMTargetLayout &layout); - -protected: - // Add any runtime files and their atoms to the output - void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override; - -private: - ARMLinkingContext &_ctx; -}; - -ARMDynamicLibraryWriter::ARMDynamicLibraryWriter(ARMLinkingContext &ctx, - ARMTargetLayout &layout) - : ARMELFWriter(ctx, layout), _ctx(ctx) {} - -void ARMDynamicLibraryWriter::createImplicitFiles( - std::vector<std::unique_ptr<File>> &result) { - DynamicLibraryWriter::createImplicitFiles(result); - auto file = llvm::make_unique<RuntimeFile<ELF32LE>>(_ctx, "ARM dynamic file"); - file->addAbsoluteAtom(gotSymbol); - file->addAbsoluteAtom(dynamicSymbol); - result.push_back(std::move(file)); -} - -} // namespace elf -} // namespace lld - -#endif // LLD_READER_WRITER_ELF_ARM_ARM_DYNAMIC_LIBRARY_WRITER_H diff --git a/lib/ReaderWriter/ELF/ARM/ARMELFFile.h b/lib/ReaderWriter/ELF/ARM/ARMELFFile.h deleted file mode 100644 index 8f5477017e55..000000000000 --- a/lib/ReaderWriter/ELF/ARM/ARMELFFile.h +++ /dev/null @@ -1,154 +0,0 @@ -//===--------- lib/ReaderWriter/ELF/ARM/ARMELFFile.h ----------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_ARM_ARM_ELF_FILE_H -#define LLD_READER_WRITER_ELF_ARM_ARM_ELF_FILE_H - -#include "ELFReader.h" - -namespace lld { -namespace elf { - -class ARMLinkingContext; - -class ARMELFBaseDefinedAtom : public ELFDefinedAtom<ELF32LE> { -public: - /// The values of custom content type enum must not interfere - /// with ones in base defined atom class' enum. - enum ARMContentType { - typeARMExidx = 0x1000, // Identifies ARM_EXIDX section - }; - - template <typename... T> - ARMELFBaseDefinedAtom(T &&... args) - : ELFDefinedAtom<ELF32LE>(std::forward<T>(args)...) {} - - DefinedAtom::ContentPermissions permissions() const override { - if (_permissions != DefinedAtom::permUnknown) - return _permissions; - - switch (_section->sh_type) { - case llvm::ELF::SHT_ARM_EXIDX: - return _permissions = permR__; - } - return ELFDefinedAtom::permissions(); - } - - DefinedAtom::ContentType contentType() const override { - if (_contentType != DefinedAtom::typeUnknown) - return _contentType; - - switch (_section->sh_type) { - case llvm::ELF::SHT_ARM_EXIDX: - return _contentType = (DefinedAtom::ContentType)typeARMExidx; - } - return ELFDefinedAtom::contentType(); - } -}; - -class ARMELFMappingAtom : public ARMELFBaseDefinedAtom { -public: - template <typename... T> - ARMELFMappingAtom(DefinedAtom::CodeModel model, T &&... args) - : ARMELFBaseDefinedAtom(std::forward<T>(args)...), _model(model) {} - - DefinedAtom::CodeModel codeModel() const override { return _model; } - -private: - DefinedAtom::CodeModel _model; -}; - -class ARMELFDefinedAtom : public ARMELFBaseDefinedAtom { -public: - template <typename... T> - ARMELFDefinedAtom(T &&... args) - : ARMELFBaseDefinedAtom(std::forward<T>(args)...) {} - - bool isThumbFunc() const { - const auto *symbol = _symbol; - return symbol->getType() == llvm::ELF::STT_FUNC && - (static_cast<uint64_t>(symbol->st_value) & 0x1); - } - - /// Correct st_value for symbols addressing Thumb instructions - /// by removing its zero bit. - uint64_t getSymbolValue() const override { - const auto value = static_cast<uint64_t>(_symbol->st_value); - return isThumbFunc() ? value & ~0x1 : value; - } - - DefinedAtom::CodeModel codeModel() const override { - return isThumbFunc() ? DefinedAtom::codeARMThumb : DefinedAtom::codeNA; - } -}; - -class ARMELFFile : public ELFFile<ELF32LE> { - typedef llvm::object::Elf_Rel_Impl<ELF32LE, false> Elf_Rel; - -public: - ARMELFFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx) - : ELFFile(std::move(mb), ctx) {} - -protected: - /// Returns initial addend; for ARM it is 0, because it is read - /// during the relocations applying - Reference::Addend getInitialAddend(ArrayRef<uint8_t>, uint64_t, - const Elf_Rel &) const override { - return 0; - } - -private: - typedef llvm::object::Elf_Sym_Impl<ELF32LE> Elf_Sym; - typedef llvm::object::Elf_Shdr_Impl<ELF32LE> Elf_Shdr; - - /// Correct st_value for symbols addressing Thumb instructions - /// by removing its zero bit. - uint64_t getSymbolValue(const Elf_Sym *symbol) const override { - const auto value = static_cast<uint64_t>(symbol->st_value); - return symbol->getType() == llvm::ELF::STT_FUNC ? value & ~0x1 : value; - } - - /// Process the Defined symbol and create an atom for it. - ELFDefinedAtom<ELF32LE> *createDefinedAtom( - StringRef symName, StringRef sectionName, const Elf_Sym *sym, - const Elf_Shdr *sectionHdr, ArrayRef<uint8_t> contentData, - unsigned int referenceStart, unsigned int referenceEnd, - std::vector<ELFReference<ELF32LE> *> &referenceList) override { - if (symName.size() >= 2 && symName[0] == '$') { - switch (symName[1]) { - case 'a': - return new (_readerStorage) - ARMELFMappingAtom(DefinedAtom::codeARM_a, *this, symName, - sectionName, sym, sectionHdr, contentData, - referenceStart, referenceEnd, referenceList); - case 'd': - return new (_readerStorage) - ARMELFMappingAtom(DefinedAtom::codeARM_d, *this, symName, - sectionName, sym, sectionHdr, contentData, - referenceStart, referenceEnd, referenceList); - case 't': - return new (_readerStorage) - ARMELFMappingAtom(DefinedAtom::codeARM_t, *this, symName, - sectionName, sym, sectionHdr, contentData, - referenceStart, referenceEnd, referenceList); - default: - // Fall through and create regular defined atom. - break; - } - } - return new (_readerStorage) ARMELFDefinedAtom( - *this, symName, sectionName, sym, sectionHdr, contentData, - referenceStart, referenceEnd, referenceList); - } -}; - -} // elf -} // lld - -#endif // LLD_READER_WRITER_ELF_ARM_ARM_ELF_FILE_H diff --git a/lib/ReaderWriter/ELF/ARM/ARMELFWriters.h b/lib/ReaderWriter/ELF/ARM/ARMELFWriters.h deleted file mode 100644 index a842ebe53038..000000000000 --- a/lib/ReaderWriter/ELF/ARM/ARMELFWriters.h +++ /dev/null @@ -1,120 +0,0 @@ -//===- lib/ReaderWriter/ELF/ARM/ARMELFWriters.h ---------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef LLD_READER_WRITER_ELF_ARM_ARM_ELF_WRITERS_H -#define LLD_READER_WRITER_ELF_ARM_ARM_ELF_WRITERS_H - -#include "ARMLinkingContext.h" -#include "ARMSymbolTable.h" -#include "llvm/Support/ELF.h" - -namespace lld { -namespace elf { - -template <class WriterT> class ARMELFWriter : public WriterT { -public: - ARMELFWriter(ARMLinkingContext &ctx, TargetLayout<ELF32LE> &layout); - - void finalizeDefaultAtomValues() override; - - /// \brief Create symbol table. - unique_bump_ptr<SymbolTable<ELF32LE>> createSymbolTable() override; - - // Setup the ELF header. - std::error_code setELFHeader() override; - -protected: - static const char *gotSymbol; - static const char *dynamicSymbol; - -private: - ARMLinkingContext &_ctx; - TargetLayout<ELF32LE> &_armLayout; -}; - -template <class WriterT> -const char *ARMELFWriter<WriterT>::gotSymbol = "_GLOBAL_OFFSET_TABLE_"; -template <class WriterT> -const char *ARMELFWriter<WriterT>::dynamicSymbol = "_DYNAMIC"; - -template <class WriterT> -ARMELFWriter<WriterT>::ARMELFWriter(ARMLinkingContext &ctx, - TargetLayout<ELF32LE> &layout) - : WriterT(ctx, layout), _ctx(ctx), _armLayout(layout) {} - -template <class WriterT> -void ARMELFWriter<WriterT>::finalizeDefaultAtomValues() { - // Finalize the atom values that are part of the parent. - WriterT::finalizeDefaultAtomValues(); - - if (auto *gotAtom = _armLayout.findAbsoluteAtom(gotSymbol)) { - if (auto gotpltSection = _armLayout.findOutputSection(".got.plt")) - gotAtom->_virtualAddr = gotpltSection->virtualAddr(); - else if (auto gotSection = _armLayout.findOutputSection(".got")) - gotAtom->_virtualAddr = gotSection->virtualAddr(); - else - gotAtom->_virtualAddr = 0; - } - - if (auto *dynamicAtom = _armLayout.findAbsoluteAtom(dynamicSymbol)) { - if (auto dynamicSection = _armLayout.findOutputSection(".dynamic")) - dynamicAtom->_virtualAddr = dynamicSection->virtualAddr(); - else - dynamicAtom->_virtualAddr = 0; - } - - // Set required by gcc libc __ehdr_start symbol with pointer to ELF header - if (auto ehdr = _armLayout.findAbsoluteAtom("__ehdr_start")) - ehdr->_virtualAddr = this->_elfHeader->virtualAddr(); - - // Set required by gcc libc symbols __exidx_start/__exidx_end - this->updateScopeAtomValues("exidx", ".ARM.exidx"); -} - -template <class WriterT> -unique_bump_ptr<SymbolTable<ELF32LE>> -ARMELFWriter<WriterT>::createSymbolTable() { - return unique_bump_ptr<SymbolTable<ELF32LE>>(new (this->_alloc) - ARMSymbolTable(_ctx)); -} - -template <class WriterT> std::error_code ARMELFWriter<WriterT>::setELFHeader() { - if (std::error_code ec = WriterT::setELFHeader()) - return ec; - - // Set ARM-specific flags. - this->_elfHeader->e_flags(llvm::ELF::EF_ARM_EABI_VER5 | - llvm::ELF::EF_ARM_VFP_FLOAT); - - StringRef entryName = _ctx.entrySymbolName(); - if (const AtomLayout *al = _armLayout.findAtomLayoutByName(entryName)) { - if (const auto *ea = dyn_cast<DefinedAtom>(al->_atom)) { - switch (ea->codeModel()) { - case DefinedAtom::codeNA: - if (al->_virtualAddr & 0x3) { - llvm::report_fatal_error( - "Two least bits must be zero for ARM entry point"); - } - break; - case DefinedAtom::codeARMThumb: - // Fixup entry point for Thumb code. - this->_elfHeader->e_entry(al->_virtualAddr | 0x1); - break; - default: - llvm_unreachable("Wrong code model of entry point atom"); - } - } - } - - return std::error_code(); -} - -} // namespace elf -} // namespace lld - -#endif // LLD_READER_WRITER_ELF_ARM_ARM_ELF_WRITERS_H diff --git a/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h b/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h deleted file mode 100644 index 974dab63a126..000000000000 --- a/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h +++ /dev/null @@ -1,68 +0,0 @@ -//===--------- lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h -------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef LLD_READER_WRITER_ELF_ARM_ARM_EXECUTABLE_WRITER_H -#define LLD_READER_WRITER_ELF_ARM_ARM_EXECUTABLE_WRITER_H - -#include "ExecutableWriter.h" -#include "ARMELFWriters.h" -#include "ARMLinkingContext.h" -#include "ARMTargetHandler.h" - -namespace lld { -namespace elf { - -class ARMExecutableWriter : public ARMELFWriter<ExecutableWriter<ELF32LE>> { -public: - ARMExecutableWriter(ARMLinkingContext &ctx, ARMTargetLayout &layout); - -protected: - // Add any runtime files and their atoms to the output - void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override; - - void processUndefinedSymbol(StringRef symName, - RuntimeFile<ELF32LE> &file) const override; - -private: - ARMLinkingContext &_ctx; -}; - -ARMExecutableWriter::ARMExecutableWriter(ARMLinkingContext &ctx, - ARMTargetLayout &layout) - : ARMELFWriter(ctx, layout), _ctx(ctx) {} - -void ARMExecutableWriter::createImplicitFiles( - std::vector<std::unique_ptr<File>> &result) { - ExecutableWriter::createImplicitFiles(result); - // Add default atoms for ARM. - if (_ctx.isDynamic()) { - auto file = llvm::make_unique<RuntimeFile<ELF32LE>>(_ctx, "ARM exec file"); - file->addAbsoluteAtom(gotSymbol); - file->addAbsoluteAtom(dynamicSymbol); - result.push_back(std::move(file)); - } -} - -void ARMExecutableWriter::processUndefinedSymbol( - StringRef symName, RuntimeFile<ELF32LE> &file) const { - ARMELFWriter<ExecutableWriter<ELF32LE>>::processUndefinedSymbol(symName, - file); - if (symName == gotSymbol) { - file.addAbsoluteAtom(gotSymbol); - } else if (symName.startswith("__exidx")) { - file.addAbsoluteAtom("__exidx_start"); - file.addAbsoluteAtom("__exidx_end"); - } else if (symName == "__ehdr_start") { - file.addAbsoluteAtom("__ehdr_start"); - } -} - -} // namespace elf -} // namespace lld - -#endif // LLD_READER_WRITER_ELF_ARM_ARM_EXECUTABLE_WRITER_H diff --git a/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp b/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp deleted file mode 100644 index 74905b47820f..000000000000 --- a/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp +++ /dev/null @@ -1,64 +0,0 @@ -//===--------- lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp -------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "ARMLinkingContext.h" -#include "ARMRelocationPass.h" -#include "ARMTargetHandler.h" - -namespace lld { -namespace elf { - -std::unique_ptr<ELFLinkingContext> -createARMLinkingContext(llvm::Triple triple) { - if (triple.getArch() == llvm::Triple::arm) - return llvm::make_unique<ARMLinkingContext>(triple); - return nullptr; -} - -ARMLinkingContext::ARMLinkingContext(llvm::Triple triple) - : ELFLinkingContext(triple, llvm::make_unique<ARMTargetHandler>(*this)) {} - -void ARMLinkingContext::addPasses(PassManager &pm) { - auto pass = createARMRelocationPass(*this); - if (pass) - pm.add(std::move(pass)); - ELFLinkingContext::addPasses(pm); -} - -bool isARMCode(const DefinedAtom *atom) { - return isARMCode(atom->codeModel()); -} - -bool isARMCode(DefinedAtom::CodeModel codeModel) { - return !isThumbCode(codeModel); -} - -bool isThumbCode(const DefinedAtom *atom) { - return isThumbCode(atom->codeModel()); -} - -bool isThumbCode(DefinedAtom::CodeModel codeModel) { - return codeModel == DefinedAtom::codeARMThumb || - codeModel == DefinedAtom::codeARM_t; -} - -static const Registry::KindStrings kindStrings[] = { -#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name), -#include "llvm/Support/ELFRelocs/ARM.def" -#undef ELF_RELOC - LLD_KIND_STRING_END -}; - -void ARMLinkingContext::registerRelocationNames(Registry ®istry) { - registry.addKindTable(Reference::KindNamespace::ELF, Reference::KindArch::ARM, - kindStrings); -} - -} // namespace elf -} // namespace lld diff --git a/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h b/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h deleted file mode 100644 index f687713b25b8..000000000000 --- a/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h +++ /dev/null @@ -1,80 +0,0 @@ -//===--------- lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h ---------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_ARM_ARM_LINKING_CONTEXT_H -#define LLD_READER_WRITER_ELF_ARM_ARM_LINKING_CONTEXT_H - -#include "lld/ReaderWriter/ELFLinkingContext.h" -#include "llvm/Object/ELF.h" -#include "llvm/Support/ELF.h" - -namespace lld { -namespace elf { - -class ARMLinkingContext final : public ELFLinkingContext { -public: - int getMachineType() const override { return llvm::ELF::EM_ARM; } - ARMLinkingContext(llvm::Triple); - - void addPasses(PassManager &) override; - void registerRelocationNames(Registry &r) override; - - bool isRelaOutputFormat() const override { return false; } - - uint64_t getBaseAddress() const override { - if (_baseAddress == 0) - return 0x400000; - return _baseAddress; - } - - bool isDynamicRelocation(const Reference &r) const override { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - assert(r.kindArch() == Reference::KindArch::ARM); - switch (r.kindValue()) { - case llvm::ELF::R_ARM_GLOB_DAT: - case llvm::ELF::R_ARM_TLS_TPOFF32: - case llvm::ELF::R_ARM_COPY: - return true; - default: - return false; - } - } - - bool isCopyRelocation(const Reference &r) const override { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - assert(r.kindArch() == Reference::KindArch::ARM); - return r.kindValue() == llvm::ELF::R_ARM_COPY; - } - - bool isPLTRelocation(const Reference &r) const override { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - assert(r.kindArch() == Reference::KindArch::ARM); - switch (r.kindValue()) { - case llvm::ELF::R_ARM_JUMP_SLOT: - case llvm::ELF::R_ARM_IRELATIVE: - return true; - default: - return false; - } - } -}; - -// Special methods to check code model of atoms. -bool isARMCode(const DefinedAtom *atom); -bool isARMCode(DefinedAtom::CodeModel codeModel); -bool isThumbCode(const DefinedAtom *atom); -bool isThumbCode(DefinedAtom::CodeModel codeModel); - -} // end namespace elf -} // end namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp b/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp deleted file mode 100644 index 97b149133ff2..000000000000 --- a/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp +++ /dev/null @@ -1,680 +0,0 @@ -//===--------- lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp ----------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "ARMTargetHandler.h" -#include "ARMLinkingContext.h" - -#include "llvm/Support/Debug.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/MathExtras.h" - -#define DEBUG_TYPE "ARM" - -using namespace lld; -using namespace lld::elf; -using namespace llvm::support::endian; - -static Reference::Addend readAddend_THM_MOV(const uint8_t *location) { - const uint16_t halfHi = read16le(location); - const uint16_t halfLo = read16le(location + 2); - - const uint16_t imm8 = halfLo & 0xFF; - const uint16_t imm3 = (halfLo >> 12) & 0x7; - - const uint16_t imm4 = halfHi & 0xF; - const uint16_t bitI = (halfHi >> 10) & 0x1; - - const auto result = int16_t((imm4 << 12) | (bitI << 11) | (imm3 << 8) | imm8); - return result; -} - -static Reference::Addend readAddend_ARM_MOV(const uint8_t *location) { - const uint32_t value = read32le(location); - - const uint32_t imm12 = value & 0xFFF; - const uint32_t imm4 = (value >> 16) & 0xF; - - const auto result = int32_t((imm4 << 12) | imm12); - return result; -} - -static Reference::Addend readAddend_THM_CALL(const uint8_t *location) { - const uint16_t halfHi = read16le(location); - const uint16_t halfLo = read16le(location + 2); - - const uint16_t imm10 = halfHi & 0x3FF; - const uint16_t bitS = (halfHi >> 10) & 0x1; - - const uint16_t imm11 = halfLo & 0x7FF; - const uint16_t bitJ2 = (halfLo >> 11) & 0x1; - const uint16_t bitI2 = (~(bitJ2 ^ bitS)) & 0x1; - const uint16_t bitJ1 = (halfLo >> 13) & 0x1; - const uint16_t bitI1 = (~(bitJ1 ^ bitS)) & 0x1; - - const auto result = int32_t((bitS << 24) | (bitI1 << 23) | (bitI2 << 22) | - (imm10 << 12) | (imm11 << 1)); - return llvm::SignExtend64<25>(result); -} - -static Reference::Addend readAddend_ARM_CALL(const uint8_t *location) { - const uint32_t value = read32le(location); - - const bool isBLX = (value & 0xF0000000) == 0xF0000000; - const uint32_t bitH = isBLX ? ((value & 0x1000000) >> 24) : 0; - - const auto result = int32_t(((value & 0xFFFFFF) << 2) | (bitH << 1)); - return llvm::SignExtend64<26>(result); -} - -static Reference::Addend readAddend_THM_JUMP11(const uint8_t *location) { - const auto value = read16le(location); - const uint16_t imm11 = value & 0x7FF; - - return llvm::SignExtend64<12>(imm11 << 1); -} - -static Reference::Addend readAddend(const uint8_t *location, - Reference::KindValue kindValue) { - switch (kindValue) { - case R_ARM_ABS32: - case R_ARM_REL32: - case R_ARM_TARGET1: - case R_ARM_GOT_BREL: - case R_ARM_BASE_PREL: - case R_ARM_TLS_IE32: - case R_ARM_TLS_LE32: - case R_ARM_TLS_TPOFF32: - return (int32_t)read32le(location); - case R_ARM_PREL31: - return llvm::SignExtend64<31>(read32le(location) & 0x7FFFFFFF); - case R_ARM_THM_CALL: - case R_ARM_THM_JUMP24: - return readAddend_THM_CALL(location); - case R_ARM_THM_JUMP11: - return readAddend_THM_JUMP11(location); - case R_ARM_CALL: - case R_ARM_JUMP24: - return readAddend_ARM_CALL(location); - case R_ARM_MOVW_ABS_NC: - case R_ARM_MOVT_ABS: - return readAddend_ARM_MOV(location); - case R_ARM_THM_MOVW_ABS_NC: - case R_ARM_THM_MOVT_ABS: - return readAddend_THM_MOV(location); - default: - return 0; - } -} - -static inline void report_unsupported_range_group_reloc_error() { - llvm::report_fatal_error( - "Negative offsets for group relocations are not implemented"); -} - -static inline std::error_code applyArmReloc(uint8_t *location, uint32_t result, - uint32_t mask = 0xFFFFFFFF) { - assert(!(result & ~mask)); - write32le(location, (read32le(location) & ~mask) | (result & mask)); - return std::error_code(); -} - -static inline std::error_code applyThumb32Reloc(uint8_t *location, - uint16_t resHi, uint16_t resLo, - uint16_t maskHi, - uint16_t maskLo = 0xFFFF) { - assert(!(resHi & ~maskHi) && !(resLo & ~maskLo)); - write16le(location, (read16le(location) & ~maskHi) | (resHi & maskHi)); - location += 2; - write16le(location, (read16le(location) & ~maskLo) | (resLo & maskLo)); - return std::error_code(); -} - -static inline std::error_code -applyThumb16Reloc(uint8_t *location, uint16_t result, uint16_t mask = 0xFFFF) { - assert(!(result & ~mask)); - write16le(location, (read16le(location) & ~mask) | (result & mask)); - return std::error_code(); -} - -/// \brief R_ARM_ABS32 - (S + A) | T -static std::error_code relocR_ARM_ABS32(uint8_t *location, uint64_t P, - uint64_t S, int64_t A, - bool addressesThumb) { - uint64_t T = addressesThumb; - uint32_t result = (uint32_t)((S + A) | T); - - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " T: 0x" << Twine::utohexstr(T); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - return applyArmReloc(location, result); -} - -/// \brief R_ARM_REL32 - ((S + A) | T) - P -static std::error_code relocR_ARM_REL32(uint8_t *location, uint64_t P, - uint64_t S, int64_t A, - bool addressesThumb) { - uint64_t T = addressesThumb; - uint32_t result = (uint32_t)(((S + A) | T) - P); - - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " T: 0x" << Twine::utohexstr(T); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - return applyArmReloc(location, result); -} - -/// \brief R_ARM_PREL31 - ((S + A) | T) - P -static std::error_code relocR_ARM_PREL31(uint8_t *location, uint64_t P, - uint64_t S, int64_t A, - bool addressesThumb) { - uint64_t T = addressesThumb; - uint32_t result = (uint32_t)(((S + A) | T) - P); - if (!llvm::isInt<31>((int32_t)result)) - return make_out_of_range_reloc_error(); - - const uint32_t mask = 0x7FFFFFFF; - uint32_t rel31 = result & mask; - - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " T: 0x" << Twine::utohexstr(T); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result); - llvm::dbgs() << " rel31: 0x" << Twine::utohexstr(rel31) << "\n"); - - return applyArmReloc(location, rel31, mask); -} - -/// \brief Relocate B/BL instructions. useJs defines whether J1 & J2 are used -static std::error_code relocR_ARM_THM_B_L(uint8_t *location, uint32_t result, - bool useJs) { - if ((useJs && !llvm::isInt<25>((int32_t)result)) || - (!useJs && !llvm::isInt<23>((int32_t)result))) - return make_out_of_range_reloc_error(); - - result = (result & 0x01FFFFFE) >> 1; - - const uint16_t imm10 = (result >> 11) & 0x3FF; - const uint16_t bitS = (result >> 23) & 0x1; - const uint16_t resHi = (bitS << 10) | imm10; - - const uint16_t imm11 = result & 0x7FF; - const uint16_t bitJ2 = useJs ? ((result >> 21) & 0x1) : bitS; - const uint16_t bitI2 = (~(bitJ2 ^ bitS)) & 0x1; - const uint16_t bitJ1 = useJs ? ((result >> 22) & 0x1) : bitS; - const uint16_t bitI1 = (~(bitJ1 ^ bitS)) & 0x1; - const uint16_t resLo = (bitI1 << 13) | (bitI2 << 11) | imm11; - - return applyThumb32Reloc(location, resHi, resLo, 0x7FF, 0x2FFF); -} - -/// \brief R_ARM_THM_CALL - ((S + A) | T) - P -static std::error_code relocR_ARM_THM_CALL(uint8_t *location, uint64_t P, - uint64_t S, int64_t A, bool useJs, - bool addressesThumb) { - uint64_t T = addressesThumb; - const bool switchMode = !addressesThumb; - - if (switchMode) { - P &= ~0x3; // Align(P, 4) by rounding down - } - - uint32_t result = (uint32_t)(((S + A) | T) - P); - - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " T: 0x" << Twine::utohexstr(T); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - if (auto ec = relocR_ARM_THM_B_L(location, result, useJs)) - return ec; - - if (switchMode) { - return applyThumb32Reloc(location, 0, 0, 0, 0x1001); - } - return std::error_code(); -} - -/// \brief R_ARM_THM_JUMP24 - ((S + A) | T) - P -static std::error_code relocR_ARM_THM_JUMP24(uint8_t *location, uint64_t P, - uint64_t S, int64_t A, - bool addressesThumb) { - uint64_t T = addressesThumb; - uint32_t result = (uint32_t)(((S + A) | T) - P); - - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " T: 0x" << Twine::utohexstr(T); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - return relocR_ARM_THM_B_L(location, result, true); -} - -/// \brief R_ARM_THM_JUMP11 - S + A - P -static std::error_code relocR_ARM_THM_JUMP11(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - uint32_t result = (uint32_t)(S + A - P); - - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - - if (!llvm::isInt<12>((int32_t)result)) - return make_out_of_range_reloc_error(); - - // we cut off first bit because it is always 1 according to p. 4.5.3 - result = (result & 0x0FFE) >> 1; - return applyThumb16Reloc(location, result, 0x7FF); -} - -/// \brief R_ARM_BASE_PREL - B(S) + A - P => S + A - P -static std::error_code relocR_ARM_BASE_PREL(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - uint32_t result = (uint32_t)(S + A - P); - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - return applyArmReloc(location, result); -} - -/// \brief R_ARM_GOT_BREL - GOT(S) + A - GOT_ORG => S + A - GOT_ORG -static std::error_code relocR_ARM_GOT_BREL(uint8_t *location, uint64_t P, - uint64_t S, int64_t A, - uint64_t GOT_ORG) { - uint32_t result = (uint32_t)(S + A - GOT_ORG); - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - return applyArmReloc(location, result); -} - -/// \brief R_ARM_CALL - ((S + A) | T) - P -static std::error_code relocR_ARM_CALL(uint8_t *location, uint64_t P, - uint64_t S, int64_t A, - bool addressesThumb) { - uint64_t T = addressesThumb; - const bool switchMode = addressesThumb; - - uint32_t result = (uint32_t)(((S + A) | T) - P); - if (!llvm::isInt<26>((int32_t)result)) - return make_out_of_range_reloc_error(); - - const uint32_t imm24 = (result & 0x03FFFFFC) >> 2; - - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " T: 0x" << Twine::utohexstr(T); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - if (auto ec = applyArmReloc(location, imm24, 0xFFFFFF)) - return ec; - - if (switchMode) { - const uint32_t bitH = (result & 0x2) >> 1; - return applyArmReloc(location, (0xFA | bitH) << 24, 0xFF000000); - } - return std::error_code(); -} - -/// \brief R_ARM_JUMP24 - ((S + A) | T) - P -static std::error_code relocR_ARM_JUMP24(uint8_t *location, uint64_t P, - uint64_t S, int64_t A, - bool addressesThumb) { - uint64_t T = addressesThumb; - uint32_t result = (uint32_t)(((S + A) | T) - P); - if (!llvm::isInt<26>((int32_t)result)) - return make_out_of_range_reloc_error(); - - const uint32_t imm24 = (result & 0x03FFFFFC) >> 2; - - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " T: 0x" << Twine::utohexstr(T); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - return applyArmReloc(location, imm24, 0xFFFFFF); -} - -/// \brief Relocate ARM MOVW/MOVT instructions -static std::error_code relocR_ARM_MOV(uint8_t *location, uint32_t result) { - const uint32_t imm12 = result & 0xFFF; - const uint32_t imm4 = (result >> 12) & 0xF; - - return applyArmReloc(location, (imm4 << 16) | imm12, 0xF0FFF); -} - -/// \brief R_ARM_MOVW_ABS_NC - (S + A) | T -static std::error_code relocR_ARM_MOVW_ABS_NC(uint8_t *location, uint64_t P, - uint64_t S, int64_t A, - bool addressesThumb) { - uint64_t T = addressesThumb; - uint32_t result = (uint32_t)((S + A) | T); - const uint32_t arg = result & 0x0000FFFF; - - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " T: 0x" << Twine::utohexstr(T); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - return relocR_ARM_MOV(location, arg); -} - -/// \brief R_ARM_MOVT_ABS - S + A -static std::error_code relocR_ARM_MOVT_ABS(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - uint32_t result = (uint32_t)(S + A); - const uint32_t arg = (result & 0xFFFF0000) >> 16; - - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - return relocR_ARM_MOV(location, arg); -} - -/// \brief Relocate Thumb MOVW/MOVT instructions -static std::error_code relocR_ARM_THM_MOV(uint8_t *location, uint32_t result) { - const uint16_t imm8 = result & 0xFF; - const uint16_t imm3 = (result >> 8) & 0x7; - const uint16_t resLo = (imm3 << 12) | imm8; - - const uint16_t imm4 = (result >> 12) & 0xF; - const uint16_t bitI = (result >> 11) & 0x1; - const uint16_t resHi = (bitI << 10) | imm4; - - return applyThumb32Reloc(location, resHi, resLo, 0x40F, 0x70FF); -} - -/// \brief R_ARM_THM_MOVW_ABS_NC - (S + A) | T -static std::error_code relocR_ARM_THM_MOVW_ABS_NC(uint8_t *location, uint64_t P, - uint64_t S, int64_t A, - bool addressesThumb) { - uint64_t T = addressesThumb; - uint32_t result = (uint32_t)((S + A) | T); - const uint32_t arg = result & 0x0000FFFF; - - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " T: 0x" << Twine::utohexstr(T); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - return relocR_ARM_THM_MOV(location, arg); -} - -/// \brief R_ARM_THM_MOVT_ABS - S + A -static std::error_code relocR_ARM_THM_MOVT_ABS(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - uint32_t result = (uint32_t)(S + A); - const uint32_t arg = (result & 0xFFFF0000) >> 16; - - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - return relocR_ARM_THM_MOV(location, arg); -} - -/// \brief R_ARM_TLS_IE32 - GOT(S) + A - P => S + A - P -static std::error_code relocR_ARM_TLS_IE32(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - uint32_t result = (uint32_t)(S + A - P); - - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - return applyArmReloc(location, result); -} - -/// \brief R_ARM_TLS_LE32 - S + A - tp => S + A + tpoff -static std::error_code relocR_ARM_TLS_LE32(uint8_t *location, uint64_t P, - uint64_t S, int64_t A, - uint64_t tpoff) { - uint32_t result = (uint32_t)(S + A + tpoff); - - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - return applyArmReloc(location, result); -} - -/// \brief R_ARM_TLS_TPOFF32 - S + A - tp => S + A (offset within TLS block) -static std::error_code relocR_ARM_TLS_TPOFF32(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - uint32_t result = (uint32_t)(S + A); - - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - return applyArmReloc(location, result); -} - -template <uint32_t lshift> -static std::error_code relocR_ARM_ALU_PC_GN_NC(uint8_t *location, - uint32_t result) { - static_assert(lshift < 32 && lshift % 2 == 0, - "lshift must be even and less than word size"); - - const uint32_t rshift = 32 - lshift; - result = ((result >> lshift) & 0xFF) | ((rshift / 2) << 8); - - return applyArmReloc(location, result, 0xFFF); -} - -/// \brief R_ARM_ALU_PC_G0_NC - ((S + A) | T) - P => S + A - P -static std::error_code relocR_ARM_ALU_PC_G0_NC(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - int32_t result = (int32_t)(S + A - P); - if (result < 0) - report_unsupported_range_group_reloc_error(); - - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " result: 0x" << Twine::utohexstr((uint32_t)result) - << "\n"); - - return relocR_ARM_ALU_PC_GN_NC<20>(location, (uint32_t)result); -} - -/// \brief R_ARM_ALU_PC_G1_NC - ((S + A) | T) - P => S + A - P -static std::error_code relocR_ARM_ALU_PC_G1_NC(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - int32_t result = (int32_t)(S + A - P); - if (result < 0) - report_unsupported_range_group_reloc_error(); - - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " result: 0x" << Twine::utohexstr((uint32_t)result) - << "\n"); - - return relocR_ARM_ALU_PC_GN_NC<12>(location, (uint32_t)result); -} - -/// \brief R_ARM_LDR_PC_G2 - S + A - P -static std::error_code relocR_ARM_LDR_PC_G2(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - int32_t result = (int32_t)(S + A - P); - if (result < 0) - report_unsupported_range_group_reloc_error(); - - DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; - llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); - llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); - llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); - llvm::dbgs() << " result: 0x" << Twine::utohexstr((uint32_t)result) - << "\n"); - - const uint32_t mask = 0xFFF; - return applyArmReloc(location, (uint32_t)result & mask, mask); -} - -/// \brief Fixup unresolved weak reference with NOP instruction -static bool fixupUnresolvedWeakCall(uint8_t *location, - Reference::KindValue kindValue) { - // TODO: workaround for archs without NOP instruction - switch (kindValue) { - case R_ARM_THM_CALL: - case R_ARM_THM_JUMP24: - // Thumb32 NOP.W - write32le(location, 0x8000F3AF); - break; - case R_ARM_THM_JUMP11: - // Thumb16 NOP - write16le(location, 0xBF00); - break; - case R_ARM_CALL: - case R_ARM_JUMP24: - // A1 NOP<c>, save condition bits - applyArmReloc(location, 0x320F000, 0xFFFFFFF); - break; - default: - return false; - } - - return true; -} - -std::error_code ARMTargetRelocationHandler::applyRelocation( - ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom, - const Reference &ref) const { - uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset; - uint8_t *loc = atomContent + ref.offsetInAtom(); - uint64_t target = writer.addressOfAtom(ref.target()); - uint64_t reloc = atom._virtualAddr + ref.offsetInAtom(); - - if (ref.kindNamespace() != Reference::KindNamespace::ELF) - return std::error_code(); - assert(ref.kindArch() == Reference::KindArch::ARM); - - // Fixup unresolved weak references - if (!target) { - bool isCallFixed = fixupUnresolvedWeakCall(loc, ref.kindValue()); - - if (isCallFixed) { - DEBUG(llvm::dbgs() << "\t\tFixup unresolved weak reference '"; - llvm::dbgs() << ref.target()->name() << "'"; - llvm::dbgs() << " at address: 0x" << Twine::utohexstr(reloc); - llvm::dbgs() << (isCallFixed ? "\n" : " isn't possible\n")); - return std::error_code(); - } - } - - // Calculate proper initial addend for the relocation - const Reference::Addend addend = - readAddend(loc, ref.kindValue()) + ref.addend(); - - // Flags that the relocation addresses Thumb instruction - bool thumb = false; - if (const auto *definedAtom = dyn_cast<DefinedAtom>(ref.target())) { - thumb = isThumbCode(definedAtom); - } - - switch (ref.kindValue()) { - case R_ARM_NONE: - return std::error_code(); - case R_ARM_ABS32: - return relocR_ARM_ABS32(loc, reloc, target, addend, thumb); - case R_ARM_REL32: - return relocR_ARM_REL32(loc, reloc, target, addend, thumb); - case R_ARM_TARGET1: - if (_armLayout.target1Rel()) - return relocR_ARM_REL32(loc, reloc, target, addend, thumb); - else - return relocR_ARM_ABS32(loc, reloc, target, addend, thumb); - case R_ARM_THM_CALL: - // TODO: consider adding bool variable to disable J1 & J2 for archs - // before ARMv6 - return relocR_ARM_THM_CALL(loc, reloc, target, addend, true, thumb); - case R_ARM_CALL: - return relocR_ARM_CALL(loc, reloc, target, addend, thumb); - case R_ARM_JUMP24: - return relocR_ARM_JUMP24(loc, reloc, target, addend, thumb); - case R_ARM_THM_JUMP24: - return relocR_ARM_THM_JUMP24(loc, reloc, target, addend, thumb); - case R_ARM_THM_JUMP11: - return relocR_ARM_THM_JUMP11(loc, reloc, target, addend); - case R_ARM_MOVW_ABS_NC: - return relocR_ARM_MOVW_ABS_NC(loc, reloc, target, addend, thumb); - case R_ARM_MOVT_ABS: - return relocR_ARM_MOVT_ABS(loc, reloc, target, addend); - case R_ARM_THM_MOVW_ABS_NC: - return relocR_ARM_THM_MOVW_ABS_NC(loc, reloc, target, addend, thumb); - case R_ARM_THM_MOVT_ABS: - return relocR_ARM_THM_MOVT_ABS(loc, reloc, target, addend); - case R_ARM_PREL31: - return relocR_ARM_PREL31(loc, reloc, target, addend, thumb); - case R_ARM_TLS_IE32: - return relocR_ARM_TLS_IE32(loc, reloc, target, addend); - case R_ARM_TLS_LE32: - return relocR_ARM_TLS_LE32(loc, reloc, target, addend, - _armLayout.getTPOffset()); - case R_ARM_TLS_TPOFF32: - return relocR_ARM_TLS_TPOFF32(loc, reloc, target, addend); - case R_ARM_GOT_BREL: - return relocR_ARM_GOT_BREL(loc, reloc, target, addend, - _armLayout.getGOTSymAddr()); - case R_ARM_BASE_PREL: - // GOT origin is used for NULL symbol and when explicitly specified - if (!target || ref.target()->name().equals("_GLOBAL_OFFSET_TABLE_")) { - target = _armLayout.getGOTSymAddr(); - } else { - return make_dynamic_error_code( - "Segment-base relative addressing is not supported"); - } - return relocR_ARM_BASE_PREL(loc, reloc, target, addend); - case R_ARM_ALU_PC_G0_NC: - return relocR_ARM_ALU_PC_G0_NC(loc, reloc, target, addend); - case R_ARM_ALU_PC_G1_NC: - return relocR_ARM_ALU_PC_G1_NC(loc, reloc, target, addend); - case R_ARM_LDR_PC_G2: - return relocR_ARM_LDR_PC_G2(loc, reloc, target, addend); - case R_ARM_JUMP_SLOT: - case R_ARM_GLOB_DAT: - case R_ARM_IRELATIVE: - // Runtime only relocations. Ignore here. - return std::error_code(); - case R_ARM_V4BX: - // TODO implement - return std::error_code(); - default: - return make_unhandled_reloc_error(); - } - - llvm_unreachable("All switch cases must return directly"); -} diff --git a/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h b/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h deleted file mode 100644 index a1f3d091f204..000000000000 --- a/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h +++ /dev/null @@ -1,35 +0,0 @@ -//===--------- lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h ------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_HANDLER_H -#define LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_HANDLER_H - -#include "lld/ReaderWriter/ELFLinkingContext.h" - -namespace lld { -namespace elf { - -class ARMTargetLayout; - -class ARMTargetRelocationHandler final : public TargetRelocationHandler { -public: - ARMTargetRelocationHandler(ARMTargetLayout &layout) : _armLayout(layout) {} - - std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &, - const AtomLayout &, - const Reference &) const override; - -private: - ARMTargetLayout &_armLayout; -}; - -} // end namespace elf -} // end namespace lld - -#endif // LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_HANDLER_H diff --git a/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp b/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp deleted file mode 100644 index fc2ae75cd7a7..000000000000 --- a/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp +++ /dev/null @@ -1,985 +0,0 @@ -//===--------- lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp -------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Defines the relocation processing pass for ARM. This includes -/// GOT and PLT entries, TLS, COPY, and ifunc. -/// -/// This also includes additional behavior that gnu-ld and gold implement but -/// which is not specified anywhere. -/// -//===----------------------------------------------------------------------===// - -#include "ARMRelocationPass.h" -#include "ARMLinkingContext.h" -#include "Atoms.h" -#include "lld/Core/Simple.h" -#include "llvm/ADT/MapVector.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/Support/Debug.h" - -using namespace lld; -using namespace lld::elf; -using namespace llvm::ELF; - -namespace { -// ARM B/BL instructions of absolute relocation veneer. -// TODO: consider different instruction set for archs below ARMv5 -// (one as for Thumb may be used though it's less optimal). -static const uint8_t Veneer_ARM_B_BL_Abs_a_AtomContent[4] = { - 0x04, 0xf0, 0x1f, 0xe5 // ldr pc, [pc, #-4] -}; -static const uint8_t Veneer_ARM_B_BL_Abs_d_AtomContent[4] = { - 0x00, 0x00, 0x00, 0x00 // <target_symbol_address> -}; - -// Thumb B/BL instructions of absolute relocation veneer. -// TODO: consider different instruction set for archs above ARMv5 -// (one as for ARM may be used since it's more optimal). -static const uint8_t Veneer_THM_B_BL_Abs_t_AtomContent[4] = { - 0x78, 0x47, // bx pc - 0x00, 0x00 // nop -}; -static const uint8_t Veneer_THM_B_BL_Abs_a_AtomContent[4] = { - 0xfe, 0xff, 0xff, 0xea // b <target_symbol_address> -}; - -// .got values -static const uint8_t ARMGotAtomContent[4] = {0}; - -// .plt value (entry 0) -static const uint8_t ARMPlt0_a_AtomContent[16] = { - 0x04, 0xe0, 0x2d, 0xe5, // push {lr} - 0x04, 0xe0, 0x9f, 0xe5, // ldr lr, [pc, #4] - 0x0e, 0xe0, 0x8f, 0xe0, // add lr, pc, lr - 0x00, 0xf0, 0xbe, 0xe5 // ldr pc, [lr, #0]! -}; -static const uint8_t ARMPlt0_d_AtomContent[4] = { - 0x00, 0x00, 0x00, 0x00 // <got1_symbol_address> -}; - -// .plt values (other entries) -static const uint8_t ARMPltAtomContent[12] = { - 0x00, 0xc0, 0x8f, 0xe2, // add ip, pc, #offset[G0] - 0x00, 0xc0, 0x8c, 0xe2, // add ip, ip, #offset[G1] - 0x00, 0xf0, 0xbc, 0xe5 // ldr pc, [ip, #offset[G2]]! -}; - -// Veneer for switching from Thumb to ARM code for PLT entries. -static const uint8_t ARMPltVeneerAtomContent[4] = { - 0x78, 0x47, // bx pc - 0x00, 0x00 // nop -}; - -// Determine proper names for mapping symbols. -static std::string getMappingAtomName(DefinedAtom::CodeModel model, - const std::string &part) { - switch (model) { - case DefinedAtom::codeARM_a: - return part.empty() ? "$a" : "$a." + part; - case DefinedAtom::codeARM_d: - return part.empty() ? "$d" : "$d." + part; - case DefinedAtom::codeARM_t: - return part.empty() ? "$t" : "$t." + part; - default: - llvm_unreachable("Wrong code model of mapping atom"); - } -} - -/// \brief Atoms that hold veneer code. -class VeneerAtom : public SimpleELFDefinedAtom { - StringRef _section; - -public: - VeneerAtom(const File &f, StringRef secName, const std::string &name = "") - : SimpleELFDefinedAtom(f), _section(secName), _name(name) {} - - Scope scope() const override { return DefinedAtom::scopeTranslationUnit; } - - SectionChoice sectionChoice() const override { - return DefinedAtom::sectionBasedOnContent; - } - - StringRef customSectionName() const override { return _section; } - - ContentType contentType() const override { return DefinedAtom::typeCode; } - - uint64_t size() const override { return rawContent().size(); } - - ContentPermissions permissions() const override { return permR_X; } - - Alignment alignment() const override { return 4; } - - StringRef name() const override { return _name; } - -private: - std::string _name; -}; - -/// \brief Atoms that hold veneer for relocated ARM B/BL instructions -/// in absolute code. -class Veneer_ARM_B_BL_Abs_a_Atom : public VeneerAtom { -public: - Veneer_ARM_B_BL_Abs_a_Atom(const File &f, StringRef secName, - const std::string &name) - : VeneerAtom(f, secName, name) {} - - ArrayRef<uint8_t> rawContent() const override { - return llvm::makeArrayRef(Veneer_ARM_B_BL_Abs_a_AtomContent); - } -}; - -class Veneer_ARM_B_BL_Abs_d_Atom : public VeneerAtom { -public: - Veneer_ARM_B_BL_Abs_d_Atom(const File &f, StringRef secName) - : VeneerAtom(f, secName) {} - - ArrayRef<uint8_t> rawContent() const override { - return llvm::makeArrayRef(Veneer_ARM_B_BL_Abs_d_AtomContent); - } -}; - -/// \brief Atoms that hold veneer for relocated Thumb B/BL instructions -/// in absolute code. -class Veneer_THM_B_BL_Abs_t_Atom : public VeneerAtom { -public: - Veneer_THM_B_BL_Abs_t_Atom(const File &f, StringRef secName, - const std::string &name) - : VeneerAtom(f, secName, name) {} - - DefinedAtom::CodeModel codeModel() const override { - return DefinedAtom::codeARMThumb; - } - - ArrayRef<uint8_t> rawContent() const override { - return llvm::makeArrayRef(Veneer_THM_B_BL_Abs_t_AtomContent); - } -}; - -class Veneer_THM_B_BL_Abs_a_Atom : public VeneerAtom { -public: - Veneer_THM_B_BL_Abs_a_Atom(const File &f, StringRef secName) - : VeneerAtom(f, secName) {} - - ArrayRef<uint8_t> rawContent() const override { - return llvm::makeArrayRef(Veneer_THM_B_BL_Abs_a_AtomContent); - } -}; - -template <DefinedAtom::CodeModel Model> -class ARMVeneerMappingAtom : public VeneerAtom { -public: - ARMVeneerMappingAtom(const File &f, StringRef secName, StringRef name) - : VeneerAtom(f, secName, getMappingAtomName(Model, name)) { - static_assert((Model == DefinedAtom::codeARM_a || - Model == DefinedAtom::codeARM_d || - Model == DefinedAtom::codeARM_t), - "Only mapping atom types are allowed"); - } - - uint64_t size() const override { return 0; } - - ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); } - - DefinedAtom::CodeModel codeModel() const override { return Model; } -}; - -template <class BaseAtom, DefinedAtom::CodeModel Model> -class BaseMappingAtom : public BaseAtom { -public: - BaseMappingAtom(const File &f, StringRef secName, StringRef name) - : BaseAtom(f, secName) { - static_assert((Model == DefinedAtom::codeARM_a || - Model == DefinedAtom::codeARM_d || - Model == DefinedAtom::codeARM_t), - "Only mapping atom types are allowed"); -#ifndef NDEBUG - _name = name; -#else - _name = getMappingAtomName(Model, name); -#endif - } - - DefinedAtom::CodeModel codeModel() const override { -#ifndef NDEBUG - return isThumbCode(Model) ? DefinedAtom::codeARMThumb : DefinedAtom::codeNA; -#else - return Model; -#endif - } - - StringRef name() const override { return _name; } - -private: - std::string _name; -}; - -/// \brief Atoms that are used by ARM dynamic linking -class ARMGOTAtom : public GOTAtom { -public: - ARMGOTAtom(const File &f) : GOTAtom(f, ".got") {} - - ArrayRef<uint8_t> rawContent() const override { - return llvm::makeArrayRef(ARMGotAtomContent); - } - - Alignment alignment() const override { return 4; } - -protected: - // Constructor for PLTGOT atom. - ARMGOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {} -}; - -class ARMGOTPLTAtom : public ARMGOTAtom { -public: - ARMGOTPLTAtom(const File &f) : ARMGOTAtom(f, ".got.plt") {} -}; - -/// \brief Proxy class to keep type compatibility with PLT0Atom. -class ARMPLT0Atom : public PLT0Atom { -public: - ARMPLT0Atom(const File &f, StringRef) : PLT0Atom(f) {} -}; - -/// \brief PLT0 entry atom. -/// Serves as a mapping symbol in the release mode. -class ARMPLT0_a_Atom - : public BaseMappingAtom<ARMPLT0Atom, DefinedAtom::codeARM_a> { -public: - ARMPLT0_a_Atom(const File &f, const std::string &name) - : BaseMappingAtom(f, ".plt", name) {} - - ArrayRef<uint8_t> rawContent() const override { - return llvm::makeArrayRef(ARMPlt0_a_AtomContent); - } - - Alignment alignment() const override { return 4; } -}; - -class ARMPLT0_d_Atom - : public BaseMappingAtom<ARMPLT0Atom, DefinedAtom::codeARM_d> { -public: - ARMPLT0_d_Atom(const File &f, const std::string &name) - : BaseMappingAtom(f, ".plt", name) {} - - ArrayRef<uint8_t> rawContent() const override { - return llvm::makeArrayRef(ARMPlt0_d_AtomContent); - } - - Alignment alignment() const override { return 4; } -}; - -/// \brief PLT entry atom. -/// Serves as a mapping symbol in the release mode. -class ARMPLTAtom : public BaseMappingAtom<PLTAtom, DefinedAtom::codeARM_a> { -public: - ARMPLTAtom(const File &f, const std::string &name) - : BaseMappingAtom(f, ".plt", name) {} - - ArrayRef<uint8_t> rawContent() const override { - return llvm::makeArrayRef(ARMPltAtomContent); - } - - Alignment alignment() const override { return 4; } -}; - -/// \brief Veneer atom for PLT entry. -/// Serves as a mapping symbol in the release mode. -class ARMPLTVeneerAtom - : public BaseMappingAtom<PLTAtom, DefinedAtom::codeARM_t> { -public: - ARMPLTVeneerAtom(const File &f, const std::string &name) - : BaseMappingAtom(f, ".plt", name) {} - - ArrayRef<uint8_t> rawContent() const override { - return llvm::makeArrayRef(ARMPltVeneerAtomContent); - } - - Alignment alignment() const override { return 4; } -}; - -/// \brief Atom which represents an object for which a COPY relocation will -/// be generated. -class ARMObjectAtom : public ObjectAtom { -public: - ARMObjectAtom(const File &f) : ObjectAtom(f) {} - Alignment alignment() const override { return 4; } -}; - -class ELFPassFile : public SimpleFile { -public: - ELFPassFile(const ELFLinkingContext &eti) : SimpleFile("ELFPassFile") { - setOrdinal(eti.getNextOrdinalAndIncrement()); - } - - llvm::BumpPtrAllocator _alloc; -}; - -/// \brief CRTP base for handling relocations. -template <class Derived> class ARMRelocationPass : public Pass { - /// \brief Handle a specific reference. - void handleReference(const DefinedAtom &atom, const Reference &ref) { - DEBUG_WITH_TYPE( - "ARM", llvm::dbgs() << "\t" << LLVM_FUNCTION_NAME << "()" - << ": Name of Defined Atom: " << atom.name().str(); - llvm::dbgs() << " kindValue: " << ref.kindValue() << "\n"); - if (ref.kindNamespace() != Reference::KindNamespace::ELF) - return; - assert(ref.kindArch() == Reference::KindArch::ARM); - switch (ref.kindValue()) { - case R_ARM_ABS32: - case R_ARM_REL32: - case R_ARM_TARGET1: - case R_ARM_MOVW_ABS_NC: - case R_ARM_MOVT_ABS: - case R_ARM_THM_MOVW_ABS_NC: - case R_ARM_THM_MOVT_ABS: - static_cast<Derived *>(this)->handlePlain(isThumbCode(&atom), ref); - break; - case R_ARM_THM_CALL: - case R_ARM_CALL: - case R_ARM_JUMP24: - case R_ARM_THM_JUMP24: - case R_ARM_THM_JUMP11: { - const auto actualModel = actualSourceCodeModel(atom, ref); - const bool fromThumb = isThumbCode(actualModel); - static_cast<Derived *>(this)->handlePlain(fromThumb, ref); - static_cast<Derived *>(this)->handleVeneer(atom, fromThumb, ref); - } break; - case R_ARM_TLS_IE32: - static_cast<Derived *>(this)->handleTLSIE32(ref); - break; - case R_ARM_GOT_BREL: - static_cast<Derived *>(this)->handleGOT(ref); - break; - default: - break; - } - } - -protected: - /// \brief Determine source atom's actual code model. - /// - /// Actual code model may differ from the existing one if fixup - /// is possible on the later stages for given relocation type. - DefinedAtom::CodeModel actualSourceCodeModel(const DefinedAtom &atom, - const Reference &ref) { - const auto kindValue = ref.kindValue(); - if (kindValue != R_ARM_CALL && kindValue != R_ARM_THM_CALL) - return atom.codeModel(); - - // TODO: For unconditional jump instructions (R_ARM_CALL and R_ARM_THM_CALL) - // fixup isn't possible without veneer generation for archs below ARMv5. - - auto actualModel = atom.codeModel(); - if (const auto *da = dyn_cast<DefinedAtom>(ref.target())) { - actualModel = da->codeModel(); - } else if (const auto *sla = dyn_cast<SharedLibraryAtom>(ref.target())) { - if (sla->type() == SharedLibraryAtom::Type::Code) { - // PLT entry will be generated here - assume we don't want a veneer - // on top of it and prefer instruction fixup if needed. - actualModel = DefinedAtom::codeNA; - } - } - return actualModel; - } - - std::error_code handleVeneer(const DefinedAtom &atom, bool fromThumb, - const Reference &ref) { - // Actual instruction mode differs meaning that further fixup will be - // applied. - if (isThumbCode(&atom) != fromThumb) - return std::error_code(); - - const VeneerAtom *(Derived::*getVeneer)(const DefinedAtom *, StringRef) = - nullptr; - const auto kindValue = ref.kindValue(); - switch (kindValue) { - case R_ARM_JUMP24: - getVeneer = &Derived::getVeneer_ARM_B_BL; - break; - case R_ARM_THM_JUMP24: - getVeneer = &Derived::getVeneer_THM_B_BL; - break; - default: - return std::error_code(); - } - - // Target symbol and relocated place should have different - // instruction sets in order a veneer to be generated in between. - const auto *target = dyn_cast<DefinedAtom>(ref.target()); - if (!target || isThumbCode(target) == isThumbCode(&atom)) - return std::error_code(); - - // Veneers may only be generated for STT_FUNC target symbols - // or for symbols located in sections different to the place of relocation. - StringRef secName = atom.customSectionName(); - if (DefinedAtom::typeCode != target->contentType() && - !target->customSectionName().equals(secName)) { - StringRef kindValStr; - if (!this->_ctx.registry().referenceKindToString( - ref.kindNamespace(), ref.kindArch(), kindValue, kindValStr)) { - kindValStr = "unknown"; - } - - std::string errStr = - (Twine("Reference of type ") + Twine(kindValue) + " (" + kindValStr + - ") from " + atom.name() + "+" + Twine(ref.offsetInAtom()) + " to " + - ref.target()->name() + "+" + Twine(ref.addend()) + - " cannot be effected without a veneer").str(); - - llvm_unreachable(errStr.c_str()); - } - - assert(getVeneer && "The veneer handler is missing"); - const Atom *veneer = - (static_cast<Derived *>(this)->*getVeneer)(target, secName); - - assert(veneer && "The veneer is not set"); - const_cast<Reference &>(ref).setTarget(veneer); - return std::error_code(); - } - - /// \brief Get the veneer for ARM B/BL instructions - /// in absolute code. - const VeneerAtom *getVeneer_ARM_B_BL_Abs(const DefinedAtom *da, - StringRef secName) { - auto veneer = _veneerAtoms.lookup(da); - if (!veneer.empty()) - return veneer._veneer; - - std::string name = "__"; - name += da->name(); - name += "_from_arm"; - // Create parts of veneer with mapping symbols. - auto v_a = - new (_file._alloc) Veneer_ARM_B_BL_Abs_a_Atom(_file, secName, name); - addVeneerWithMapping<DefinedAtom::codeARM_a>(da, v_a, name); - auto v_d = new (_file._alloc) Veneer_ARM_B_BL_Abs_d_Atom(_file, secName); - addVeneerWithMapping<DefinedAtom::codeARM_d>(v_a, v_d, name); - - // Fake reference to show connection between parts of veneer. - v_a->addReferenceELF_ARM(R_ARM_NONE, 0, v_d, 0); - // Real reference to fixup. - v_d->addReferenceELF_ARM(R_ARM_ABS32, 0, da, 0); - return v_a; - } - - /// \brief Get the veneer for Thumb B/BL instructions - /// in absolute code. - const VeneerAtom *getVeneer_THM_B_BL_Abs(const DefinedAtom *da, - StringRef secName) { - auto veneer = _veneerAtoms.lookup(da); - if (!veneer.empty()) - return veneer._veneer; - - std::string name = "__"; - name += da->name(); - name += "_from_thumb"; - // Create parts of veneer with mapping symbols. - auto v_t = - new (_file._alloc) Veneer_THM_B_BL_Abs_t_Atom(_file, secName, name); - addVeneerWithMapping<DefinedAtom::codeARM_t>(da, v_t, name); - auto v_a = new (_file._alloc) Veneer_THM_B_BL_Abs_a_Atom(_file, secName); - addVeneerWithMapping<DefinedAtom::codeARM_a>(v_t, v_a, name); - - // Fake reference to show connection between parts of veneer. - v_t->addReferenceELF_ARM(R_ARM_NONE, 0, v_a, 0); - // Real reference to fixup. - v_a->addReferenceELF_ARM(R_ARM_JUMP24, 0, da, 0); - return v_t; - } - - std::error_code handleTLSIE32(const Reference &ref) { - if (const auto *target = dyn_cast<DefinedAtom>(ref.target())) { - const_cast<Reference &>(ref) - .setTarget(static_cast<Derived *>(this)->getTLSTPOFF32(target)); - return std::error_code(); - } - llvm_unreachable("R_ARM_TLS_IE32 reloc targets wrong atom type"); - } - - /// \brief Create a GOT entry for TLS with reloc type and addend specified. - template <Reference::KindValue R_ARM_TLS, Reference::Addend A = 0> - const GOTAtom *getGOTTLSEntry(const DefinedAtom *da) { - StringRef source; -#ifndef NDEBUG - source = "_tls_"; -#endif - return getGOT<R_ARM_TLS, A>(da, source); - } - - /// \brief Add veneer with mapping symbol. - template <DefinedAtom::CodeModel Model> - void addVeneerWithMapping(const DefinedAtom *da, VeneerAtom *va, - const std::string &name) { - assert(_veneerAtoms.lookup(da).empty() && - "Veneer or mapping already exists"); - auto *ma = new (_file._alloc) - ARMVeneerMappingAtom<Model>(_file, va->customSectionName(), name); - - // Fake reference to show connection between the mapping symbol and veneer. - va->addReferenceELF_ARM(R_ARM_NONE, 0, ma, 0); - _veneerAtoms[da] = VeneerWithMapping(va, ma); - } - - /// \brief get a veneer for a PLT entry. - const PLTAtom *getPLTVeneer(const Atom *da, PLTAtom *pa, StringRef source) { - std::string name = "__plt_from_thumb"; - name += source.empty() ? "_" : source; - name += da->name(); - // Create veneer for PLT entry. - auto va = new (_file._alloc) ARMPLTVeneerAtom(_file, name); - // Fake reference to show connection between veneer and PLT entry. - va->addReferenceELF_ARM(R_ARM_NONE, 0, pa, 0); - - _pltAtoms[da] = PLTWithVeneer(pa, va); - return va; - } - - typedef const GOTAtom *(Derived::*GOTFactory)(const Atom *); - - /// \brief get a PLT entry referencing PLTGOT entry. - /// - /// If the entry does not exist, both GOT and PLT entry are created. - const PLTAtom *getPLT(const Atom *da, bool fromThumb, GOTFactory gotFactory, - StringRef source = "") { - auto pltVeneer = _pltAtoms.lookup(da); - if (!pltVeneer.empty()) { - // Return clean PLT entry provided it is ARM code. - if (!fromThumb) - return pltVeneer._plt; - - // Check if veneer is present for Thumb to ARM transition. - if (pltVeneer._veneer) - return pltVeneer._veneer; - - // Create veneer for existing PLT entry. - return getPLTVeneer(da, pltVeneer._plt, source); - } - - // Create specific GOT entry. - const auto *ga = (static_cast<Derived *>(this)->*gotFactory)(da); - assert(_gotpltAtoms.lookup(da) == ga && - "GOT entry should be added to the PLTGOT map"); - assert(ga->customSectionName() == ".got.plt" && - "GOT entry should be in a special section"); - - std::string name = "__plt"; - name += source.empty() ? "_" : source; - name += da->name(); - // Create PLT entry for the GOT entry. - auto pa = new (_file._alloc) ARMPLTAtom(_file, name); - pa->addReferenceELF_ARM(R_ARM_ALU_PC_G0_NC, 0, ga, -8); - pa->addReferenceELF_ARM(R_ARM_ALU_PC_G1_NC, 4, ga, -4); - pa->addReferenceELF_ARM(R_ARM_LDR_PC_G2, 8, ga, 0); - - // Since all PLT entries are in ARM code, Thumb to ARM - // switching should be added if the relocated place contais Thumb code. - if (fromThumb) - return getPLTVeneer(da, pa, source); - - // Otherwise just add PLT entry and return it to the caller. - _pltAtoms[da] = PLTWithVeneer(pa); - return pa; - } - - /// \brief Create the GOT entry for a given IFUNC Atom. - const GOTAtom *createIFUNCGOT(const Atom *da) { - assert(!_gotpltAtoms.lookup(da) && "IFUNC GOT entry already exists"); - auto g = new (_file._alloc) ARMGOTPLTAtom(_file); - g->addReferenceELF_ARM(R_ARM_ABS32, 0, da, 0); - g->addReferenceELF_ARM(R_ARM_IRELATIVE, 0, da, 0); -#ifndef NDEBUG - g->_name = "__got_ifunc_"; - g->_name += da->name(); -#endif - _gotpltAtoms[da] = g; - return g; - } - - /// \brief get the PLT entry for a given IFUNC Atom. - const PLTAtom *getIFUNCPLTEntry(const DefinedAtom *da, bool fromThumb) { - return getPLT(da, fromThumb, &Derived::createIFUNCGOT, "_ifunc_"); - } - - /// \brief Redirect the call to the PLT stub for the target IFUNC. - /// - /// This create a PLT and GOT entry for the IFUNC if one does not exist. The - /// GOT entry and a IRELATIVE relocation to the original target resolver. - std::error_code handleIFUNC(bool fromThumb, const Reference &ref) { - auto target = dyn_cast<const DefinedAtom>(ref.target()); - if (target && target->contentType() == DefinedAtom::typeResolver) { - const_cast<Reference &>(ref) - .setTarget(getIFUNCPLTEntry(target, fromThumb)); - } - return std::error_code(); - } - - /// \brief Create a GOT entry containing 0. - const GOTAtom *getNullGOT() { - if (!_null) { - _null = new (_file._alloc) ARMGOTPLTAtom(_file); -#ifndef NDEBUG - _null->_name = "__got_null"; -#endif - } - return _null; - } - - /// \brief Create regular GOT entry which cannot be used in PLTGOT operation. - template <Reference::KindValue R_ARM_REL, Reference::Addend A = 0> - const GOTAtom *getGOT(const Atom *da, StringRef source = "") { - if (auto got = _gotAtoms.lookup(da)) - return got; - auto g = new (_file._alloc) ARMGOTAtom(_file); - g->addReferenceELF_ARM(R_ARM_REL, 0, da, A); -#ifndef NDEBUG - g->_name = "__got"; - g->_name += source.empty() ? "_" : source; - g->_name += da->name(); -#endif - _gotAtoms[da] = g; - return g; - } - - /// \brief get GOT entry for a regular defined atom. - const GOTAtom *getGOTEntry(const DefinedAtom *da) { - return getGOT<R_ARM_ABS32>(da); - } - - std::error_code handleGOT(const Reference &ref) { - if (isa<UndefinedAtom>(ref.target())) - const_cast<Reference &>(ref).setTarget(getNullGOT()); - else if (const auto *da = dyn_cast<DefinedAtom>(ref.target())) - const_cast<Reference &>(ref).setTarget(getGOTEntry(da)); - return std::error_code(); - } - -public: - ARMRelocationPass(const ELFLinkingContext &ctx) : _file(ctx), _ctx(ctx) {} - - /// \brief Do the pass. - /// - /// The goal here is to first process each reference individually. Each call - /// to handleReference may modify the reference itself and/or create new - /// atoms which must be stored in one of the maps below. - /// - /// After all references are handled, the atoms created during that are all - /// added to mf. - std::error_code perform(SimpleFile &mf) override { - ScopedTask task(getDefaultDomain(), "ARM GOT/PLT Pass"); - DEBUG_WITH_TYPE( - "ARM", llvm::dbgs() << "Undefined Atoms" << "\n"; - for (const auto &atom - : mf.undefined()) { - llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n"; - } - - llvm::dbgs() << "Shared Library Atoms" << "\n"; - for (const auto &atom - : mf.sharedLibrary()) { - llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n"; - } - - llvm::dbgs() << "Absolute Atoms" << "\n"; - for (const auto &atom - : mf.absolute()) { - llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n"; - } - - llvm::dbgs() << "Defined Atoms" << "\n"; - for (const auto &atom - : mf.defined()) { - llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n"; - }); - - // Process all references. - for (const auto &atom : mf.defined()) { - for (const auto &ref : *atom) { - handleReference(*atom, *ref); - } - } - - // Add all created atoms to the link. - uint64_t ordinal = 0; - if (_plt0) { - _plt0->setOrdinal(ordinal++); - mf.addAtom(*_plt0); - _plt0_d->setOrdinal(ordinal++); - mf.addAtom(*_plt0_d); - } - for (auto &pltKV : _pltAtoms) { - auto &plt = pltKV.second; - if (auto *v = plt._veneer) { - v->setOrdinal(ordinal++); - mf.addAtom(*v); - } - auto *p = plt._plt; - p->setOrdinal(ordinal++); - mf.addAtom(*p); - } - if (_null) { - _null->setOrdinal(ordinal++); - mf.addAtom(*_null); - } - if (_plt0) { - _got0->setOrdinal(ordinal++); - mf.addAtom(*_got0); - _got1->setOrdinal(ordinal++); - mf.addAtom(*_got1); - } - for (auto &gotKV : _gotAtoms) { - auto &got = gotKV.second; - got->setOrdinal(ordinal++); - mf.addAtom(*got); - } - for (auto &gotKV : _gotpltAtoms) { - auto &got = gotKV.second; - got->setOrdinal(ordinal++); - mf.addAtom(*got); - } - for (auto &objectKV : _objectAtoms) { - auto &obj = objectKV.second; - obj->setOrdinal(ordinal++); - mf.addAtom(*obj); - } - for (auto &veneerKV : _veneerAtoms) { - auto &veneer = veneerKV.second; - auto *m = veneer._mapping; - m->setOrdinal(ordinal++); - mf.addAtom(*m); - auto *v = veneer._veneer; - v->setOrdinal(ordinal++); - mf.addAtom(*v); - } - - return std::error_code(); - } - -protected: - /// \brief Owner of all the Atoms created by this pass. - ELFPassFile _file; - const ELFLinkingContext &_ctx; - - /// \brief Map Atoms to their GOT entries. - llvm::MapVector<const Atom *, GOTAtom *> _gotAtoms; - - /// \brief Map Atoms to their PLTGOT entries. - llvm::MapVector<const Atom *, GOTAtom *> _gotpltAtoms; - - /// \brief Map Atoms to their Object entries. - llvm::MapVector<const Atom *, ObjectAtom *> _objectAtoms; - - /// \brief Map Atoms to their PLT entries depending on the code model. - struct PLTWithVeneer { - PLTWithVeneer(PLTAtom *p = nullptr, PLTAtom *v = nullptr) - : _plt(p), _veneer(v) {} - - bool empty() const { - assert((_plt || !_veneer) && "Veneer appears without PLT entry"); - return !_plt && !_veneer; - } - - PLTAtom *_plt; - PLTAtom *_veneer; - }; - llvm::MapVector<const Atom *, PLTWithVeneer> _pltAtoms; - - /// \brief Map Atoms to their veneers. - struct VeneerWithMapping { - VeneerWithMapping(VeneerAtom *v = nullptr, VeneerAtom *m = nullptr) - : _veneer(v), _mapping(m) {} - - bool empty() const { - assert(((bool)_veneer == (bool)_mapping) && - "Mapping symbol should always be paired with veneer"); - return !_veneer && !_mapping; - } - - VeneerAtom *_veneer; - VeneerAtom *_mapping; - }; - llvm::MapVector<const Atom *, VeneerWithMapping> _veneerAtoms; - - /// \brief GOT entry that is always 0. Used for undefined weaks. - GOTAtom *_null = nullptr; - - /// \brief The got and plt entries for .PLT0. This is used to call into the - /// dynamic linker for symbol resolution. - /// @{ - PLT0Atom *_plt0 = nullptr; - PLT0Atom *_plt0_d = nullptr; - GOTAtom *_got0 = nullptr; - GOTAtom *_got1 = nullptr; - /// @} -}; - -/// This implements the static relocation model. Meaning GOT and PLT entries are -/// not created for references that can be directly resolved. These are -/// converted to a direct relocation. For entries that do require a GOT or PLT -/// entry, that entry is statically bound. -/// -/// TLS always assumes module 1 and attempts to remove indirection. -class ARMStaticRelocationPass final - : public ARMRelocationPass<ARMStaticRelocationPass> { -public: - ARMStaticRelocationPass(const elf::ARMLinkingContext &ctx) - : ARMRelocationPass(ctx) {} - - /// \brief Handle ordinary relocation references. - std::error_code handlePlain(bool fromThumb, const Reference &ref) { - return handleIFUNC(fromThumb, ref); - } - - /// \brief Get the veneer for ARM B/BL instructions. - const VeneerAtom *getVeneer_ARM_B_BL(const DefinedAtom *da, - StringRef secName) { - return getVeneer_ARM_B_BL_Abs(da, secName); - } - - /// \brief Get the veneer for Thumb B/BL instructions. - const VeneerAtom *getVeneer_THM_B_BL(const DefinedAtom *da, - StringRef secName) { - return getVeneer_THM_B_BL_Abs(da, secName); - } - - /// \brief Create a GOT entry for R_ARM_TLS_TPOFF32 reloc. - const GOTAtom *getTLSTPOFF32(const DefinedAtom *da) { - return getGOTTLSEntry<R_ARM_TLS_LE32>(da); - } -}; - -/// This implements the dynamic relocation model. GOT and PLT entries are -/// created for references that cannot be directly resolved. -class ARMDynamicRelocationPass final - : public ARMRelocationPass<ARMDynamicRelocationPass> { -public: - ARMDynamicRelocationPass(const elf::ARMLinkingContext &ctx) - : ARMRelocationPass(ctx) {} - - /// \brief get the PLT entry for a given atom. - const PLTAtom *getPLTEntry(const SharedLibraryAtom *sla, bool fromThumb) { - return getPLT(sla, fromThumb, &ARMDynamicRelocationPass::createPLTGOT); - } - - /// \brief Create the GOT entry for a given atom. - const GOTAtom *createPLTGOT(const Atom *da) { - assert(!_gotpltAtoms.lookup(da) && "PLTGOT entry already exists"); - auto g = new (_file._alloc) ARMGOTPLTAtom(_file); - g->addReferenceELF_ARM(R_ARM_ABS32, 0, getPLT0(), 0); - g->addReferenceELF_ARM(R_ARM_JUMP_SLOT, 0, da, 0); -#ifndef NDEBUG - g->_name = "__got_plt0_"; - g->_name += da->name(); -#endif - _gotpltAtoms[da] = g; - return g; - } - - const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a) { - if (auto obj = _objectAtoms.lookup(a)) - return obj; - - auto oa = new (_file._alloc) ARMObjectAtom(_file); - oa->addReferenceELF_ARM(R_ARM_COPY, 0, oa, 0); - - oa->_name = a->name(); - oa->_size = a->size(); - - _objectAtoms[a] = oa; - return oa; - } - - /// \brief Handle ordinary relocation references. - std::error_code handlePlain(bool fromThumb, const Reference &ref) { - if (auto sla = dyn_cast<SharedLibraryAtom>(ref.target())) { - if (sla->type() == SharedLibraryAtom::Type::Data && - _ctx.getOutputELFType() == llvm::ELF::ET_EXEC) { - const_cast<Reference &>(ref).setTarget(getObjectEntry(sla)); - } else if (sla->type() == SharedLibraryAtom::Type::Code) { - const_cast<Reference &>(ref).setTarget(getPLTEntry(sla, fromThumb)); - } - return std::error_code(); - } - return handleIFUNC(fromThumb, ref); - } - - /// \brief Get the veneer for ARM B/BL instructions. - const VeneerAtom *getVeneer_ARM_B_BL(const DefinedAtom *da, - StringRef secName) { - if (_ctx.getOutputELFType() == llvm::ELF::ET_EXEC) { - return getVeneer_ARM_B_BL_Abs(da, secName); - } - llvm_unreachable("Handle ARM veneer for DSOs"); - } - - /// \brief Get the veneer for Thumb B/BL instructions. - const VeneerAtom *getVeneer_THM_B_BL(const DefinedAtom *da, - StringRef secName) { - if (_ctx.getOutputELFType() == llvm::ELF::ET_EXEC) { - return getVeneer_THM_B_BL_Abs(da, secName); - } - llvm_unreachable("Handle Thumb veneer for DSOs"); - } - - /// \brief Create a GOT entry for R_ARM_TLS_TPOFF32 reloc. - const GOTAtom *getTLSTPOFF32(const DefinedAtom *da) { - return getGOTTLSEntry<R_ARM_TLS_TPOFF32>(da); - } - - const PLT0Atom *getPLT0() { - if (_plt0) - return _plt0; - // Fill in the null entry. - getNullGOT(); - _plt0 = new (_file._alloc) ARMPLT0_a_Atom(_file, "__PLT0"); - _plt0_d = new (_file._alloc) ARMPLT0_d_Atom(_file, "__PLT0_d"); - _got0 = new (_file._alloc) ARMGOTPLTAtom(_file); - _got1 = new (_file._alloc) ARMGOTPLTAtom(_file); - _plt0_d->addReferenceELF_ARM(R_ARM_REL32, 0, _got1, 0); - // Fake reference to show connection between the GOT and PLT entries. - _plt0->addReferenceELF_ARM(R_ARM_NONE, 0, _got0, 0); - // Fake reference to show connection between parts of PLT entry. - _plt0->addReferenceELF_ARM(R_ARM_NONE, 0, _plt0_d, 0); -#ifndef NDEBUG - _got0->_name = "__got0"; - _got1->_name = "__got1"; -#endif - return _plt0; - } - - const GOTAtom *getSharedGOTEntry(const SharedLibraryAtom *sla) { - return getGOT<R_ARM_GLOB_DAT>(sla); - } - - std::error_code handleGOT(const Reference &ref) { - if (const auto sla = dyn_cast<const SharedLibraryAtom>(ref.target())) { - const_cast<Reference &>(ref).setTarget(getSharedGOTEntry(sla)); - return std::error_code(); - } - return ARMRelocationPass::handleGOT(ref); - } -}; - -} // end of anon namespace - -std::unique_ptr<Pass> -lld::elf::createARMRelocationPass(const ARMLinkingContext &ctx) { - switch (ctx.getOutputELFType()) { - case llvm::ELF::ET_EXEC: - if (ctx.isDynamic()) - return llvm::make_unique<ARMDynamicRelocationPass>(ctx); - return llvm::make_unique<ARMStaticRelocationPass>(ctx); - case llvm::ELF::ET_DYN: - return llvm::make_unique<ARMDynamicRelocationPass>(ctx); - default: - llvm_unreachable("Unhandled output file type"); - } -} diff --git a/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h b/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h deleted file mode 100644 index 651e798f33b1..000000000000 --- a/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h +++ /dev/null @@ -1,31 +0,0 @@ -//===--------- lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h ---------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Declares the relocation processing pass for ARM. This includes -/// GOT and PLT entries, TLS, COPY, and ifunc. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_PASS_H -#define LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_PASS_H - -#include <memory> - -namespace lld { -class Pass; -namespace elf { -class ARMLinkingContext; - -/// \brief Create ARM relocation pass for the given linking context. -std::unique_ptr<Pass> createARMRelocationPass(const ARMLinkingContext &); -} -} - -#endif diff --git a/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h b/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h deleted file mode 100644 index 85b9c9162589..000000000000 --- a/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h +++ /dev/null @@ -1,59 +0,0 @@ -//===--------- lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h ------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_ARM_ARM_SYMBOL_TABLE_H -#define LLD_READER_WRITER_ELF_ARM_ARM_SYMBOL_TABLE_H - -#include "SectionChunks.h" -#include "TargetLayout.h" -#include "ARMELFFile.h" - -namespace lld { -namespace elf { - -/// \brief The SymbolTable class represents the symbol table in a ELF file -class ARMSymbolTable : public SymbolTable<ELF32LE> { -public: - typedef llvm::object::Elf_Sym_Impl<ELF32LE> Elf_Sym; - - ARMSymbolTable(const ELFLinkingContext &ctx); - - void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da, - int64_t addr) override; -}; - -ARMSymbolTable::ARMSymbolTable(const ELFLinkingContext &ctx) - : SymbolTable(ctx, ".symtab", TargetLayout<ELF32LE>::ORDER_SYMBOL_TABLE) {} - -void ARMSymbolTable::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da, - int64_t addr) { - SymbolTable::addDefinedAtom(sym, da, addr); - - if ((ARMELFDefinedAtom::ARMContentType)da->contentType() == - ARMELFDefinedAtom::typeARMExidx) - sym.st_value = addr; - - // Set zero bit to distinguish real symbols addressing Thumb instructions. - // Don't care about mapping symbols like $t and others. - if (DefinedAtom::codeARMThumb == da->codeModel()) - sym.st_value = static_cast<int64_t>(sym.st_value) | 0x1; - - // Mapping symbols should have special values of binding, type and size set. - if ((DefinedAtom::codeARM_a == da->codeModel()) || - (DefinedAtom::codeARM_d == da->codeModel()) || - (DefinedAtom::codeARM_t == da->codeModel())) { - sym.setBindingAndType(llvm::ELF::STB_LOCAL, llvm::ELF::STT_NOTYPE); - sym.st_size = 0; - } -} - -} // elf -} // lld - -#endif // LLD_READER_WRITER_ELF_ARM_ARM_SYMBOL_TABLE_H diff --git a/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp b/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp deleted file mode 100644 index e1f5eadbe789..000000000000 --- a/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp +++ /dev/null @@ -1,32 +0,0 @@ -//===--------- lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp --------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Atoms.h" -#include "ARMExecutableWriter.h" -#include "ARMDynamicLibraryWriter.h" -#include "ARMTargetHandler.h" -#include "ARMLinkingContext.h" - -using namespace lld; -using namespace elf; - -ARMTargetHandler::ARMTargetHandler(ARMLinkingContext &ctx) - : _ctx(ctx), _targetLayout(new ARMTargetLayout(ctx)), - _relocationHandler(new ARMTargetRelocationHandler(*_targetLayout)) {} - -std::unique_ptr<Writer> ARMTargetHandler::getWriter() { - switch (this->_ctx.getOutputELFType()) { - case llvm::ELF::ET_EXEC: - return llvm::make_unique<ARMExecutableWriter>(_ctx, *_targetLayout); - case llvm::ELF::ET_DYN: - return llvm::make_unique<ARMDynamicLibraryWriter>(_ctx, *_targetLayout); - default: - llvm_unreachable("unsupported output type"); - } -} diff --git a/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h b/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h deleted file mode 100644 index 0352e81a1f61..000000000000 --- a/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h +++ /dev/null @@ -1,174 +0,0 @@ -//===--------- lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h ----------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_ARM_ARM_TARGET_HANDLER_H -#define LLD_READER_WRITER_ELF_ARM_ARM_TARGET_HANDLER_H - -#include "ARMELFFile.h" -#include "ARMRelocationHandler.h" -#include "ELFReader.h" -#include "TargetLayout.h" - -namespace lld { -class ELFLinkingContext; - -namespace elf { - -/// \brief ARM specific section (.ARM.exidx) with indexes to exception handlers -class ARMExidxSection : public AtomSection<ELF32LE> { - typedef AtomSection<ELF32LE> Base; - -public: - ARMExidxSection(const ELFLinkingContext &ctx, StringRef sectionName, - int32_t permissions, int32_t order) - : Base(ctx, sectionName, ARMELFDefinedAtom::typeARMExidx, permissions, - order) { - this->_type = SHT_ARM_EXIDX; - this->_isLoadedInMemory = true; - } - - bool hasOutputSegment() const override { return true; } - - const AtomLayout *appendAtom(const Atom *atom) override { - const DefinedAtom *definedAtom = cast<DefinedAtom>(atom); - assert((ARMELFDefinedAtom::ARMContentType)definedAtom->contentType() == - ARMELFDefinedAtom::typeARMExidx && - "atom content type for .ARM.exidx section has to be typeARMExidx"); - - DefinedAtom::Alignment atomAlign = definedAtom->alignment(); - uint64_t fOffset = alignOffset(this->fileSize(), atomAlign); - uint64_t mOffset = alignOffset(this->memSize(), atomAlign); - - _atoms.push_back(new (_alloc) AtomLayout(atom, fOffset, 0)); - this->_fsize = fOffset + definedAtom->size(); - this->_msize = mOffset + definedAtom->size(); - DEBUG_WITH_TYPE("Section", llvm::dbgs() - << "[" << this->name() << " " << this << "] " - << "Adding atom: " << atom->name() << "@" - << fOffset << "\n"); - - uint64_t alignment = atomAlign.value; - if (this->_alignment < alignment) - this->_alignment = alignment; - - return _atoms.back(); - } -}; - -class ARMTargetLayout : public TargetLayout<ELF32LE> { -public: - enum ARMSectionOrder { - ORDER_ARM_EXIDX = TargetLayout::ORDER_EH_FRAME + 1, - }; - - ARMTargetLayout(ELFLinkingContext &ctx) : TargetLayout(ctx) {} - - SectionOrder getSectionOrder(StringRef name, int32_t contentType, - int32_t contentPermissions) override { - switch (contentType) { - case ARMELFDefinedAtom::typeARMExidx: - return ORDER_ARM_EXIDX; - default: - return TargetLayout::getSectionOrder(name, contentType, - contentPermissions); - } - } - - StringRef getOutputSectionName(StringRef archivePath, StringRef memberPath, - StringRef inputSectionName) const override { - return llvm::StringSwitch<StringRef>(inputSectionName) - .StartsWith(".ARM.exidx", ".ARM.exidx") - .StartsWith(".ARM.extab", ".ARM.extab") - .Default(TargetLayout::getOutputSectionName(archivePath, memberPath, - inputSectionName)); - } - - SegmentType getSegmentType(const Section<ELF32LE> *section) const override { - switch (section->order()) { - case ORDER_ARM_EXIDX: - return llvm::ELF::PT_ARM_EXIDX; - default: - return TargetLayout::getSegmentType(section); - } - } - - AtomSection<ELF32LE> * - createSection(StringRef name, int32_t contentType, - DefinedAtom::ContentPermissions contentPermissions, - SectionOrder sectionOrder) override { - if ((ARMELFDefinedAtom::ARMContentType)contentType == - ARMELFDefinedAtom::typeARMExidx) - return new ARMExidxSection(_ctx, name, contentPermissions, sectionOrder); - - return TargetLayout::createSection(name, contentType, contentPermissions, - sectionOrder); - } - - uint64_t getGOTSymAddr() { - std::call_once(_gotSymOnce, [this]() { - if (AtomLayout *gotAtom = findAbsoluteAtom("_GLOBAL_OFFSET_TABLE_")) - _gotSymAddr = gotAtom->_virtualAddr; - }); - return _gotSymAddr; - } - - uint64_t getTPOffset() { - std::call_once(_tpOffOnce, [this]() { - for (const auto &phdr : *_programHeader) { - if (phdr->p_type == llvm::ELF::PT_TLS) { - _tpOff = llvm::RoundUpToAlignment(TCB_SIZE, phdr->p_align); - break; - } - } - assert(_tpOff != 0 && "TLS segment not found"); - }); - return _tpOff; - } - - bool target1Rel() const { return _ctx.armTarget1Rel(); } - -private: - // TCB block size of the TLS. - enum { TCB_SIZE = 0x8 }; - -private: - uint64_t _gotSymAddr = 0; - uint64_t _tpOff = 0; - std::once_flag _gotSymOnce; - std::once_flag _tpOffOnce; -}; - -class ARMTargetHandler final : public TargetHandler { -public: - ARMTargetHandler(ARMLinkingContext &ctx); - - const TargetRelocationHandler &getRelocationHandler() const override { - return *_relocationHandler; - } - - std::unique_ptr<Reader> getObjReader() override { - return llvm::make_unique<ELFReader<ARMELFFile>>(_ctx); - } - - std::unique_ptr<Reader> getDSOReader() override { - return llvm::make_unique<ELFReader<DynamicFile<ELF32LE>>>(_ctx); - } - - std::unique_ptr<Writer> getWriter() override; - -private: - ARMLinkingContext &_ctx; - std::unique_ptr<ARMTargetLayout> _targetLayout; - std::unique_ptr<ARMTargetRelocationHandler> _relocationHandler; -}; - -} // end namespace elf -} // end namespace lld - -#endif // LLD_READER_WRITER_ELF_ARM_ARM_TARGET_HANDLER_H diff --git a/lib/ReaderWriter/ELF/ARM/CMakeLists.txt b/lib/ReaderWriter/ELF/ARM/CMakeLists.txt deleted file mode 100644 index c8cd6533d902..000000000000 --- a/lib/ReaderWriter/ELF/ARM/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -add_lld_library(lldARMELFTarget - ARMLinkingContext.cpp - ARMTargetHandler.cpp - ARMRelocationHandler.cpp - ARMRelocationPass.cpp - LINK_LIBS - lldELF - lldReaderWriter - lldCore - LLVMObject - LLVMSupport - ) diff --git a/lib/ReaderWriter/ELF/ARM/TODO.rst b/lib/ReaderWriter/ELF/ARM/TODO.rst deleted file mode 100644 index 61b585ae698c..000000000000 --- a/lib/ReaderWriter/ELF/ARM/TODO.rst +++ /dev/null @@ -1,21 +0,0 @@ -ELF ARM -~~~~~~~~~~~ - -Unimplemented Features -###################### - -* DSO linking -* C++ code linking -* PLT entries' generation for images larger than 2^28 bytes (see Sec. A.3 of the ARM ELF reference) -* ARM/Thumb interwork veneers in position-independent code -* .ARM.exidx section (exception handling) -* -init/-fini options -* Proper debug information (DWARF data) -* TLS relocations for dynamic models -* Lots of other relocations - -Unimplemented Relocations -######################### - -All of these relocations are defined in: -http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044e/IHI0044E_aaelf.pdf diff --git a/lib/ReaderWriter/ELF/Atoms.cpp b/lib/ReaderWriter/ELF/Atoms.cpp deleted file mode 100644 index 639633393161..000000000000 --- a/lib/ReaderWriter/ELF/Atoms.cpp +++ /dev/null @@ -1,297 +0,0 @@ -//===- lib/ReaderWriter/ELF/Atoms.cpp -------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Atoms.h" -#include "DynamicFile.h" -#include "ELFFile.h" -#include "TargetHandler.h" - -namespace lld { -namespace elf { - -template <class ELFT> AbsoluteAtom::Scope ELFAbsoluteAtom<ELFT>::scope() const { - if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN) - return scopeLinkageUnit; - if (_symbol->getBinding() == llvm::ELF::STB_LOCAL) - return scopeTranslationUnit; - return scopeGlobal; -} - -template <class ELFT> -UndefinedAtom::CanBeNull ELFUndefinedAtom<ELFT>::canBeNull() const { - if (_symbol->getBinding() == llvm::ELF::STB_WEAK) - return CanBeNull::canBeNullAtBuildtime; - return CanBeNull::canBeNullNever; -} - -template <class ELFT> uint64_t ELFDefinedAtom<ELFT>::size() const { - // Common symbols are not allocated in object files, - // so use st_size to tell how many bytes are required. - if (_symbol && (_symbol->getType() == llvm::ELF::STT_COMMON || - _symbol->st_shndx == llvm::ELF::SHN_COMMON)) - return (uint64_t)_symbol->st_size; - - return _contentData.size(); -} - -template <class ELFT> AbsoluteAtom::Scope ELFDefinedAtom<ELFT>::scope() const { - if (!_symbol) - return scopeGlobal; - if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN) - return scopeLinkageUnit; - if (_symbol->getBinding() != llvm::ELF::STB_LOCAL) - return scopeGlobal; - return scopeTranslationUnit; -} - -template <class ELFT> DefinedAtom::Merge ELFDefinedAtom<ELFT>::merge() const { - if (!_symbol) - return mergeNo; - if (_symbol->getBinding() == llvm::ELF::STB_WEAK) - return mergeAsWeak; - if (_symbol->getType() == llvm::ELF::STT_COMMON || - _symbol->st_shndx == llvm::ELF::SHN_COMMON) - return mergeAsTentative; - return mergeNo; -} - -template <class ELFT> -DefinedAtom::ContentType ELFDefinedAtom<ELFT>::doContentType() const { - using namespace llvm::ELF; - - if (_section->sh_type == SHT_GROUP) - return typeGroupComdat; - if (!_symbol && _sectionName.startswith(".gnu.linkonce")) - return typeGnuLinkOnce; - - uint64_t flags = _section->sh_flags; - - if (!(flags & SHF_ALLOC)) { - if (_section->sh_type == SHT_NOTE) - return (flags == SHF_WRITE) ? typeRWNote : typeRONote; - return _contentType = typeNoAlloc; - } - - if (_section->sh_flags == (SHF_ALLOC | SHF_WRITE | SHF_TLS)) - return _section->sh_type == SHT_NOBITS ? typeThreadZeroFill - : typeThreadData; - - if (_section->sh_flags == SHF_ALLOC && _section->sh_type == SHT_PROGBITS) - return _contentType = typeConstant; - if (_symbol->getType() == STT_GNU_IFUNC) - return _contentType = typeResolver; - if (_symbol->st_shndx == SHN_COMMON) - return _contentType = typeZeroFill; - - if (_section->sh_type == SHT_PROGBITS) { - flags &= ~SHF_ALLOC; - flags &= ~SHF_GROUP; - if ((flags & SHF_STRINGS) || (flags & SHF_MERGE)) - return typeConstant; - if (flags == SHF_WRITE) - return typeData; - return typeCode; - } - if (_section->sh_type == SHT_NOTE) { - flags &= ~SHF_ALLOC; - return (flags == SHF_WRITE) ? typeRWNote : typeRONote; - } - if (_section->sh_type == SHT_NOBITS) - return typeZeroFill; - - if (_section->sh_type == SHT_NULL) - if (_symbol->getType() == STT_COMMON || _symbol->st_shndx == SHN_COMMON) - return typeZeroFill; - - if (_section->sh_type == SHT_INIT_ARRAY || - _section->sh_type == SHT_FINI_ARRAY) - return typeData; - return typeUnknown; -} - -template <class ELFT> -DefinedAtom::ContentType ELFDefinedAtom<ELFT>::contentType() const { - if (_contentType != typeUnknown) - return _contentType; - _contentType = doContentType(); - return _contentType; -} - -template <class ELFT> -DefinedAtom::Alignment ELFDefinedAtom<ELFT>::alignment() const { - if (!_symbol) - return 1; - - // Obtain proper value of st_value field. - const auto symValue = getSymbolValue(); - - // Unallocated common symbols specify their alignment constraints in - // st_value. - if ((_symbol->getType() == llvm::ELF::STT_COMMON) || - _symbol->st_shndx == llvm::ELF::SHN_COMMON) { - return symValue; - } - if (_section->sh_addralign == 0) { - // sh_addralign of 0 means no alignment - return Alignment(1, symValue); - } - return Alignment(_section->sh_addralign, symValue % _section->sh_addralign); -} - -// Do we have a choice for ELF? All symbols live in explicit sections. -template <class ELFT> -DefinedAtom::SectionChoice ELFDefinedAtom<ELFT>::sectionChoice() const { - switch (contentType()) { - case typeCode: - case typeData: - case typeZeroFill: - case typeThreadZeroFill: - case typeThreadData: - case typeConstant: - if ((_sectionName == ".text") || (_sectionName == ".data") || - (_sectionName == ".bss") || (_sectionName == ".rodata") || - (_sectionName == ".tdata") || (_sectionName == ".tbss")) - return sectionBasedOnContent; - default: - break; - } - return sectionCustomRequired; -} - -template <class ELFT> -StringRef ELFDefinedAtom<ELFT>::customSectionName() const { - if ((contentType() == typeZeroFill) || - (_symbol && _symbol->st_shndx == llvm::ELF::SHN_COMMON)) - return ".bss"; - return _sectionName; -} - -template <class ELFT> -DefinedAtom::ContentPermissions ELFDefinedAtom<ELFT>::permissions() const { - if (_permissions != permUnknown) - return _permissions; - - uint64_t flags = _section->sh_flags; - - if (!(flags & llvm::ELF::SHF_ALLOC)) - return _permissions = perm___; - - switch (_section->sh_type) { - // permRW_L is for sections modified by the runtime - // loader. - case llvm::ELF::SHT_REL: - case llvm::ELF::SHT_RELA: - return _permissions = permRW_L; - - case llvm::ELF::SHT_DYNAMIC: - case llvm::ELF::SHT_PROGBITS: - case llvm::ELF::SHT_NOTE: - flags &= ~llvm::ELF::SHF_ALLOC; - flags &= ~llvm::ELF::SHF_GROUP; - switch (flags) { - // Code - case llvm::ELF::SHF_EXECINSTR: - return _permissions = permR_X; - case (llvm::ELF::SHF_WRITE | llvm::ELF::SHF_EXECINSTR): - return _permissions = permRWX; - // Data - case llvm::ELF::SHF_WRITE: - return _permissions = permRW_; - // Strings - case llvm::ELF::SHF_MERGE: - case llvm::ELF::SHF_STRINGS: - return _permissions = permR__; - - default: - if (flags & llvm::ELF::SHF_WRITE) - return _permissions = permRW_; - return _permissions = permR__; - } - - case llvm::ELF::SHT_NOBITS: - return _permissions = permRW_; - - case llvm::ELF::SHT_INIT_ARRAY: - case llvm::ELF::SHT_FINI_ARRAY: - return _permissions = permRW_; - - default: - return _permissions = perm___; - } -} - -template <class ELFT> -DefinedAtom::reference_iterator ELFDefinedAtom<ELFT>::begin() const { - uintptr_t index = _referenceStartIndex; - const void *it = reinterpret_cast<const void *>(index); - return reference_iterator(*this, it); -} - -template <class ELFT> -DefinedAtom::reference_iterator ELFDefinedAtom<ELFT>::end() const { - uintptr_t index = _referenceEndIndex; - const void *it = reinterpret_cast<const void *>(index); - return reference_iterator(*this, it); -} - -template <class ELFT> -const Reference *ELFDefinedAtom<ELFT>::derefIterator(const void *It) const { - uintptr_t index = reinterpret_cast<uintptr_t>(It); - assert(index >= _referenceStartIndex); - assert(index < _referenceEndIndex); - return ((_referenceList)[index]); -} - -template <class ELFT> -void ELFDefinedAtom<ELFT>::incrementIterator(const void *&It) const { - uintptr_t index = reinterpret_cast<uintptr_t>(It); - ++index; - It = reinterpret_cast<const void *>(index); -} - -template <class ELFT> -void ELFDefinedAtom<ELFT>::addReference(ELFReference<ELFT> *reference) { - _referenceList.push_back(reference); - _referenceEndIndex = _referenceList.size(); -} - -template <class ELFT> AbsoluteAtom::Scope ELFDynamicAtom<ELFT>::scope() const { - if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN) - return scopeLinkageUnit; - if (_symbol->getBinding() != llvm::ELF::STB_LOCAL) - return scopeGlobal; - return scopeTranslationUnit; -} - -template <class ELFT> -SharedLibraryAtom::Type ELFDynamicAtom<ELFT>::type() const { - switch (_symbol->getType()) { - case llvm::ELF::STT_FUNC: - case llvm::ELF::STT_GNU_IFUNC: - return Type::Code; - case llvm::ELF::STT_OBJECT: - return Type::Data; - default: - return Type::Unknown; - } -} - -#define INSTANTIATE(klass) \ - template class klass<ELF32LE>; \ - template class klass<ELF32BE>; \ - template class klass<ELF64LE>; \ - template class klass<ELF64BE> - -INSTANTIATE(ELFAbsoluteAtom); -INSTANTIATE(ELFDefinedAtom); -INSTANTIATE(ELFDynamicAtom); -INSTANTIATE(ELFUndefinedAtom); - -} // end namespace elf -} // end namespace lld diff --git a/lib/ReaderWriter/ELF/Atoms.h b/lib/ReaderWriter/ELF/Atoms.h deleted file mode 100644 index 390c0e16baf8..000000000000 --- a/lib/ReaderWriter/ELF/Atoms.h +++ /dev/null @@ -1,493 +0,0 @@ -//===- lib/ReaderWriter/ELF/Atoms.h ---------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_ATOMS_H -#define LLD_READER_WRITER_ELF_ATOMS_H - -#include "TargetHandler.h" -#include "lld/Core/LLVM.h" -#include "lld/Core/Simple.h" -#include "lld/ReaderWriter/ELFLinkingContext.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringSwitch.h" -#include <memory> -#include <vector> - -namespace lld { -namespace elf { -template <class ELFT> class DynamicFile; -template <typename ELFT> class ELFFile; - -/// \brief Relocation References: Defined Atoms may contain references that will -/// need to be patched before the executable is written. -/// -/// Construction of ELFReferences is two pass process. ELFReferences are -/// instantiated while we are iterating over symbol tables to atomize -/// symbols. At that time we only know the index of relocation target symbol -/// (not target atom) about a relocation, so we store the index to -/// ELFREference. In the second pass, ELFReferences are revisited to update -/// target atoms by target symbol indexes. -template <class ELFT> class ELFReference : public Reference { - typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel; - typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela; - typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym; - -public: - ELFReference(const Elf_Rela *rela, uint64_t off, Reference::KindArch arch, - Reference::KindValue relocType, uint32_t idx) - : Reference(Reference::KindNamespace::ELF, arch, relocType), - _targetSymbolIndex(idx), _offsetInAtom(off), _addend(rela->r_addend) {} - - ELFReference(uint64_t off, Reference::KindArch arch, - Reference::KindValue relocType, uint32_t idx) - : Reference(Reference::KindNamespace::ELF, arch, relocType), - _targetSymbolIndex(idx), _offsetInAtom(off) {} - - ELFReference(uint32_t edgeKind) - : Reference(Reference::KindNamespace::all, Reference::KindArch::all, - edgeKind) {} - - uint64_t offsetInAtom() const override { return _offsetInAtom; } - - const Atom *target() const override { return _target; } - - /// \brief The symbol table index that contains the target reference. - uint64_t targetSymbolIndex() const { - return _targetSymbolIndex; - } - - Addend addend() const override { return _addend; } - - virtual void setOffset(uint64_t off) { _offsetInAtom = off; } - - void setAddend(Addend A) override { _addend = A; } - - void setTarget(const Atom *newAtom) override { _target = newAtom; } - -private: - const Atom *_target = nullptr; - uint64_t _targetSymbolIndex = 0; - uint64_t _offsetInAtom = 0; - Addend _addend = 0; -}; - -/// \brief These atoms store symbols that are fixed to a particular address. -/// This atom has no content its address will be used by the writer to fixup -/// references that point to it. -template <class ELFT> class ELFAbsoluteAtom : public AbsoluteAtom { - typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym; - -public: - ELFAbsoluteAtom(const ELFFile<ELFT> &file, StringRef name, - const Elf_Sym *symbol, uint64_t value) - : _owningFile(file), _name(name), _symbol(symbol), _value(value) {} - - const ELFFile<ELFT> &file() const override { return _owningFile; } - Scope scope() const override; - StringRef name() const override { return _name; } - uint64_t value() const override { return _value; } - -private: - const ELFFile<ELFT> &_owningFile; - StringRef _name; - const Elf_Sym *_symbol; - uint64_t _value; -}; - -/// \brief ELFUndefinedAtom: These atoms store undefined symbols and are place -/// holders that will be replaced by defined atoms later in the linking process. -template <class ELFT> class ELFUndefinedAtom : public UndefinedAtom { - typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym; - -public: - ELFUndefinedAtom(const File &file, StringRef name, const Elf_Sym *symbol) - : _owningFile(file), _name(name), _symbol(symbol) {} - - const File &file() const override { return _owningFile; } - StringRef name() const override { return _name; } - - // A symbol in ELF can be undefined at build time if the symbol is a undefined - // weak symbol. - CanBeNull canBeNull() const override; - -private: - const File &_owningFile; - StringRef _name; - const Elf_Sym *_symbol; -}; - -/// \brief This atom stores defined symbols and will contain either data or -/// code. -template <class ELFT> class ELFDefinedAtom : public DefinedAtom { - typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym; - typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr; - -public: - ELFDefinedAtom(const ELFFile<ELFT> &file, StringRef symbolName, - StringRef sectionName, const Elf_Sym *symbol, - const Elf_Shdr *section, ArrayRef<uint8_t> contentData, - unsigned int referenceStart, unsigned int referenceEnd, - std::vector<ELFReference<ELFT> *> &referenceList) - : _owningFile(file), _symbolName(symbolName), _sectionName(sectionName), - _symbol(symbol), _section(section), _contentData(contentData), - _referenceStartIndex(referenceStart), _referenceEndIndex(referenceEnd), - _referenceList(referenceList), _contentType(typeUnknown), - _permissions(permUnknown) {} - - ~ELFDefinedAtom() override = default; - - const ELFFile<ELFT> &file() const override { return _owningFile; } - StringRef name() const override { return _symbolName; } - uint64_t ordinal() const override { return _ordinal; } - const Elf_Sym *symbol() const { return _symbol; } - const Elf_Shdr *section() const { return _section; } - uint64_t size() const override; - Scope scope() const override; - - // FIXME: Need to revisit this in future. - Interposable interposable() const override { return interposeNo; } - - Merge merge() const override; - ContentType contentType() const override; - Alignment alignment() const override; - SectionChoice sectionChoice() const override; - StringRef customSectionName() const override; - - // It isn't clear that __attribute__((used)) is transmitted to the ELF object - // file. - DeadStripKind deadStrip() const override { return deadStripNormal; } - - ContentPermissions permissions() const override; - ArrayRef<uint8_t> rawContent() const override { return _contentData; } - - DefinedAtom::reference_iterator begin() const override; - DefinedAtom::reference_iterator end() const override; - const Reference *derefIterator(const void *It) const override; - void incrementIterator(const void *&It) const override; - void addReference(ELFReference<ELFT> *reference); - - virtual void setOrdinal(uint64_t ord) { _ordinal = ord; } - -protected: - /// Returns correct st_value for the symbol depending on the architecture. - /// For most architectures it's just a regular st_value with no changes. - virtual uint64_t getSymbolValue() const { - return _symbol->st_value; - } - - ContentType doContentType() const; - - const ELFFile<ELFT> &_owningFile; - StringRef _symbolName; - StringRef _sectionName; - const Elf_Sym *_symbol; - const Elf_Shdr *_section; - /// \brief Holds the bits that make up the atom. - ArrayRef<uint8_t> _contentData; - - uint64_t _ordinal; - unsigned int _referenceStartIndex; - unsigned int _referenceEndIndex; - std::vector<ELFReference<ELFT> *> &_referenceList; - mutable ContentType _contentType; - mutable ContentPermissions _permissions; -}; - -/// \brief This atom stores mergeable Strings -template <class ELFT> class ELFMergeAtom : public DefinedAtom { - typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr; - -public: - ELFMergeAtom(const ELFFile<ELFT> &file, StringRef sectionName, - const Elf_Shdr *section, ArrayRef<uint8_t> contentData, - uint64_t offset) - : _owningFile(file), _sectionName(sectionName), _section(section), - _contentData(contentData), _offset(offset) { - } - - const ELFFile<ELFT> &file() const override { return _owningFile; } - StringRef name() const override { return ""; } - virtual uint64_t section() const { return _section->sh_name; } - virtual uint64_t offset() const { return _offset; } - virtual void setOrdinal(uint64_t ord) { _ordinal = ord; } - uint64_t ordinal() const override { return _ordinal; } - uint64_t size() const override { return _contentData.size(); } - Scope scope() const override { return scopeTranslationUnit; } - Interposable interposable() const override { return interposeNo; } - Merge merge() const override { return mergeByContent; } - ContentType contentType() const override { return typeConstant; } - - Alignment alignment() const override { - return Alignment(_section->sh_addralign); - } - - SectionChoice sectionChoice() const override { return sectionCustomRequired; } - StringRef customSectionName() const override { return _sectionName; } - DeadStripKind deadStrip() const override { return deadStripNormal; } - ContentPermissions permissions() const override { return permR__; } - ArrayRef<uint8_t> rawContent() const override { return _contentData; } - - DefinedAtom::reference_iterator begin() const override { - uintptr_t index = 0; - const void *it = reinterpret_cast<const void *>(index); - return reference_iterator(*this, it); - } - - DefinedAtom::reference_iterator end() const override { - uintptr_t index = 0; - const void *it = reinterpret_cast<const void *>(index); - return reference_iterator(*this, it); - } - - const Reference *derefIterator(const void *It) const override { - return nullptr; - } - - void incrementIterator(const void *&It) const override {} - -private: - const ELFFile<ELFT> &_owningFile; - StringRef _sectionName; - const Elf_Shdr *_section; - /// \brief Holds the bits that make up the atom. - ArrayRef<uint8_t> _contentData; - uint64_t _ordinal; - uint64_t _offset; -}; - -template <class ELFT> class ELFCommonAtom : public DefinedAtom { - typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym; -public: - ELFCommonAtom(const ELFFile<ELFT> &file, StringRef symbolName, - const Elf_Sym *symbol) - : _owningFile(file), _symbolName(symbolName), _symbol(symbol) {} - - const ELFFile<ELFT> &file() const override { return _owningFile; } - StringRef name() const override { return _symbolName; } - uint64_t ordinal() const override { return _ordinal; } - virtual void setOrdinal(uint64_t ord) { _ordinal = ord; } - uint64_t size() const override { return _symbol->st_size; } - - Scope scope() const override { - if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN) - return scopeLinkageUnit; - if (_symbol->getBinding() != llvm::ELF::STB_LOCAL) - return scopeGlobal; - return scopeTranslationUnit; - } - - Interposable interposable() const override { return interposeNo; } - Merge merge() const override { return mergeAsTentative; } - ContentType contentType() const override { return typeZeroFill; } - Alignment alignment() const override { return Alignment(_symbol->st_value); } - SectionChoice sectionChoice() const override { return sectionBasedOnContent; } - StringRef customSectionName() const override { return ".bss"; } - DeadStripKind deadStrip() const override { return deadStripNormal; } - ContentPermissions permissions() const override { return permRW_; } - ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); } - - DefinedAtom::reference_iterator begin() const override { - uintptr_t index = 0; - const void *it = reinterpret_cast<const void *>(index); - return reference_iterator(*this, it); - } - - DefinedAtom::reference_iterator end() const override { - uintptr_t index = 0; - const void *it = reinterpret_cast<const void *>(index); - return reference_iterator(*this, it); - } - -protected: - const Reference *derefIterator(const void *iter) const override { - return nullptr; - } - - void incrementIterator(const void *&iter) const override {} - - const ELFFile<ELFT> &_owningFile; - StringRef _symbolName; - const Elf_Sym *_symbol; - uint64_t _ordinal; -}; - -/// \brief An atom from a shared library. -template <class ELFT> class ELFDynamicAtom : public SharedLibraryAtom { - typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym; - -public: - ELFDynamicAtom(const DynamicFile<ELFT> &file, StringRef symbolName, - StringRef loadName, const Elf_Sym *symbol) - : _owningFile(file), _symbolName(symbolName), _loadName(loadName), - _symbol(symbol) {} - - const DynamicFile<ELFT> &file() const override { return _owningFile; } - StringRef name() const override { return _symbolName; } - virtual Scope scope() const; - StringRef loadName() const override { return _loadName; } - - bool canBeNullAtRuntime() const override { - return _symbol->getBinding() == llvm::ELF::STB_WEAK; - } - - Type type() const override; - uint64_t size() const override { return _symbol->st_size; } - -private: - - const DynamicFile<ELFT> &_owningFile; - StringRef _symbolName; - StringRef _loadName; - const Elf_Sym *_symbol; -}; - -class SimpleELFDefinedAtom : public SimpleDefinedAtom { -public: - SimpleELFDefinedAtom(const File &f) : SimpleDefinedAtom(f) {} - - void addReferenceELF(Reference::KindArch arch, Reference::KindValue kindValue, - uint64_t off, const Atom *t, Reference::Addend a) { - addReference(Reference::KindNamespace::ELF, arch, kindValue, off, t, a); - } - - void addReferenceELF_Hexagon(Reference::KindValue relocType, uint64_t off, - const Atom *t, Reference::Addend a) { - addReferenceELF(Reference::KindArch::Hexagon, relocType, off, t, a); - } - - void addReferenceELF_x86_64(Reference::KindValue relocType, uint64_t off, - const Atom *t, Reference::Addend a) { - addReferenceELF(Reference::KindArch::x86_64, relocType, off, t, a); - } - - void addReferenceELF_Mips(Reference::KindValue relocType, uint64_t off, - const Atom *t, Reference::Addend a) { - addReferenceELF(Reference::KindArch::Mips, relocType, off, t, a); - } - - void addReferenceELF_AArch64(Reference::KindValue relocType, uint64_t off, - const Atom *t, Reference::Addend a) { - addReferenceELF(Reference::KindArch::AArch64, relocType, off, t, a); - } - - void addReferenceELF_ARM(Reference::KindValue relocType, uint64_t off, - const Atom *t, Reference::Addend a) { - addReferenceELF(Reference::KindArch::ARM, relocType, off, t, a); - } -}; - -/// \brief Atom which represents an object for which a COPY relocation will be -/// generated. -class ObjectAtom : public SimpleELFDefinedAtom { -public: - ObjectAtom(const File &f) : SimpleELFDefinedAtom(f) {} - Scope scope() const override { return scopeGlobal; } - SectionChoice sectionChoice() const override { return sectionBasedOnContent; } - ContentType contentType() const override { return typeZeroFill; } - uint64_t size() const override { return _size; } - DynamicExport dynamicExport() const override { return dynamicExportAlways; } - ContentPermissions permissions() const override { return permRW_; } - ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); } - Alignment alignment() const override { return 8; } - StringRef name() const override { return _name; } - - std::string _name; - uint64_t _size; -}; - -class GOTAtom : public SimpleELFDefinedAtom { - StringRef _section; - -public: - GOTAtom(const File &f, StringRef secName) - : SimpleELFDefinedAtom(f), _section(secName) {} - - Scope scope() const override { return scopeTranslationUnit; } - SectionChoice sectionChoice() const override { return sectionCustomRequired; } - StringRef customSectionName() const override { return _section; } - ContentType contentType() const override { return typeGOT; } - uint64_t size() const override { return rawContent().size(); } - ContentPermissions permissions() const override { return permRW_; } - Alignment alignment() const override { return 8; } - -#ifndef NDEBUG - StringRef name() const override { return _name; } - std::string _name; -#else - StringRef name() const override { return ""; } -#endif -}; - -class PLTAtom : public SimpleELFDefinedAtom { - StringRef _section; - -public: - PLTAtom(const File &f, StringRef secName) - : SimpleELFDefinedAtom(f), _section(secName) {} - - Scope scope() const override { return scopeTranslationUnit; } - SectionChoice sectionChoice() const override { return sectionCustomRequired; } - StringRef customSectionName() const override { return _section; } - ContentType contentType() const override { return typeStub; } - uint64_t size() const override { return rawContent().size(); } - ContentPermissions permissions() const override { return permR_X; } - Alignment alignment() const override { return 16; } - -#ifndef NDEBUG - StringRef name() const override { return _name; } - std::string _name; -#else - StringRef name() const override { return ""; } -#endif -}; - -class PLT0Atom : public PLTAtom { -public: - PLT0Atom(const File &f) : PLTAtom(f, ".plt") { -#ifndef NDEBUG - _name = ".PLT0"; -#endif - } -}; - -class GlobalOffsetTableAtom : public SimpleELFDefinedAtom { -public: - GlobalOffsetTableAtom(const File &f) : SimpleELFDefinedAtom(f) {} - - StringRef name() const override { return "_GLOBAL_OFFSET_TABLE_"; } - Scope scope() const override { return scopeLinkageUnit; } - SectionChoice sectionChoice() const override { return sectionCustomRequired; } - StringRef customSectionName() const override { return ".got.plt"; } - ContentType contentType() const override { return typeGOT; } - uint64_t size() const override { return 0; } - ContentPermissions permissions() const override { return permRW_; } - Alignment alignment() const override { return 8; } - ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); } -}; - -class DynamicAtom : public SimpleELFDefinedAtom { -public: - DynamicAtom(const File &f) : SimpleELFDefinedAtom(f) {} - - StringRef name() const override { return "_DYNAMIC"; } - Scope scope() const override { return scopeLinkageUnit; } - Merge merge() const override { return mergeNo; } - SectionChoice sectionChoice() const override { return sectionCustomRequired; } - StringRef customSectionName() const override { return ".dynamic"; } - ContentType contentType() const override { return typeData; } - uint64_t size() const override { return 0; } - ContentPermissions permissions() const override { return permRW_; } - Alignment alignment() const override { return 1; } - ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); } -}; - -} // end namespace elf -} // end namespace lld - -#endif // LLD_READER_WRITER_ELF_ATOMS_H diff --git a/lib/ReaderWriter/ELF/CMakeLists.txt b/lib/ReaderWriter/ELF/CMakeLists.txt deleted file mode 100644 index 3bc338507db6..000000000000 --- a/lib/ReaderWriter/ELF/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -add_lld_library(lldELF - Atoms.cpp - DynamicFile.cpp - ELFFile.cpp - ELFLinkingContext.cpp - FileCommon.cpp - HeaderChunks.cpp - OutputELFWriter.cpp - Reader.cpp - SectionChunks.cpp - SegmentChunks.cpp - TargetLayout.cpp - Writer.cpp - LINK_LIBS - lldReaderWriter - lldCore - lldYAML - LLVMObject - LLVMSupport - ) - -include_directories(.) - -add_subdirectory(X86) -add_subdirectory(X86_64) -add_subdirectory(Mips) -add_subdirectory(Hexagon) -add_subdirectory(AArch64) -add_subdirectory(ARM) diff --git a/lib/ReaderWriter/ELF/Chunk.h b/lib/ReaderWriter/ELF/Chunk.h deleted file mode 100644 index f223b6c54163..000000000000 --- a/lib/ReaderWriter/ELF/Chunk.h +++ /dev/null @@ -1,111 +0,0 @@ -//===- lib/ReaderWriter/ELF/Chunks.h --------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_CHUNKS_H -#define LLD_READER_WRITER_ELF_CHUNKS_H - -#include "lld/Core/LLVM.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Object/ELF.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/ELF.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/FileOutputBuffer.h" -#include <memory> - -namespace lld { -class ELFLinkingContext; - -namespace elf { -class ELFWriter; -template <class ELFT> class TargetLayout; - -/// \brief A chunk is a contiguous region of space -template <class ELFT> class Chunk { -public: - /// \brief Describes the type of Chunk - enum Kind : uint8_t { - ELFHeader, ///< ELF Header - ProgramHeader, ///< Program Header - SectionHeader, ///< Section header - ELFSegment, ///< Segment - ELFSection, ///< Section - AtomSection, ///< A section containing atoms - Expression ///< A linker script expression - }; - - /// \brief the ContentType of the chunk - enum ContentType : uint8_t { Unknown, Header, Code, Data, Note, TLS }; - - Chunk(StringRef name, Kind kind, const ELFLinkingContext &ctx) - : _name(name), _kind(kind), _ctx(ctx) {} - - virtual ~Chunk() {} - - // The name of the chunk - StringRef name() const { return _name; } - - // Kind of chunk - Kind kind() const { return _kind; } - virtual uint64_t fileSize() const { return _fsize; } - virtual void setFileSize(uint64_t sz) { _fsize = sz; } - virtual void setAlign(uint64_t align) { _alignment = align; } - virtual uint64_t alignment() const { return _alignment; } - - // The ordinal value of the chunk - uint64_t ordinal() const { return _ordinal; } - void setOrdinal(uint64_t newVal) { _ordinal = newVal; } - - // The order in which the chunk would appear in the output file - uint64_t order() const { return _order; } - void setOrder(uint32_t order) { _order = order; } - - // Output file offset of the chunk - uint64_t fileOffset() const { return _fileoffset; } - void setFileOffset(uint64_t offset) { _fileoffset = offset; } - - // Output start address of the chunk - virtual void setVirtualAddr(uint64_t start) { _start = start; } - virtual uint64_t virtualAddr() const { return _start; } - - // Memory size of the chunk - uint64_t memSize() const { return _msize; } - void setMemSize(uint64_t msize) { _msize = msize; } - - // Returns the ContentType of the chunk - virtual int getContentType() const = 0; - - // Writer the chunk - virtual void write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) = 0; - - // Finalize the chunk before assigning offsets/virtual addresses - virtual void doPreFlight() {} - - // Finalize the chunk before writing - virtual void finalize() {} - -protected: - StringRef _name; - Kind _kind; - const ELFLinkingContext &_ctx; - uint64_t _fsize = 0; - uint64_t _msize = 0; - uint64_t _alignment = 1; - uint32_t _order = 0; - uint64_t _ordinal = 1; - uint64_t _start = 0; - uint64_t _fileoffset = 0; -}; - -} // end namespace elf -} // end namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/DynamicFile.cpp b/lib/ReaderWriter/ELF/DynamicFile.cpp deleted file mode 100644 index 5339c7d66577..000000000000 --- a/lib/ReaderWriter/ELF/DynamicFile.cpp +++ /dev/null @@ -1,146 +0,0 @@ -//===- lib/ReaderWriter/ELF/DynamicFile.cpp -------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "DynamicFile.h" -#include "FileCommon.h" -#include "lld/ReaderWriter/ELFLinkingContext.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/Object/ELF.h" -#include "llvm/Support/Path.h" - -namespace lld { -namespace elf { - -template <class ELFT> -DynamicFile<ELFT>::DynamicFile(std::unique_ptr<MemoryBuffer> mb, - ELFLinkingContext &ctx) - : SharedLibraryFile(mb->getBufferIdentifier()), _mb(std::move(mb)), - _ctx(ctx), _useShlibUndefines(ctx.useShlibUndefines()) {} - -template <typename ELFT> -std::error_code DynamicFile<ELFT>::isCompatible(MemoryBufferRef mb, - ELFLinkingContext &ctx) { - return elf::isCompatible<ELFT>(mb, ctx); -} - -template <class ELFT> -const SharedLibraryAtom *DynamicFile<ELFT>::exports(StringRef name, - bool dataSymbolOnly) const { - assert(!dataSymbolOnly && "Invalid option for ELF exports!"); - // See if we have the symbol. - auto sym = _nameToSym.find(name); - if (sym == _nameToSym.end()) - return nullptr; - // Have we already created a SharedLibraryAtom for it? - if (sym->second._atom) - return sym->second._atom; - // Create a SharedLibraryAtom for this symbol. - return sym->second._atom = new (_alloc) - ELFDynamicAtom<ELFT>(*this, name, _soname, sym->second._symbol); -} - -template <class ELFT> StringRef DynamicFile<ELFT>::getDSOName() const { - return _soname; -} - -template <class ELFT> bool DynamicFile<ELFT>::canParse(file_magic magic) { - return magic == file_magic::elf_shared_object; -} - -template <class ELFT> std::error_code DynamicFile<ELFT>::doParse() { - typedef llvm::object::ELFFile<ELFT> ELFO; - typedef typename ELFO::Elf_Shdr Elf_Shdr; - typedef typename ELFO::Elf_Dyn Elf_Dyn; - - std::error_code ec; - _objFile.reset(new ELFO(_mb->getBuffer(), ec)); - if (ec) - return ec; - - ELFO &obj = *_objFile; - - const char *base = _mb->getBuffer().data(); - const Elf_Dyn *dynStart = nullptr; - const Elf_Dyn *dynEnd = nullptr; - - const Elf_Shdr *dynSymSec = nullptr; - for (const Elf_Shdr &sec : obj.sections()) { - switch (sec.sh_type) { - case llvm::ELF::SHT_DYNAMIC: { - dynStart = reinterpret_cast<const Elf_Dyn *>(base + sec.sh_offset); - uint64_t size = sec.sh_size; - if (size % sizeof(Elf_Dyn)) - return llvm::object::object_error::parse_failed; - dynEnd = dynStart + size / sizeof(Elf_Dyn); - break; - } - case llvm::ELF::SHT_DYNSYM: - dynSymSec = &sec; - break; - } - } - - ErrorOr<StringRef> strTableOrErr = obj.getStringTableForSymtab(*dynSymSec); - if (std::error_code ec = strTableOrErr.getError()) - return ec; - StringRef stringTable = *strTableOrErr; - - for (const Elf_Dyn &dyn : llvm::make_range(dynStart, dynEnd)) { - if (dyn.d_tag == llvm::ELF::DT_SONAME) { - uint64_t offset = dyn.getVal(); - if (offset >= stringTable.size()) - return llvm::object::object_error::parse_failed; - _soname = StringRef(stringTable.data() + offset); - break; - } - } - - if (_soname.empty()) - _soname = llvm::sys::path::filename(path()); - - // Create a map from names to dynamic symbol table entries. - // TODO: This should use the object file's build in hash table instead if - // it exists. - for (auto i = obj.symbol_begin(dynSymSec), e = obj.symbol_end(dynSymSec); - i != e; ++i) { - auto name = i->getName(stringTable); - if ((ec = name.getError())) - return ec; - - // Dont add local symbols to dynamic entries. The first symbol in the - // dynamic symbol table is a local symbol. - if (i->getBinding() == llvm::ELF::STB_LOCAL) - continue; - - // TODO: Add absolute symbols - if (i->st_shndx == llvm::ELF::SHN_ABS) - continue; - - if (i->st_shndx == llvm::ELF::SHN_UNDEF) { - if (!_useShlibUndefines) - continue; - // Create an undefined atom. - if (!name->empty()) { - auto *newAtom = new (_alloc) ELFUndefinedAtom<ELFT>(*this, *name, &*i); - _undefinedAtoms.push_back(newAtom); - } - continue; - } - _nameToSym[*name]._symbol = &*i; - } - return std::error_code(); -} - -template class DynamicFile<ELF32LE>; -template class DynamicFile<ELF32BE>; -template class DynamicFile<ELF64LE>; -template class DynamicFile<ELF64BE>; - -} // end namespace elf -} // end namespace lld diff --git a/lib/ReaderWriter/ELF/DynamicFile.h b/lib/ReaderWriter/ELF/DynamicFile.h deleted file mode 100644 index a155900de781..000000000000 --- a/lib/ReaderWriter/ELF/DynamicFile.h +++ /dev/null @@ -1,59 +0,0 @@ -//===- lib/ReaderWriter/ELF/DynamicFile.h ---------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_DYNAMIC_FILE_H -#define LLD_READER_WRITER_ELF_DYNAMIC_FILE_H - -#include "Atoms.h" -#include "lld/Core/SharedLibraryFile.h" -#include <unordered_map> - -namespace lld { -class ELFLinkingContext; - -namespace elf { - -template <class ELFT> class DynamicFile : public SharedLibraryFile { -public: - DynamicFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx); - - static std::error_code isCompatible(MemoryBufferRef mb, - ELFLinkingContext &ctx); - - const SharedLibraryAtom *exports(StringRef name, - bool dataSymbolOnly) const override; - - StringRef getDSOName() const override; - - static bool canParse(file_magic magic); - -protected: - std::error_code doParse() override; - -private: - mutable llvm::BumpPtrAllocator _alloc; - std::unique_ptr<llvm::object::ELFFile<ELFT>> _objFile; - /// \brief DT_SONAME - StringRef _soname; - - struct SymAtomPair { - const typename llvm::object::ELFFile<ELFT>::Elf_Sym *_symbol = nullptr; - const SharedLibraryAtom *_atom = nullptr; - }; - - std::unique_ptr<MemoryBuffer> _mb; - ELFLinkingContext &_ctx; - bool _useShlibUndefines; - mutable std::unordered_map<StringRef, SymAtomPair> _nameToSym; -}; - -} // end namespace elf -} // end namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/DynamicLibraryWriter.h b/lib/ReaderWriter/ELF/DynamicLibraryWriter.h deleted file mode 100644 index 5f2c1d1a8288..000000000000 --- a/lib/ReaderWriter/ELF/DynamicLibraryWriter.h +++ /dev/null @@ -1,86 +0,0 @@ -//===- lib/ReaderWriter/ELF/DynamicLibraryWriter.h ------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef LLD_READER_WRITER_ELF_DYNAMIC_LIBRARY_WRITER_H -#define LLD_READER_WRITER_ELF_DYNAMIC_LIBRARY_WRITER_H - -#include "OutputELFWriter.h" - -namespace lld { -namespace elf { -using namespace llvm; -using namespace llvm::object; - -//===----------------------------------------------------------------------===// -// DynamicLibraryWriter Class -//===----------------------------------------------------------------------===// -template<class ELFT> -class DynamicLibraryWriter : public OutputELFWriter<ELFT> { -public: - DynamicLibraryWriter(ELFLinkingContext &ctx, TargetLayout<ELFT> &layout) - : OutputELFWriter<ELFT>(ctx, layout) {} - -protected: - void buildDynamicSymbolTable(const File &file) override; - void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override; - void finalizeDefaultAtomValues() override; -}; - -//===----------------------------------------------------------------------===// -// DynamicLibraryWriter -//===----------------------------------------------------------------------===// -template <class ELFT> -void DynamicLibraryWriter<ELFT>::buildDynamicSymbolTable(const File &file) { - // Add all the defined symbols to the dynamic symbol table - // we need hooks into the Atom to find out which atoms need - // to be exported - for (auto sec : this->_layout.sections()) - if (auto section = dyn_cast<AtomSection<ELFT>>(sec)) - for (const auto &atom : section->atoms()) { - const DefinedAtom *da = dyn_cast<const DefinedAtom>(atom->_atom); - if (da && (da->scope() == DefinedAtom::scopeGlobal)) - this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(), - atom->_virtualAddr, atom); - } - - for (const UndefinedAtom *a : file.undefined()) - this->_dynamicSymbolTable->addSymbol(a, ELF::SHN_UNDEF); - - OutputELFWriter<ELFT>::buildDynamicSymbolTable(file); -} - -/// \brief Hook in lld to add CRuntime file -template <class ELFT> -void DynamicLibraryWriter<ELFT>::createImplicitFiles( - std::vector<std::unique_ptr<File> > &result) { - OutputELFWriter<ELFT>::createImplicitFiles(result); - // Add the default atoms as defined by executables - auto file = llvm::make_unique<RuntimeFile<ELFT>>(this->_ctx, "C runtime"); - file->addAbsoluteAtom("_end"); - result.push_back(std::move(file)); -} - -template <class ELFT> -void DynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues() { - OutputELFWriter<ELFT>::finalizeDefaultAtomValues(); - AtomLayout *underScoreEndAtom = this->_layout.findAbsoluteAtom("_end"); - assert(underScoreEndAtom); - - if (auto bssSection = this->_layout.findOutputSection(".bss")) { - underScoreEndAtom->_virtualAddr = - bssSection->virtualAddr() + bssSection->memSize(); - } else if (auto dataSection = this->_layout.findOutputSection(".data")) { - underScoreEndAtom->_virtualAddr = - dataSection->virtualAddr() + dataSection->memSize(); - } -} - -} // namespace elf -} // namespace lld - -#endif // LLD_READER_WRITER_ELF_DYNAMIC_LIBRARY_WRITER_H diff --git a/lib/ReaderWriter/ELF/ELFFile.cpp b/lib/ReaderWriter/ELF/ELFFile.cpp deleted file mode 100644 index 1488f1862b8d..000000000000 --- a/lib/ReaderWriter/ELF/ELFFile.cpp +++ /dev/null @@ -1,829 +0,0 @@ -//===- lib/ReaderWriter/ELF/ELFFile.cpp -------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "ELFFile.h" -#include "FileCommon.h" -#include "llvm/ADT/STLExtras.h" - -namespace lld { -namespace elf { - -template <typename ELFT> -ELFFile<ELFT>::ELFFile(StringRef name, ELFLinkingContext &ctx) - : SimpleFile(name), _ordinal(0), _doStringsMerge(ctx.mergeCommonStrings()), - _useWrap(false), _ctx(ctx) { - setLastError(std::error_code()); -} - -template <typename ELFT> -ELFFile<ELFT>::ELFFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx) - : SimpleFile(mb->getBufferIdentifier()), _mb(std::move(mb)), _ordinal(0), - _doStringsMerge(ctx.mergeCommonStrings()), - _useWrap(ctx.wrapCalls().size()), _ctx(ctx) {} - -template <typename ELFT> -std::error_code ELFFile<ELFT>::isCompatible(MemoryBufferRef mb, - ELFLinkingContext &ctx) { - return elf::isCompatible<ELFT>(mb, ctx); -} - -template <typename ELFT> -Atom *ELFFile<ELFT>::findAtom(const Elf_Sym *sourceSym, - const Elf_Sym *targetSym) { - // Return the atom for targetSym if we can do so. - Atom *target = _symbolToAtomMapping.lookup(targetSym); - if (!target) - // Some realocations (R_ARM_V4BX) do not have a defined - // target. For this cases make it points to itself. - target = _symbolToAtomMapping.lookup(sourceSym); - - if (target->definition() != Atom::definitionRegular) - return target; - Atom::Scope scope = llvm::cast<DefinedAtom>(target)->scope(); - if (scope == DefinedAtom::scopeTranslationUnit) - return target; - if (!redirectReferenceUsingUndefAtom(sourceSym, targetSym)) - return target; - - // Otherwise, create a new undefined symbol and returns it. - StringRef targetName = target->name(); - auto it = _undefAtomsForGroupChild.find(targetName); - if (it != _undefAtomsForGroupChild.end()) - return it->getValue(); - auto atom = new (_readerStorage) SimpleUndefinedAtom(*this, targetName); - _undefAtomsForGroupChild[targetName] = atom; - addAtom(*atom); - return atom; -} - -template <typename ELFT> -ErrorOr<StringRef> ELFFile<ELFT>::getSectionName(const Elf_Shdr *shdr) const { - if (!shdr) - return StringRef(); - return _objFile->getSectionName(shdr); -} - -template <class ELFT> std::error_code ELFFile<ELFT>::doParse() { - std::error_code ec; - _objFile.reset(new llvm::object::ELFFile<ELFT>(_mb->getBuffer(), ec)); - if (ec) - return ec; - - if ((ec = createAtomsFromContext())) - return ec; - - // Read input sections from the input file that need to be converted to - // atoms - if ((ec = createAtomizableSections())) - return ec; - - // For mergeable strings, we would need to split the section into various - // atoms - if ((ec = createMergeableAtoms())) - return ec; - - // Create the necessary symbols that are part of the section that we - // created in createAtomizableSections function - if ((ec = createSymbolsFromAtomizableSections())) - return ec; - - // Create the appropriate atoms from the file - if ((ec = createAtoms())) - return ec; - return std::error_code(); -} - -template <class ELFT> Reference::KindArch ELFFile<ELFT>::kindArch() { - switch (_objFile->getHeader()->e_machine) { - case llvm::ELF::EM_X86_64: - return Reference::KindArch::x86_64; - case llvm::ELF::EM_386: - return Reference::KindArch::x86; - case llvm::ELF::EM_ARM: - return Reference::KindArch::ARM; - case llvm::ELF::EM_HEXAGON: - return Reference::KindArch::Hexagon; - case llvm::ELF::EM_MIPS: - return Reference::KindArch::Mips; - case llvm::ELF::EM_AARCH64: - return Reference::KindArch::AArch64; - } - llvm_unreachable("unsupported e_machine value"); -} - -template <class ELFT> -std::error_code ELFFile<ELFT>::createAtomizableSections() { - // Handle: SHT_REL and SHT_RELA sections: - // Increment over the sections, when REL/RELA section types are found add - // the contents to the RelocationReferences map. - // Record the number of relocs to guess at preallocating the buffer. - uint64_t totalRelocs = 0; - for (const Elf_Shdr §ion : _objFile->sections()) { - switch (section.sh_type) { - case llvm::ELF::SHT_SYMTAB: - _symtab = §ion; - continue; - case llvm::ELF::SHT_SYMTAB_SHNDX: { - ErrorOr<ArrayRef<Elf_Word>> tableOrErr = _objFile->getSHNDXTable(section); - if (std::error_code ec = tableOrErr.getError()) - return ec; - _shndxTable = *tableOrErr; - continue; - } - } - - if (isIgnoredSection(§ion)) - continue; - - if (isMergeableStringSection(§ion)) { - _mergeStringSections.push_back(§ion); - continue; - } - - if (section.sh_type == llvm::ELF::SHT_RELA) { - auto sHdrOrErr = _objFile->getSection(section.sh_info); - if (std::error_code ec = sHdrOrErr.getError()) - return ec; - auto sHdr = *sHdrOrErr; - auto rai = _objFile->rela_begin(§ion); - auto rae = _objFile->rela_end(§ion); - _relocationAddendReferences[sHdr] = make_range(rai, rae); - totalRelocs += std::distance(rai, rae); - } else if (section.sh_type == llvm::ELF::SHT_REL) { - auto sHdrOrErr = _objFile->getSection(section.sh_info); - if (std::error_code ec = sHdrOrErr.getError()) - return ec; - auto sHdr = *sHdrOrErr; - auto ri = _objFile->rel_begin(§ion); - auto re = _objFile->rel_end(§ion); - _relocationReferences[sHdr] = §ion; - totalRelocs += std::distance(ri, re); - } else { - auto sectionName = _objFile->getSectionName(§ion); - if (std::error_code ec = sectionName.getError()) - return ec; - _ctx.notifyInputSectionName(*sectionName); - _sectionSymbols[§ion]; - } - } - _references.reserve(totalRelocs); - return std::error_code(); -} - -template <class ELFT> std::error_code ELFFile<ELFT>::createMergeableAtoms() { - // Divide the section that contains mergeable strings into tokens - // TODO - // a) add resolver support to recognize multibyte chars - // b) Create a separate section chunk to write mergeable atoms - std::vector<MergeString *> tokens; - for (const Elf_Shdr *msi : _mergeStringSections) { - auto sectionName = getSectionName(msi); - if (std::error_code ec = sectionName.getError()) - return ec; - - auto sectionContents = getSectionContents(msi); - if (std::error_code ec = sectionContents.getError()) - return ec; - - StringRef secCont(reinterpret_cast<const char *>(sectionContents->begin()), - sectionContents->size()); - - unsigned int prev = 0; - for (std::size_t i = 0, e = sectionContents->size(); i != e; ++i) { - if ((*sectionContents)[i] == '\0') { - tokens.push_back(new (_readerStorage) MergeString( - prev, secCont.slice(prev, i + 1), msi, *sectionName)); - prev = i + 1; - } - } - } - - // Create Mergeable atoms - for (const MergeString *tai : tokens) { - ArrayRef<uint8_t> content((const uint8_t *)tai->_string.data(), - tai->_string.size()); - ELFMergeAtom<ELFT> *atom = createMergedString(tai->_sectionName, tai->_shdr, - content, tai->_offset); - atom->setOrdinal(++_ordinal); - addAtom(*atom); - _mergeAtoms.push_back(atom); - } - return std::error_code(); -} - -template <class ELFT> -std::error_code ELFFile<ELFT>::createSymbolsFromAtomizableSections() { - // Increment over all the symbols collecting atoms and symbol names for - // later use. - if (!_symtab) - return std::error_code(); - - ErrorOr<StringRef> strTableOrErr = - _objFile->getStringTableForSymtab(*_symtab); - if (std::error_code ec = strTableOrErr.getError()) - return ec; - StringRef strTable = *strTableOrErr; - - auto SymI = _objFile->symbol_begin(_symtab), - SymE = _objFile->symbol_end(_symtab); - // Skip over dummy sym. - ++SymI; - - for (; SymI != SymE; ++SymI) { - ErrorOr<const Elf_Shdr *> section = - _objFile->getSection(SymI, _symtab, _shndxTable); - if (std::error_code ec = section.getError()) - return ec; - - auto symbolName = SymI->getName(strTable); - if (std::error_code ec = symbolName.getError()) - return ec; - - if (SymI->isAbsolute()) { - ELFAbsoluteAtom<ELFT> *absAtom = createAbsoluteAtom( - *symbolName, &*SymI, (int64_t)getSymbolValue(&*SymI)); - addAtom(*absAtom); - _symbolToAtomMapping.insert(std::make_pair(&*SymI, absAtom)); - } else if (SymI->isUndefined()) { - if (_useWrap && - (_wrapSymbolMap.find(*symbolName) != _wrapSymbolMap.end())) { - auto wrapAtom = _wrapSymbolMap.find(*symbolName); - _symbolToAtomMapping.insert( - std::make_pair(&*SymI, wrapAtom->getValue())); - continue; - } - ELFUndefinedAtom<ELFT> *undefAtom = - createUndefinedAtom(*symbolName, &*SymI); - addAtom(*undefAtom); - _symbolToAtomMapping.insert(std::make_pair(&*SymI, undefAtom)); - } else if (isCommonSymbol(&*SymI)) { - ELFCommonAtom<ELFT> *commonAtom = createCommonAtom(*symbolName, &*SymI); - commonAtom->setOrdinal(++_ordinal); - addAtom(*commonAtom); - _symbolToAtomMapping.insert(std::make_pair(&*SymI, commonAtom)); - } else if (SymI->isDefined()) { - _sectionSymbols[*section].push_back(SymI); - } else { - llvm::errs() << "Unable to create atom for: " << *symbolName << "\n"; - return llvm::object::object_error::parse_failed; - } - } - - return std::error_code(); -} - -template <class ELFT> std::error_code ELFFile<ELFT>::createAtoms() { - // Holds all the atoms that are part of the section. They are the targets of - // the kindGroupChild reference. - llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> atomsForSection; - - // Contains a list of comdat sections for a group. - for (auto &i : _sectionSymbols) { - const Elf_Shdr *section = i.first; - std::vector<const Elf_Sym *> &symbols = i.second; - - // Sort symbols by position. - std::stable_sort(symbols.begin(), symbols.end(), - [this](const Elf_Sym *a, const Elf_Sym *b) { - return getSymbolValue(&*a) < getSymbolValue(&*b); - }); - - ErrorOr<StringRef> sectionName = this->getSectionName(section); - if (std::error_code ec = sectionName.getError()) - return ec; - - auto sectionContents = getSectionContents(section); - if (std::error_code ec = sectionContents.getError()) - return ec; - - // SHT_GROUP sections are handled in the following loop. - if (isGroupSection(section)) - continue; - - bool addAtoms = (!isGnuLinkOnceSection(*sectionName) && - !isSectionMemberOfGroup(section)); - - if (handleSectionWithNoSymbols(section, symbols)) { - ELFDefinedAtom<ELFT> *newAtom = - createSectionAtom(section, *sectionName, *sectionContents); - newAtom->setOrdinal(++_ordinal); - if (addAtoms) - addAtom(*newAtom); - else - atomsForSection[*sectionName].push_back(newAtom); - continue; - } - - ELFDefinedAtom<ELFT> *previousAtom = nullptr; - ELFReference<ELFT> *anonFollowedBy = nullptr; - - if (!_symtab) - continue; - ErrorOr<StringRef> strTableOrErr = - _objFile->getStringTableForSymtab(*_symtab); - if (std::error_code ec = strTableOrErr.getError()) - return ec; - StringRef strTable = *strTableOrErr; - for (auto si = symbols.begin(), se = symbols.end(); si != se; ++si) { - auto symbol = *si; - StringRef symbolName = ""; - if (symbol->getType() != llvm::ELF::STT_SECTION) { - auto symName = symbol->getName(strTable); - if (std::error_code ec = symName.getError()) - return ec; - symbolName = *symName; - } - - uint64_t contentSize = symbolContentSize( - section, &*symbol, (si + 1 == se) ? nullptr : &**(si + 1)); - - // Check to see if we need to add the FollowOn Reference - ELFReference<ELFT> *followOn = nullptr; - if (previousAtom) { - // Replace the followon atom with the anonymous atom that we created, - // so that the next symbol that we create is a followon from the - // anonymous atom. - if (anonFollowedBy) { - followOn = anonFollowedBy; - } else { - followOn = new (_readerStorage) - ELFReference<ELFT>(Reference::kindLayoutAfter); - previousAtom->addReference(followOn); - } - } - - ArrayRef<uint8_t> symbolData((const uint8_t *)sectionContents->data() + - getSymbolValue(&*symbol), - contentSize); - - // If the linker finds that a section has global atoms that are in a - // mergeable section, treat them as defined atoms as they shouldn't be - // merged away as well as these symbols have to be part of symbol - // resolution - if (isMergeableStringSection(section)) { - if (symbol->getBinding() != llvm::ELF::STB_GLOBAL) - continue; - ELFDefinedAtom<ELFT> *atom = createDefinedAtom( - symbolName, *sectionName, &**si, section, symbolData, - _references.size(), _references.size(), _references); - atom->setOrdinal(++_ordinal); - if (addAtoms) - addAtom(*atom); - else - atomsForSection[*sectionName].push_back(atom); - continue; - } - - // Don't allocate content to a weak symbol, as they may be merged away. - // Create an anonymous atom to hold the data. - ELFDefinedAtom<ELFT> *anonAtom = nullptr; - anonFollowedBy = nullptr; - if (symbol->getBinding() == llvm::ELF::STB_WEAK) { - // Create anonymous new non-weak ELF symbol that holds the symbol - // data. - auto sym = new (_readerStorage) Elf_Sym(*symbol); - sym->setBinding(llvm::ELF::STB_GLOBAL); - anonAtom = createDefinedAtomAndAssignRelocations( - "", *sectionName, sym, section, symbolData, *sectionContents); - symbolData = ArrayRef<uint8_t>(); - - // If this is the last atom, let's not create a followon reference. - if (anonAtom && (si + 1) != se) { - anonFollowedBy = new (_readerStorage) - ELFReference<ELFT>(Reference::kindLayoutAfter); - anonAtom->addReference(anonFollowedBy); - } - } - - ELFDefinedAtom<ELFT> *newAtom = createDefinedAtomAndAssignRelocations( - symbolName, *sectionName, &*symbol, section, symbolData, - *sectionContents); - newAtom->setOrdinal(++_ordinal); - - // If the atom was a weak symbol, let's create a followon reference to - // the anonymous atom that we created. - if (anonAtom) - createEdge(newAtom, anonAtom, Reference::kindLayoutAfter); - - if (previousAtom) { - // Set the followon atom to the weak atom that we have created, so - // that they would alias when the file gets written. - followOn->setTarget(anonAtom ? anonAtom : newAtom); - } - - // The previous atom is always the atom created before unless the atom - // is a weak atom. - previousAtom = anonAtom ? anonAtom : newAtom; - - if (addAtoms) - addAtom(*newAtom); - else - atomsForSection[*sectionName].push_back(newAtom); - - _symbolToAtomMapping.insert(std::make_pair(&*symbol, newAtom)); - if (anonAtom) { - anonAtom->setOrdinal(++_ordinal); - if (addAtoms) - addAtom(*anonAtom); - else - atomsForSection[*sectionName].push_back(anonAtom); - } - } - } - - for (auto &i : _sectionSymbols) - if (std::error_code ec = handleSectionGroup(i.first, atomsForSection)) - return ec; - for (auto &i : _sectionSymbols) - if (std::error_code ec = handleGnuLinkOnceSection(i.first, atomsForSection)) - return ec; - - updateReferences(); - return std::error_code(); -} - -template <class ELFT> -std::error_code ELFFile<ELFT>::handleGnuLinkOnceSection( - const Elf_Shdr *section, - llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection) { - ErrorOr<StringRef> sectionName = this->getSectionName(section); - if (std::error_code ec = sectionName.getError()) - return ec; - if (!isGnuLinkOnceSection(*sectionName)) - return std::error_code(); - - unsigned int referenceStart = _references.size(); - std::vector<ELFReference<ELFT> *> refs; - for (auto ha : atomsForSection[*sectionName]) { - _groupChild[ha->symbol()] = std::make_pair(*sectionName, section); - auto *ref = - new (_readerStorage) ELFReference<ELFT>(Reference::kindGroupChild); - ref->setTarget(ha); - refs.push_back(ref); - } - atomsForSection[*sectionName].clear(); - // Create a gnu linkonce atom. - ELFDefinedAtom<ELFT> *atom = createDefinedAtom( - *sectionName, *sectionName, nullptr, section, ArrayRef<uint8_t>(), - referenceStart, _references.size(), _references); - atom->setOrdinal(++_ordinal); - addAtom(*atom); - for (auto reference : refs) - atom->addReference(reference); - return std::error_code(); -} - -template <class ELFT> -std::error_code ELFFile<ELFT>::handleSectionGroup( - const Elf_Shdr *section, - llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection) { - ErrorOr<StringRef> sectionName = this->getSectionName(section); - if (std::error_code ec = sectionName.getError()) - return ec; - if (!isGroupSection(section)) - return std::error_code(); - - auto sectionContents = getSectionContents(section); - if (std::error_code ec = sectionContents.getError()) - return ec; - - // A section of type SHT_GROUP defines a grouping of sections. The - // name of a symbol from one of the containing object's symbol tables - // provides a signature for the section group. The section header of - // the SHT_GROUP section specifies the identifying symbol entry, as - // described: the sh_link member contains the section header index of - // the symbol table section that contains the entry. The sh_info - // member contains the symbol table index of the identifying entry. - // The sh_flags member of the section header contains 0. The name of - // the section (sh_name) is not specified. - std::vector<StringRef> sectionNames; - const Elf_Word *groupMembers = - reinterpret_cast<const Elf_Word *>(sectionContents->data()); - const size_t count = section->sh_size / sizeof(Elf_Word); - for (size_t i = 1; i < count; i++) { - ErrorOr<const Elf_Shdr *> shdr = _objFile->getSection(groupMembers[i]); - if (std::error_code ec = shdr.getError()) - return ec; - ErrorOr<StringRef> sectionName = _objFile->getSectionName(*shdr); - if (std::error_code ec = sectionName.getError()) - return ec; - sectionNames.push_back(*sectionName); - } - ErrorOr<const Elf_Shdr *> symtab = _objFile->getSection(section->sh_link); - if (std::error_code ec = symtab.getError()) - return ec; - const Elf_Sym *symbol = _objFile->getSymbol(*symtab, section->sh_info); - ErrorOr<const Elf_Shdr *> strtab_sec = - _objFile->getSection((*symtab)->sh_link); - if (std::error_code ec = strtab_sec.getError()) - return ec; - ErrorOr<StringRef> strtab_or_err = _objFile->getStringTable(*strtab_sec); - if (std::error_code ec = strtab_or_err.getError()) - return ec; - StringRef strtab = *strtab_or_err; - ErrorOr<StringRef> symbolName = symbol->getName(strtab); - if (std::error_code ec = symbolName.getError()) - return ec; - - unsigned int referenceStart = _references.size(); - std::vector<ELFReference<ELFT> *> refs; - for (auto name : sectionNames) { - for (auto ha : atomsForSection[name]) { - _groupChild[ha->symbol()] = std::make_pair(*symbolName, section); - auto *ref = - new (_readerStorage) ELFReference<ELFT>(Reference::kindGroupChild); - ref->setTarget(ha); - refs.push_back(ref); - } - atomsForSection[name].clear(); - } - - // Create an atom for comdat signature. - ELFDefinedAtom<ELFT> *atom = createDefinedAtom( - *symbolName, *sectionName, nullptr, section, ArrayRef<uint8_t>(), - referenceStart, _references.size(), _references); - atom->setOrdinal(++_ordinal); - addAtom(*atom); - for (auto reference : refs) - atom->addReference(reference); - return std::error_code(); -} - -template <class ELFT> std::error_code ELFFile<ELFT>::createAtomsFromContext() { - if (!_useWrap) - return std::error_code(); - // Steps: - // a) Create an undefined atom for the symbol specified by the --wrap option, - // as that may be needed to be pulled from an archive. - // b) Create an undefined atom for __wrap_<symbolname>. - // c) All references to the symbol specified by wrap should point to - // __wrap_<symbolname> - // d) All references to __real_symbol should point to the <symbol> - for (auto &wrapsym : _ctx.wrapCalls()) { - StringRef wrapStr = wrapsym.getKey(); - // Create a undefined symbol fror the wrap symbol. - UndefinedAtom *wrapSymAtom = - new (_readerStorage) SimpleUndefinedAtom(*this, wrapStr); - StringRef wrapCallSym = - _ctx.allocateString((llvm::Twine("__wrap_") + wrapStr).str()); - StringRef realCallSym = - _ctx.allocateString((llvm::Twine("__real_") + wrapStr).str()); - UndefinedAtom *wrapCallAtom = - new (_readerStorage) SimpleUndefinedAtom(*this, wrapCallSym); - // Create maps, when there is call to sym, it should point to wrapCallSym. - _wrapSymbolMap.insert(std::make_pair(wrapStr, wrapCallAtom)); - // Whenever there is a reference to realCall it should point to the symbol - // created for each wrap usage. - _wrapSymbolMap.insert(std::make_pair(realCallSym, wrapSymAtom)); - addAtom(*wrapSymAtom); - addAtom(*wrapCallAtom); - } - return std::error_code(); -} - -template <class ELFT> -ELFDefinedAtom<ELFT> *ELFFile<ELFT>::createDefinedAtomAndAssignRelocations( - StringRef symbolName, StringRef sectionName, const Elf_Sym *symbol, - const Elf_Shdr *section, ArrayRef<uint8_t> symContent, - ArrayRef<uint8_t> secContent) { - unsigned int referenceStart = _references.size(); - - // Add Rela (those with r_addend) references: - auto rari = _relocationAddendReferences.find(section); - if (rari != _relocationAddendReferences.end()) - createRelocationReferences(symbol, symContent, rari->second); - - // Add Rel references. - auto rri = _relocationReferences.find(section); - if (rri != _relocationReferences.end()) - createRelocationReferences(symbol, symContent, secContent, rri->second); - - // Create the DefinedAtom and add it to the list of DefinedAtoms. - return createDefinedAtom(symbolName, sectionName, symbol, section, symContent, - referenceStart, _references.size(), _references); -} - -template <class ELFT> -void ELFFile<ELFT>::createRelocationReferences(const Elf_Sym *symbol, - ArrayRef<uint8_t> content, - range<const Elf_Rela *> rels) { - bool isMips64EL = _objFile->isMips64EL(); - const auto symValue = getSymbolValue(symbol); - for (const auto &rel : rels) { - if (rel.r_offset < symValue || symValue + content.size() <= rel.r_offset) - continue; - auto elfRelocation = new (_readerStorage) - ELFReference<ELFT>(&rel, rel.r_offset - symValue, kindArch(), - rel.getType(isMips64EL), rel.getSymbol(isMips64EL)); - addReferenceToSymbol(elfRelocation, symbol); - _references.push_back(elfRelocation); - } -} - -template <class ELFT> -void ELFFile<ELFT>::createRelocationReferences(const Elf_Sym *symbol, - ArrayRef<uint8_t> symContent, - ArrayRef<uint8_t> secContent, - const Elf_Shdr *relSec) { - auto rels = _objFile->rels(relSec); - bool isMips64EL = _objFile->isMips64EL(); - const auto symValue = getSymbolValue(symbol); - for (const auto &rel : rels) { - if (rel.r_offset < symValue || symValue + symContent.size() <= rel.r_offset) - continue; - auto elfRelocation = new (_readerStorage) - ELFReference<ELFT>(rel.r_offset - symValue, kindArch(), - rel.getType(isMips64EL), rel.getSymbol(isMips64EL)); - Reference::Addend addend = getInitialAddend(symContent, symValue, rel); - elfRelocation->setAddend(addend); - addReferenceToSymbol(elfRelocation, symbol); - _references.push_back(elfRelocation); - } -} - -template <class ELFT> -void ELFFile<ELFT>::updateReferenceForMergeStringAccess(ELFReference<ELFT> *ref, - const Elf_Sym *symbol, - const Elf_Shdr *shdr) { - // If the target atom is mergeable strefng atom, the atom might have been - // merged with other atom having the same contents. Try to find the - // merged one if that's the case. - int64_t addend = ref->addend(); - if (addend < 0) - addend = 0; - - const MergeSectionKey ms = {shdr, addend}; - auto msec = _mergedSectionMap.find(ms); - if (msec != _mergedSectionMap.end()) { - ref->setTarget(msec->second); - return; - } - - // The target atom was not merged. Mergeable atoms are not in - // _symbolToAtomMapping, so we cannot find it by calling findAtom(). We - // instead call findMergeAtom(). - if (symbol->getType() != llvm::ELF::STT_SECTION) - addend = getSymbolValue(symbol) + addend; - ELFMergeAtom<ELFT> *mergedAtom = findMergeAtom(shdr, addend); - ref->setOffset(addend - mergedAtom->offset()); - ref->setAddend(0); - ref->setTarget(mergedAtom); -} - -template <class ELFT> void ELFFile<ELFT>::updateReferences() { - for (auto &ri : _references) { - if (ri->kindNamespace() != Reference::KindNamespace::ELF) - continue; - const Elf_Sym *symbol = - _objFile->getSymbol(_symtab, ri->targetSymbolIndex()); - ErrorOr<const Elf_Shdr *> shdr = - _objFile->getSection(symbol, _symtab, _shndxTable); - - // If the atom is not in mergeable string section, the target atom is - // simply that atom. - if (isMergeableStringSection(*shdr)) - updateReferenceForMergeStringAccess(ri, symbol, *shdr); - else - ri->setTarget(findAtom(findSymbolForReference(ri), symbol)); - } -} - -template <class ELFT> -bool ELFFile<ELFT>::isIgnoredSection(const Elf_Shdr *section) { - switch (section->sh_type) { - case llvm::ELF::SHT_NULL: - case llvm::ELF::SHT_STRTAB: - case llvm::ELF::SHT_SYMTAB: - case llvm::ELF::SHT_SYMTAB_SHNDX: - return true; - default: - break; - } - return false; -} - -template <class ELFT> -bool ELFFile<ELFT>::isMergeableStringSection(const Elf_Shdr *section) { - if (_doStringsMerge && section) { - int64_t sectionFlags = section->sh_flags; - sectionFlags &= ~llvm::ELF::SHF_ALLOC; - // Mergeable string sections have both SHF_MERGE and SHF_STRINGS flags - // set. sh_entsize is the size of each character which is normally 1. - if ((section->sh_entsize < 2) && - (sectionFlags == (llvm::ELF::SHF_MERGE | llvm::ELF::SHF_STRINGS))) { - return true; - } - } - return false; -} - -template <class ELFT> -ELFDefinedAtom<ELFT> * -ELFFile<ELFT>::createSectionAtom(const Elf_Shdr *section, StringRef sectionName, - ArrayRef<uint8_t> content) { - auto *sym = new (_readerStorage) Elf_Sym; - sym->st_name = 0; - sym->setBindingAndType(llvm::ELF::STB_LOCAL, llvm::ELF::STT_SECTION); - sym->st_other = 0; - sym->st_shndx = 0; - sym->st_value = 0; - sym->st_size = 0; - auto *newAtom = createDefinedAtomAndAssignRelocations( - "", sectionName, sym, section, content, content); - newAtom->setOrdinal(++_ordinal); - return newAtom; -} - -template <class ELFT> -uint64_t ELFFile<ELFT>::symbolContentSize(const Elf_Shdr *section, - const Elf_Sym *symbol, - const Elf_Sym *nextSymbol) { - const auto symValue = getSymbolValue(symbol); - // if this is the last symbol, take up the remaining data. - return nextSymbol ? getSymbolValue(nextSymbol) - symValue - : section->sh_size - symValue; -} - -template <class ELFT> -void ELFFile<ELFT>::createEdge(ELFDefinedAtom<ELFT> *from, - ELFDefinedAtom<ELFT> *to, uint32_t edgeKind) { - auto reference = new (_readerStorage) ELFReference<ELFT>(edgeKind); - reference->setTarget(to); - from->addReference(reference); -} - -/// Does the atom need to be redirected using a separate undefined atom? -template <class ELFT> -bool ELFFile<ELFT>::redirectReferenceUsingUndefAtom( - const Elf_Sym *sourceSymbol, const Elf_Sym *targetSymbol) const { - auto groupChildTarget = _groupChild.find(targetSymbol); - - // If the reference is not to a group child atom, there is no need to redirect - // using a undefined atom. Its also not needed if the source and target are - // from the same section. - if ((groupChildTarget == _groupChild.end()) || - (sourceSymbol->st_shndx == targetSymbol->st_shndx)) - return false; - - auto groupChildSource = _groupChild.find(sourceSymbol); - - // If the source symbol is not in a group, use a undefined symbol too. - if (groupChildSource == _groupChild.end()) - return true; - - // If the source and child are from the same group, we dont need the - // relocation to go through a undefined symbol. - if (groupChildSource->second.second == groupChildTarget->second.second) - return false; - return true; -} - -template <class ELFT> -void RuntimeFile<ELFT>::addAbsoluteAtom(StringRef symbolName, bool isHidden) { - assert(!symbolName.empty() && "AbsoluteAtoms must have a name"); - auto *sym = new (this->_readerStorage) Elf_Sym; - sym->st_name = 0; - sym->st_value = 0; - sym->st_shndx = llvm::ELF::SHN_ABS; - sym->setBindingAndType(llvm::ELF::STB_GLOBAL, llvm::ELF::STT_OBJECT); - if (isHidden) - sym->setVisibility(llvm::ELF::STV_HIDDEN); - else - sym->setVisibility(llvm::ELF::STV_DEFAULT); - sym->st_size = 0; - ELFAbsoluteAtom<ELFT> *atom = this->createAbsoluteAtom(symbolName, sym, -1); - this->addAtom(*atom); -} - -template <class ELFT> -void RuntimeFile<ELFT>::addUndefinedAtom(StringRef symbolName) { - assert(!symbolName.empty() && "UndefinedAtoms must have a name"); - auto *sym = new (this->_readerStorage) Elf_Sym; - sym->st_name = 0; - sym->st_value = 0; - sym->st_shndx = llvm::ELF::SHN_UNDEF; - sym->setBindingAndType(llvm::ELF::STB_GLOBAL, llvm::ELF::STT_NOTYPE); - sym->setVisibility(llvm::ELF::STV_DEFAULT); - sym->st_size = 0; - ELFUndefinedAtom<ELFT> *atom = this->createUndefinedAtom(symbolName, sym); - this->addAtom(*atom); -} - -template class ELFFile<ELF32LE>; -template class ELFFile<ELF32BE>; -template class ELFFile<ELF64LE>; -template class ELFFile<ELF64BE>; - -template class RuntimeFile<ELF32LE>; -template class RuntimeFile<ELF32BE>; -template class RuntimeFile<ELF64LE>; -template class RuntimeFile<ELF64BE>; - -} // end namespace elf -} // end namespace lld diff --git a/lib/ReaderWriter/ELF/ELFFile.h b/lib/ReaderWriter/ELF/ELFFile.h deleted file mode 100644 index 5e0c2fc75a87..000000000000 --- a/lib/ReaderWriter/ELF/ELFFile.h +++ /dev/null @@ -1,395 +0,0 @@ -//===- lib/ReaderWriter/ELF/ELFFile.h ---------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_FILE_H -#define LLD_READER_WRITER_ELF_FILE_H - -#include "Atoms.h" -#include "FileCommon.h" -#include "llvm/ADT/MapVector.h" -#include <map> -#include <unordered_map> - -namespace lld { - -namespace elf { -/// \brief Read a binary, find out based on the symbol table contents what kind -/// of symbol it is and create corresponding atoms for it -template <class ELFT> class ELFFile : public SimpleFile { - typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym; - typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr; - typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel; - typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word; - - // A Map is used to hold the atoms that have been divided up - // after reading the section that contains Merge String attributes - struct MergeSectionKey { - const Elf_Shdr *_shdr; - int64_t _offset; - }; - - struct MergeSectionEq { - int64_t operator()(const MergeSectionKey &k) const { - return llvm::hash_combine((int64_t)(k._shdr->sh_name), - (int64_t)k._offset); - } - bool operator()(const MergeSectionKey &lhs, - const MergeSectionKey &rhs) const { - return ((lhs._shdr->sh_name == rhs._shdr->sh_name) && - (lhs._offset == rhs._offset)); - } - }; - - struct MergeString { - MergeString(int64_t offset, StringRef str, const Elf_Shdr *shdr, - StringRef sectionName) - : _offset(offset), _string(str), _shdr(shdr), - _sectionName(sectionName) {} - // the offset of this atom - int64_t _offset; - // The content - StringRef _string; - // Section header - const Elf_Shdr *_shdr; - // Section name - StringRef _sectionName; - }; - - // This is used to find the MergeAtom given a relocation - // offset - typedef std::vector<ELFMergeAtom<ELFT> *> MergeAtomsT; - - /// \brief find a merge atom given a offset - ELFMergeAtom<ELFT> *findMergeAtom(const Elf_Shdr *shdr, int64_t offset) { - auto it = std::find_if(_mergeAtoms.begin(), _mergeAtoms.end(), - [=](const ELFMergeAtom<ELFT> *a) { - int64_t off = a->offset(); - return shdr->sh_name == a->section() && - offset >= off && - offset <= off + (int64_t)a->size(); - }); - assert(it != _mergeAtoms.end()); - return *it; - } - - typedef std::unordered_map<MergeSectionKey, DefinedAtom *, MergeSectionEq, - MergeSectionEq> MergedSectionMapT; - typedef typename MergedSectionMapT::iterator MergedSectionMapIterT; - -public: - ELFFile(StringRef name, ELFLinkingContext &ctx); - ELFFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx); - - static std::error_code isCompatible(MemoryBufferRef mb, - ELFLinkingContext &ctx); - - static bool canParse(file_magic magic) { - return magic == file_magic::elf_relocatable; - } - - virtual Reference::KindArch kindArch(); - - /// \brief Create symbols from LinkingContext. - std::error_code createAtomsFromContext(); - - /// \brief Read input sections and populate necessary data structures - /// to read them later and create atoms - std::error_code createAtomizableSections(); - - /// \brief Create mergeable atoms from sections that have the merge attribute - /// set - std::error_code createMergeableAtoms(); - - /// \brief Add the symbols that the sections contain. The symbols will be - /// converted to atoms for - /// Undefined symbols, absolute symbols - std::error_code createSymbolsFromAtomizableSections(); - - /// \brief Create individual atoms - std::error_code createAtoms(); - - // Assuming sourceSymbol has a reference to targetSym, find an atom - // for targetSym. Usually it's just the atom for targetSym. - // However, if an atom is in a section group, we may want to return an - // undefined atom for targetSym to let the resolver to resolve the - // symbol. (It's because if targetSym is in a section group A, and the - // group A is not linked in because other file already provides a - // section group B, we want to resolve references to B, not to A.) - Atom *findAtom(const Elf_Sym *sourceSym, const Elf_Sym *targetSym); - -protected: - ELFDefinedAtom<ELFT> *createDefinedAtomAndAssignRelocations( - StringRef symbolName, StringRef sectionName, const Elf_Sym *symbol, - const Elf_Shdr *section, ArrayRef<uint8_t> symContent, - ArrayRef<uint8_t> secContent); - - std::error_code doParse() override; - - /// \brief Iterate over Elf_Rela relocations list and create references. - virtual void createRelocationReferences(const Elf_Sym *symbol, - ArrayRef<uint8_t> content, - range<const Elf_Rela *> rels); - - /// \brief Iterate over Elf_Rel relocations list and create references. - virtual void createRelocationReferences(const Elf_Sym *symbol, - ArrayRef<uint8_t> symContent, - ArrayRef<uint8_t> secContent, - const Elf_Shdr *relSec); - - /// \brief After all the Atoms and References are created, update each - /// Reference's target with the Atom pointer it refers to. - void updateReferences(); - - /// \brief Update the reference if the access corresponds to a merge string - /// section. - void updateReferenceForMergeStringAccess(ELFReference<ELFT> *ref, - const Elf_Sym *symbol, - const Elf_Shdr *shdr); - - /// \brief Do we want to ignore the section. Ignored sections are - /// not processed to create atoms - bool isIgnoredSection(const Elf_Shdr *section); - - /// \brief Is the current section be treated as a mergeable string section. - /// The contents of a mergeable string section are null-terminated strings. - /// If the section have mergeable strings, the linker would need to split - /// the section into multiple atoms and mark them mergeByContent. - bool isMergeableStringSection(const Elf_Shdr *section); - - /// \brief Returns a new anonymous atom whose size is equal to the - /// section size. That atom will be used to represent the entire - /// section that have no symbols. - ELFDefinedAtom<ELFT> *createSectionAtom(const Elf_Shdr *section, - StringRef sectionName, - ArrayRef<uint8_t> contents); - - /// Returns the symbol's content size. The nextSymbol should be null if the - /// symbol is the last one in the section. - uint64_t symbolContentSize(const Elf_Shdr *section, - const Elf_Sym *symbol, - const Elf_Sym *nextSymbol); - - void createEdge(ELFDefinedAtom<ELFT> *from, ELFDefinedAtom<ELFT> *to, - uint32_t edgeKind); - - /// Get the section name for a section. - ErrorOr<StringRef> getSectionName(const Elf_Shdr *shdr) const; - - /// Determines if the section occupy memory space. - bool sectionOccupiesMemorySpace(const Elf_Shdr *shdr) const { - return (shdr->sh_type != llvm::ELF::SHT_NOBITS); - } - - /// Return the section contents. - ErrorOr<ArrayRef<uint8_t>> getSectionContents(const Elf_Shdr *shdr) const { - if (!shdr || !sectionOccupiesMemorySpace(shdr)) - return ArrayRef<uint8_t>(); - return _objFile->getSectionContents(shdr); - } - - /// Determines if the target wants to create an atom for a section that has no - /// symbol references. - bool - handleSectionWithNoSymbols(const Elf_Shdr *shdr, - std::vector<const Elf_Sym *> &syms) const { - return shdr && - (shdr->sh_type == llvm::ELF::SHT_PROGBITS || - shdr->sh_type == llvm::ELF::SHT_INIT_ARRAY || - shdr->sh_type == llvm::ELF::SHT_FINI_ARRAY || - shdr->sh_type == llvm::ELF::SHT_NOTE) && - syms.empty(); - } - - /// Handle creation of atoms for .gnu.linkonce sections. - std::error_code handleGnuLinkOnceSection( - const Elf_Shdr *section, - llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection); - - // Handle COMDAT scetions. - std::error_code handleSectionGroup( - const Elf_Shdr *section, - llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection); - - /// Process the Undefined symbol and create an atom for it. - ELFUndefinedAtom<ELFT> *createUndefinedAtom(StringRef symName, - const Elf_Sym *sym) { - return new (_readerStorage) ELFUndefinedAtom<ELFT>(*this, symName, sym); - } - - /// Process the Absolute symbol and create an atom for it. - ELFAbsoluteAtom<ELFT> *createAbsoluteAtom(StringRef symName, - const Elf_Sym *sym, int64_t value) { - return new (_readerStorage) - ELFAbsoluteAtom<ELFT>(*this, symName, sym, value); - } - - /// Returns true if the symbol is common symbol. A common symbol represents a - /// tentive definition in C. It has name, size and alignment constraint, but - /// actual storage has not yet been allocated. (The linker will allocate - /// storage for them in the later pass after coalescing tentative symbols by - /// name.) - virtual bool isCommonSymbol(const Elf_Sym *symbol) const { - return symbol->getType() == llvm::ELF::STT_COMMON || - symbol->st_shndx == llvm::ELF::SHN_COMMON; - } - - /// Returns true if the section is a gnulinkonce section. - bool isGnuLinkOnceSection(StringRef sectionName) const { - return sectionName.startswith(".gnu.linkonce."); - } - - /// Returns true if the section is a COMDAT group section. - bool isGroupSection(const Elf_Shdr *shdr) const { - return (shdr->sh_type == llvm::ELF::SHT_GROUP); - } - - /// Returns true if the section is a member of some group. - bool isSectionMemberOfGroup(const Elf_Shdr *shdr) const { - return (shdr->sh_flags & llvm::ELF::SHF_GROUP); - } - - /// Returns correct st_value for the symbol depending on the architecture. - /// For most architectures it's just a regular st_value with no changes. - virtual uint64_t getSymbolValue(const Elf_Sym *symbol) const { - return symbol->st_value; - } - - /// Returns initial addend - virtual Reference::Addend getInitialAddend(ArrayRef<uint8_t> symContent, - uint64_t symbolValue, - const Elf_Rel& reference) const { - return *(symContent.data() + reference.r_offset - symbolValue); - } - - /// Process the common symbol and create an atom for it. - virtual ELFCommonAtom<ELFT> *createCommonAtom(StringRef symName, - const Elf_Sym *sym) { - return new (_readerStorage) ELFCommonAtom<ELFT>(*this, symName, sym); - } - - /// Creates an atom for a given defined symbol. - virtual ELFDefinedAtom<ELFT> * - createDefinedAtom(StringRef symName, StringRef sectionName, - const Elf_Sym *sym, const Elf_Shdr *sectionHdr, - ArrayRef<uint8_t> contentData, unsigned int referenceStart, - unsigned int referenceEnd, - std::vector<ELFReference<ELFT> *> &referenceList) { - return new (_readerStorage) ELFDefinedAtom<ELFT>( - *this, symName, sectionName, sym, sectionHdr, contentData, - referenceStart, referenceEnd, referenceList); - } - - /// Process the Merge string and create an atom for it. - ELFMergeAtom<ELFT> *createMergedString(StringRef sectionName, - const Elf_Shdr *sectionHdr, - ArrayRef<uint8_t> contentData, - unsigned int offset) { - auto *mergeAtom = new (_readerStorage) - ELFMergeAtom<ELFT>(*this, sectionName, sectionHdr, contentData, offset); - const MergeSectionKey mergedSectionKey = {sectionHdr, offset}; - if (_mergedSectionMap.find(mergedSectionKey) == _mergedSectionMap.end()) - _mergedSectionMap.insert(std::make_pair(mergedSectionKey, mergeAtom)); - return mergeAtom; - } - - /// References to the sections comprising a group, from sections - /// outside the group, must be made via global UNDEF symbols, - /// referencing global symbols defined as addresses in the group - /// sections. They may not reference local symbols for addresses in - /// the group's sections, including section symbols. - /// ABI Doc : https://mentorembedded.github.io/cxx-abi/abi/prop-72-comdat.html - /// Does the atom need to be redirected using a separate undefined atom? - bool redirectReferenceUsingUndefAtom(const Elf_Sym *sourceSymbol, - const Elf_Sym *targetSymbol) const; - - void addReferenceToSymbol(const ELFReference<ELFT> *r, const Elf_Sym *sym) { - _referenceToSymbol[r] = sym; - } - - const Elf_Sym *findSymbolForReference(const ELFReference<ELFT> *r) const { - auto elfReferenceToSymbol = _referenceToSymbol.find(r); - if (elfReferenceToSymbol != _referenceToSymbol.end()) - return elfReferenceToSymbol->second; - return nullptr; - } - - llvm::BumpPtrAllocator _readerStorage; - std::unique_ptr<llvm::object::ELFFile<ELFT> > _objFile; - const Elf_Shdr *_symtab = nullptr; - ArrayRef<Elf_Word> _shndxTable; - - /// \brief _relocationAddendReferences and _relocationReferences contain the - /// list of relocations references. In ELF, if a section named, ".text" has - /// relocations will also have a section named ".rel.text" or ".rela.text" - /// which will hold the entries. - std::unordered_map<const Elf_Shdr *, range<const Elf_Rela *>> - _relocationAddendReferences; - MergedSectionMapT _mergedSectionMap; - std::unordered_map<const Elf_Shdr *, const Elf_Shdr *> _relocationReferences; - std::vector<ELFReference<ELFT> *> _references; - llvm::DenseMap<const Elf_Sym *, Atom *> _symbolToAtomMapping; - llvm::DenseMap<const ELFReference<ELFT> *, const Elf_Sym *> - _referenceToSymbol; - // Group child atoms have a pair corresponding to the signature and the - // section header of the section that was used for generating the signature. - llvm::DenseMap<const Elf_Sym *, std::pair<StringRef, const Elf_Shdr *>> - _groupChild; - llvm::StringMap<Atom *> _undefAtomsForGroupChild; - - /// \brief Atoms that are created for a section that has the merge property - /// set - MergeAtomsT _mergeAtoms; - - /// \brief the section and the symbols that are contained within it to create - /// used to create atoms - llvm::MapVector<const Elf_Shdr *, std::vector<const Elf_Sym *>> - _sectionSymbols; - - /// \brief Sections that have merge string property - std::vector<const Elf_Shdr *> _mergeStringSections; - - std::unique_ptr<MemoryBuffer> _mb; - int64_t _ordinal; - - /// \brief the cached options relevant while reading the ELF File - bool _doStringsMerge; - - /// \brief Is --wrap on? - bool _useWrap; - - /// \brief The LinkingContext. - ELFLinkingContext &_ctx; - - // Wrap map - llvm::StringMap<UndefinedAtom *> _wrapSymbolMap; -}; - -/// \brief All atoms are owned by a File. To add linker specific atoms -/// the atoms need to be inserted to a file called (RuntimeFile) which -/// are basically additional symbols required by libc and other runtime -/// libraries part of executing a program. This class provides support -/// for adding absolute symbols and undefined symbols -template <class ELFT> class RuntimeFile : public ELFFile<ELFT> { -public: - typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym; - RuntimeFile(ELFLinkingContext &ctx, StringRef name) - : ELFFile<ELFT>(name, ctx) {} - - /// \brief add a global absolute atom - virtual void addAbsoluteAtom(StringRef symbolName, bool isHidden = false); - - /// \brief add an undefined atom - virtual void addUndefinedAtom(StringRef symbolName); -}; - -} // end namespace elf -} // end namespace lld - -#endif // LLD_READER_WRITER_ELF_FILE_H diff --git a/lib/ReaderWriter/ELF/ELFLinkingContext.cpp b/lib/ReaderWriter/ELF/ELFLinkingContext.cpp deleted file mode 100644 index 70d6d618207d..000000000000 --- a/lib/ReaderWriter/ELF/ELFLinkingContext.cpp +++ /dev/null @@ -1,263 +0,0 @@ -//===- 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) - 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 diff --git a/lib/ReaderWriter/ELF/ELFReader.h b/lib/ReaderWriter/ELF/ELFReader.h deleted file mode 100644 index 60af6dff9980..000000000000 --- a/lib/ReaderWriter/ELF/ELFReader.h +++ /dev/null @@ -1,47 +0,0 @@ -//===- lib/ReaderWriter/ELF/ELFReader.h -----------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_READER_H -#define LLD_READER_WRITER_ELF_READER_H - -#include "DynamicFile.h" -#include "ELFFile.h" -#include "lld/Core/File.h" -#include "lld/Core/Reader.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/Object/ELF.h" - -namespace lld { -namespace elf { - -template <typename FileT> class ELFReader : public Reader { -public: - ELFReader(ELFLinkingContext &ctx) : _ctx(ctx) {} - - bool canParse(file_magic magic, MemoryBufferRef mb) const override { - return FileT::canParse(magic); - } - - ErrorOr<std::unique_ptr<File>> - loadFile(std::unique_ptr<MemoryBuffer> mb, - const class Registry &) const override { - if (std::error_code ec = FileT::isCompatible(mb->getMemBufferRef(), _ctx)) - return ec; - std::unique_ptr<File> ret = llvm::make_unique<FileT>(std::move(mb), _ctx); - return std::move(ret); - } - -private: - ELFLinkingContext &_ctx; -}; - -} // namespace elf -} // namespace lld - -#endif // LLD_READER_WRITER_ELF_READER_H diff --git a/lib/ReaderWriter/ELF/ExecutableWriter.h b/lib/ReaderWriter/ELF/ExecutableWriter.h deleted file mode 100644 index 9d9f4d9ce0a5..000000000000 --- a/lib/ReaderWriter/ELF/ExecutableWriter.h +++ /dev/null @@ -1,157 +0,0 @@ -//===- lib/ReaderWriter/ELF/ExecutableWriter.h ----------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef LLD_READER_WRITER_ELF_EXECUTABLE_WRITER_H -#define LLD_READER_WRITER_ELF_EXECUTABLE_WRITER_H - -#include "OutputELFWriter.h" - -namespace lld { -namespace elf { -using namespace llvm; -using namespace llvm::object; - -//===----------------------------------------------------------------------===// -// ExecutableWriter Class -//===----------------------------------------------------------------------===// -template<class ELFT> -class ExecutableWriter : public OutputELFWriter<ELFT> { -public: - ExecutableWriter(ELFLinkingContext &ctx, TargetLayout<ELFT> &layout) - : OutputELFWriter<ELFT>(ctx, layout) {} - -protected: - void buildDynamicSymbolTable(const File &file) override; - void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override; - void finalizeDefaultAtomValues() override; - void createDefaultSections() override; - - bool isNeededTagRequired(const SharedLibraryAtom *sla) const override { - return this->_layout.isCopied(sla); - } - - unique_bump_ptr<InterpSection<ELFT>> _interpSection; - -private: - std::unique_ptr<RuntimeFile<ELFT>> createRuntimeFile(); -}; - -//===----------------------------------------------------------------------===// -// ExecutableWriter -//===----------------------------------------------------------------------===// -template<class ELFT> -void ExecutableWriter<ELFT>::buildDynamicSymbolTable(const File &file) { - for (auto sec : this->_layout.sections()) - if (auto section = dyn_cast<AtomSection<ELFT>>(sec)) - for (const auto &atom : section->atoms()) { - const DefinedAtom *da = dyn_cast<const DefinedAtom>(atom->_atom); - if (!da) - continue; - if (da->dynamicExport() != DefinedAtom::dynamicExportAlways && - !this->_ctx.isDynamicallyExportedSymbol(da->name()) && - !(this->_ctx.shouldExportDynamic() && - da->scope() == Atom::Scope::scopeGlobal)) - continue; - this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(), - atom->_virtualAddr, atom); - } - - // Put weak symbols in the dynamic symbol table. - if (this->_ctx.isDynamic()) { - for (const UndefinedAtom *a : file.undefined()) { - if (this->_layout.isReferencedByDefinedAtom(a) && - a->canBeNull() != UndefinedAtom::canBeNullNever) - this->_dynamicSymbolTable->addSymbol(a, ELF::SHN_UNDEF); - } - } - - OutputELFWriter<ELFT>::buildDynamicSymbolTable(file); -} - -template<class ELFT> -std::unique_ptr<RuntimeFile<ELFT>> ExecutableWriter<ELFT>::createRuntimeFile() { - auto file = llvm::make_unique<RuntimeFile<ELFT>>(this->_ctx, "C runtime"); - file->addUndefinedAtom(this->_ctx.entrySymbolName()); - file->addAbsoluteAtom("__bss_start"); - file->addAbsoluteAtom("__bss_end"); - file->addAbsoluteAtom("_end"); - file->addAbsoluteAtom("end"); - file->addAbsoluteAtom("__preinit_array_start", true); - file->addAbsoluteAtom("__preinit_array_end", true); - file->addAbsoluteAtom("__init_array_start", true); - file->addAbsoluteAtom("__init_array_end", true); - if (this->_ctx.isRelaOutputFormat()) { - file->addAbsoluteAtom("__rela_iplt_start"); - file->addAbsoluteAtom("__rela_iplt_end"); - } else { - file->addAbsoluteAtom("__rel_iplt_start"); - file->addAbsoluteAtom("__rel_iplt_end"); - } - file->addAbsoluteAtom("__fini_array_start", true); - file->addAbsoluteAtom("__fini_array_end", true); - return file; -} - -/// \brief Hook in lld to add CRuntime file -template <class ELFT> -void ExecutableWriter<ELFT>::createImplicitFiles( - std::vector<std::unique_ptr<File> > &result) { - OutputELFWriter<ELFT>::createImplicitFiles(result); - result.push_back(createRuntimeFile()); -} - -template <class ELFT> void ExecutableWriter<ELFT>::createDefaultSections() { - OutputELFWriter<ELFT>::createDefaultSections(); - if (this->_ctx.isDynamic()) { - _interpSection.reset(new (this->_alloc) InterpSection<ELFT>( - this->_ctx, ".interp", TargetLayout<ELFT>::ORDER_INTERP, - this->_ctx.getInterpreter())); - this->_layout.addSection(_interpSection.get()); - } -} - -/// Finalize the value of all the absolute symbols that we -/// created -template <class ELFT> void ExecutableWriter<ELFT>::finalizeDefaultAtomValues() { - OutputELFWriter<ELFT>::finalizeDefaultAtomValues(); - AtomLayout *bssStartAtom = this->_layout.findAbsoluteAtom("__bss_start"); - AtomLayout *bssEndAtom = this->_layout.findAbsoluteAtom("__bss_end"); - AtomLayout *underScoreEndAtom = this->_layout.findAbsoluteAtom("_end"); - AtomLayout *endAtom = this->_layout.findAbsoluteAtom("end"); - - assert((bssStartAtom || bssEndAtom || underScoreEndAtom || endAtom) && - "Unable to find the absolute atoms that have been added by lld"); - - this->updateScopeAtomValues("preinit_array", ".preinit_array"); - this->updateScopeAtomValues("init_array", ".init_array"); - if (this->_ctx.isRelaOutputFormat()) - this->updateScopeAtomValues("rela_iplt", ".rela.plt"); - else - this->updateScopeAtomValues("rel_iplt", ".rel.plt"); - this->updateScopeAtomValues("fini_array", ".fini_array"); - - auto bssSection = this->_layout.findOutputSection(".bss"); - - // If we don't find a bss section, then don't set these values - if (bssSection) { - bssStartAtom->_virtualAddr = bssSection->virtualAddr(); - bssEndAtom->_virtualAddr = - bssSection->virtualAddr() + bssSection->memSize(); - underScoreEndAtom->_virtualAddr = bssEndAtom->_virtualAddr; - endAtom->_virtualAddr = bssEndAtom->_virtualAddr; - } else if (auto dataSection = this->_layout.findOutputSection(".data")) { - underScoreEndAtom->_virtualAddr = - dataSection->virtualAddr() + dataSection->memSize(); - endAtom->_virtualAddr = underScoreEndAtom->_virtualAddr; - } -} - -} // namespace elf -} // namespace lld - -#endif // LLD_READER_WRITER_ELF_EXECUTABLE_WRITER_H diff --git a/lib/ReaderWriter/ELF/FileCommon.cpp b/lib/ReaderWriter/ELF/FileCommon.cpp deleted file mode 100644 index c23e3f6656cd..000000000000 --- a/lib/ReaderWriter/ELF/FileCommon.cpp +++ /dev/null @@ -1,66 +0,0 @@ -//===- lib/ReaderWriter/ELF/FileCommon.cpp --------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "ELFFile.h" -#include "FileCommon.h" - -using namespace llvm::ELF; - -namespace lld { -namespace elf { - -static const char *elf32_expected = "ELF32 expected, but got ELF64"; -static const char *elf64_expected = "ELF64 expected, but got ELF32"; -static const char *le_expected = - "Little endian files are expected, but got a big endian file."; -static const char *be_expected = - "Big endian files are expected, but got a little endian file."; - -template <> -std::error_code checkCompatibility<ELF32LE>(unsigned char size, - unsigned char endian) { - if (size == ELFCLASS64) - return make_dynamic_error_code(elf32_expected); - if (endian == ELFDATA2MSB) - return make_dynamic_error_code(le_expected); - return std::error_code(); -} - -template <> -std::error_code checkCompatibility<ELF32BE>(unsigned char size, - unsigned char endian) { - if (size == ELFCLASS64) - return make_dynamic_error_code(elf32_expected); - if (endian == ELFDATA2LSB) - return make_dynamic_error_code(be_expected); - return std::error_code(); -} - -template <> -std::error_code checkCompatibility<ELF64LE>(unsigned char size, - unsigned char endian) { - if (size == ELFCLASS32) - return make_dynamic_error_code(elf64_expected); - if (endian == ELFDATA2MSB) - return make_dynamic_error_code(le_expected); - return std::error_code(); -} - -template <> -std::error_code checkCompatibility<ELF64BE>(unsigned char size, - unsigned char endian) { - if (size == ELFCLASS32) - return make_dynamic_error_code(elf64_expected); - if (endian == ELFDATA2LSB) - return make_dynamic_error_code(be_expected); - return std::error_code(); -} - -} // end namespace elf -} // end namespace lld diff --git a/lib/ReaderWriter/ELF/FileCommon.h b/lib/ReaderWriter/ELF/FileCommon.h deleted file mode 100644 index eaff12afe72f..000000000000 --- a/lib/ReaderWriter/ELF/FileCommon.h +++ /dev/null @@ -1,45 +0,0 @@ -//===- lib/ReaderWriter/ELF/FileCommon.h ----------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_FILE_COMMON_H -#define LLD_READER_WRITER_ELF_FILE_COMMON_H - -#include "lld/ReaderWriter/ELFLinkingContext.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/ELF.h" - -namespace lld { -namespace elf { - -template <class ELFT> -std::error_code checkCompatibility(unsigned char size, unsigned char endian); - -template <typename ELFT> -std::error_code isCompatible(MemoryBufferRef mb, ELFLinkingContext &ctx) { - typedef llvm::object::Elf_Ehdr_Impl<ELFT> Elf_Ehdr; - - if (uintptr_t(mb.getBufferStart()) & 1) - return make_dynamic_error_code("invalid alignment"); - - auto *hdr = reinterpret_cast<const Elf_Ehdr *>(mb.getBuffer().data()); - if (hdr->e_machine != ctx.getMachineType()) - return make_dynamic_error_code("incompatible machine type"); - - unsigned char size; - unsigned char endian; - std::tie(size, endian) = llvm::object::getElfArchType(mb.getBuffer()); - if (std::error_code ec = checkCompatibility<ELFT>(size, endian)) - return ec; - return std::error_code(); -} - -} // end namespace elf -} // end namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/HeaderChunks.cpp b/lib/ReaderWriter/ELF/HeaderChunks.cpp deleted file mode 100644 index 193937c18061..000000000000 --- a/lib/ReaderWriter/ELF/HeaderChunks.cpp +++ /dev/null @@ -1,205 +0,0 @@ -//===- lib/ReaderWriter/ELF/HeaderChunks.cpp --------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "HeaderChunks.h" -#include "TargetLayout.h" -#include "llvm/ADT/STLExtras.h" - -namespace lld { -namespace elf { - -template <class ELFT> void ELFHeader<ELFT>::finalize() { - _eh.e_ident[llvm::ELF::EI_CLASS] = - (ELFT::Is64Bits) ? llvm::ELF::ELFCLASS64 : llvm::ELF::ELFCLASS32; - _eh.e_ident[llvm::ELF::EI_DATA] = - (ELFT::TargetEndianness == llvm::support::little) - ? llvm::ELF::ELFDATA2LSB - : llvm::ELF::ELFDATA2MSB; - _eh.e_type = this->_ctx.getOutputELFType(); - _eh.e_machine = this->_ctx.getOutputMachine(); -} - -template <class ELFT> -ELFHeader<ELFT>::ELFHeader(const ELFLinkingContext &ctx) - : Chunk<ELFT>("elfhdr", Chunk<ELFT>::Kind::ELFHeader, ctx) { - this->_alignment = ELFT::Is64Bits ? 8 : 4; - this->_fsize = sizeof(Elf_Ehdr); - this->_msize = sizeof(Elf_Ehdr); - memset(_eh.e_ident, 0, llvm::ELF::EI_NIDENT); - e_ident(llvm::ELF::EI_MAG0, 0x7f); - e_ident(llvm::ELF::EI_MAG1, 'E'); - e_ident(llvm::ELF::EI_MAG2, 'L'); - e_ident(llvm::ELF::EI_MAG3, 'F'); - e_ehsize(sizeof(Elf_Ehdr)); - e_flags(0); -} - -template <class ELFT> -void ELFHeader<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) { - uint8_t *chunkBuffer = buffer.getBufferStart(); - uint8_t *atomContent = chunkBuffer + this->fileOffset(); - memcpy(atomContent, &_eh, fileSize()); -} - -template <class ELFT> -bool ProgramHeader<ELFT>::addSegment(Segment<ELFT> *segment) { - bool allocatedNew = false; - ELFLinkingContext::OutputMagic outputMagic = this->_ctx.getOutputMagic(); - // For segments that are not a loadable segment, we - // just pick the values directly from the segment as there - // wouldnt be any slices within that - if (segment->segmentType() != llvm::ELF::PT_LOAD) { - Elf_Phdr *phdr = allocateProgramHeader(allocatedNew); - phdr->p_type = segment->segmentType(); - phdr->p_offset = segment->fileOffset(); - phdr->p_vaddr = segment->virtualAddr(); - phdr->p_paddr = segment->virtualAddr(); - phdr->p_filesz = segment->fileSize(); - phdr->p_memsz = segment->memSize(); - phdr->p_flags = segment->flags(); - phdr->p_align = segment->alignment(); - this->_fsize = fileSize(); - this->_msize = this->_fsize; - return allocatedNew; - } - // For all other segments, use the slice - // to derive program headers - for (auto slice : segment->slices()) { - Elf_Phdr *phdr = allocateProgramHeader(allocatedNew); - phdr->p_type = segment->segmentType(); - phdr->p_offset = slice->fileOffset(); - phdr->p_vaddr = slice->virtualAddr(); - phdr->p_paddr = slice->virtualAddr(); - phdr->p_filesz = slice->fileSize(); - phdr->p_memsz = slice->memSize(); - phdr->p_flags = segment->flags(); - phdr->p_align = slice->alignment(); - uint64_t segPageSize = segment->pageSize(); - uint64_t sliceAlign = slice->alignment(); - // Alignment of PT_LOAD segments are set to the page size, but if the - // alignment of the slice is greater than the page size, set the alignment - // of the segment appropriately. - if (outputMagic != ELFLinkingContext::OutputMagic::NMAGIC && - outputMagic != ELFLinkingContext::OutputMagic::OMAGIC) { - phdr->p_align = - (phdr->p_type == llvm::ELF::PT_LOAD) - ? (segPageSize < sliceAlign) ? sliceAlign : segPageSize - : sliceAlign; - } else - phdr->p_align = slice->alignment(); - } - this->_fsize = fileSize(); - this->_msize = this->_fsize; - - return allocatedNew; -} - -template <class ELFT> -void ProgramHeader<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) { - uint8_t *chunkBuffer = buffer.getBufferStart(); - uint8_t *dest = chunkBuffer + this->fileOffset(); - for (auto phi : _ph) { - memcpy(dest, phi, sizeof(Elf_Phdr)); - dest += sizeof(Elf_Phdr); - } -} - -template <class ELFT> -typename ProgramHeader<ELFT>::Elf_Phdr * -ProgramHeader<ELFT>::allocateProgramHeader(bool &allocatedNew) { - Elf_Phdr *phdr; - if (_phi == _ph.end()) { - phdr = new (_allocator) Elf_Phdr; - _ph.push_back(phdr); - _phi = _ph.end(); - allocatedNew = true; - } else { - phdr = (*_phi); - ++_phi; - } - return phdr; -} - -template <class ELFT> -SectionHeader<ELFT>::SectionHeader(const ELFLinkingContext &ctx, int32_t order) - : Chunk<ELFT>("shdr", Chunk<ELFT>::Kind::SectionHeader, ctx) { - this->_fsize = 0; - this->_alignment = 8; - this->setOrder(order); - // The first element in the list is always NULL - auto *nullshdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr; - ::memset(nullshdr, 0, sizeof(Elf_Shdr)); - _sectionInfo.push_back(nullshdr); - this->_fsize += sizeof(Elf_Shdr); -} - -template <class ELFT> -void SectionHeader<ELFT>::appendSection(OutputSection<ELFT> *section) { - auto *shdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr; - shdr->sh_name = _stringSection->addString(section->name()); - shdr->sh_type = section->type(); - shdr->sh_flags = section->flags(); - shdr->sh_offset = section->fileOffset(); - shdr->sh_addr = section->virtualAddr(); - if (section->isLoadableSection()) - shdr->sh_size = section->memSize(); - else - shdr->sh_size = section->fileSize(); - shdr->sh_link = section->link(); - shdr->sh_info = section->shinfo(); - shdr->sh_addralign = section->alignment(); - shdr->sh_entsize = section->entsize(); - _sectionInfo.push_back(shdr); -} - -template <class ELFT> -void SectionHeader<ELFT>::updateSection(Section<ELFT> *section) { - Elf_Shdr *shdr = _sectionInfo[section->ordinal()]; - shdr->sh_type = section->getType(); - shdr->sh_flags = section->getFlags(); - shdr->sh_offset = section->fileOffset(); - shdr->sh_addr = section->virtualAddr(); - shdr->sh_size = section->fileSize(); - shdr->sh_link = section->getLink(); - shdr->sh_info = section->getInfo(); - shdr->sh_addralign = section->alignment(); - shdr->sh_entsize = section->getEntSize(); -} - -template <class ELFT> -void SectionHeader<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) { - uint8_t *chunkBuffer = buffer.getBufferStart(); - uint8_t *dest = chunkBuffer + this->fileOffset(); - for (auto shi : _sectionInfo) { - memcpy(dest, shi, sizeof(Elf_Shdr)); - dest += sizeof(Elf_Shdr); - } - _stringSection->write(writer, layout, buffer); -} - -template class ELFHeader<ELF32LE>; -template class ELFHeader<ELF32BE>; -template class ELFHeader<ELF64LE>; -template class ELFHeader<ELF64BE>; - -template class ProgramHeader<ELF32LE>; -template class ProgramHeader<ELF32BE>; -template class ProgramHeader<ELF64LE>; -template class ProgramHeader<ELF64BE>; - -template class SectionHeader<ELF32LE>; -template class SectionHeader<ELF32BE>; -template class SectionHeader<ELF64LE>; -template class SectionHeader<ELF64BE>; - -} // end namespace elf -} // end namespace lld diff --git a/lib/ReaderWriter/ELF/HeaderChunks.h b/lib/ReaderWriter/ELF/HeaderChunks.h deleted file mode 100644 index 51fbe38f1a00..000000000000 --- a/lib/ReaderWriter/ELF/HeaderChunks.h +++ /dev/null @@ -1,154 +0,0 @@ -//===- lib/ReaderWriter/ELF/HeaderChunks.h --------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_HEADER_CHUNKS_H -#define LLD_READER_WRITER_ELF_HEADER_CHUNKS_H - -#include "SegmentChunks.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/Object/ELF.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/ELF.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/FileOutputBuffer.h" - -/// \brief An Header represents the Elf[32/64]_Ehdr structure at the -/// start of an ELF executable file. -namespace lld { -namespace elf { - -template <class ELFT> class ELFHeader : public Chunk<ELFT> { -public: - typedef llvm::object::Elf_Ehdr_Impl<ELFT> Elf_Ehdr; - - ELFHeader(const ELFLinkingContext &); - - void e_ident(int I, unsigned char C) { _eh.e_ident[I] = C; } - void e_type(uint16_t type) { _eh.e_type = type; } - void e_machine(uint16_t machine) { _eh.e_machine = machine; } - void e_version(uint32_t version) { _eh.e_version = version; } - void e_entry(int64_t entry) { _eh.e_entry = entry; } - void e_phoff(int64_t phoff) { _eh.e_phoff = phoff; } - void e_shoff(int64_t shoff) { _eh.e_shoff = shoff; } - void e_flags(uint32_t flags) { _eh.e_flags = flags; } - void e_ehsize(uint16_t ehsize) { _eh.e_ehsize = ehsize; } - void e_phentsize(uint16_t phentsize) { _eh.e_phentsize = phentsize; } - void e_phnum(uint16_t phnum) { _eh.e_phnum = phnum; } - void e_shentsize(uint16_t shentsize) { _eh.e_shentsize = shentsize; } - void e_shnum(uint16_t shnum) { _eh.e_shnum = shnum; } - void e_shstrndx(uint16_t shstrndx) { _eh.e_shstrndx = shstrndx; } - uint64_t fileSize() const override { return sizeof(Elf_Ehdr); } - - static bool classof(const Chunk<ELFT> *c) { - return c->kind() == Chunk<ELFT>::Kind::ELFHeader; - } - - int getContentType() const override { - return Chunk<ELFT>::ContentType::Header; - } - - void write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) override; - - void finalize() override; - -private: - Elf_Ehdr _eh; -}; - -/// \brief An ProgramHeader represents the Elf[32/64]_Phdr structure at the -/// start of an ELF executable file. -template<class ELFT> -class ProgramHeader : public Chunk<ELFT> { -public: - typedef llvm::object::Elf_Phdr_Impl<ELFT> Elf_Phdr; - typedef typename std::vector<Elf_Phdr *>::iterator PhIterT; - typedef typename std::reverse_iterator<PhIterT> ReversePhIterT; - - ProgramHeader(const ELFLinkingContext &ctx) - : Chunk<ELFT>("elfphdr", Chunk<ELFT>::Kind::ProgramHeader, ctx) { - this->_alignment = ELFT::Is64Bits ? 8 : 4; - resetProgramHeaders(); - } - - bool addSegment(Segment<ELFT> *segment); - void resetProgramHeaders() { _phi = _ph.begin(); } - uint64_t fileSize() const override { return sizeof(Elf_Phdr) * _ph.size(); } - - static bool classof(const Chunk<ELFT> *c) { - return c->kind() == Chunk<ELFT>::Kind::ProgramHeader; - } - - void write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) override; - - PhIterT begin() { return _ph.begin(); } - PhIterT end() { return _ph.end(); } - ReversePhIterT rbegin() { return _ph.rbegin(); } - ReversePhIterT rend() { return _ph.rend(); } - - int64_t entsize() { return sizeof(Elf_Phdr); } - int64_t numHeaders() { return _ph.size(); } - - int getContentType() const override { - return Chunk<ELFT>::ContentType::Header; - } - -private: - Elf_Phdr *allocateProgramHeader(bool &allocatedNew); - - std::vector<Elf_Phdr *> _ph; - PhIterT _phi; - llvm::BumpPtrAllocator _allocator; -}; - -/// \brief An SectionHeader represents the Elf[32/64]_Shdr structure -/// at the end of the file -template<class ELFT> -class SectionHeader : public Chunk<ELFT> { -public: - typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr; - - SectionHeader(const ELFLinkingContext &, int32_t order); - void appendSection(OutputSection<ELFT> *section); - void updateSection(Section<ELFT> *section); - - static bool classof(const Chunk<ELFT> *c) { - return c->kind() == Chunk<ELFT>::Kind::SectionHeader; - } - - void setStringSection(StringTable<ELFT> *s) { - _stringSection = s; - } - - void write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) override; - - uint64_t fileSize() const override { - return sizeof(Elf_Shdr) * _sectionInfo.size(); - } - - uint64_t entsize() { return sizeof(Elf_Shdr); } - - int getContentType() const override { - return Chunk<ELFT>::ContentType::Header; - } - - uint64_t numHeaders() { return _sectionInfo.size(); } - -private: - StringTable<ELFT> *_stringSection; - std::vector<Elf_Shdr *> _sectionInfo; - llvm::BumpPtrAllocator _sectionAllocate; -}; - -} // end namespace elf -} // end namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/Hexagon/CMakeLists.txt b/lib/ReaderWriter/ELF/Hexagon/CMakeLists.txt deleted file mode 100644 index e5c5cb77f38c..000000000000 --- a/lib/ReaderWriter/ELF/Hexagon/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -add_lld_library(lldHexagonELFTarget - HexagonLinkingContext.cpp - HexagonRelocationHandler.cpp - HexagonTargetHandler.cpp - LINK_LIBS - lldELF - lldReaderWriter - lldCore - LLVMObject - LLVMSupport - ) diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonDynamicLibraryWriter.h b/lib/ReaderWriter/ELF/Hexagon/HexagonDynamicLibraryWriter.h deleted file mode 100644 index 84415b273f44..000000000000 --- a/lib/ReaderWriter/ELF/Hexagon/HexagonDynamicLibraryWriter.h +++ /dev/null @@ -1,67 +0,0 @@ -//===- lib/ReaderWriter/ELF/Hexagon/HexagonDynamicLibraryWriter.h ---------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef HEXAGON_DYNAMIC_LIBRARY_WRITER_H -#define HEXAGON_DYNAMIC_LIBRARY_WRITER_H - -#include "DynamicLibraryWriter.h" -#include "HexagonLinkingContext.h" - -namespace lld { -namespace elf { - -class HexagonTargetLayout; - -class HexagonDynamicLibraryWriter : public DynamicLibraryWriter<ELF32LE> { -public: - HexagonDynamicLibraryWriter(HexagonLinkingContext &ctx, - HexagonTargetLayout &layout); - -protected: - // Add any runtime files and their atoms to the output - void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override; - - void finalizeDefaultAtomValues() override; - - std::error_code setELFHeader() override { - DynamicLibraryWriter::setELFHeader(); - setHexagonELFHeader(*_elfHeader); - return std::error_code(); - } - -private: - HexagonLinkingContext &_ctx; - HexagonTargetLayout &_targetLayout; -}; - -HexagonDynamicLibraryWriter::HexagonDynamicLibraryWriter( - HexagonLinkingContext &ctx, HexagonTargetLayout &layout) - : DynamicLibraryWriter(ctx, layout), _ctx(ctx), _targetLayout(layout) {} - -void HexagonDynamicLibraryWriter::createImplicitFiles( - std::vector<std::unique_ptr<File>> &result) { - DynamicLibraryWriter::createImplicitFiles(result); - // Add the default atoms as defined for hexagon - auto file = - llvm::make_unique<RuntimeFile<ELF32LE>>(_ctx, "Hexagon runtime file"); - file->addAbsoluteAtom("_GLOBAL_OFFSET_TABLE_"); - file->addAbsoluteAtom("_DYNAMIC"); - result.push_back(std::move(file)); -} - -void HexagonDynamicLibraryWriter::finalizeDefaultAtomValues() { - // Finalize the atom values that are part of the parent. - DynamicLibraryWriter::finalizeDefaultAtomValues(); - if (_ctx.isDynamic()) - finalizeHexagonRuntimeAtomValues(_targetLayout); -} - -} // namespace elf -} // namespace lld - -#endif // HEXAGON_DYNAMIC_LIBRARY_WRITER_H diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h b/lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h deleted file mode 100644 index 3d0d38f387dd..000000000000 --- a/lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h +++ /dev/null @@ -1,149 +0,0 @@ -//===- lib/ReaderWriter/ELF/HexagonELFFile.h ------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_HEXAGON_ELF_FILE_H -#define LLD_READER_WRITER_ELF_HEXAGON_ELF_FILE_H - -#include "ELFReader.h" -#include "HexagonLinkingContext.h" - -namespace lld { -namespace elf { - -class HexagonELFFile; - -class HexagonELFDefinedAtom : public ELFDefinedAtom<ELF32LE> { - typedef llvm::object::Elf_Sym_Impl<ELF32LE> Elf_Sym; - typedef llvm::object::Elf_Shdr_Impl<ELF32LE> Elf_Shdr; - -public: - template <typename... T> - HexagonELFDefinedAtom(T &&... args) - : ELFDefinedAtom(std::forward<T>(args)...) {} - - DefinedAtom::ContentType contentType() const override { - if (_contentType != DefinedAtom::typeUnknown) - return _contentType; - if (_section->sh_flags & llvm::ELF::SHF_HEX_GPREL) { - if (_section->sh_type == llvm::ELF::SHT_NOBITS) - return (_contentType = DefinedAtom::typeZeroFillFast); - return (_contentType = DefinedAtom::typeDataFast); - } - return ELFDefinedAtom::contentType(); - } - - DefinedAtom::ContentPermissions permissions() const override { - if (_section->sh_flags & llvm::ELF::SHF_HEX_GPREL) - return DefinedAtom::permRW_; - return ELFDefinedAtom::permissions(); - } -}; - -class HexagonELFCommonAtom : public ELFCommonAtom<ELF32LE> { - typedef llvm::object::Elf_Sym_Impl<ELF32LE> Elf_Sym; - typedef llvm::object::Elf_Shdr_Impl<ELF32LE> Elf_Shdr; - -public: - HexagonELFCommonAtom(const ELFFile<ELF32LE> &file, StringRef symbolName, - const Elf_Sym *symbol) - : ELFCommonAtom(file, symbolName, symbol) {} - - virtual bool isSmallCommonSymbol() const { - switch (_symbol->st_shndx) { - // Common symbols - case llvm::ELF::SHN_HEXAGON_SCOMMON: - case llvm::ELF::SHN_HEXAGON_SCOMMON_1: - case llvm::ELF::SHN_HEXAGON_SCOMMON_2: - case llvm::ELF::SHN_HEXAGON_SCOMMON_4: - case llvm::ELF::SHN_HEXAGON_SCOMMON_8: - return true; - default: - break; - } - return false; - } - - uint64_t size() const override { - if (isSmallCommonSymbol()) - return _symbol->st_size; - return ELFCommonAtom::size(); - } - - DefinedAtom::Merge merge() const override { - if (_symbol->getBinding() == llvm::ELF::STB_WEAK) - return DefinedAtom::mergeAsWeak; - if (isSmallCommonSymbol()) - return DefinedAtom::mergeAsTentative; - return ELFCommonAtom::merge(); - } - - DefinedAtom::ContentType contentType() const override { - if (isSmallCommonSymbol()) - return DefinedAtom::typeZeroFillFast; - return ELFCommonAtom::contentType(); - } - - DefinedAtom::Alignment alignment() const override { - if (isSmallCommonSymbol()) - return DefinedAtom::Alignment(_symbol->st_value); - return 1; - } - - DefinedAtom::ContentPermissions permissions() const override { - if (isSmallCommonSymbol()) - return DefinedAtom::permRW_; - return ELFCommonAtom::permissions(); - } -}; - -class HexagonELFFile : public ELFFile<ELF32LE> { - typedef llvm::object::Elf_Sym_Impl<ELF32LE> Elf_Sym; - typedef llvm::object::Elf_Shdr_Impl<ELF32LE> Elf_Shdr; - -public: - HexagonELFFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx) - : ELFFile(std::move(mb), ctx) {} - - bool isCommonSymbol(const Elf_Sym *symbol) const override { - switch (symbol->st_shndx) { - // Common symbols - case llvm::ELF::SHN_HEXAGON_SCOMMON: - case llvm::ELF::SHN_HEXAGON_SCOMMON_1: - case llvm::ELF::SHN_HEXAGON_SCOMMON_2: - case llvm::ELF::SHN_HEXAGON_SCOMMON_4: - case llvm::ELF::SHN_HEXAGON_SCOMMON_8: - return true; - default: - break; - } - return ELFFile::isCommonSymbol(symbol); - } - - /// Process the Defined symbol and create an atom for it. - ELFDefinedAtom<ELF32LE> *createDefinedAtom( - StringRef symName, StringRef sectionName, const Elf_Sym *sym, - const Elf_Shdr *sectionHdr, ArrayRef<uint8_t> contentData, - unsigned int referenceStart, unsigned int referenceEnd, - std::vector<ELFReference<ELF32LE> *> &referenceList) override { - return new (_readerStorage) HexagonELFDefinedAtom( - *this, symName, sectionName, sym, sectionHdr, contentData, - referenceStart, referenceEnd, referenceList); - } - - /// Process the Common symbol and create an atom for it. - ELFCommonAtom<ELF32LE> *createCommonAtom(StringRef symName, - const Elf_Sym *sym) override { - return new (_readerStorage) HexagonELFCommonAtom(*this, symName, sym); - } -}; - -} // elf -} // lld - -#endif // LLD_READER_WRITER_ELF_HEXAGON_ELF_FILE_H diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h b/lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h deleted file mode 100644 index 6af43d88afbb..000000000000 --- a/lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h +++ /dev/null @@ -1,638 +0,0 @@ -//===- lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h -------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/ADT/STLExtras.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/ErrorHandling.h" - -namespace lld { -namespace elf { - -/// \brief Applying fixup on Hexagon requires the relocator to fetch the fixup -/// mask from the instruction. To fetch the fixup encoding, the linker uses a -/// static array that contains the instruction mask, the compare mask and the -/// relocation mask. -typedef struct { - uint32_t insnMask; // Instruction mask. - uint32_t insnCmpMask; // Compare mask. - uint32_t insnBitMask; // Relocation mask. - bool isDuplex; // Indicates if the instruction is a duplex instruction. -} Instruction; - -Instruction insn_encodings[] = { - // InsnMask CompareMask BitMask IsDuplexInstruction - { 0xffe00004, 0x40000000, 0x20f8, 0x0 }, - { 0xffe03080, 0x9ca03080, 0xf60, 0x0 }, - { 0xf9e00000, 0x48c00000, 0x61f20ff, 0x0 }, - { 0xf7c02300, 0x13802100, 0x3000fe, 0x0 }, - { 0xffe00000, 0x60c00000, 0x1f18, 0x0 }, - { 0xffe00000, 0x69c00000, 0x1f18, 0x0 }, - { 0xffe02000, 0x43000000, 0x7e0, 0x0 }, - { 0xff602060, 0x3e000060, 0x1f80, 0x0 }, - { 0xffe03000, 0x9ae01000, 0xf60, 0x0 }, - { 0xf9e00000, 0x91600000, 0x6003fe0, 0x0 }, - { 0xffe02084, 0xaf000084, 0x30078, 0x0 }, - { 0xff602060, 0x3e000020, 0x1f80, 0x0 }, - { 0xff602060, 0x3e200040, 0x1f80, 0x0 }, - { 0xf7c02000, 0x10c02000, 0x3000fe, 0x0 }, - { 0xffe00000, 0x60200000, 0x1f18, 0x0 }, - { 0xffe00000, 0x69200000, 0x1f18, 0x0 }, - { 0xffe038c0, 0xada00880, 0x3f, 0x0 }, - { 0xff602000, 0x73002000, 0x1fe0, 0x0 }, - { 0xf7c02000, 0x26c02000, 0x3000fe, 0x0 }, - { 0xffe03880, 0x9f403880, 0x1f0100, 0x0 }, - { 0xf9e00000, 0x48400000, 0x61f20ff, 0x0 }, - { 0xffe02000, 0x41600000, 0x7e0, 0x0 }, - { 0xffe02084, 0xaf000080, 0x30078, 0x0 }, - { 0xf7c02300, 0x13800100, 0x3000fe, 0x0 }, - { 0xffe01804, 0x46a00000, 0x20f8, 0x0 }, - { 0xffe00004, 0x42400000, 0x20f8, 0x0 }, - { 0xf7c02000, 0x22400000, 0x3000fe, 0x0 }, - { 0xf7c02000, 0x12402000, 0x3000fe, 0x0 }, - { 0xfc003d18, 0x28003c18, 0x3f00000, 0x1 }, - { 0xffe00000, 0x39000000, 0x201f, 0x0 }, - { 0xff601018, 0xdd400008, 0xfe0, 0x0 }, - { 0xffc0001c, 0x75400000, 0x203fe0, 0x0 }, - { 0xfc003fc7, 0x48003f47, 0x3f00000, 0x1 }, - { 0xffe03080, 0x9ca03000, 0xf60, 0x0 }, - { 0xf9e00000, 0x90800000, 0x6003fe0, 0x0 }, - { 0xf8003fc7, 0x40003fc4, 0x7f00000, 0x1 }, - { 0xfc003e00, 0x68003c00, 0x3f00000, 0x1 }, - { 0xf8003fc7, 0x40003fc5, 0x7f00000, 0x1 }, - { 0xf9e00000, 0x91800000, 0x6003fe0, 0x0 }, - { 0xff602060, 0x3e400060, 0x1f80, 0x0 }, - { 0xff602060, 0x3e000000, 0x1f80, 0x0 }, - { 0xf8003d18, 0x20003c18, 0x7f00000, 0x1 }, - { 0xf8003f00, 0x20003800, 0x7f00000, 0x1 }, - { 0xf8003d18, 0x20003c10, 0x7f00000, 0x1 }, - { 0xff602000, 0x73602000, 0x1fe0, 0x0 }, - { 0xffe03880, 0x9f002080, 0x1f0100, 0x0 }, - { 0xffe02000, 0x47000000, 0x7e0, 0x0 }, - { 0xf9e00000, 0x91400000, 0x6003fe0, 0x0 }, - { 0xffe02080, 0xabc00080, 0x3f, 0x0 }, - { 0xf7c02000, 0x20802000, 0x3000fe, 0x0 }, - { 0xf8003fc7, 0x40003f44, 0x7f00000, 0x1 }, - { 0xffe03884, 0xafa03084, 0x30078, 0x0 }, - { 0xffe03000, 0x9b001000, 0xf60, 0x0 }, - { 0xffe01804, 0x42a00800, 0x20f8, 0x0 }, - { 0xfc003f00, 0x28003100, 0x3f00000, 0x1 }, - { 0xffe02080, 0xab800080, 0x3f, 0x0 }, - { 0xf7c02000, 0x24c00000, 0x3000fe, 0x0 }, - { 0xffe00000, 0x39a00000, 0x201f, 0x0 }, - { 0xf7c02300, 0x13802300, 0x3000fe, 0x0 }, - { 0xffe01804, 0x46a00800, 0x20f8, 0x0 }, - { 0xffe020c0, 0xad602080, 0x3f, 0x0 }, - { 0xfc003f00, 0x28003500, 0x3f00000, 0x1 }, - { 0xfc003f00, 0x28003400, 0x3f00000, 0x1 }, - { 0xffe020c0, 0xad6000c0, 0x3f, 0x0 }, - { 0xffe00000, 0x60000000, 0x1f18, 0x0 }, - { 0xf8003000, 0x40000000, 0x7f00000, 0x1 }, - { 0xffe00000, 0x69000000, 0x1f18, 0x0 }, - { 0xffe03080, 0x9c601080, 0xf60, 0x0 }, - { 0xffe03080, 0x9ce01000, 0xf60, 0x0 }, - { 0xffe03080, 0x9c601000, 0xf60, 0x0 }, - { 0xf7c02000, 0x13402000, 0x3000fe, 0x0 }, - { 0xffe03080, 0x9c603000, 0xf60, 0x0 }, - { 0xf7c02000, 0x21c00000, 0x3000fe, 0x0 }, - { 0xfc003000, 0x68000000, 0x3f00000, 0x1 }, - { 0xf8003800, 0x60002000, 0x7f00000, 0x1 }, - { 0xffe02084, 0xaf802084, 0x30078, 0x0 }, - { 0xfc003000, 0x48000000, 0x3f00000, 0x1 }, - { 0xf7c02300, 0x11c02100, 0x3000fe, 0x0 }, - { 0xf7c02000, 0x12800000, 0x3000fe, 0x0 }, - { 0xfc003e70, 0x28003a40, 0x3f00000, 0x1 }, - { 0xfc003f00, 0x28003300, 0x3f00000, 0x1 }, - { 0xff800000, 0xe0000000, 0x1fe0, 0x0 }, - { 0xff602060, 0x3f400000, 0x1f80, 0x0 }, - { 0xffe00004, 0x42000000, 0x20f8, 0x0 }, - { 0xf8003f00, 0x60003300, 0x7f00000, 0x1 }, - { 0xffe01804, 0x42a00000, 0x20f8, 0x0 }, - { 0xf7c02000, 0x12c00000, 0x3000fe, 0x0 }, - { 0xf0000000, 0x0, 0xfff3fff, 0x0 }, - { 0xff000016, 0xde000016, 0xe020e8, 0x0 }, - { 0xffe03000, 0x9b201000, 0xf60, 0x0 }, - { 0xffe03880, 0xaba00880, 0x3f, 0x0 }, - { 0xf8003e00, 0x40003c00, 0x7f00000, 0x1 }, - { 0xff602060, 0x3f200040, 0x1f80, 0x0 }, - { 0xffe03880, 0x9f203880, 0x1f0100, 0x0 }, - { 0xf7c02000, 0x20c00000, 0x3000fe, 0x0 }, - { 0xf9e01800, 0x48a00800, 0x61f20ff, 0x0 }, - { 0xf9e00000, 0x90a00000, 0x6003fe0, 0x0 }, - { 0xff802000, 0x74802000, 0x1fe0, 0x0 }, - { 0xffe03000, 0x9a401000, 0xf60, 0x0 }, - { 0xf7c02000, 0x10002000, 0x3000fe, 0x0 }, - { 0xf7c03000, 0x14803000, 0x3000fe, 0x0 }, - { 0xffe020c0, 0xad0020c0, 0x3f, 0x0 }, - { 0xffe0001c, 0x75800000, 0x3fe0, 0x0 }, - { 0xf9e01800, 0x48a01000, 0x61f20ff, 0x0 }, - { 0xffe03080, 0x9dc03000, 0xf60, 0x0 }, - { 0xffe03080, 0x9dc03080, 0xf60, 0x0 }, - { 0xffe03080, 0x9dc01000, 0xf60, 0x0 }, - { 0xffe03080, 0x9dc01080, 0xf60, 0x0 }, - { 0xffe03080, 0x9d601000, 0xf60, 0x0 }, - { 0xffe03080, 0x9d601080, 0xf60, 0x0 }, - { 0xffe03080, 0x9d603000, 0xf60, 0x0 }, - { 0xffe03080, 0x9d603080, 0xf60, 0x0 }, - { 0xfc003e00, 0x48003c00, 0x3f00000, 0x1 }, - { 0xffe02084, 0xaf402084, 0x30078, 0x0 }, - { 0xffe00004, 0x46600000, 0x20f8, 0x0 }, - { 0xffe03880, 0x9f203080, 0x1f0100, 0x0 }, - { 0xf8003f00, 0x20003100, 0x7f00000, 0x1 }, - { 0xf7c02000, 0x11402000, 0x3000fe, 0x0 }, - { 0xf8003d08, 0x20003d00, 0x7f00000, 0x1 }, - { 0xffe03080, 0x9ca01080, 0xf60, 0x0 }, - { 0xffe03080, 0x9ca01000, 0xf60, 0x0 }, - { 0xffe00000, 0x38a00000, 0x201f, 0x0 }, - { 0xf7c02300, 0x11800000, 0x3000fe, 0x0 }, - { 0xf7c02300, 0x13c02300, 0x3000fe, 0x0 }, - { 0xffe03080, 0x9ce03000, 0xf60, 0x0 }, - { 0xf9e00000, 0x90e00000, 0x6003fe0, 0x0 }, - { 0xffe02084, 0xaf400080, 0x30078, 0x0 }, - { 0xffe03080, 0x9ce03080, 0xf60, 0x0 }, - { 0xff000000, 0x78000000, 0xdf3fe0, 0x0 }, - { 0xffe03080, 0x9ce01080, 0xf60, 0x0 }, - { 0xffe03880, 0xaba01080, 0x3f, 0x0 }, - { 0xffe020c0, 0xad002080, 0x3f, 0x0 }, - { 0xffe020c0, 0xad0000c0, 0x3f, 0x0 }, - { 0xffe020c0, 0xad000080, 0x3f, 0x0 }, - { 0xf7c02000, 0x25000000, 0x3000fe, 0x0 }, - { 0xff602060, 0x3f200020, 0x1f80, 0x0 }, - { 0xffe02084, 0xafc00084, 0x30078, 0x0 }, - { 0xf7c02000, 0x24400000, 0x3000fe, 0x0 }, - { 0xfc003000, 0x48001000, 0x3f00000, 0x1 }, - { 0xf9e01800, 0xa1a01000, 0x60020ff, 0x0 }, - { 0xff602060, 0x3f000040, 0x1f80, 0x0 }, - { 0xffe02084, 0xaf602084, 0x30078, 0x0 }, - { 0xf8003f00, 0x20003400, 0x7f00000, 0x1 }, - { 0xffe02084, 0xaf400084, 0x30078, 0x0 }, - { 0xffe01804, 0x44a01000, 0x20f8, 0x0 }, - { 0xff602060, 0x3e200000, 0x1f80, 0x0 }, - { 0xf8003e70, 0x20003a70, 0x7f00000, 0x1 }, - { 0xf8003f00, 0x40003e00, 0x7f00000, 0x1 }, - { 0xf8003f00, 0x20003300, 0x7f00000, 0x1 }, - { 0xf7c02300, 0x13800300, 0x3000fe, 0x0 }, - { 0xffe038c0, 0xada00080, 0x3f, 0x0 }, - { 0xf9e00000, 0x49400000, 0x61f3fe0, 0x0 }, - { 0xf8003800, 0x40002800, 0x7f00000, 0x1 }, - { 0xffe038c0, 0xada020c0, 0x3f, 0x0 }, - { 0xffe03884, 0xafa00880, 0x30078, 0x0 }, - { 0xf9e00000, 0x49000000, 0x61f3fe0, 0x0 }, - { 0xff800000, 0xd7000000, 0x6020e0, 0x0 }, - { 0xffc00000, 0xda000000, 0x203fe0, 0x0 }, - { 0xf7c02000, 0x12802000, 0x3000fe, 0x0 }, - { 0xf9e00000, 0x49600000, 0x61f3fe0, 0x0 }, - { 0xffe02000, 0x47400000, 0x7e0, 0x0 }, - { 0xf9e00000, 0x49c00000, 0x61f3fe0, 0x0 }, - { 0xffe03000, 0x9bc01000, 0xf60, 0x0 }, - { 0xf7c02300, 0x13c00100, 0x3000fe, 0x0 }, - { 0xffe03880, 0x9f002880, 0x1f0100, 0x0 }, - { 0xffe03000, 0x9b601000, 0xf60, 0x0 }, - { 0xffe01804, 0x40a00800, 0x20f8, 0x0 }, - { 0xffe00004, 0x42800000, 0x20f8, 0x0 }, - { 0xf7c03000, 0x14800000, 0x3000fe, 0x0 }, - { 0xfc003000, 0x68001000, 0x3f00000, 0x1 }, - { 0xfc003fc7, 0x48003f44, 0x3f00000, 0x1 }, - { 0xfc003fc7, 0x48003f45, 0x3f00000, 0x1 }, - { 0xf7c02000, 0x10800000, 0x3000fe, 0x0 }, - { 0xf8003e70, 0x20003a50, 0x7f00000, 0x1 }, - { 0xf7c02000, 0x21002000, 0x3000fe, 0x0 }, - { 0xf8003fc4, 0x40003fc0, 0x7f00000, 0x1 }, - { 0xf9e00000, 0x48000000, 0x61f20ff, 0x0 }, - { 0xffc0001c, 0x75000010, 0x203fe0, 0x0 }, - { 0xf8003f00, 0x20003800, 0x7f00000, 0x1 }, - { 0xf9e00000, 0xa1800000, 0x60020ff, 0x0 }, - { 0xffc01000, 0x61c00000, 0x202ffe, 0x0 }, - { 0xffe02084, 0xaf402080, 0x30078, 0x0 }, - { 0xffe03880, 0x9f602880, 0x1f0100, 0x0 }, - { 0xfc003f00, 0x68003000, 0x3f00000, 0x1 }, - { 0xfc003f00, 0x68003100, 0x3f00000, 0x1 }, - { 0xff602060, 0x3f200000, 0x1f80, 0x0 }, - { 0xffe03000, 0x9a801000, 0xf60, 0x0 }, - { 0xf7c02000, 0x24802000, 0x3000fe, 0x0 }, - { 0xffe00004, 0x42c00000, 0x20f8, 0x0 }, - { 0xf7c02300, 0x11802000, 0x3000fe, 0x0 }, - { 0xffc01000, 0x61401000, 0x202ffe, 0x0 }, - { 0xffe02000, 0x43c00000, 0x7e0, 0x0 }, - { 0xf7c02000, 0x11400000, 0x3000fe, 0x0 }, - { 0xf7c02000, 0x21800000, 0x3000fe, 0x0 }, - { 0xfc003c00, 0x28002c00, 0x3f00000, 0x1 }, - { 0xfc003f00, 0x28003200, 0x3f00000, 0x1 }, - { 0xffe03080, 0x9c803080, 0xf60, 0x0 }, - { 0xf7c03000, 0x14c03000, 0x3000fe, 0x0 }, - { 0xff800000, 0xdb800000, 0x6020e0, 0x0 }, - { 0xf7c02000, 0x22402000, 0x3000fe, 0x0 }, - { 0xffe00004, 0x46800000, 0x20f8, 0x0 }, - { 0xffe00000, 0x69a00000, 0x1f18, 0x0 }, - { 0xfc003e00, 0x68002a00, 0x3f00000, 0x1 }, - { 0xffe00000, 0x60a00000, 0x1f18, 0x0 }, - { 0xf7c02000, 0x25400000, 0x3000fe, 0x0 }, - { 0xfc003e70, 0x28003a70, 0x3f00000, 0x1 }, - { 0xffe03080, 0x9c803000, 0xf60, 0x0 }, - { 0xffc01000, 0x61400000, 0x202ffe, 0x0 }, - { 0xffe01804, 0x42a01000, 0x20f8, 0x0 }, - { 0xffc0001c, 0x75000000, 0x203fe0, 0x0 }, - { 0xffe02084, 0xafc02080, 0x30078, 0x0 }, - { 0xffe03884, 0xafa00884, 0x30078, 0x0 }, - { 0xffe03884, 0xafa02080, 0x30078, 0x0 }, - { 0xffe00000, 0x38c00000, 0x201f, 0x0 }, - { 0xffc01000, 0x61001000, 0x202ffe, 0x0 }, - { 0xf9e00000, 0x48800000, 0x61f20ff, 0x0 }, - { 0xf8003800, 0x40003000, 0x7f00000, 0x1 }, - { 0xf7c03000, 0x15403000, 0x3000fe, 0x0 }, - { 0xf7c03000, 0x15400000, 0x3000fe, 0x0 }, - { 0xf7c02000, 0x21000000, 0x3000fe, 0x0 }, - { 0xffe00004, 0x40c00000, 0x20f8, 0x0 }, - { 0xffe01804, 0x46a01000, 0x20f8, 0x0 }, - { 0xf8003d08, 0x20003d08, 0x7f00000, 0x1 }, - { 0xffe038c0, 0xada02080, 0x3f, 0x0 }, - { 0xffe03080, 0x9c203000, 0xf60, 0x0 }, - { 0xfc003800, 0x68002000, 0x3f00000, 0x1 }, - { 0xf9e00000, 0x90600000, 0x6003fe0, 0x0 }, - { 0xf7c03000, 0x14000000, 0x3000fe, 0x0 }, - { 0xf8003e70, 0x20003a40, 0x7f00000, 0x1 }, - { 0xff201800, 0x5c000800, 0xdf20fe, 0x0 }, - { 0xffe02000, 0x41800000, 0x7e0, 0x0 }, - { 0xff800000, 0xdb000000, 0x6020e0, 0x0 }, - { 0xfc003f00, 0x48003e00, 0x3f00000, 0x1 }, - { 0xf7c03000, 0x14002000, 0x3000fe, 0x0 }, - { 0xf7c02300, 0x11800100, 0x3000fe, 0x0 }, - { 0xfc003e00, 0x68002800, 0x3f00000, 0x1 }, - { 0xffe00004, 0x44c00000, 0x20f8, 0x0 }, - { 0xffe03880, 0x9f003880, 0x1f0100, 0x0 }, - { 0xff602000, 0x73402000, 0x1fe0, 0x0 }, - { 0xffe00000, 0x38200000, 0x201f, 0x0 }, - { 0xf7c02000, 0x24800000, 0x3000fe, 0x0 }, - { 0xf7c03000, 0x15001000, 0x3000fe, 0x0 }, - { 0xff800000, 0x7c800000, 0x1f2000, 0x0 }, - { 0xf8003fc7, 0x40003fc6, 0x7f00000, 0x1 }, - { 0xf7c02000, 0x12000000, 0x3000fe, 0x0 }, - { 0xff602000, 0x73202000, 0x1fe0, 0x0 }, - { 0xf7c02300, 0x13c00000, 0x3000fe, 0x0 }, - { 0xff602060, 0x3f400040, 0x1f80, 0x0 }, - { 0xf7c02000, 0x24002000, 0x3000fe, 0x0 }, - { 0xffe02084, 0xaf800080, 0x30078, 0x0 }, - { 0xffe00000, 0x38800000, 0x201f, 0x0 }, - { 0xfc003f00, 0x28003800, 0x3f00000, 0x1 }, - { 0xffe03080, 0x9c801080, 0xf60, 0x0 }, - { 0xffe020c0, 0xad4000c0, 0x3f, 0x0 }, - { 0xffe00000, 0x39400000, 0x201f, 0x0 }, - { 0xf7c02300, 0x13c02100, 0x3000fe, 0x0 }, - { 0xffe020c0, 0xad400080, 0x3f, 0x0 }, - { 0xffe03880, 0x9f603880, 0x1f0100, 0x0 }, - { 0xff000016, 0xde000002, 0xe020e8, 0x0 }, - { 0xfc003d08, 0x28003d00, 0x3f00000, 0x1 }, - { 0xfc003f00, 0x28003000, 0x3f00000, 0x1 }, - { 0xffe03080, 0x9c401000, 0xf60, 0x0 }, - { 0xf7c02000, 0x21402000, 0x3000fe, 0x0 }, - { 0xff201800, 0x5c200800, 0xdf20fe, 0x0 }, - { 0xffe01804, 0x40a01000, 0x20f8, 0x0 }, - { 0xfc003f00, 0x68003300, 0x3f00000, 0x1 }, - { 0xfc003f00, 0x68003200, 0x3f00000, 0x1 }, - { 0xf7c03000, 0x15401000, 0x3000fe, 0x0 }, - { 0xffe01804, 0x44a00800, 0x20f8, 0x0 }, - { 0xf7c02000, 0x26000000, 0x3000fe, 0x0 }, - { 0xffc00000, 0xda400000, 0x203fe0, 0x0 }, - { 0xffe00004, 0x40600000, 0x20f8, 0x0 }, - { 0xffe02080, 0xab600080, 0x3f, 0x0 }, - { 0xf8003f00, 0x20003600, 0x7f00000, 0x1 }, - { 0xf7c02300, 0x11c00300, 0x3000fe, 0x0 }, - { 0xf8003f00, 0x20003700, 0x7f00000, 0x1 }, - { 0xf7c02000, 0x25c00000, 0x3000fe, 0x0 }, - { 0xf7c02300, 0x11800300, 0x3000fe, 0x0 }, - { 0xffe03880, 0x9f802880, 0x1f0100, 0x0 }, - { 0xfc003800, 0x48003000, 0x3f00000, 0x1 }, - { 0xf8003c00, 0x20002c00, 0x7f00000, 0x1 }, - { 0xf7c02000, 0x10400000, 0x3000fe, 0x0 }, - { 0xff602060, 0x3f400060, 0x1f80, 0x0 }, - { 0xffe03080, 0x9c801000, 0xf60, 0x0 }, - { 0xff602060, 0x3e400040, 0x1f80, 0x0 }, - { 0xf7c03000, 0x14402000, 0x3000fe, 0x0 }, - { 0xffe0001c, 0x75800010, 0x3fe0, 0x0 }, - { 0xff000016, 0xde000014, 0xe020e8, 0x0 }, - { 0xf7c02300, 0x11c02000, 0x3000fe, 0x0 }, - { 0xff600018, 0xdd200008, 0x1fe0, 0x0 }, - { 0xff602060, 0x3e200060, 0x1f80, 0x0 }, - { 0xff000016, 0xde000006, 0xe020e8, 0x0 }, - { 0xffe00004, 0x44600000, 0x20f8, 0x0 }, - { 0xf8003e00, 0x60002800, 0x7f00000, 0x1 }, - { 0xfe600000, 0x3c000000, 0x207f, 0x0 }, - { 0xffe03884, 0xafa02884, 0x30078, 0x0 }, - { 0xf7c02300, 0x11802300, 0x3000fe, 0x0 }, - { 0xffe00000, 0x38000000, 0x201f, 0x0 }, - { 0xff200800, 0x5c000000, 0xdf20fe, 0x0 }, - { 0xf7c02000, 0x13400000, 0x3000fe, 0x0 }, - { 0xff200800, 0x5c200000, 0xdf20fe, 0x0 }, - { 0xffe02000, 0x41000000, 0x7e0, 0x0 }, - { 0xffe03880, 0x9fc02880, 0x1f0100, 0x0 }, - { 0xffe00004, 0x46000000, 0x20f8, 0x0 }, - { 0xff602060, 0x3f000020, 0x1f80, 0x0 }, - { 0xfc003d08, 0x28003d08, 0x3f00000, 0x1 }, - { 0xff602060, 0x3f200060, 0x1f80, 0x0 }, - { 0xffe038c0, 0xada028c0, 0x3f, 0x0 }, - { 0xffe038c0, 0xada008c0, 0x3f, 0x0 }, - { 0xf8003f00, 0x20003500, 0x7f00000, 0x1 }, - { 0xfc003fc4, 0x48003f40, 0x3f00000, 0x1 }, - { 0xf9e01800, 0x48a00000, 0x61f20ff, 0x0 }, - { 0xf7c03000, 0x14802000, 0x3000fe, 0x0 }, - { 0xfc003f00, 0x28003900, 0x3f00000, 0x1 }, - { 0xf8003fc7, 0x40003fc7, 0x7f00000, 0x1 }, - { 0xffe02000, 0x45400000, 0x7e0, 0x0 }, - { 0xffe038c0, 0xada02880, 0x3f, 0x0 }, - { 0xffe02084, 0xaf002080, 0x30078, 0x0 }, - { 0xffe03880, 0x9f803880, 0x1f0100, 0x0 }, - { 0xf7c03000, 0x15000000, 0x3000fe, 0x0 }, - { 0xfc003f00, 0x28003700, 0x3f00000, 0x1 }, - { 0xfc003f00, 0x28003600, 0x3f00000, 0x1 }, - { 0xffe02000, 0x47200000, 0x7e0, 0x0 }, - { 0xffe03880, 0xaba00080, 0x3f, 0x0 }, - { 0xffe02084, 0xafc00080, 0x30078, 0x0 }, - { 0xff802000, 0x73800000, 0x1fe0, 0x0 }, - { 0xffe03880, 0x9f202880, 0x1f0100, 0x0 }, - { 0xf8003d18, 0x20003c00, 0x7f00000, 0x1 }, - { 0xf9e00000, 0xa1600000, 0x60020ff, 0x0 }, - { 0xffe00004, 0x44800000, 0x20f8, 0x0 }, - { 0xf7c02000, 0x21802000, 0x3000fe, 0x0 }, - { 0xff000000, 0xd8000000, 0x6020e0, 0x0 }, - { 0xf9e00000, 0xa1000000, 0x60020ff, 0x0 }, - { 0xffe03884, 0xafa00084, 0x30078, 0x0 }, - { 0xff201800, 0x5c201800, 0xdf20fe, 0x0 }, - { 0xff000016, 0xde000010, 0xe020e8, 0x0 }, - { 0xffe03880, 0x9f603080, 0x1f0100, 0x0 }, - { 0xffe02000, 0x41c00000, 0x7e0, 0x0 }, - { 0xf7c02000, 0x20402000, 0x3000fe, 0x0 }, - { 0xff800000, 0xe1000000, 0x1fe0, 0x0 }, - { 0xf9e00000, 0xa1400000, 0x60020ff, 0x0 }, - { 0xf7c03000, 0x14c00000, 0x3000fe, 0x0 }, - { 0xf8003fc7, 0x40003f47, 0x7f00000, 0x1 }, - { 0xffe00004, 0x40800000, 0x20f8, 0x0 }, - { 0xff800000, 0xe1800000, 0x1fe0, 0x0 }, - { 0xf7c02300, 0x11802100, 0x3000fe, 0x0 }, - { 0xf9e00000, 0x49800000, 0x61f3fe0, 0x0 }, - { 0xf7c02000, 0x26400000, 0x3000fe, 0x0 }, - { 0xf8003c00, 0x20002800, 0x7f00000, 0x1 }, - { 0xff902000, 0x7e002000, 0xf1fe0, 0x0 }, - { 0xff902000, 0x7e802000, 0xf1fe0, 0x0 }, - { 0xf9e00000, 0x91c00000, 0x6003fe0, 0x0 }, - { 0xffe03884, 0xafa02880, 0x30078, 0x0 }, - { 0xf7c02000, 0x22000000, 0x3000fe, 0x0 }, - { 0xffe03080, 0x9d203000, 0xf60, 0x0 }, - { 0xf7c02000, 0x26002000, 0x3000fe, 0x0 }, - { 0xff800000, 0xe2000000, 0x1fe0, 0x0 }, - { 0xf7c02000, 0x26c00000, 0x3000fe, 0x0 }, - { 0xff602060, 0x3e400000, 0x1f80, 0x0 }, - { 0xffe00000, 0x38400000, 0x201f, 0x0 }, - { 0xfc003800, 0x48002000, 0x3f00000, 0x1 }, - { 0xff000016, 0xde000000, 0xe020e8, 0x0 }, - { 0xf8003f00, 0x20003000, 0x7f00000, 0x1 }, - { 0xf8003e70, 0x20003a60, 0x7f00000, 0x1 }, - { 0xff902000, 0x7e800000, 0xf1fe0, 0x0 }, - { 0xffe020c0, 0xad6020c0, 0x3f, 0x0 }, - { 0xf7c02300, 0x13802000, 0x3000fe, 0x0 }, - { 0xffe020c0, 0xad600080, 0x3f, 0x0 }, - { 0xff902000, 0x7e000000, 0xf1fe0, 0x0 }, - { 0xf7000000, 0x17000000, 0x3000fe, 0x0 }, - { 0xf7000000, 0x16000000, 0x3000fe, 0x0 }, - { 0xf7c02000, 0x25002000, 0x3000fe, 0x0 }, - { 0xfc003fc7, 0x48003fc7, 0x3f00000, 0x1 }, - { 0xffc01000, 0x61801000, 0x202ffe, 0x0 }, - { 0xffe03884, 0xafa03080, 0x30078, 0x0 }, - { 0xf8003fc4, 0x40003f40, 0x7f00000, 0x1 }, - { 0xfc003e70, 0x28003a60, 0x3f00000, 0x1 }, - { 0xf7c02300, 0x13800000, 0x3000fe, 0x0 }, - { 0xffe03880, 0x9f802080, 0x1f0100, 0x0 }, - { 0xf0000000, 0xb0000000, 0xfe03fe0, 0x0 }, - { 0xffe03880, 0x9f402080, 0x1f0100, 0x0 }, - { 0xffe02000, 0x43200000, 0x7e0, 0x0 }, - { 0xffe00000, 0x39800000, 0x201f, 0x0 }, - { 0xffe03880, 0x9fc03880, 0x1f0100, 0x0 }, - { 0xffe02000, 0x45600000, 0x7e0, 0x0 }, - { 0xf9e00000, 0x91200000, 0x6003fe0, 0x0 }, - { 0xffe02000, 0x43600000, 0x7e0, 0x0 }, - { 0xfc003f00, 0x28003800, 0x3f00000, 0x1 }, - { 0xff802000, 0x74000000, 0x1fe0, 0x0 }, - { 0xffe02084, 0xaf002084, 0x30078, 0x0 }, - { 0xff802000, 0x74800000, 0x1fe0, 0x0 }, - { 0xf7c03000, 0x14c02000, 0x3000fe, 0x0 }, - { 0xfe000001, 0x5a000000, 0x1ff3ffe, 0x0 }, - { 0xff602060, 0x3f400020, 0x1f80, 0x0 }, - { 0xf7c02000, 0x10802000, 0x3000fe, 0x0 }, - { 0xffe02084, 0xaf802080, 0x30078, 0x0 }, - { 0xffe00004, 0x46400000, 0x20f8, 0x0 }, - { 0xffe020c0, 0xad800080, 0x3f, 0x0 }, - { 0xffe020c0, 0xad8000c0, 0x3f, 0x0 }, - { 0xf8003fc7, 0x40003f45, 0x7f00000, 0x1 }, - { 0xf8003e00, 0x60002a00, 0x7f00000, 0x1 }, - { 0xffe02084, 0xaf600084, 0x30078, 0x0 }, - { 0xffe03080, 0x9c201000, 0xf60, 0x0 }, - { 0xffe02000, 0x43400000, 0x7e0, 0x0 }, - { 0xffe03080, 0x9c203080, 0xf60, 0x0 }, - { 0xffe02000, 0x41200000, 0x7e0, 0x0 }, - { 0xffe03080, 0x9c201080, 0xf60, 0x0 }, - { 0xf7c02300, 0x11c02300, 0x3000fe, 0x0 }, - { 0xffe03880, 0x9fc03080, 0x1f0100, 0x0 }, - { 0xffe03880, 0x9f402880, 0x1f0100, 0x0 }, - { 0xf8003800, 0x40002000, 0x7f00000, 0x1 }, - { 0xf7c02000, 0x24402000, 0x3000fe, 0x0 }, - { 0xf7c02000, 0x20c02000, 0x3000fe, 0x0 }, - { 0xf7c02300, 0x11c00000, 0x3000fe, 0x0 }, - { 0xffe02000, 0x45200000, 0x7e0, 0x0 }, - { 0xf8003f00, 0x20003900, 0x7f00000, 0x1 }, - { 0xf7c02300, 0x11c00100, 0x3000fe, 0x0 }, - { 0xffe02084, 0xaf800084, 0x30078, 0x0 }, - { 0xfe600000, 0x3c200000, 0x207f, 0x0 }, - { 0xf7c02000, 0x26800000, 0x3000fe, 0x0 }, - { 0xffe03880, 0x9f003080, 0x1f0100, 0x0 }, - { 0xffe03884, 0xafa01084, 0x30078, 0x0 }, - { 0xffc00000, 0x76000000, 0x203fe0, 0x0 }, - { 0xff602060, 0x3e000040, 0x1f80, 0x0 }, - { 0xffe020c0, 0xadc020c0, 0x3f, 0x0 }, - { 0xffe00004, 0x44400000, 0x20f8, 0x0 }, - { 0xffe020c0, 0xadc02080, 0x3f, 0x0 }, - { 0xfe600000, 0x3c400000, 0x207f, 0x0 }, - { 0xf7c02000, 0x20400000, 0x3000fe, 0x0 }, - { 0xff800000, 0x7c000000, 0x1fe0, 0x0 }, - { 0xffe03884, 0xafa00080, 0x30078, 0x0 }, - { 0xff201800, 0x5c001800, 0xdf20fe, 0x0 }, - { 0xffe02000, 0x47800000, 0x7e0, 0x0 }, - { 0xff601018, 0xdd400000, 0xfe0, 0x0 }, - { 0xffe020c0, 0xad4020c0, 0x3f, 0x0 }, - { 0xffe020c0, 0xad402080, 0x3f, 0x0 }, - { 0xf8003000, 0x40001000, 0x7f00000, 0x1 }, - { 0xffe02084, 0xafc02084, 0x30078, 0x0 }, - { 0xffe03080, 0x9c403080, 0xf60, 0x0 }, - { 0xfc003e40, 0x28003a00, 0x3f00000, 0x1 }, - { 0xffe038c0, 0xada010c0, 0x3f, 0x0 }, - { 0xffe038c0, 0xada01080, 0x3f, 0x0 }, - { 0xffe038c0, 0xada030c0, 0x3f, 0x0 }, - { 0xffe038c0, 0xada03080, 0x3f, 0x0 }, - { 0xf7c02000, 0x20800000, 0x3000fe, 0x0 }, - { 0xfc003fc7, 0x48003f46, 0x3f00000, 0x1 }, - { 0xffe01804, 0x44a00000, 0x20f8, 0x0 }, - { 0xf7c02000, 0x20002000, 0x3000fe, 0x0 }, - { 0xf7c02000, 0x12c02000, 0x3000fe, 0x0 }, - { 0xffe03000, 0x9a601000, 0xf60, 0x0 }, - { 0xffc00000, 0xda800000, 0x203fe0, 0x0 }, - { 0xf9e00000, 0x90400000, 0x6003fe0, 0x0 }, - { 0xffe02000, 0x47600000, 0x7e0, 0x0 }, - { 0xffe03080, 0x9d403000, 0xf60, 0x0 }, - { 0xffe03080, 0x9d403080, 0xf60, 0x0 }, - { 0xffe03080, 0x9d401000, 0xf60, 0x0 }, - { 0xffe03080, 0x9d401080, 0xf60, 0x0 }, - { 0xffe02000, 0x41400000, 0x7e0, 0x0 }, - { 0xff800000, 0xdf800000, 0x6020e0, 0x0 }, - { 0xffc01000, 0x61000000, 0x202ffe, 0x0 }, - { 0xffe03880, 0x9f202080, 0x1f0100, 0x0 }, - { 0xfc003fc7, 0x48003fc6, 0x3f00000, 0x1 }, - { 0xfe000000, 0x7a000000, 0x1fe0, 0x0 }, - { 0xffff0000, 0x6a490000, 0x1f80, 0x0 }, - { 0xff802000, 0x73000000, 0x1fe0, 0x0 }, - { 0xff602060, 0x3e200020, 0x1f80, 0x0 }, - { 0xf7c02000, 0x24000000, 0x3000fe, 0x0 }, - { 0xf8003e40, 0x20003a00, 0x7f00000, 0x1 }, - { 0xf7c03000, 0x14401000, 0x3000fe, 0x0 }, - { 0xf8003f00, 0x20003200, 0x7f00000, 0x1 }, - { 0xffc00000, 0x76400000, 0x203fe0, 0x0 }, - { 0xf7c02000, 0x22002000, 0x3000fe, 0x0 }, - { 0xffc01000, 0x61c01000, 0x202ffe, 0x0 }, - { 0xf7c03000, 0x14801000, 0x3000fe, 0x0 }, - { 0xf7c02000, 0x12002000, 0x3000fe, 0x0 }, - { 0xf7c02000, 0x10402000, 0x3000fe, 0x0 }, - { 0xff201800, 0x5d200000, 0xdf20fe, 0x0 }, - { 0xf7c02000, 0x21400000, 0x3000fe, 0x0 }, - { 0xff201800, 0x5d000000, 0xdf20fe, 0x0 }, - { 0xffe02000, 0x45c00000, 0x7e0, 0x0 }, - { 0xf7c02000, 0x25802000, 0x3000fe, 0x0 }, - { 0xfc003e70, 0x28003a50, 0x3f00000, 0x1 }, - { 0xf7c02300, 0x13c00300, 0x3000fe, 0x0 }, - { 0xf9e01800, 0xa1a00800, 0x60020ff, 0x0 }, - { 0xffe02000, 0x43800000, 0x7e0, 0x0 }, - { 0xfc003fc4, 0x48003fc0, 0x3f00000, 0x1 }, - { 0xff800000, 0xe2800000, 0x1fe0, 0x0 }, - { 0xf7c02300, 0x13c02000, 0x3000fe, 0x0 }, - { 0xffe03080, 0x9d803080, 0xf60, 0x0 }, - { 0xffe03080, 0x9d803000, 0xf60, 0x0 }, - { 0xffe03080, 0x9d801080, 0xf60, 0x0 }, - { 0xf8003fc4, 0x40003f00, 0x7f00000, 0x1 }, - { 0xffe00000, 0x39c00000, 0x201f, 0x0 }, - { 0xffe03080, 0x9d203080, 0xf60, 0x0 }, - { 0xffe02080, 0xab000080, 0x3f, 0x0 }, - { 0xf8003e00, 0x60003c00, 0x7f00000, 0x1 }, - { 0xffe03880, 0x9f602080, 0x1f0100, 0x0 }, - { 0xffc00000, 0x76800000, 0x203fe0, 0x0 }, - { 0xffe03884, 0xafa02084, 0x30078, 0x0 }, - { 0xf7c02000, 0x13002000, 0x3000fe, 0x0 }, - { 0xf9e00000, 0x91000000, 0x6003fe0, 0x0 }, - { 0xffe03080, 0x9d201080, 0xf60, 0x0 }, - { 0xf7c03000, 0x15002000, 0x3000fe, 0x0 }, - { 0xf8003000, 0x60000000, 0x7f00000, 0x1 }, - { 0xffc01000, 0x61800000, 0x202ffe, 0x0 }, - { 0xf7c03000, 0x14400000, 0x3000fe, 0x0 }, - { 0xffe03000, 0x9b401000, 0xf60, 0x0 }, - { 0xf7c03000, 0x14003000, 0x3000fe, 0x0 }, - { 0xffe03880, 0x9fc02080, 0x1f0100, 0x0 }, - { 0xfc003fc4, 0x48003f00, 0x3f00000, 0x1 }, - { 0xffe02000, 0x45000000, 0x7e0, 0x0 }, - { 0xfc003800, 0x48002800, 0x3f00000, 0x1 }, - { 0xfc003fc7, 0x48003fc5, 0x3f00000, 0x1 }, - { 0xfc003d18, 0x28003c00, 0x3f00000, 0x1 }, - { 0xfc003fc7, 0x48003fc4, 0x3f00000, 0x1 }, - { 0xf8003f00, 0x60003200, 0x7f00000, 0x1 }, - { 0xffe02084, 0xaf600080, 0x30078, 0x0 }, - { 0xf9e01800, 0xa1a00000, 0x60020ff, 0x0 }, - { 0xf7c03000, 0x14001000, 0x3000fe, 0x0 }, - { 0xf7c03000, 0x14c01000, 0x3000fe, 0x0 }, - { 0xffe00004, 0x46c00000, 0x20f8, 0x0 }, - { 0xf7c03000, 0x15003000, 0x3000fe, 0x0 }, - { 0xf7c02000, 0x10000000, 0x3000fe, 0x0 }, - { 0xf8003d18, 0x20003c08, 0x7f00000, 0x1 }, - { 0xffc0001c, 0x75400010, 0x203fe0, 0x0 }, - { 0xf9e00000, 0x48600000, 0x61f20ff, 0x0 }, - { 0xffe03080, 0x9c603080, 0xf60, 0x0 }, - { 0xfe000000, 0x58000000, 0x1ff3ffe, 0x0 }, - { 0xffe03000, 0x9a201000, 0xf60, 0x0 }, - { 0xffe00000, 0x69e00000, 0x1f18, 0x0 }, - { 0xffe020c0, 0xad802080, 0x3f, 0x0 }, - { 0xffe02000, 0x47c00000, 0x7e0, 0x0 }, - { 0xffe00000, 0x60e00000, 0x1f18, 0x0 }, - { 0xf7c03000, 0x15402000, 0x3000fe, 0x0 }, - { 0xffe020c0, 0xad8020c0, 0x3f, 0x0 }, - { 0xff000016, 0xde000012, 0xe020e8, 0x0 }, - { 0xf7c02000, 0x25c02000, 0x3000fe, 0x0 }, - { 0xf8003f00, 0x60003100, 0x7f00000, 0x1 }, - { 0xf8003f00, 0x60003000, 0x7f00000, 0x1 }, - { 0xf7c02000, 0x25800000, 0x3000fe, 0x0 }, - { 0xf7c03000, 0x14403000, 0x3000fe, 0x0 }, - { 0xfc003d18, 0x28003c08, 0x3f00000, 0x1 }, - { 0xffe03880, 0x9f403080, 0x1f0100, 0x0 }, - { 0xf7c02000, 0x25402000, 0x3000fe, 0x0 }, - { 0xf7c02000, 0x10c00000, 0x3000fe, 0x0 }, - { 0xffe02000, 0x45800000, 0x7e0, 0x0 }, - { 0xffe03880, 0x9f803080, 0x1f0100, 0x0 }, - { 0xffe03080, 0x9d001000, 0xf60, 0x0 }, - { 0xffe03080, 0x9d001080, 0xf60, 0x0 }, - { 0xffe03080, 0x9d003000, 0xf60, 0x0 }, - { 0xffe03080, 0x9d003080, 0xf60, 0x0 }, - { 0xffe03080, 0x9d801000, 0xf60, 0x0 }, - { 0xf9e00000, 0x49200000, 0x61f3fe0, 0x0 }, - { 0xf9e00000, 0xa1c00000, 0x60020ff, 0x0 }, - { 0xf9e00000, 0x90200000, 0x6003fe0, 0x0 }, - { 0xffe03080, 0x9d201000, 0xf60, 0x0 }, - { 0xffe03884, 0xafa01080, 0x30078, 0x0 }, - { 0xffe02084, 0xaf602080, 0x30078, 0x0 }, - { 0xffe038c0, 0xada000c0, 0x3f, 0x0 }, - { 0xffe02080, 0xab400080, 0x3f, 0x0 }, - { 0xff000016, 0xde000004, 0xe020e8, 0x0 }, - { 0xffe00004, 0x44000000, 0x20f8, 0x0 }, - { 0xf7c02000, 0x20000000, 0x3000fe, 0x0 }, - { 0xfc003d18, 0x28003c10, 0x3f00000, 0x1 }, - { 0xff600018, 0xdd000008, 0x1fe0, 0x0 }, - { 0xffe020c0, 0xadc000c0, 0x3f, 0x0 }, - { 0xffe020c0, 0xadc00080, 0x3f, 0x0 }, - { 0xffe03000, 0x9b801000, 0xf60, 0x0 }, - { 0xf8003fc7, 0x40003f46, 0x7f00000, 0x1 }, - { 0xf7c02000, 0x21c02000, 0x3000fe, 0x0 }, - { 0xffe01804, 0x40a00000, 0x20f8, 0x0 }, - { 0xf7c02000, 0x26402000, 0x3000fe, 0x0 }, - { 0xffe03080, 0x9c401080, 0xf60, 0x0 }, - { 0xffe00000, 0x39200000, 0x201f, 0x0 }, - { 0xffe03080, 0x9c403000, 0xf60, 0x0 }, - { 0xf7c02000, 0x11002000, 0x3000fe, 0x0 }, - { 0xfc003c00, 0x28002800, 0x3f00000, 0x1 }, - { 0xffe00004, 0x40400000, 0x20f8, 0x0 }, - { 0xf7c02000, 0x26802000, 0x3000fe, 0x0 }, - { 0xf7c02000, 0x13000000, 0x3000fe, 0x0 }, - { 0xffe00004, 0x42600000, 0x20f8, 0x0 }, - { 0xf8003000, 0x60001000, 0x7f00000, 0x1 }, - { 0xff602060, 0x3e400020, 0x1f80, 0x0 }, - { 0xff602060, 0x3f000000, 0x1f80, 0x0 }, - { 0xf7c02000, 0x24c02000, 0x3000fe, 0x0 }, - { 0xff802000, 0x74002000, 0x1fe0, 0x0 }, - { 0xf8003800, 0x20002000, 0x7f00000, 0x1 }, - { 0xffe03000, 0x9aa01000, 0xf60, 0x0 }, - { 0xf7c02000, 0x12400000, 0x3000fe, 0x0 }, - { 0xff602060, 0x3f000060, 0x1f80, 0x0 }, - { 0xf7c02000, 0x11000000, 0x3000fe, 0x0 }, -}; - -/// \brief finds the scatter Bits that need to be used to apply relocations -inline uint32_t findv4bitmask(uint8_t *location) { - uint32_t insn = llvm::support::endian::read32le(location); - for (int32_t i = 0, e = llvm::array_lengthof(insn_encodings); i < e; i++) { - if ((insn & 0xc000) == 0 && !insn_encodings[i].isDuplex) - continue; - if ((insn & 0xc000) != 0 && insn_encodings[i].isDuplex) - continue; - if ((insn_encodings[i].insnMask & insn) == insn_encodings[i].insnCmpMask) - return insn_encodings[i].insnBitMask; - } - llvm_unreachable("found unknown Hexagon instruction"); -} - -} // namespace elf -} // namespace lld diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableWriter.h b/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableWriter.h deleted file mode 100644 index 390694954a75..000000000000 --- a/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableWriter.h +++ /dev/null @@ -1,73 +0,0 @@ -//===- lib/ReaderWriter/ELF/Hexagon/HexagonExecutableWriter.h -------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef HEXAGON_EXECUTABLE_WRITER_H -#define HEXAGON_EXECUTABLE_WRITER_H - -#include "ExecutableWriter.h" -#include "HexagonLinkingContext.h" -#include "HexagonTargetHandler.h" - -namespace lld { -namespace elf { - -class HexagonTargetLayout; - -class HexagonExecutableWriter : public ExecutableWriter<ELF32LE> { -public: - HexagonExecutableWriter(HexagonLinkingContext &ctx, - HexagonTargetLayout &layout); - -protected: - // Add any runtime files and their atoms to the output - void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override; - - void finalizeDefaultAtomValues() override; - - std::error_code setELFHeader() override { - ExecutableWriter::setELFHeader(); - setHexagonELFHeader(*_elfHeader); - return std::error_code(); - } - -private: - HexagonLinkingContext &_ctx; - HexagonTargetLayout &_targetLayout; -}; - -HexagonExecutableWriter::HexagonExecutableWriter(HexagonLinkingContext &ctx, - HexagonTargetLayout &layout) - : ExecutableWriter(ctx, layout), _ctx(ctx), _targetLayout(layout) {} - -void HexagonExecutableWriter::createImplicitFiles( - std::vector<std::unique_ptr<File>> &result) { - ExecutableWriter::createImplicitFiles(result); - // Add the default atoms as defined for hexagon - auto file = - llvm::make_unique<RuntimeFile<ELF32LE>>(_ctx, "Hexagon runtime file"); - file->addAbsoluteAtom("_SDA_BASE_"); - if (_ctx.isDynamic()) { - file->addAbsoluteAtom("_GLOBAL_OFFSET_TABLE_"); - file->addAbsoluteAtom("_DYNAMIC"); - } - result.push_back(std::move(file)); -} - -void HexagonExecutableWriter::finalizeDefaultAtomValues() { - // Finalize the atom values that are part of the parent. - ExecutableWriter::finalizeDefaultAtomValues(); - AtomLayout *sdabaseAtom = _targetLayout.findAbsoluteAtom("_SDA_BASE_"); - sdabaseAtom->_virtualAddr = _targetLayout.getSDataSection()->virtualAddr(); - if (_ctx.isDynamic()) - finalizeHexagonRuntimeAtomValues(_targetLayout); -} - -} // namespace elf -} // namespace lld - -#endif // HEXAGON_EXECUTABLE_WRITER_H diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp b/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp deleted file mode 100644 index 11eabf7e26fc..000000000000 --- a/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp +++ /dev/null @@ -1,47 +0,0 @@ -//===- lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp -------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "HexagonLinkingContext.h" -#include "HexagonTargetHandler.h" - -namespace lld { -namespace elf { - -std::unique_ptr<ELFLinkingContext> -createHexagonLinkingContext(llvm::Triple triple) { - if (triple.getArch() == llvm::Triple::hexagon) - return llvm::make_unique<HexagonLinkingContext>(triple); - return nullptr; -} - -HexagonLinkingContext::HexagonLinkingContext(llvm::Triple triple) - : ELFLinkingContext(triple, std::unique_ptr<TargetHandler>( - new HexagonTargetHandler(*this))) {} - -static const Registry::KindStrings kindStrings[] = { -#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name), -#include "llvm/Support/ELFRelocs/Hexagon.def" -#undef ELF_RELOC - LLD_KIND_STRING_END -}; - -void HexagonLinkingContext::registerRelocationNames(Registry ®istry) { - registry.addKindTable(Reference::KindNamespace::ELF, - Reference::KindArch::Hexagon, kindStrings); -} - -void setHexagonELFHeader(ELFHeader<ELF32LE> &elfHeader) { - elfHeader.e_ident(llvm::ELF::EI_VERSION, 1); - elfHeader.e_ident(llvm::ELF::EI_OSABI, 0); - elfHeader.e_version(1); - elfHeader.e_flags(0x3); -} - -} // namespace elf -} // namespace lld diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h b/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h deleted file mode 100644 index ab91e405fd56..000000000000 --- a/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h +++ /dev/null @@ -1,61 +0,0 @@ -//===- lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h ---------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_LINKING_CONTEXT_H -#define LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_LINKING_CONTEXT_H - -#include "OutputELFWriter.h" -#include "lld/ReaderWriter/ELFLinkingContext.h" -#include "llvm/Object/ELF.h" -#include "llvm/Support/ELF.h" - -namespace lld { -namespace elf { - -class HexagonLinkingContext final : public ELFLinkingContext { -public: - int getMachineType() const override { return llvm::ELF::EM_HEXAGON; } - HexagonLinkingContext(llvm::Triple triple); - - void addPasses(PassManager &) override; - void registerRelocationNames(Registry &r) override; - - bool isDynamicRelocation(const Reference &r) const override { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - switch (r.kindValue()) { - case llvm::ELF::R_HEX_RELATIVE: - case llvm::ELF::R_HEX_GLOB_DAT: - return true; - default: - return false; - } - } - - bool isPLTRelocation(const Reference &r) const override { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - return r.kindValue() == llvm::ELF::R_HEX_JMP_SLOT; - } - - /// \brief Hexagon has only one relative relocation - /// a) for supporting relative relocs - R_HEX_RELATIVE - bool isRelativeReloc(const Reference &r) const override { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - return r.kindValue() == llvm::ELF::R_HEX_RELATIVE; - } -}; - -void setHexagonELFHeader(ELFHeader<ELF32LE> &elfHeader); - -} // elf -} // lld - -#endif // LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_LINKING_CONTEXT_H diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp b/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp deleted file mode 100644 index 0a201b32b5f1..000000000000 --- a/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp +++ /dev/null @@ -1,330 +0,0 @@ -//===- lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp ---------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "HexagonEncodings.h" -#include "HexagonLinkingContext.h" -#include "HexagonRelocationHandler.h" -#include "HexagonTargetHandler.h" -#include "llvm/Support/Endian.h" - -using namespace lld; -using namespace lld::elf; -using namespace llvm::ELF; -using namespace llvm::support::endian; - -// Scatter val's bits as specified by the mask. Example: -// -// Val: 0bABCDEFG -// Mask: 0b10111100001011 -// Output: 0b00ABCD0000E0FG -static uint32_t scatterBits(uint32_t val, uint32_t mask) { - uint32_t result = 0; - size_t off = 0; - for (size_t bit = 0; bit < 32; ++bit) { - if ((mask >> bit) & 1) { - uint32_t valBit = (val >> off) & 1; - result |= valBit << bit; - ++off; - } - } - return result; -} - -static void relocBNPCREL(uint8_t *loc, uint64_t P, uint64_t S, uint64_t A, - int32_t nBits) { - int32_t result = (S + A - P) >> 2; - int32_t range = 1 << nBits; - if (result < range && result > -range) { - result = scatterBits(result, findv4bitmask(loc)); - write32le(loc, result | read32le(loc)); - } -} - -/// \brief Word32_LO: 0x00c03fff : (S + A) : Truncate -static void relocLO16(uint8_t *loc, uint64_t P, uint64_t S, uint64_t A) { - uint32_t result = S + A; - result = scatterBits(result, 0x00c03fff); - write32le(loc, result | read32le(loc)); -} - -/// \brief Word32_LO: 0x00c03fff : (S + A) >> 16 : Truncate -static void relocHI16(uint8_t *loc, uint64_t P, uint64_t S, uint64_t A) { - uint32_t result = (S + A) >> 16; - result = scatterBits(result, 0x00c03fff); - write32le(loc, result | read32le(loc)); -} - -/// \brief Word32: 0xffffffff : (S + A) : Truncate -static void reloc32(uint8_t *loc, uint64_t P, uint64_t S, uint64_t A) { - uint32_t result = S + A; - write32le(loc, result | read32le(loc)); -} - -static void reloc32_6_X(uint8_t *loc, uint64_t P, uint64_t S, uint64_t A) { - int64_t result = (S + A) >> 6; - int64_t range = int64_t(1) << 32; - if (result > range) - result = scatterBits(result, 0xfff3fff); - write32le(loc, result | read32le(loc)); -} - -// R_HEX_B32_PCREL_X -static void relocHexB32PCRELX(uint8_t *loc, uint64_t P, uint64_t S, - uint64_t A) { - int64_t result = (S + A - P) >> 6; - result = scatterBits(result, 0xfff3fff); - write32le(loc, result | read32le(loc)); -} - -// R_HEX_BN_PCREL_X -static void relocHexBNPCRELX(uint8_t *loc, uint64_t P, uint64_t S, uint64_t A, - int nbits) { - int32_t result = (S + A - P) & 0x3f; - int32_t range = 1 << nbits; - if (result < range && result > -range) { - result = scatterBits(result, findv4bitmask(loc)); - write32le(loc, result | read32le(loc)); - } -} - -// R_HEX_6_PCREL_X -static void relocHex6PCRELX(uint8_t *loc, uint64_t P, uint64_t S, uint64_t A) { - int32_t result = S + A - P; - result = scatterBits(result, findv4bitmask(loc)); - write32le(loc, result | read32le(loc)); -} - -// R_HEX_N_X : Word32_U6 : (S + A) : Unsigned Truncate -static void relocHex_N_X(uint8_t *loc, uint64_t P, uint64_t S, uint64_t A) { - uint32_t result = S + A; - result = scatterBits(result, findv4bitmask(loc)); - write32le(loc, result | read32le(loc)); -} - -// GP REL relocs -static void relocHexGPRELN(uint8_t *loc, uint64_t P, uint64_t S, uint64_t A, - uint64_t GP, int nShiftBits) { - int32_t result = (S + A - GP) >> nShiftBits; - int32_t range = 1L << 16; - if (result <= range) { - result = scatterBits(result, findv4bitmask(loc)); - write32le(loc, result | read32le(loc)); - } -} - -/// \brief Word32_LO: 0x00c03fff : (G) : Truncate -static void relocHexGOTLO16(uint8_t *loc, uint64_t A, uint64_t GOT) { - int32_t result = A - GOT; - result = scatterBits(result, 0x00c03fff); - write32le(loc, result | read32le(loc)); -} - -/// \brief Word32_LO: 0x00c03fff : (G) >> 16 : Truncate -static void relocHexGOTHI16(uint8_t *loc, uint64_t A, uint64_t GOT) { - int32_t result = (A - GOT) >> 16; - result = scatterBits(result, 0x00c03fff); - write32le(loc, result | read32le(loc)); -} - -/// \brief Word32: 0xffffffff : (G) : Truncate -static void relocHexGOT32(uint8_t *loc, uint64_t A, uint64_t GOT) { - int32_t result = GOT - A; - write32le(loc, result | read32le(loc)); -} - -/// \brief Word32_U16 : (G) : Truncate -static void relocHexGOT16(uint8_t *loc, uint64_t A, uint64_t GOT) { - int32_t result = GOT - A; - int32_t range = 1L << 16; - if (result <= range) { - result = scatterBits(result, findv4bitmask(loc)); - write32le(loc, result | read32le(loc)); - } -} - -static void relocHexGOT32_6_X(uint8_t *loc, uint64_t A, uint64_t GOT) { - int32_t result = (A - GOT) >> 6; - result = scatterBits(result, findv4bitmask(loc)); - write32le(loc, result | read32le(loc)); -} - -static void relocHexGOT16_X(uint8_t *loc, uint64_t A, uint64_t GOT) { - int32_t result = A - GOT; - int32_t range = 1L << 6; - if (result <= range) { - result = scatterBits(result, findv4bitmask(loc)); - write32le(loc, result | read32le(loc)); - } -} - -static void relocHexGOT11_X(uint8_t *loc, uint64_t A, uint64_t GOT) { - uint32_t result = A - GOT; - result = scatterBits(result, findv4bitmask(loc)); - write32le(loc, result | read32le(loc)); -} - -static void relocHexGOTRELSigned(uint8_t *loc, uint64_t P, uint64_t S, - uint64_t A, uint64_t GOT, int shiftBits) { - int32_t result = (S + A - GOT) >> shiftBits; - result = scatterBits(result, findv4bitmask(loc)); - write32le(loc, result | read32le(loc)); -} - -static void relocHexGOTRELUnsigned(uint8_t *loc, uint64_t P, uint64_t S, - uint64_t A, uint64_t GOT) { - uint32_t result = S + A - GOT; - result = scatterBits(result, findv4bitmask(loc)); - write32le(loc, result | read32le(loc)); -} - -static void relocHexGOTREL_HILO16(uint8_t *loc, uint64_t P, uint64_t S, - uint64_t A, uint64_t GOT, int shiftBits) { - int32_t result = (S + A - GOT) >> shiftBits; - result = scatterBits(result, 0x00c03fff); - write32le(loc, result | read32le(loc)); -} - -static void relocHexGOTREL_32(uint8_t *loc, uint64_t P, uint64_t S, uint64_t A, - uint64_t GOT) { - int32_t result = S + A - GOT; - write32le(loc, result | read32le(loc)); -} - -std::error_code HexagonTargetRelocationHandler::applyRelocation( - ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom, - const Reference &ref) const { - uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset; - uint8_t *loc = atomContent + ref.offsetInAtom(); - uint64_t target = writer.addressOfAtom(ref.target()); - uint64_t reloc = atom._virtualAddr + ref.offsetInAtom(); - - if (ref.kindNamespace() != Reference::KindNamespace::ELF) - return std::error_code(); - assert(ref.kindArch() == Reference::KindArch::Hexagon); - switch (ref.kindValue()) { - case R_HEX_B22_PCREL: - relocBNPCREL(loc, reloc, target, ref.addend(), 21); - break; - case R_HEX_B15_PCREL: - relocBNPCREL(loc, reloc, target, ref.addend(), 14); - break; - case R_HEX_B9_PCREL: - relocBNPCREL(loc, reloc, target, ref.addend(), 8); - break; - case R_HEX_LO16: - relocLO16(loc, reloc, target, ref.addend()); - break; - case R_HEX_HI16: - relocHI16(loc, reloc, target, ref.addend()); - break; - case R_HEX_32: - reloc32(loc, reloc, target, ref.addend()); - break; - case R_HEX_32_6_X: - reloc32_6_X(loc, reloc, target, ref.addend()); - break; - case R_HEX_B32_PCREL_X: - relocHexB32PCRELX(loc, reloc, target, ref.addend()); - break; - case R_HEX_B22_PCREL_X: - relocHexBNPCRELX(loc, reloc, target, ref.addend(), 21); - break; - case R_HEX_B15_PCREL_X: - relocHexBNPCRELX(loc, reloc, target, ref.addend(), 14); - break; - case R_HEX_B13_PCREL_X: - relocHexBNPCRELX(loc, reloc, target, ref.addend(), 12); - break; - case R_HEX_B9_PCREL_X: - relocHexBNPCRELX(loc, reloc, target, ref.addend(), 8); - break; - case R_HEX_B7_PCREL_X: - relocHexBNPCRELX(loc, reloc, target, ref.addend(), 6); - break; - case R_HEX_GPREL16_0: - relocHexGPRELN(loc, reloc, target, ref.addend(), - _targetLayout.getSDataSection()->virtualAddr(), 0); - break; - case R_HEX_GPREL16_1: - relocHexGPRELN(loc, reloc, target, ref.addend(), - _targetLayout.getSDataSection()->virtualAddr(), 1); - break; - case R_HEX_GPREL16_2: - relocHexGPRELN(loc, reloc, target, ref.addend(), - _targetLayout.getSDataSection()->virtualAddr(), 2); - break; - case R_HEX_GPREL16_3: - relocHexGPRELN(loc, reloc, target, ref.addend(), - _targetLayout.getSDataSection()->virtualAddr(), 3); - break; - case R_HEX_16_X: - case R_HEX_12_X: - case R_HEX_11_X: - case R_HEX_10_X: - case R_HEX_9_X: - case R_HEX_8_X: - case R_HEX_7_X: - case R_HEX_6_X: - relocHex_N_X(loc, reloc, target, ref.addend()); - break; - case R_HEX_6_PCREL_X: - relocHex6PCRELX(loc, reloc, target, ref.addend()); - break; - case R_HEX_JMP_SLOT: - case R_HEX_GLOB_DAT: - break; - case R_HEX_GOTREL_32: - relocHexGOTREL_32(loc, reloc, target, ref.addend(), - _targetLayout.getGOTSymAddr()); - break; - case R_HEX_GOTREL_LO16: - relocHexGOTREL_HILO16(loc, reloc, target, ref.addend(), - _targetLayout.getGOTSymAddr(), 0); - break; - case R_HEX_GOTREL_HI16: - relocHexGOTREL_HILO16(loc, reloc, target, ref.addend(), - _targetLayout.getGOTSymAddr(), 16); - break; - case R_HEX_GOT_LO16: - relocHexGOTLO16(loc, target, _targetLayout.getGOTSymAddr()); - break; - case R_HEX_GOT_HI16: - relocHexGOTHI16(loc, target, _targetLayout.getGOTSymAddr()); - break; - case R_HEX_GOT_32: - relocHexGOT32(loc, target, _targetLayout.getGOTSymAddr()); - break; - case R_HEX_GOT_16: - relocHexGOT16(loc, target, _targetLayout.getGOTSymAddr()); - break; - case R_HEX_GOT_32_6_X: - relocHexGOT32_6_X(loc, target, _targetLayout.getGOTSymAddr()); - break; - case R_HEX_GOT_16_X: - relocHexGOT16_X(loc, target, _targetLayout.getGOTSymAddr()); - break; - case R_HEX_GOT_11_X: - relocHexGOT11_X(loc, target, _targetLayout.getGOTSymAddr()); - break; - case R_HEX_GOTREL_32_6_X: - relocHexGOTRELSigned(loc, reloc, target, ref.addend(), - _targetLayout.getGOTSymAddr(), 6); - break; - case R_HEX_GOTREL_16_X: - case R_HEX_GOTREL_11_X: - relocHexGOTRELUnsigned(loc, reloc, target, ref.addend(), - _targetLayout.getGOTSymAddr()); - break; - - default: - return make_unhandled_reloc_error(); - } - - return std::error_code(); -} diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h b/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h deleted file mode 100644 index 6afba0ddb8f3..000000000000 --- a/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h +++ /dev/null @@ -1,33 +0,0 @@ -//===- lld/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h -----------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_RELOCATION_HANDLER_H -#define LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_RELOCATION_HANDLER_H - -#include "lld/ReaderWriter/ELFLinkingContext.h" - -namespace lld { -namespace elf { -class HexagonTargetHandler; -class HexagonTargetLayout; - -class HexagonTargetRelocationHandler final : public TargetRelocationHandler { -public: - HexagonTargetRelocationHandler(HexagonTargetLayout &layout) - : _targetLayout(layout) {} - - std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &, - const AtomLayout &, - const Reference &) const override; - -private: - HexagonTargetLayout &_targetLayout; -}; -} // elf -} // lld -#endif diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp b/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp deleted file mode 100644 index 6c0360c310f4..000000000000 --- a/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp +++ /dev/null @@ -1,382 +0,0 @@ -//===- lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp --------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "HexagonExecutableWriter.h" -#include "HexagonDynamicLibraryWriter.h" -#include "HexagonLinkingContext.h" -#include "HexagonTargetHandler.h" - -using namespace llvm::ELF; - -using llvm::makeArrayRef; - -namespace lld { -namespace elf { - -HexagonTargetHandler::HexagonTargetHandler(HexagonLinkingContext &ctx) - : _ctx(ctx), _targetLayout(new HexagonTargetLayout(ctx)), - _relocationHandler(new HexagonTargetRelocationHandler(*_targetLayout)) {} - -std::unique_ptr<Writer> HexagonTargetHandler::getWriter() { - switch (_ctx.getOutputELFType()) { - case llvm::ELF::ET_EXEC: - return llvm::make_unique<HexagonExecutableWriter>(_ctx, *_targetLayout); - case llvm::ELF::ET_DYN: - return llvm::make_unique<HexagonDynamicLibraryWriter>(_ctx, *_targetLayout); - case llvm::ELF::ET_REL: - llvm_unreachable("TODO: support -r mode"); - default: - llvm_unreachable("unsupported output type"); - } -} - -using namespace llvm::ELF; - -// .got atom -const uint8_t hexagonGotAtomContent[4] = { 0 }; -// .got.plt atom (entry 0) -const uint8_t hexagonGotPlt0AtomContent[16] = { 0 }; -// .got.plt atom (all other entries) -const uint8_t hexagonGotPltAtomContent[4] = { 0 }; -// .plt (entry 0) -const uint8_t hexagonPlt0AtomContent[28] = { - 0x00, 0x40, 0x00, 0x00, // { immext (#0) - 0x1c, 0xc0, 0x49, 0x6a, // r28 = add (pc, ##GOT0@PCREL) } # address of GOT0 - 0x0e, 0x42, 0x9c, 0xe2, // { r14 -= add (r28, #16) # offset of GOTn from GOTa - 0x4f, 0x40, 0x9c, 0x91, // r15 = memw (r28 + #8) # object ID at GOT2 - 0x3c, 0xc0, 0x9c, 0x91, // r28 = memw (r28 + #4) }# dynamic link at GOT1 - 0x0e, 0x42, 0x0e, 0x8c, // { r14 = asr (r14, #2) # index of PLTn - 0x00, 0xc0, 0x9c, 0x52, // jumpr r28 } # call dynamic linker -}; - -// .plt (other entries) -const uint8_t hexagonPltAtomContent[16] = { - 0x00, 0x40, 0x00, 0x00, // { immext (#0) - 0x0e, 0xc0, 0x49, 0x6a, // r14 = add (pc, ##GOTn@PCREL) } # address of GOTn - 0x1c, 0xc0, 0x8e, 0x91, // r28 = memw (r14) # contents of GOTn - 0x00, 0xc0, 0x9c, 0x52, // jumpr r28 # call it -}; - -class HexagonGOTAtom : public GOTAtom { -public: - HexagonGOTAtom(const File &f) : GOTAtom(f, ".got") {} - - ArrayRef<uint8_t> rawContent() const override { - return makeArrayRef(hexagonGotAtomContent); - } - - Alignment alignment() const override { return 4; } -}; - -class HexagonGOTPLTAtom : public GOTAtom { -public: - HexagonGOTPLTAtom(const File &f) : GOTAtom(f, ".got.plt") {} - - ArrayRef<uint8_t> rawContent() const override { - return makeArrayRef(hexagonGotPltAtomContent); - } - - Alignment alignment() const override { return 4; } -}; - -class HexagonGOTPLT0Atom : public GOTAtom { -public: - HexagonGOTPLT0Atom(const File &f) : GOTAtom(f, ".got.plt") {} - - ArrayRef<uint8_t> rawContent() const override { - return makeArrayRef(hexagonGotPlt0AtomContent); - } - - Alignment alignment() const override { return 8; } -}; - -class HexagonPLT0Atom : public PLT0Atom { -public: - HexagonPLT0Atom(const File &f) : PLT0Atom(f) {} - - ArrayRef<uint8_t> rawContent() const override { - return makeArrayRef(hexagonPlt0AtomContent); - } -}; - -class HexagonPLTAtom : public PLTAtom { - -public: - HexagonPLTAtom(const File &f, StringRef secName) : PLTAtom(f, secName) {} - - ArrayRef<uint8_t> rawContent() const override { - return makeArrayRef(hexagonPltAtomContent); - } -}; - -class ELFPassFile : public SimpleFile { -public: - ELFPassFile(const ELFLinkingContext &eti) : SimpleFile("ELFPassFile") { - setOrdinal(eti.getNextOrdinalAndIncrement()); - } - - llvm::BumpPtrAllocator _alloc; -}; - -/// \brief Create GOT and PLT entries for relocations. Handles standard GOT/PLT -template <class Derived> class GOTPLTPass : public Pass { - /// \brief Handle a specific reference. - void handleReference(const DefinedAtom &atom, const Reference &ref) { - if (ref.kindNamespace() != Reference::KindNamespace::ELF) - return; - assert(ref.kindArch() == Reference::KindArch::Hexagon); - switch (ref.kindValue()) { - case R_HEX_PLT_B22_PCREL: - case R_HEX_B22_PCREL: - static_cast<Derived *>(this)->handlePLT32(ref); - break; - case R_HEX_GOT_LO16: - case R_HEX_GOT_HI16: - case R_HEX_GOT_32_6_X: - case R_HEX_GOT_16_X: - case R_HEX_GOT_11_X: - static_cast<Derived *>(this)->handleGOTREL(ref); - break; - } - } - -protected: - /// \brief Create a GOT entry containing 0. - const GOTAtom *getNullGOT() { - if (!_null) { - _null = new (_file._alloc) HexagonGOTPLTAtom(_file); -#ifndef NDEBUG - _null->_name = "__got_null"; -#endif - } - return _null; - } - -public: - GOTPLTPass(const ELFLinkingContext &ctx) : _file(ctx) {} - - /// \brief Do the pass. - /// - /// The goal here is to first process each reference individually. Each call - /// to handleReference may modify the reference itself and/or create new - /// atoms which must be stored in one of the maps below. - /// - /// After all references are handled, the atoms created during that are all - /// added to mf. - std::error_code perform(SimpleFile &mf) override { - // Process all references. - for (const auto &atom : mf.defined()) - for (const auto &ref : *atom) - handleReference(*atom, *ref); - - // Add all created atoms to the link. - uint64_t ordinal = 0; - if (_plt0) { - _plt0->setOrdinal(ordinal++); - mf.addAtom(*_plt0); - } - for (auto &plt : _pltVector) { - plt->setOrdinal(ordinal++); - mf.addAtom(*plt); - } - if (_null) { - _null->setOrdinal(ordinal++); - mf.addAtom(*_null); - } - if (_got0) { - _got0->setOrdinal(ordinal++); - mf.addAtom(*_got0); - } - for (auto &got : _gotVector) { - got->setOrdinal(ordinal++); - mf.addAtom(*got); - } - - return std::error_code(); - } - -protected: - /// \brief Owner of all the Atoms created by this pass. - ELFPassFile _file; - - /// \brief Map Atoms to their GOT entries. - llvm::DenseMap<const Atom *, GOTAtom *> _gotMap; - - /// \brief Map Atoms to their PLT entries. - llvm::DenseMap<const Atom *, PLTAtom *> _pltMap; - - /// \brief the list of GOT/PLT atoms - std::vector<GOTAtom *> _gotVector; - std::vector<PLTAtom *> _pltVector; - - /// \brief GOT entry that is always 0. Used for undefined weaks. - GOTAtom *_null = nullptr; - - /// \brief The got and plt entries for .PLT0. This is used to call into the - /// dynamic linker for symbol resolution. - /// @{ - PLT0Atom *_plt0 = nullptr; - GOTAtom *_got0 = nullptr; - /// @} -}; - -class DynamicGOTPLTPass final : public GOTPLTPass<DynamicGOTPLTPass> { -public: - DynamicGOTPLTPass(const HexagonLinkingContext &ctx) : GOTPLTPass(ctx) { - _got0 = new (_file._alloc) HexagonGOTPLT0Atom(_file); -#ifndef NDEBUG - _got0->_name = "__got0"; -#endif - } - - const PLT0Atom *getPLT0() { - if (_plt0) - return _plt0; - _plt0 = new (_file._alloc) HexagonPLT0Atom(_file); - _plt0->addReferenceELF_Hexagon(R_HEX_B32_PCREL_X, 0, _got0, 0); - _plt0->addReferenceELF_Hexagon(R_HEX_6_PCREL_X, 4, _got0, 4); - DEBUG_WITH_TYPE("PLT", llvm::dbgs() << "[ PLT0/GOT0 ] " - << "Adding plt0/got0 \n"); - return _plt0; - } - - const PLTAtom *getPLTEntry(const Atom *a) { - auto plt = _pltMap.find(a); - if (plt != _pltMap.end()) - return plt->second; - auto ga = new (_file._alloc) HexagonGOTPLTAtom(_file); - ga->addReferenceELF_Hexagon(R_HEX_JMP_SLOT, 0, a, 0); - auto pa = new (_file._alloc) HexagonPLTAtom(_file, ".plt"); - pa->addReferenceELF_Hexagon(R_HEX_B32_PCREL_X, 0, ga, 0); - pa->addReferenceELF_Hexagon(R_HEX_6_PCREL_X, 4, ga, 4); - - // Point the got entry to the PLT0 atom initially - ga->addReferenceELF_Hexagon(R_HEX_32, 0, getPLT0(), 0); -#ifndef NDEBUG - ga->_name = "__got_"; - ga->_name += a->name(); - pa->_name = "__plt_"; - pa->_name += a->name(); - DEBUG_WITH_TYPE("PLT", llvm::dbgs() << "[" << a->name() << "] " - << "Adding plt/got: " << pa->_name - << "/" << ga->_name << "\n"); -#endif - _gotMap[a] = ga; - _pltMap[a] = pa; - _gotVector.push_back(ga); - _pltVector.push_back(pa); - return pa; - } - - const GOTAtom *getGOTEntry(const Atom *a) { - auto got = _gotMap.find(a); - if (got != _gotMap.end()) - return got->second; - auto ga = new (_file._alloc) HexagonGOTAtom(_file); - ga->addReferenceELF_Hexagon(R_HEX_GLOB_DAT, 0, a, 0); - -#ifndef NDEBUG - ga->_name = "__got_"; - ga->_name += a->name(); - DEBUG_WITH_TYPE("GOT", llvm::dbgs() << "[" << a->name() << "] " - << "Adding got: " << ga->_name << "\n"); -#endif - _gotMap[a] = ga; - _gotVector.push_back(ga); - return ga; - } - - std::error_code handleGOTREL(const Reference &ref) { - // Turn this so that the target is set to the GOT entry - const_cast<Reference &>(ref).setTarget(getGOTEntry(ref.target())); - return std::error_code(); - } - - std::error_code handlePLT32(const Reference &ref) { - // Turn this into a PC32 to the PLT entry. - assert(ref.kindNamespace() == Reference::KindNamespace::ELF); - assert(ref.kindArch() == Reference::KindArch::Hexagon); - const_cast<Reference &>(ref).setKindValue(R_HEX_B22_PCREL); - const_cast<Reference &>(ref).setTarget(getPLTEntry(ref.target())); - return std::error_code(); - } -}; - -void HexagonLinkingContext::addPasses(PassManager &pm) { - if (isDynamic()) - pm.add(llvm::make_unique<DynamicGOTPLTPass>(*this)); - ELFLinkingContext::addPasses(pm); -} - -void SDataSection::doPreFlight() { - // sort the atoms on the alignments they have been set - std::stable_sort(_atoms.begin(), _atoms.end(), [](const AtomLayout *A, - const AtomLayout *B) { - const DefinedAtom *definedAtomA = cast<DefinedAtom>(A->_atom); - const DefinedAtom *definedAtomB = cast<DefinedAtom>(B->_atom); - int64_t alignmentA = definedAtomA->alignment().value; - int64_t alignmentB = definedAtomB->alignment().value; - if (alignmentA == alignmentB) { - if (definedAtomA->merge() == DefinedAtom::mergeAsTentative) - return false; - if (definedAtomB->merge() == DefinedAtom::mergeAsTentative) - return true; - } - return alignmentA < alignmentB; - }); - - // Set the fileOffset, and the appropriate size of the section - for (auto &ai : _atoms) { - const DefinedAtom *definedAtom = cast<DefinedAtom>(ai->_atom); - DefinedAtom::Alignment atomAlign = definedAtom->alignment(); - uint64_t fOffset = alignOffset(fileSize(), atomAlign); - uint64_t mOffset = alignOffset(memSize(), atomAlign); - ai->_fileOffset = fOffset; - _fsize = fOffset + definedAtom->size(); - _msize = mOffset + definedAtom->size(); - } -} // finalize - -SDataSection::SDataSection(const HexagonLinkingContext &ctx) - : AtomSection(ctx, ".sdata", DefinedAtom::typeDataFast, 0, - HexagonTargetLayout::ORDER_SDATA) { - _type = SHT_PROGBITS; - _flags = SHF_ALLOC | SHF_WRITE; - _alignment = 4096; -} - -const AtomLayout *SDataSection::appendAtom(const Atom *atom) { - const DefinedAtom *definedAtom = cast<DefinedAtom>(atom); - DefinedAtom::Alignment atomAlign = definedAtom->alignment(); - uint64_t alignment = atomAlign.value; - _atoms.push_back(new (_alloc) AtomLayout(atom, 0, 0)); - // Set the section alignment to the largest alignment - // std::max doesn't support uint64_t - if (_alignment < alignment) - _alignment = alignment; - return _atoms.back(); -} - -void finalizeHexagonRuntimeAtomValues(HexagonTargetLayout &layout) { - AtomLayout *gotAtom = layout.findAbsoluteAtom("_GLOBAL_OFFSET_TABLE_"); - OutputSection<ELF32LE> *gotpltSection = layout.findOutputSection(".got.plt"); - if (gotpltSection) - gotAtom->_virtualAddr = gotpltSection->virtualAddr(); - else - gotAtom->_virtualAddr = 0; - AtomLayout *dynamicAtom = layout.findAbsoluteAtom("_DYNAMIC"); - OutputSection<ELF32LE> *dynamicSection = layout.findOutputSection(".dynamic"); - if (dynamicSection) - dynamicAtom->_virtualAddr = dynamicSection->virtualAddr(); - else - dynamicAtom->_virtualAddr = 0; -} - -} // namespace elf -} // namespace lld diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h b/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h deleted file mode 100644 index b1366bed09ea..000000000000 --- a/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h +++ /dev/null @@ -1,134 +0,0 @@ -//===- lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h ----------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef HEXAGON_TARGET_HANDLER_H -#define HEXAGON_TARGET_HANDLER_H - -#include "ELFReader.h" -#include "HexagonELFFile.h" -#include "HexagonRelocationHandler.h" -#include "TargetLayout.h" - -namespace lld { -namespace elf { -class HexagonLinkingContext; - -/// \brief Handle Hexagon SData section -class SDataSection : public AtomSection<ELF32LE> { -public: - SDataSection(const HexagonLinkingContext &ctx); - - /// \brief Finalize the section contents before writing - void doPreFlight() override; - - /// \brief Does this section have an output segment. - bool hasOutputSegment() const override { return true; } - - const AtomLayout *appendAtom(const Atom *atom) override; -}; - -/// \brief TargetLayout for Hexagon -class HexagonTargetLayout final : public TargetLayout<ELF32LE> { -public: - enum HexagonSectionOrder { - ORDER_SDATA = 205 - }; - - HexagonTargetLayout(HexagonLinkingContext &ctx) - : TargetLayout(ctx), _sdataSection(ctx) {} - - /// \brief Return the section order for a input section - TargetLayout::SectionOrder - getSectionOrder(StringRef name, int32_t contentType, - int32_t contentPermissions) override { - if (contentType == DefinedAtom::typeDataFast || - contentType == DefinedAtom::typeZeroFillFast) - return ORDER_SDATA; - return TargetLayout::getSectionOrder(name, contentType, contentPermissions); - } - - /// \brief Return the appropriate input section name. - StringRef getInputSectionName(const DefinedAtom *da) const override { - switch (da->contentType()) { - case DefinedAtom::typeDataFast: - case DefinedAtom::typeZeroFillFast: - return ".sdata"; - default: - break; - } - return TargetLayout::getInputSectionName(da); - } - - /// \brief Gets or creates a section. - AtomSection<ELF32LE> * - createSection(StringRef name, int32_t contentType, - DefinedAtom::ContentPermissions contentPermissions, - TargetLayout::SectionOrder sectionOrder) override { - if (contentType == DefinedAtom::typeDataFast || - contentType == DefinedAtom::typeZeroFillFast) - return &_sdataSection; - return TargetLayout::createSection(name, contentType, contentPermissions, - sectionOrder); - } - - /// \brief get the segment type for the section thats defined by the target - TargetLayout::SegmentType - getSegmentType(const Section<ELF32LE> *section) const override { - if (section->order() == ORDER_SDATA) - return PT_LOAD; - return TargetLayout::getSegmentType(section); - } - - Section<ELF32LE> *getSDataSection() { return &_sdataSection; } - - uint64_t getGOTSymAddr() { - std::call_once(_gotOnce, [this]() { - if (AtomLayout *got = findAbsoluteAtom("_GLOBAL_OFFSET_TABLE_")) - _gotAddr = got->_virtualAddr; - }); - return _gotAddr; - } - -private: - SDataSection _sdataSection; - uint64_t _gotAddr = 0; - std::once_flag _gotOnce; -}; - -/// \brief TargetHandler for Hexagon -class HexagonTargetHandler final : public TargetHandler { -public: - HexagonTargetHandler(HexagonLinkingContext &targetInfo); - - const TargetRelocationHandler &getRelocationHandler() const override { - return *_relocationHandler; - } - - std::unique_ptr<Reader> getObjReader() override { - return llvm::make_unique<ELFReader<HexagonELFFile>>(_ctx); - } - - std::unique_ptr<Reader> getDSOReader() override { - return llvm::make_unique<ELFReader<DynamicFile<ELF32LE>>>(_ctx); - } - - std::unique_ptr<Writer> getWriter() override; - -private: - HexagonLinkingContext &_ctx; - std::unique_ptr<HexagonTargetLayout> _targetLayout; - std::unique_ptr<HexagonTargetRelocationHandler> _relocationHandler; -}; - -void finalizeHexagonRuntimeAtomValues(HexagonTargetLayout &layout); - -} // end namespace elf -} // end namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/Mips/CMakeLists.txt b/lib/ReaderWriter/ELF/Mips/CMakeLists.txt deleted file mode 100644 index fd52a08ad2d8..000000000000 --- a/lib/ReaderWriter/ELF/Mips/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -add_lld_library(lldMipsELFTarget - MipsAbiInfoHandler.cpp - MipsCtorsOrderPass.cpp - MipsELFFile.cpp - MipsELFWriters.cpp - MipsLinkingContext.cpp - MipsRelocationHandler.cpp - MipsRelocationPass.cpp - MipsSectionChunks.cpp - MipsTargetHandler.cpp - MipsTargetLayout.cpp - LINK_LIBS - lldELF - lldReaderWriter - lldCore - LLVMObject - LLVMSupport - ) diff --git a/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.cpp b/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.cpp deleted file mode 100644 index ad4e62e64680..000000000000 --- a/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.cpp +++ /dev/null @@ -1,675 +0,0 @@ -//===- lib/ReaderWriter/ELF/MipsAbiInfoHandler.cpp ------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "MipsAbiInfoHandler.h" -#include "lld/Core/Error.h" -#include "lld/ReaderWriter/ELFLinkingContext.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Support/ELF.h" -#include "llvm/Support/MipsABIFlags.h" -#include "llvm/Support/raw_ostream.h" - -using namespace lld; -using namespace lld::elf; -using namespace llvm; -using namespace llvm::ELF; -using namespace llvm::Mips; - -namespace { - -// The joined set of MIPS ISAs and MIPS ISA extensions. -enum MipsISAs { - ArchNone, - - // General ISAs - Arch1, - Arch2, - Arch3, - Arch4, - Arch5, - Arch32, - Arch32r2, - Arch32r3, - Arch32r5, - Arch32r6, - Arch64, - Arch64r2, - Arch64r3, - Arch64r5, - Arch64r6, - - // CPU specific ISAs - Arch3900, - Arch4010, - Arch4100, - Arch4111, - Arch4120, - Arch4650, - Arch5400, - Arch5500, - Arch5900, - Arch9000, - Arch10000, - ArchLs2e, - ArchLs2f, - ArchLs3a, - ArchOcteon, - ArchOcteonP, - ArchOcteon2, - ArchOcteon3, - ArchSB1, - ArchXLR -}; - -struct MipsISATreeEdge { - MipsISAs child; - MipsISAs parent; -}; - -struct ElfArchPair { - uint32_t _elfFlag; - MipsISAs _arch; -}; - -struct AbiIsaArchPair { - uint8_t _isaLevel; - uint8_t _isaRev; - uint8_t _isaExt; - MipsISAs _arch; -}; -} - -static const MipsISATreeEdge isaTree[] = { - // MIPS32R6 and MIPS64R6 are not compatible with other extensions - - // MIPS64R2 extensions. - {ArchOcteon3, ArchOcteon2}, - {ArchOcteon2, ArchOcteonP}, - {ArchOcteonP, ArchOcteon}, - {ArchOcteon, Arch64r2}, - {ArchLs3a, Arch64r2}, - - // MIPS64 extensions. - {Arch64r2, Arch64}, - {ArchSB1, Arch64}, - {ArchXLR, Arch64}, - - // MIPS V extensions. - {Arch64, Arch5}, - - // R5000 extensions. - {Arch5500, Arch5400}, - - // MIPS IV extensions. - {Arch5, Arch4}, - {Arch5400, Arch4}, - {Arch9000, Arch4}, - - // VR4100 extensions. - {Arch4120, Arch4100}, - {Arch4111, Arch4100}, - - // MIPS III extensions. - {ArchLs2e, Arch3}, - {ArchLs2f, Arch3}, - {Arch4650, Arch3}, - {Arch4100, Arch3}, - {Arch4010, Arch3}, - {Arch5900, Arch3}, - {Arch4, Arch3}, - - // MIPS32 extensions. - {Arch32r2, Arch32}, - - // MIPS II extensions. - {Arch3, Arch2}, - {Arch32, Arch2}, - - // MIPS I extensions. - {Arch3900, Arch1}, - {Arch2, Arch1}, -}; - -// Conversion ELF arch flags => MipsISAs -static const ElfArchPair elfArchPairs[] = { - {EF_MIPS_ARCH_1 | EF_MIPS_MACH_3900, Arch3900}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4010, Arch4010}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100, Arch4100}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4111, Arch4111}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4120, Arch4120}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4650, Arch4650}, - {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400, Arch5400}, - {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5500, Arch5500}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_5900, Arch5900}, - {EF_MIPS_ARCH_4 | EF_MIPS_MACH_9000, Arch9000}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2E, ArchLs2e}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2F, ArchLs2f}, - {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_LS3A, ArchLs3a}, - {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, ArchOcteon}, - {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON2, ArchOcteon2}, - {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, ArchOcteon3}, - {EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, ArchSB1}, - {EF_MIPS_ARCH_64 | EF_MIPS_MACH_XLR, ArchXLR}, - {EF_MIPS_ARCH_1, Arch1}, - {EF_MIPS_ARCH_2, Arch2}, - {EF_MIPS_ARCH_3, Arch3}, - {EF_MIPS_ARCH_4, Arch4}, - {EF_MIPS_ARCH_5, Arch5}, - {EF_MIPS_ARCH_32, Arch32}, - {EF_MIPS_ARCH_32R2, Arch32r2}, - {EF_MIPS_ARCH_32R6, Arch32r6}, - {EF_MIPS_ARCH_64, Arch64}, - {EF_MIPS_ARCH_64R2, Arch64r2}, - {EF_MIPS_ARCH_64R6, Arch64r6} -}; - -// Conversion MipsISAs => ELF arch flags -static const ElfArchPair archElfPairs[] = { - {EF_MIPS_ARCH_1, Arch1}, - {EF_MIPS_ARCH_2, Arch2}, - {EF_MIPS_ARCH_3, Arch3}, - {EF_MIPS_ARCH_4, Arch4}, - {EF_MIPS_ARCH_5, Arch5}, - {EF_MIPS_ARCH_32, Arch32}, - {EF_MIPS_ARCH_32R2, Arch32r2}, - {EF_MIPS_ARCH_32R2, Arch32r3}, - {EF_MIPS_ARCH_32R2, Arch32r5}, - {EF_MIPS_ARCH_32R6, Arch32r6}, - {EF_MIPS_ARCH_64, Arch64}, - {EF_MIPS_ARCH_64R2, Arch64r2}, - {EF_MIPS_ARCH_64R2, Arch64r3}, - {EF_MIPS_ARCH_64R2, Arch64r5}, - {EF_MIPS_ARCH_64R6, Arch64r6}, - {EF_MIPS_ARCH_1 | EF_MIPS_MACH_3900, Arch3900}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4010, Arch4010}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100, Arch4100}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4111, Arch4111}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4120, Arch4120}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4650, Arch4650}, - {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400, Arch5400}, - {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5500, Arch5500}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_5900, Arch5900}, - {EF_MIPS_ARCH_4 | EF_MIPS_MACH_9000, Arch9000}, - {EF_MIPS_ARCH_4, Arch10000}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2E, ArchLs2e}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2F, ArchLs2f}, - {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_LS3A, ArchLs3a}, - {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, ArchOcteon}, - {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, ArchOcteonP}, - {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON2, ArchOcteon2}, - {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, ArchOcteon3}, - {EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, ArchSB1}, - {EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, ArchXLR} -}; - -// Conversion .MIPS.abiflags isa/level/extension <=> MipsISAs -static const AbiIsaArchPair abiIsaArchPair[] = { - { 0, 0, 0, ArchNone}, - { 1, 0, 0, Arch1}, - { 2, 0, 0, Arch2}, - { 3, 0, 0, Arch3}, - { 4, 0, 0, Arch4}, - { 5, 0, 0, Arch5}, - {32, 1, 0, Arch32}, - {32, 2, 0, Arch32r2}, - {32, 3, 0, Arch32r3}, - {32, 5, 0, Arch32r5}, - {32, 6, 0, Arch32r6}, - {64, 1, 0, Arch64}, - {64, 2, 0, Arch64r2}, - {64, 3, 0, Arch64r3}, - {64, 5, 0, Arch64r5}, - {64, 6, 0, Arch64r6}, - { 1, 0, AFL_EXT_3900, Arch3900}, - { 3, 0, AFL_EXT_4010, Arch4010}, - { 3, 0, AFL_EXT_4100, Arch4100}, - { 3, 0, AFL_EXT_4111, Arch4111}, - { 3, 0, AFL_EXT_4120, Arch4120}, - { 3, 0, AFL_EXT_4650, Arch4650}, - { 4, 0, AFL_EXT_5400, Arch5400}, - { 4, 0, AFL_EXT_5500, Arch5500}, - { 3, 0, AFL_EXT_5900, Arch5900}, - { 4, 0, AFL_EXT_10000, Arch10000}, - { 3, 0, AFL_EXT_LOONGSON_2E, ArchLs2e}, - { 3, 0, AFL_EXT_LOONGSON_2F, ArchLs2f}, - {64, 2, AFL_EXT_LOONGSON_3A, ArchLs3a}, - {64, 2, AFL_EXT_OCTEON, ArchOcteon}, - {64, 2, AFL_EXT_OCTEON2, ArchOcteon2}, - {64, 2, AFL_EXT_OCTEON3, ArchOcteon3}, - {64, 1, AFL_EXT_SB1, ArchSB1}, - {64, 1, AFL_EXT_XLR, ArchXLR} -}; - -static bool matchMipsISA(MipsISAs base, MipsISAs ext) { - if (base == ext) - return true; - if (base == Arch32 && matchMipsISA(Arch64, ext)) - return true; - if (base == Arch32r2 && matchMipsISA(Arch64r2, ext)) - return true; - for (const auto &edge : isaTree) { - if (ext == edge.child) { - ext = edge.parent; - if (ext == base) - return true; - } - } - return false; -} - -static bool is32BitElfFlags(unsigned flags) { - if (flags & EF_MIPS_32BITMODE) - return true; - - unsigned arch = flags & EF_MIPS_ARCH; - if (arch == EF_MIPS_ARCH_1 || arch == EF_MIPS_ARCH_2 || - arch == EF_MIPS_ARCH_32 || arch == EF_MIPS_ARCH_32R2 || - arch == EF_MIPS_ARCH_32R6) - return true; - - unsigned abi = flags & EF_MIPS_ABI; - if (abi == EF_MIPS_ABI_O32 || abi == EF_MIPS_ABI_EABI32) - return true; - - return false; -} - -static ErrorOr<MipsISAs> headerFlagsToIsa(uint32_t flags) { - uint32_t arch = flags & (EF_MIPS_ARCH | EF_MIPS_MACH); - for (const auto &p : elfArchPairs) - if (p._elfFlag == arch) - return p._arch; - return make_dynamic_error_code( - StringRef("Unknown EF_MIPS_ARCH | EF_MIPS_MACH flags (0x") + - Twine::utohexstr(arch) + ")"); -} - -static uint32_t isaToHeaderFlags(unsigned isa) { - for (const auto &p : archElfPairs) - if (p._arch == isa) - return p._elfFlag; - llvm_unreachable("Unknown MIPS ISA"); -} - -static ErrorOr<uint32_t> flagsToAses(uint32_t flags) { - uint32_t ases = flags & EF_MIPS_ARCH_ASE; - switch (ases) { - case 0: - return 0; - case EF_MIPS_MICROMIPS: - return AFL_ASE_MICROMIPS; - case EF_MIPS_ARCH_ASE_M16: - return AFL_ASE_MIPS16; - case EF_MIPS_ARCH_ASE_MDMX: - return AFL_ASE_MDMX; - default: - return make_dynamic_error_code( - StringRef("Unknown EF_MIPS_ARCH_ASE flag (0x") + - Twine::utohexstr(ases) + ")"); - } -} - -static uint32_t asesToFlags(uint32_t ases) { - switch (ases) { - case AFL_ASE_MICROMIPS: - return EF_MIPS_MICROMIPS; - case AFL_ASE_MIPS16: - return EF_MIPS_ARCH_ASE_M16; - case AFL_ASE_MDMX: - return EF_MIPS_ARCH_ASE_MDMX; - default: - return 0; - } -} - -static ErrorOr<MipsISAs> sectionFlagsToIsa(uint8_t isaLevel, uint8_t isaRev, - uint8_t isaExt) { - for (const auto &p : abiIsaArchPair) - if (p._isaLevel == isaLevel && p._isaRev == isaRev && p._isaExt == isaExt) - return p._arch; - return make_dynamic_error_code( - StringRef("Unknown ISA level/revision/extension ") + Twine(isaLevel) + - "/" + Twine(isaRev) + "/" + Twine(isaExt)); -} - -static std::tuple<uint8_t, uint8_t, uint32_t> isaToSectionFlags(unsigned isa) { - for (const auto &p : abiIsaArchPair) - if (p._arch == isa) - return std::make_tuple(p._isaLevel, p._isaRev, p._isaExt); - llvm_unreachable("Unknown MIPS ISA"); -} - -static bool checkCompatibility(const MipsAbiFlags &hdr, - const MipsAbiFlags &sec) { - uint32_t secIsa = ArchNone; - switch (sec._isa) { - case Arch32r3: - case Arch32r5: - secIsa = Arch32r2; - break; - case Arch64r3: - case Arch64r5: - secIsa = Arch64r2; - break; - default: - secIsa = sec._isa; - break; - } - if (secIsa != hdr._isa) { - llvm::errs() << "inconsistent ISA between .MIPS.abiflags " - "and ELF header e_flags field\n"; - return false; - } - if ((sec._ases & hdr._ases) != hdr._ases) { - llvm::errs() << "inconsistent ASEs between .MIPS.abiflags " - "and ELF header e_flags field\n"; - return false; - } - return true; -} - -static int compareFpAbi(uint32_t fpA, uint32_t fpB) { - if (fpA == fpB) - return 0; - if (fpB == Val_GNU_MIPS_ABI_FP_ANY) - return 1; - if (fpB == Val_GNU_MIPS_ABI_FP_64A && fpA == Val_GNU_MIPS_ABI_FP_64) - return 1; - if (fpB != Val_GNU_MIPS_ABI_FP_XX) - return -1; - if (fpA == Val_GNU_MIPS_ABI_FP_DOUBLE || fpA == Val_GNU_MIPS_ABI_FP_64 || - fpA == Val_GNU_MIPS_ABI_FP_64A) - return 1; - return -1; -} - -static StringRef getFpAbiName(uint32_t fpAbi) { - switch (fpAbi) { - case Val_GNU_MIPS_ABI_FP_ANY: - return "<any>"; - case Val_GNU_MIPS_ABI_FP_DOUBLE: - return "-mdouble-float"; - case Val_GNU_MIPS_ABI_FP_SINGLE: - return "-msingle-float"; - case Val_GNU_MIPS_ABI_FP_SOFT: - return "-msoft-float"; - case Val_GNU_MIPS_ABI_FP_OLD_64: - return "-mips32r2 -mfp64 (old)"; - case Val_GNU_MIPS_ABI_FP_XX: - return "-mfpxx"; - case Val_GNU_MIPS_ABI_FP_64: - return "-mgp32 -mfp64"; - case Val_GNU_MIPS_ABI_FP_64A: - return "-mgp32 -mfp64 -mno-odd-spreg"; - default: - return "<unknown>"; - } -} - -static uint32_t selectFpAbiFlag(uint32_t oldFp, uint32_t newFp) { - if (compareFpAbi(newFp, oldFp) >= 0) - return newFp; - if (compareFpAbi(oldFp, newFp) < 0) - llvm::errs() << "FP ABI " << getFpAbiName(oldFp) << " is incompatible with " - << getFpAbiName(newFp) << "\n"; - return oldFp; -} - -namespace lld { -namespace elf { - -template <class ELFT> bool MipsAbiInfoHandler<ELFT>::isMicroMips() const { - assert(_abiFlags.hasValue()); - return _abiFlags->_ases & AFL_ASE_MICROMIPS; -} - -template <class ELFT> bool MipsAbiInfoHandler<ELFT>::isMipsR6() const { - assert(_abiFlags.hasValue()); - return _abiFlags->_isa == Arch32r6 || _abiFlags->_isa == Arch64r6; -} - -template <class ELFT> bool MipsAbiInfoHandler<ELFT>::isFp64() const { - assert(_abiFlags.hasValue()); - return _abiFlags->_fpAbi == Val_GNU_MIPS_ABI_FP_64 || - _abiFlags->_fpAbi == Val_GNU_MIPS_ABI_FP_64A; -} - -template <class ELFT> bool MipsAbiInfoHandler<ELFT>::isCPicOnly() const { - assert(_abiFlags.hasValue()); - return _abiFlags->_isCPic && !_abiFlags->_isPic; -} - -template <class ELFT> uint32_t MipsAbiInfoHandler<ELFT>::getFlags() const { - std::lock_guard<std::mutex> lock(_mutex); - uint32_t flags = 0; - if (_abiFlags.hasValue()) { - flags |= isaToHeaderFlags(_abiFlags->_isa); - flags |= asesToFlags(_abiFlags->_ases); - flags |= _abiFlags->_abi; - flags |= _abiFlags->_isPic ? EF_MIPS_PIC : 0u; - flags |= _abiFlags->_isCPic ? EF_MIPS_CPIC : 0u; - flags |= _abiFlags->_isNoReorder ? EF_MIPS_NOREORDER : 0u; - flags |= _abiFlags->_is32BitMode ? EF_MIPS_32BITMODE : 0u; - flags |= _abiFlags->_isNan2008 ? EF_MIPS_NAN2008 : 0u; - } - return flags; -} - -template <class ELFT> -llvm::Optional<typename MipsAbiInfoHandler<ELFT>::Elf_Mips_RegInfo> -MipsAbiInfoHandler<ELFT>::getRegistersMask() const { - std::lock_guard<std::mutex> lock(_mutex); - return _regMask; -} - -template <class ELFT> -llvm::Optional<typename MipsAbiInfoHandler<ELFT>::Elf_Mips_ABIFlags> -MipsAbiInfoHandler<ELFT>::getAbiFlags() const { - std::lock_guard<std::mutex> lock(_mutex); - if (!_hasAbiSection) - return llvm::Optional<Elf_Mips_ABIFlags>(); - - Elf_Mips_ABIFlags sec; - sec.version = 0; - std::tie(sec.isa_level, sec.isa_rev, sec.isa_ext) = - isaToSectionFlags(_abiFlags->_isa); - sec.gpr_size = _abiFlags->_gprSize; - sec.cpr1_size = _abiFlags->_cpr1Size; - sec.cpr2_size = _abiFlags->_cpr2Size; - sec.fp_abi = _abiFlags->_fpAbi; - sec.ases = _abiFlags->_ases; - sec.flags1 = _abiFlags->_flags1; - sec.flags2 = 0; - return sec; -} - -template <class ELFT> MipsAbi MipsAbiInfoHandler<ELFT>::getAbi() const { - if (!_abiFlags.hasValue()) - return ELFT::Is64Bits ? MipsAbi::N64 : MipsAbi::O32; - switch (_abiFlags->_abi & (EF_MIPS_ABI_O32 | EF_MIPS_ABI2)) { - case EF_MIPS_ABI_O32: - return MipsAbi::O32; - case EF_MIPS_ABI2: - return MipsAbi::N32; - case 0: - return MipsAbi::N64; - default: - llvm_unreachable("Unknown ABI flag"); - } -} - -template <class ELFT> -std::error_code -MipsAbiInfoHandler<ELFT>::mergeFlags(uint32_t newFlags, - const Elf_Mips_ABIFlags *newSec) { - std::lock_guard<std::mutex> lock(_mutex); - - ErrorOr<MipsAbiFlags> abiFlags = createAbiFlags(newFlags, newSec); - if (auto ec = abiFlags.getError()) - return ec; - - // We support three ABI: O32, N32, and N64. The last one does not have - // the corresponding ELF flag. - if (ELFT::Is64Bits) { - if (abiFlags->_abi) - return make_dynamic_error_code("Unsupported ABI"); - } else { - if (!(abiFlags->_abi & (EF_MIPS_ABI_O32 | EF_MIPS_ABI2))) - return make_dynamic_error_code("Unsupported ABI"); - } - - // ... and still do not support MIPS-16 extension. - if (abiFlags->_ases & AFL_ASE_MIPS16) - return make_dynamic_error_code("Unsupported extension: MIPS16"); - - // PIC code is inherently CPIC and may not set CPIC flag explicitly. - // Ensure that this flag will exist in the linked file. - if (abiFlags->_isPic) - abiFlags->_isCPic = true; - - // If the old set of flags is empty, use the new one as a result. - if (!_abiFlags.hasValue()) { - _abiFlags = *abiFlags; - return std::error_code(); - } - - // Check ABI compatibility. - if (abiFlags->_abi != _abiFlags->_abi) - return make_dynamic_error_code("Linking modules with incompatible ABI"); - - // Check PIC / CPIC flags compatibility. - if (abiFlags->_isCPic != _abiFlags->_isCPic) - llvm::errs() << "lld warning: linking abicalls and non-abicalls files\n"; - - if (!abiFlags->_isPic) - _abiFlags->_isPic = false; - if (abiFlags->_isCPic) - _abiFlags->_isCPic = true; - - // Check mixing -mnan=2008 / -mnan=legacy modules. - if (abiFlags->_isNan2008 != _abiFlags->_isNan2008) - return make_dynamic_error_code( - "Linking -mnan=2008 and -mnan=legacy modules"); - - // Check ISA compatibility and update the extension flag. - if (!matchMipsISA(MipsISAs(abiFlags->_isa), MipsISAs(_abiFlags->_isa))) { - if (!matchMipsISA(MipsISAs(_abiFlags->_isa), MipsISAs(abiFlags->_isa))) - return make_dynamic_error_code("Linking modules with incompatible ISA"); - _abiFlags->_isa = abiFlags->_isa; - } - - _abiFlags->_ases |= abiFlags->_ases; - _abiFlags->_isNoReorder = _abiFlags->_isNoReorder || abiFlags->_isNoReorder; - _abiFlags->_is32BitMode = _abiFlags->_is32BitMode || abiFlags->_is32BitMode; - - _abiFlags->_fpAbi = selectFpAbiFlag(_abiFlags->_fpAbi, abiFlags->_fpAbi); - _abiFlags->_gprSize = std::max(_abiFlags->_gprSize, abiFlags->_gprSize); - _abiFlags->_cpr1Size = std::max(_abiFlags->_cpr1Size, abiFlags->_cpr1Size); - _abiFlags->_cpr2Size = std::max(_abiFlags->_cpr2Size, abiFlags->_cpr2Size); - _abiFlags->_flags1 |= abiFlags->_flags1; - - return std::error_code(); -} - -template <class ELFT> -void MipsAbiInfoHandler<ELFT>::mergeRegistersMask( - const Elf_Mips_RegInfo &info) { - std::lock_guard<std::mutex> lock(_mutex); - if (!_regMask.hasValue()) { - _regMask = info; - return; - } - _regMask->ri_gprmask = _regMask->ri_gprmask | info.ri_gprmask; - _regMask->ri_cprmask[0] = _regMask->ri_cprmask[0] | info.ri_cprmask[0]; - _regMask->ri_cprmask[1] = _regMask->ri_cprmask[1] | info.ri_cprmask[1]; - _regMask->ri_cprmask[2] = _regMask->ri_cprmask[2] | info.ri_cprmask[2]; - _regMask->ri_cprmask[3] = _regMask->ri_cprmask[3] | info.ri_cprmask[3]; -} - -template <class ELFT> -ErrorOr<MipsAbiFlags> -MipsAbiInfoHandler<ELFT>::createAbiFlags(uint32_t flags, - const Elf_Mips_ABIFlags *sec) { - ErrorOr<MipsAbiFlags> hdrFlags = createAbiFromHeaderFlags(flags); - if (auto ec = hdrFlags.getError()) - return ec; - if (!sec) - return *hdrFlags; - ErrorOr<MipsAbiFlags> secFlags = createAbiFromSection(*sec); - if (auto ec = secFlags.getError()) - return ec; - if (!checkCompatibility(*hdrFlags, *secFlags)) - return *hdrFlags; - - _hasAbiSection = true; - - secFlags->_abi = hdrFlags->_abi; - secFlags->_isPic = hdrFlags->_isPic; - secFlags->_isCPic = hdrFlags->_isCPic; - secFlags->_isNoReorder = hdrFlags->_isNoReorder; - secFlags->_is32BitMode = hdrFlags->_is32BitMode; - secFlags->_isNan2008 = hdrFlags->_isNan2008; - return *secFlags; -} - -template <class ELFT> -ErrorOr<MipsAbiFlags> -MipsAbiInfoHandler<ELFT>::createAbiFromHeaderFlags(uint32_t flags) { - MipsAbiFlags abi; - ErrorOr<MipsISAs> isa = headerFlagsToIsa(flags); - if (auto ec = isa.getError()) - return ec; - abi._isa = *isa; - - abi._fpAbi = Val_GNU_MIPS_ABI_FP_ANY; - abi._cpr1Size = AFL_REG_NONE; - abi._cpr2Size = AFL_REG_NONE; - abi._gprSize = is32BitElfFlags(flags) ? AFL_REG_32 : AFL_REG_64; - - ErrorOr<uint32_t> ases = flagsToAses(flags); - if (auto ec = ases.getError()) - return ec; - abi._ases = *ases; - abi._flags1 = 0; - abi._abi = flags & (EF_MIPS_ABI | EF_MIPS_ABI2); - abi._isPic = flags & EF_MIPS_PIC; - abi._isCPic = flags & EF_MIPS_CPIC; - abi._isNoReorder = flags & EF_MIPS_NOREORDER; - abi._is32BitMode = flags & EF_MIPS_32BITMODE; - abi._isNan2008 = flags & EF_MIPS_NAN2008; - return abi; -} - -template <class ELFT> -ErrorOr<MipsAbiFlags> -MipsAbiInfoHandler<ELFT>::createAbiFromSection(const Elf_Mips_ABIFlags &sec) { - MipsAbiFlags abi; - ErrorOr<MipsISAs> isa = - sectionFlagsToIsa(sec.isa_level, sec.isa_rev, sec.isa_ext); - if (auto ec = isa.getError()) - return ec; - abi._isa = *isa; - abi._fpAbi = sec.fp_abi; - abi._cpr1Size = sec.cpr1_size; - abi._cpr2Size = sec.cpr2_size; - abi._gprSize = sec.gpr_size; - abi._ases = sec.ases; - abi._flags1 = sec.flags1; - if (sec.flags2 != 0) - return make_dynamic_error_code("unexpected non-zero 'flags2' value"); - return abi; -} - -template class MipsAbiInfoHandler<ELF32BE>; -template class MipsAbiInfoHandler<ELF32LE>; -template class MipsAbiInfoHandler<ELF64BE>; -template class MipsAbiInfoHandler<ELF64LE>; - -} -} diff --git a/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.h b/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.h deleted file mode 100644 index 44da29f09214..000000000000 --- a/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.h +++ /dev/null @@ -1,83 +0,0 @@ -//===- lib/ReaderWriter/ELF/MipsAbiInfoHandler.h --------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_ABI_INFO_HANDLER_H -#define LLD_READER_WRITER_ELF_MIPS_MIPS_ABI_INFO_HANDLER_H - -#include "llvm/ADT/Optional.h" -#include "llvm/Object/ELFTypes.h" -#include "llvm/Support/ErrorOr.h" -#include <mutex> -#include <system_error> - -namespace lld { -namespace elf { - -enum class MipsAbi { O32, N32, N64 }; - -struct MipsAbiFlags { - unsigned _isa = 0; - unsigned _fpAbi = 0; - unsigned _ases = 0; - unsigned _flags1 = 0; - unsigned _gprSize = 0; - unsigned _cpr1Size = 0; - unsigned _cpr2Size = 0; - - unsigned _abi = 0; - - bool _isPic = false; - bool _isCPic = false; - bool _isNoReorder = false; - bool _is32BitMode = false; - bool _isNan2008 = false; -}; - -template <class ELFT> class MipsAbiInfoHandler { -public: - typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo; - typedef llvm::object::Elf_Mips_ABIFlags<ELFT> Elf_Mips_ABIFlags; - - MipsAbiInfoHandler() = default; - - bool hasMipsAbiSection() const { return _hasAbiSection; } - bool isMicroMips() const; - bool isMipsR6() const; - bool isFp64() const; - bool isCPicOnly() const; - - uint32_t getFlags() const; - llvm::Optional<Elf_Mips_RegInfo> getRegistersMask() const; - llvm::Optional<Elf_Mips_ABIFlags> getAbiFlags() const; - - MipsAbi getAbi() const; - - /// \brief Merge saved ELF header flags and the new set of flags. - std::error_code mergeFlags(uint32_t newFlags, - const Elf_Mips_ABIFlags *newAbi); - - /// \brief Merge saved and new sets of registers usage masks. - void mergeRegistersMask(const Elf_Mips_RegInfo &info); - -private: - mutable std::mutex _mutex; - bool _hasAbiSection = false; - llvm::Optional<MipsAbiFlags> _abiFlags; - llvm::Optional<Elf_Mips_RegInfo> _regMask; - - llvm::ErrorOr<MipsAbiFlags> createAbiFlags(uint32_t flags, - const Elf_Mips_ABIFlags *sec); - static llvm::ErrorOr<MipsAbiFlags> createAbiFromHeaderFlags(uint32_t flags); - static llvm::ErrorOr<MipsAbiFlags> - createAbiFromSection(const Elf_Mips_ABIFlags &sec); -}; - -} // namespace elf -} // namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.cpp b/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.cpp deleted file mode 100644 index a7062813df42..000000000000 --- a/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.cpp +++ /dev/null @@ -1,76 +0,0 @@ -//===- lib/ReaderWriter/ELF/Mips/Mips/CtorsOrderPass.cpp ------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "MipsCtorsOrderPass.h" -#include "lld/Core/Simple.h" -#include <algorithm> -#include <climits> - -using namespace lld; -using namespace lld::elf; - -static bool matchCrtObjName(StringRef objName, StringRef objPath) { - if (!objPath.endswith(".o")) - return false; - - // check *<objName> case - objPath = objPath.drop_back(2); - if (objPath.endswith(objName)) - return true; - - // check *<objName>? case - return !objPath.empty() && objPath.drop_back(1).endswith(objName); -} - -static int32_t getSectionPriority(StringRef path, StringRef sectionName) { - // Arrange .ctors/.dtors sections in the following order: - // .ctors from crtbegin.o or crtbegin?.o - // .ctors from regular object files - // .ctors.* (sorted) from regular object files - // .ctors from crtend.o or crtend?.o - - if (matchCrtObjName("crtbegin", path)) - return std::numeric_limits<int32_t>::min(); - if (matchCrtObjName("crtend", path)) - return std::numeric_limits<int32_t>::max(); - - StringRef num = sectionName.drop_front().rsplit('.').second; - - int32_t priority = std::numeric_limits<int32_t>::min() + 1; - if (!num.empty()) - num.getAsInteger(10, priority); - - return priority; -} - -std::error_code MipsCtorsOrderPass::perform(SimpleFile &f) { - auto definedAtoms = f.definedAtoms(); - - auto last = std::stable_partition(definedAtoms.begin(), definedAtoms.end(), - [](const DefinedAtom *atom) { - if (atom->sectionChoice() != DefinedAtom::sectionCustomRequired) - return false; - - StringRef name = atom->customSectionName(); - return name.startswith(".ctors") || name.startswith(".dtors"); - }); - - std::stable_sort(definedAtoms.begin(), last, - [](const DefinedAtom *left, const DefinedAtom *right) { - StringRef leftSec = left->customSectionName(); - StringRef rightSec = right->customSectionName(); - - int32_t leftPriority = getSectionPriority(left->file().path(), leftSec); - int32_t rightPriority = getSectionPriority(right->file().path(), rightSec); - - return leftPriority < rightPriority; - }); - - return std::error_code(); -} diff --git a/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h b/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h deleted file mode 100644 index 5b12b7de0fa2..000000000000 --- a/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h +++ /dev/null @@ -1,25 +0,0 @@ -//===- lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h ---------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_CTORS_ORDER_PASS_H -#define LLD_READER_WRITER_ELF_MIPS_MIPS_CTORS_ORDER_PASS_H - -#include "lld/Core/Pass.h" - -namespace lld { -namespace elf { -/// \brief This pass sorts atoms in .{ctors,dtors}.<priority> sections. -class MipsCtorsOrderPass : public Pass { -public: - std::error_code perform(SimpleFile &mergedFile) override; -}; -} -} - -#endif diff --git a/lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h b/lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h deleted file mode 100644 index 480c69cf4600..000000000000 --- a/lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h +++ /dev/null @@ -1,124 +0,0 @@ -//===- lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h -----------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_DYNAMIC_TABLE_H -#define LLD_READER_WRITER_ELF_MIPS_MIPS_DYNAMIC_TABLE_H - -#include "TargetLayout.h" -#include "SectionChunks.h" - -namespace lld { -namespace elf { - -template <class ELFT> class MipsTargetLayout; - -template <class ELFT> class MipsDynamicTable : public DynamicTable<ELFT> { -public: - MipsDynamicTable(const ELFLinkingContext &ctx, MipsTargetLayout<ELFT> &layout) - : DynamicTable<ELFT>(ctx, layout, ".dynamic", - TargetLayout<ELFT>::ORDER_DYNAMIC), - _targetLayout(layout) {} - - void createDefaultEntries() override { - DynamicTable<ELFT>::createDefaultEntries(); - - // Version id for the Runtime Linker Interface. - this->addEntry(DT_MIPS_RLD_VERSION, 1); - - // The .rld_map section address. - if (this->_ctx.getOutputELFType() == ET_EXEC) { - _dt_rldmap = this->addEntry(DT_MIPS_RLD_MAP, 0); - _dt_rldmaprel = this->addEntry(DT_MIPS_RLD_MAP_REL, 0); - } - - // MIPS flags. - this->addEntry(DT_MIPS_FLAGS, RHF_NOTPOT); - - // The base address of the segment. - _dt_baseaddr = this->addEntry(DT_MIPS_BASE_ADDRESS, 0); - - // Number of local global offset table entries. - _dt_localgot = this->addEntry(DT_MIPS_LOCAL_GOTNO, 0); - - // Number of entries in the .dynsym section. - _dt_symtabno = this->addEntry(DT_MIPS_SYMTABNO, 0); - - // The index of the first dynamic symbol table entry that corresponds - // to an entry in the global offset table. - _dt_gotsym = this->addEntry(DT_MIPS_GOTSYM, 0); - - // Address of the .got section. - _dt_pltgot = this->addEntry(DT_PLTGOT, 0); - } - - void doPreFlight() override { - DynamicTable<ELFT>::doPreFlight(); - - if (_targetLayout.findOutputSection(".MIPS.options")) { - _dt_options = this->addEntry(DT_MIPS_OPTIONS, 0); - } - } - - void updateDynamicTable() override { - DynamicTable<ELFT>::updateDynamicTable(); - - // Assign the minimum segment address to the DT_MIPS_BASE_ADDRESS tag. - auto baseAddr = std::numeric_limits<uint64_t>::max(); - for (auto si : _targetLayout.segments()) - if (si->segmentType() != llvm::ELF::PT_NULL) - baseAddr = std::min(baseAddr, si->virtualAddr()); - this->_entries[_dt_baseaddr].d_un.d_val = baseAddr; - - auto &got = _targetLayout.getGOTSection(); - - this->_entries[_dt_symtabno].d_un.d_val = this->getSymbolTable()->size(); - this->_entries[_dt_gotsym].d_un.d_val = - this->getSymbolTable()->size() - got.getGlobalCount(); - this->_entries[_dt_localgot].d_un.d_val = got.getLocalCount(); - this->_entries[_dt_pltgot].d_un.d_ptr = got.virtualAddr(); - - if (const auto *sec = _targetLayout.findOutputSection(".MIPS.options")) - this->_entries[_dt_options].d_un.d_ptr = sec->virtualAddr(); - - if (const auto *sec = _targetLayout.findOutputSection(".rld_map")) { - this->_entries[_dt_rldmap].d_un.d_ptr = sec->virtualAddr(); - this->_entries[_dt_rldmaprel].d_un.d_ptr = - sec->virtualAddr() - - (this->virtualAddr() + - _dt_rldmaprel * sizeof(typename DynamicTable<ELFT>::Elf_Dyn)); - } - } - - int64_t getGotPltTag() override { return DT_MIPS_PLTGOT; } - -protected: - /// \brief Adjust the symbol's value for microMIPS code. - uint64_t getAtomVirtualAddress(const AtomLayout *al) const override { - if (const auto *da = dyn_cast<DefinedAtom>(al->_atom)) - if (da->codeModel() == DefinedAtom::codeMipsMicro || - da->codeModel() == DefinedAtom::codeMipsMicroPIC) - return al->_virtualAddr | 1; - return al->_virtualAddr; - } - -private: - std::size_t _dt_symtabno; - std::size_t _dt_localgot; - std::size_t _dt_gotsym; - std::size_t _dt_pltgot; - std::size_t _dt_baseaddr; - std::size_t _dt_options; - std::size_t _dt_rldmap; - std::size_t _dt_rldmaprel; - MipsTargetLayout<ELFT> &_targetLayout; -}; - -} // end namespace elf -} // end namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/Mips/MipsELFFile.cpp b/lib/ReaderWriter/ELF/Mips/MipsELFFile.cpp deleted file mode 100644 index b081b63d77f7..000000000000 --- a/lib/ReaderWriter/ELF/Mips/MipsELFFile.cpp +++ /dev/null @@ -1,348 +0,0 @@ -//===- lib/ReaderWriter/ELF/MipsELFFile.cpp -------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "MipsELFFile.h" -#include "MipsTargetHandler.h" -#include "llvm/ADT/StringExtras.h" - -namespace lld { -namespace elf { - -template <class ELFT> -MipsELFDefinedAtom<ELFT>::MipsELFDefinedAtom( - const MipsELFFile<ELFT> &file, StringRef symbolName, StringRef sectionName, - const Elf_Sym *symbol, const Elf_Shdr *section, - ArrayRef<uint8_t> contentData, unsigned int referenceStart, - unsigned int referenceEnd, std::vector<ELFReference<ELFT> *> &referenceList) - : ELFDefinedAtom<ELFT>(file, symbolName, sectionName, symbol, section, - contentData, referenceStart, referenceEnd, - referenceList) {} - -template <class ELFT> -const MipsELFFile<ELFT> &MipsELFDefinedAtom<ELFT>::file() const { - return static_cast<const MipsELFFile<ELFT> &>(this->_owningFile); -} - -template <class ELFT> -DefinedAtom::CodeModel MipsELFDefinedAtom<ELFT>::codeModel() const { - switch (this->_symbol->st_other & llvm::ELF::STO_MIPS_MIPS16) { - case llvm::ELF::STO_MIPS_MIPS16: - return DefinedAtom::codeMips16; - case llvm::ELF::STO_MIPS_PIC: - return DefinedAtom::codeMipsPIC; - case llvm::ELF::STO_MIPS_MICROMIPS: - return DefinedAtom::codeMipsMicro; - case llvm::ELF::STO_MIPS_MICROMIPS | llvm::ELF::STO_MIPS_PIC: - return DefinedAtom::codeMipsMicroPIC; - default: - return DefinedAtom::codeNA; - } -} - -template <class ELFT> bool MipsELFDefinedAtom<ELFT>::isPIC() const { - return file().isPIC() || codeModel() == DefinedAtom::codeMipsMicroPIC || - codeModel() == DefinedAtom::codeMipsPIC; -} - -template class MipsELFDefinedAtom<ELF32BE>; -template class MipsELFDefinedAtom<ELF32LE>; -template class MipsELFDefinedAtom<ELF64BE>; -template class MipsELFDefinedAtom<ELF64LE>; - -template <class ELFT> static bool isMips64EL() { - return ELFT::Is64Bits && ELFT::TargetEndianness == llvm::support::little; -} - -template <class ELFT, bool isRela> -static uint32_t -extractTag(const llvm::object::Elf_Rel_Impl<ELFT, isRela> &rel) { - return (rel.getType(isMips64EL<ELFT>()) & 0xffffff00) >> 8; -} - -template <class ELFT> -MipsELFReference<ELFT>::MipsELFReference(uint64_t symValue, const Elf_Rela &rel) - : ELFReference<ELFT>(&rel, rel.r_offset - symValue, - Reference::KindArch::Mips, - rel.getType(isMips64EL<ELFT>()) & 0xff, - rel.getSymbol(isMips64EL<ELFT>())), - _tag(extractTag(rel)) {} - -template <class ELFT> -MipsELFReference<ELFT>::MipsELFReference(uint64_t symValue, const Elf_Rel &rel) - : ELFReference<ELFT>(rel.r_offset - symValue, Reference::KindArch::Mips, - rel.getType(isMips64EL<ELFT>()) & 0xff, - rel.getSymbol(isMips64EL<ELFT>())), - _tag(extractTag(rel)) {} - -template class MipsELFReference<ELF32BE>; -template class MipsELFReference<ELF32LE>; -template class MipsELFReference<ELF64BE>; -template class MipsELFReference<ELF64LE>; - -template <class ELFT> -MipsELFFile<ELFT>::MipsELFFile(std::unique_ptr<MemoryBuffer> mb, - ELFLinkingContext &ctx) - : ELFFile<ELFT>(std::move(mb), ctx) {} - -template <class ELFT> bool MipsELFFile<ELFT>::isPIC() const { - return this->_objFile->getHeader()->e_flags & llvm::ELF::EF_MIPS_PIC; -} - -template <class ELFT> std::error_code MipsELFFile<ELFT>::doParse() { - if (std::error_code ec = ELFFile<ELFT>::doParse()) - return ec; - // Retrieve some auxiliary data like GP value, TLS section address etc - // from the object file. - return readAuxData(); -} - -template <class ELFT> -ELFDefinedAtom<ELFT> *MipsELFFile<ELFT>::createDefinedAtom( - StringRef symName, StringRef sectionName, const Elf_Sym *sym, - const Elf_Shdr *sectionHdr, ArrayRef<uint8_t> contentData, - unsigned int referenceStart, unsigned int referenceEnd, - std::vector<ELFReference<ELFT> *> &referenceList) { - return new (this->_readerStorage) MipsELFDefinedAtom<ELFT>( - *this, symName, sectionName, sym, sectionHdr, contentData, referenceStart, - referenceEnd, referenceList); -} - -template <class ELFT> -const typename MipsELFFile<ELFT>::Elf_Shdr * -MipsELFFile<ELFT>::findSectionByType(uint64_t type) const { - for (const Elf_Shdr §ion : this->_objFile->sections()) - if (section.sh_type == type) - return §ion; - return nullptr; -} - -template <class ELFT> -const typename MipsELFFile<ELFT>::Elf_Shdr * -MipsELFFile<ELFT>::findSectionByFlags(uint64_t flags) const { - for (const Elf_Shdr §ion : this->_objFile->sections()) - if (section.sh_flags & flags) - return §ion; - return nullptr; -} - -template <class ELFT> -ErrorOr<const typename MipsELFFile<ELFT>::Elf_Mips_RegInfo *> -MipsELFFile<ELFT>::findRegInfoSec() const { - using namespace llvm::ELF; - if (const Elf_Shdr *sec = findSectionByType(SHT_MIPS_OPTIONS)) { - auto contents = this->getSectionContents(sec); - if (std::error_code ec = contents.getError()) - return ec; - - ArrayRef<uint8_t> raw = contents.get(); - while (!raw.empty()) { - if (raw.size() < sizeof(Elf_Mips_Options)) - return make_dynamic_error_code( - StringRef("Invalid size of MIPS_OPTIONS section")); - - const auto *opt = reinterpret_cast<const Elf_Mips_Options *>(raw.data()); - if (opt->kind == ODK_REGINFO) - return &opt->getRegInfo(); - raw = raw.slice(opt->size); - } - } else if (const Elf_Shdr *sec = findSectionByType(SHT_MIPS_REGINFO)) { - auto contents = this->getSectionContents(sec); - if (std::error_code ec = contents.getError()) - return ec; - - ArrayRef<uint8_t> raw = contents.get(); - if (raw.size() != sizeof(Elf_Mips_RegInfo)) - return make_dynamic_error_code( - StringRef("Invalid size of MIPS_REGINFO section")); - - return reinterpret_cast<const Elf_Mips_RegInfo *>(raw.data()); - } - return nullptr; -} - -template <class ELFT> -ErrorOr<const typename MipsELFFile<ELFT>::Elf_Mips_ABIFlags *> -MipsELFFile<ELFT>::findAbiFlagsSec() const { - const Elf_Shdr *sec = findSectionByType(SHT_MIPS_ABIFLAGS); - if (!sec) - return nullptr; - - auto contents = this->getSectionContents(sec); - if (std::error_code ec = contents.getError()) - return ec; - - ArrayRef<uint8_t> raw = contents.get(); - if (raw.size() != sizeof(Elf_Mips_ABIFlags)) - return make_dynamic_error_code( - StringRef("Invalid size of MIPS_ABIFLAGS section")); - - const auto *abi = reinterpret_cast<const Elf_Mips_ABIFlags *>(raw.data()); - if (abi->version != 0) - return make_dynamic_error_code( - StringRef(".MIPS.abiflags section has unsupported version '") + - llvm::utostr(abi->version) + "'"); - - return abi; -} - -template <class ELFT> std::error_code MipsELFFile<ELFT>::readAuxData() { - using namespace llvm::ELF; - if (const Elf_Shdr *sec = findSectionByFlags(SHF_TLS)) { - _tpOff = sec->sh_addr + TP_OFFSET; - _dtpOff = sec->sh_addr + DTP_OFFSET; - } - - auto &handler = - static_cast<MipsTargetHandler<ELFT> &>(this->_ctx.getTargetHandler()); - auto &abi = handler.getAbiInfoHandler(); - - ErrorOr<const Elf_Mips_RegInfo *> regInfoSec = findRegInfoSec(); - if (auto ec = regInfoSec.getError()) - return ec; - if (const Elf_Mips_RegInfo *regInfo = regInfoSec.get()) { - abi.mergeRegistersMask(*regInfo); - _gp0 = regInfo->ri_gp_value; - } - - ErrorOr<const Elf_Mips_ABIFlags *> abiFlagsSec = findAbiFlagsSec(); - if (auto ec = abiFlagsSec.getError()) - return ec; - - const Elf_Ehdr *hdr = this->_objFile->getHeader(); - if (std::error_code ec = abi.mergeFlags(hdr->e_flags, abiFlagsSec.get())) - return ec; - - return std::error_code(); -} - -template <class ELFT> -void MipsELFFile<ELFT>::createRelocationReferences( - const Elf_Sym *symbol, ArrayRef<uint8_t> content, - range<const Elf_Rela *> rels) { - const auto value = this->getSymbolValue(symbol); - unsigned numInGroup = 0; - for (const auto &rel : rels) { - if (rel.r_offset < value || value + content.size() <= rel.r_offset) { - numInGroup = 0; - continue; - } - if (numInGroup > 0) { - auto &last = - *static_cast<MipsELFReference<ELFT> *>(this->_references.back()); - if (last.offsetInAtom() + value == rel.r_offset) { - last.setTag(last.tag() | - (rel.getType(isMips64EL<ELFT>()) << 8 * (numInGroup - 1))); - ++numInGroup; - continue; - } - } - auto r = new (this->_readerStorage) MipsELFReference<ELFT>(value, rel); - this->addReferenceToSymbol(r, symbol); - this->_references.push_back(r); - numInGroup = 1; - } -} - -template <class ELFT> -void MipsELFFile<ELFT>::createRelocationReferences(const Elf_Sym *symbol, - ArrayRef<uint8_t> symContent, - ArrayRef<uint8_t> secContent, - const Elf_Shdr *relSec) { - const Elf_Shdr *symtab = *this->_objFile->getSection(relSec->sh_link); - auto rels = this->_objFile->rels(relSec); - const auto value = this->getSymbolValue(symbol); - for (const Elf_Rel *rit = rels.begin(), *eit = rels.end(); rit != eit; - ++rit) { - if (rit->r_offset < value || value + symContent.size() <= rit->r_offset) - continue; - - auto r = new (this->_readerStorage) MipsELFReference<ELFT>(value, *rit); - this->addReferenceToSymbol(r, symbol); - this->_references.push_back(r); - - auto addend = readAddend(*rit, secContent); - auto pairRelType = getPairRelocation(symtab, *rit); - if (pairRelType != llvm::ELF::R_MIPS_NONE) { - addend <<= 16; - auto mit = findMatchingRelocation(pairRelType, rit, eit); - if (mit != eit) - addend += int16_t(readAddend(*mit, secContent)); - else - // FIXME (simon): Show detailed warning. - llvm::errs() << "lld warning: cannot matching LO16 relocation\n"; - } - this->_references.back()->setAddend(addend); - } -} - -template <class ELFT> -static uint8_t -getPrimaryType(const llvm::object::Elf_Rel_Impl<ELFT, false> &rel) { - return rel.getType(isMips64EL<ELFT>()) & 0xff; -} - -template <class ELFT> -Reference::Addend -MipsELFFile<ELFT>::readAddend(const Elf_Rel &ri, - const ArrayRef<uint8_t> content) const { - return readMipsRelocAddend<ELFT>(getPrimaryType(ri), - content.data() + ri.r_offset); -} - -template <class ELFT> -uint32_t MipsELFFile<ELFT>::getPairRelocation(const Elf_Shdr *symtab, - const Elf_Rel &rel) const { - switch (getPrimaryType(rel)) { - case llvm::ELF::R_MIPS_HI16: - return llvm::ELF::R_MIPS_LO16; - case llvm::ELF::R_MIPS_PCHI16: - return llvm::ELF::R_MIPS_PCLO16; - case llvm::ELF::R_MIPS_GOT16: - if (isLocalBinding(symtab, rel)) - return llvm::ELF::R_MIPS_LO16; - break; - case llvm::ELF::R_MICROMIPS_HI16: - return llvm::ELF::R_MICROMIPS_LO16; - case llvm::ELF::R_MICROMIPS_GOT16: - if (isLocalBinding(symtab, rel)) - return llvm::ELF::R_MICROMIPS_LO16; - break; - default: - // Nothing to do. - break; - } - return llvm::ELF::R_MIPS_NONE; -} - -template <class ELFT> -const typename MipsELFFile<ELFT>::Elf_Rel * -MipsELFFile<ELFT>::findMatchingRelocation(uint32_t pairRelType, - const Elf_Rel *rit, - const Elf_Rel *eit) const { - return std::find_if(rit, eit, [&](const Elf_Rel &rel) { - return getPrimaryType(rel) == pairRelType && - rel.getSymbol(isMips64EL<ELFT>()) == - rit->getSymbol(isMips64EL<ELFT>()); - }); -} - -template <class ELFT> -bool MipsELFFile<ELFT>::isLocalBinding(const Elf_Shdr *symtab, - const Elf_Rel &rel) const { - return this->_objFile->getSymbol(symtab, rel.getSymbol(isMips64EL<ELFT>())) - ->getBinding() == llvm::ELF::STB_LOCAL; -} - -template class MipsELFFile<ELF32BE>; -template class MipsELFFile<ELF32LE>; -template class MipsELFFile<ELF64BE>; -template class MipsELFFile<ELF64LE>; - -} // elf -} // lld diff --git a/lib/ReaderWriter/ELF/Mips/MipsELFFile.h b/lib/ReaderWriter/ELF/Mips/MipsELFFile.h deleted file mode 100644 index 934934b539cc..000000000000 --- a/lib/ReaderWriter/ELF/Mips/MipsELFFile.h +++ /dev/null @@ -1,126 +0,0 @@ -//===- lib/ReaderWriter/ELF/MipsELFFile.h ---------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_FILE_H -#define LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_FILE_H - -#include "ELFReader.h" -#include "MipsLinkingContext.h" -#include "MipsRelocationHandler.h" -#include "llvm/ADT/STLExtras.h" - -namespace lld { -namespace elf { - -template <class ELFT> class MipsELFFile; - -template <class ELFT> -class MipsELFDefinedAtom : public ELFDefinedAtom<ELFT> { - typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym; - typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr; - -public: - MipsELFDefinedAtom(const MipsELFFile<ELFT> &file, StringRef symbolName, - StringRef sectionName, const Elf_Sym *symbol, - const Elf_Shdr *section, ArrayRef<uint8_t> contentData, - unsigned int referenceStart, unsigned int referenceEnd, - std::vector<ELFReference<ELFT> *> &referenceList); - - const MipsELFFile<ELFT>& file() const override; - DefinedAtom::CodeModel codeModel() const override; - - bool isPIC() const; -}; - -template <class ELFT> class MipsELFReference : public ELFReference<ELFT> { - typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel; - typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela; - -public: - MipsELFReference(uint64_t symValue, const Elf_Rela &rel); - MipsELFReference(uint64_t symValue, const Elf_Rel &rel); - - uint32_t tag() const override { return _tag; } - void setTag(uint32_t tag) { _tag = tag; } - -private: - uint32_t _tag; -}; - -template <class ELFT> class MipsELFFile : public ELFFile<ELFT> { -public: - MipsELFFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx); - - bool isPIC() const; - - /// \brief gp register value stored in the .reginfo section. - int64_t getGP0() const { return _gp0; } - - /// \brief .tdata section address plus fixed offset. - uint64_t getTPOffset() const { return _tpOff; } - uint64_t getDTPOffset() const { return _dtpOff; } - -protected: - std::error_code doParse() override; - -private: - typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym; - typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela; - - enum { TP_OFFSET = 0x7000, DTP_OFFSET = 0x8000 }; - - int64_t _gp0 = 0; - uint64_t _tpOff = 0; - uint64_t _dtpOff = 0; - - ELFDefinedAtom<ELFT> * - createDefinedAtom(StringRef symName, StringRef sectionName, - const Elf_Sym *sym, const Elf_Shdr *sectionHdr, - ArrayRef<uint8_t> contentData, unsigned int referenceStart, - unsigned int referenceEnd, - std::vector<ELFReference<ELFT> *> &referenceList) override; - - void createRelocationReferences(const Elf_Sym *symbol, - ArrayRef<uint8_t> content, - range<const Elf_Rela *> rels) override; - void createRelocationReferences(const Elf_Sym *symbol, - ArrayRef<uint8_t> symContent, - ArrayRef<uint8_t> secContent, - const Elf_Shdr *RelSec) override; - - const Elf_Shdr *findSectionByType(uint64_t type) const; - const Elf_Shdr *findSectionByFlags(uint64_t flags) const; - - typedef typename llvm::object::ELFFile<ELFT>::Elf_Ehdr Elf_Ehdr; - typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo; - typedef llvm::object::Elf_Mips_Options<ELFT> Elf_Mips_Options; - typedef llvm::object::Elf_Mips_ABIFlags<ELFT> Elf_Mips_ABIFlags; - - ErrorOr<const Elf_Mips_RegInfo *> findRegInfoSec() const; - ErrorOr<const Elf_Mips_ABIFlags*> findAbiFlagsSec() const; - - std::error_code readAuxData(); - - Reference::Addend readAddend(const Elf_Rel &ri, - const ArrayRef<uint8_t> content) const; - - uint32_t getPairRelocation(const Elf_Shdr *Symtab, const Elf_Rel &rel) const; - - const Elf_Rel *findMatchingRelocation(uint32_t pairRelType, - const Elf_Rel *rit, - const Elf_Rel *eit) const; - - bool isLocalBinding(const Elf_Shdr *Symtab, const Elf_Rel &rel) const; -}; - -} // elf -} // lld - -#endif diff --git a/lib/ReaderWriter/ELF/Mips/MipsELFWriters.cpp b/lib/ReaderWriter/ELF/Mips/MipsELFWriters.cpp deleted file mode 100644 index b97a4f5a9070..000000000000 --- a/lib/ReaderWriter/ELF/Mips/MipsELFWriters.cpp +++ /dev/null @@ -1,292 +0,0 @@ -//===- lib/ReaderWriter/ELF/Mips/MipsELFWriters.cpp -----------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "MipsDynamicTable.h" -#include "MipsELFWriters.h" -#include "MipsLinkingContext.h" -#include "MipsTargetHandler.h" -#include "MipsTargetLayout.h" - -namespace { -class MipsDynamicAtom : public lld::elf::DynamicAtom { -public: - MipsDynamicAtom(const lld::File &f) : DynamicAtom(f) {} - - ContentPermissions permissions() const override { return permR__; } -}; -} - -namespace lld { -namespace elf { - -template <class ELFT> -MipsELFWriter<ELFT>::MipsELFWriter(MipsLinkingContext &ctx, - MipsTargetLayout<ELFT> &targetLayout, - const MipsAbiInfoHandler<ELFT> &abiInfo) - : _ctx(ctx), _targetLayout(targetLayout), _abiInfo(abiInfo) {} - -template <class ELFT> -void MipsELFWriter<ELFT>::setELFHeader(ELFHeader<ELFT> &elfHeader) { - elfHeader.e_version(1); - elfHeader.e_ident(llvm::ELF::EI_VERSION, llvm::ELF::EV_CURRENT); - elfHeader.e_ident(llvm::ELF::EI_OSABI, llvm::ELF::ELFOSABI_NONE); - - unsigned char abiVer = 0; - if (_ctx.getOutputELFType() == ET_EXEC && _abiInfo.isCPicOnly()) - abiVer = 1; - if (_abiInfo.isFp64()) - abiVer = 3; - - elfHeader.e_ident(llvm::ELF::EI_ABIVERSION, abiVer); - elfHeader.e_flags(_abiInfo.getFlags()); -} - -template <class ELFT> -void MipsELFWriter<ELFT>::finalizeMipsRuntimeAtomValues() { - auto gotSection = _targetLayout.findOutputSection(".got"); - auto got = gotSection ? gotSection->virtualAddr() : 0; - auto gp = gotSection ? got + _targetLayout.getGPOffset() : 0; - - setAtomValue("_gp", gp); - setAtomValue("_gp_disp", gp); - setAtomValue("__gnu_local_gp", gp); - - if (_ctx.isDynamic() && _ctx.getOutputELFType() == ET_EXEC) - setAtomValue("_DYNAMIC_LINKING", 1); -} - -template <class ELFT> -std::unique_ptr<RuntimeFile<ELFT>> MipsELFWriter<ELFT>::createRuntimeFile() { - auto file = llvm::make_unique<RuntimeFile<ELFT>>(_ctx, "Mips runtime file"); - file->addAbsoluteAtom("_gp"); - file->addAbsoluteAtom("_gp_disp"); - file->addAbsoluteAtom("__gnu_local_gp"); - if (_ctx.isDynamic()) { - file->addAtom(*new (file->allocator()) MipsDynamicAtom(*file)); - if (_ctx.getOutputELFType() == ET_EXEC) - file->addAbsoluteAtom("_DYNAMIC_LINKING"); - } - return file; -} - -template <class ELFT> -unique_bump_ptr<Section<ELFT>> -MipsELFWriter<ELFT>::createOptionsSection(llvm::BumpPtrAllocator &alloc) { - typedef unique_bump_ptr<Section<ELFT>> Ptr; - const auto ®Mask = _abiInfo.getRegistersMask(); - if (!regMask.hasValue()) - return Ptr(); - return ELFT::Is64Bits - ? Ptr(new (alloc) - MipsOptionsSection<ELFT>(_ctx, _targetLayout, *regMask)) - : Ptr(new (alloc) - MipsReginfoSection<ELFT>(_ctx, _targetLayout, *regMask)); -} - -template <class ELFT> -unique_bump_ptr<Section<ELFT>> -MipsELFWriter<ELFT>::createAbiFlagsSection(llvm::BumpPtrAllocator &alloc) { - typedef unique_bump_ptr<Section<ELFT>> Ptr; - const auto &abi = _abiInfo.getAbiFlags(); - if (!abi.hasValue()) - return Ptr(); - return Ptr(new (alloc) MipsAbiFlagsSection<ELFT>(_ctx, _targetLayout, *abi)); -} - -template <class ELFT> -void MipsELFWriter<ELFT>::setAtomValue(StringRef name, uint64_t value) { - AtomLayout *atom = _targetLayout.findAbsoluteAtom(name); - assert(atom); - atom->_virtualAddr = value; -} - -template <class ELFT> -MipsDynamicLibraryWriter<ELFT>::MipsDynamicLibraryWriter( - MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &layout, - const MipsAbiInfoHandler<ELFT> &abiInfo) - : DynamicLibraryWriter<ELFT>(ctx, layout), - _writeHelper(ctx, layout, abiInfo), _targetLayout(layout) {} - -template <class ELFT> -void MipsDynamicLibraryWriter<ELFT>::createImplicitFiles( - std::vector<std::unique_ptr<File>> &result) { - DynamicLibraryWriter<ELFT>::createImplicitFiles(result); - result.push_back(_writeHelper.createRuntimeFile()); -} - -template <class ELFT> -void MipsDynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues() { - DynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues(); - _writeHelper.finalizeMipsRuntimeAtomValues(); -} - -template <class ELFT> -void MipsDynamicLibraryWriter<ELFT>::createDefaultSections() { - DynamicLibraryWriter<ELFT>::createDefaultSections(); - _reginfo = _writeHelper.createOptionsSection(this->_alloc); - if (_reginfo) - this->_layout.addSection(_reginfo.get()); - _abiFlags = _writeHelper.createAbiFlagsSection(this->_alloc); - if (_abiFlags) - this->_layout.addSection(_abiFlags.get()); -} - -template <class ELFT> -std::error_code MipsDynamicLibraryWriter<ELFT>::setELFHeader() { - DynamicLibraryWriter<ELFT>::setELFHeader(); - _writeHelper.setELFHeader(*this->_elfHeader); - return std::error_code(); -} - -template <class ELFT> -unique_bump_ptr<SymbolTable<ELFT>> -MipsDynamicLibraryWriter<ELFT>::createSymbolTable() { - return unique_bump_ptr<SymbolTable<ELFT>>( - new (this->_alloc) MipsSymbolTable<ELFT>(this->_ctx)); -} - -template <class ELFT> -unique_bump_ptr<DynamicTable<ELFT>> -MipsDynamicLibraryWriter<ELFT>::createDynamicTable() { - return unique_bump_ptr<DynamicTable<ELFT>>( - new (this->_alloc) MipsDynamicTable<ELFT>(this->_ctx, _targetLayout)); -} - -template <class ELFT> -unique_bump_ptr<DynamicSymbolTable<ELFT>> -MipsDynamicLibraryWriter<ELFT>::createDynamicSymbolTable() { - return unique_bump_ptr<DynamicSymbolTable<ELFT>>(new ( - this->_alloc) MipsDynamicSymbolTable<ELFT>(this->_ctx, _targetLayout)); -} - -template class MipsDynamicLibraryWriter<ELF32BE>; -template class MipsDynamicLibraryWriter<ELF32LE>; -template class MipsDynamicLibraryWriter<ELF64BE>; -template class MipsDynamicLibraryWriter<ELF64LE>; - -template <class ELFT> -MipsExecutableWriter<ELFT>::MipsExecutableWriter( - MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &layout, - const MipsAbiInfoHandler<ELFT> &abiInfo) - : ExecutableWriter<ELFT>(ctx, layout), _writeHelper(ctx, layout, abiInfo), - _targetLayout(layout) {} - -template <class ELFT> -std::error_code MipsExecutableWriter<ELFT>::setELFHeader() { - std::error_code ec = ExecutableWriter<ELFT>::setELFHeader(); - if (ec) - return ec; - - StringRef entryName = this->_ctx.entrySymbolName(); - if (const AtomLayout *al = this->_layout.findAtomLayoutByName(entryName)) { - const auto *ea = cast<DefinedAtom>(al->_atom); - if (ea->codeModel() == DefinedAtom::codeMipsMicro || - ea->codeModel() == DefinedAtom::codeMipsMicroPIC) - // Adjust entry symbol value if this symbol is microMIPS encoded. - this->_elfHeader->e_entry(al->_virtualAddr | 1); - } - - _writeHelper.setELFHeader(*this->_elfHeader); - return std::error_code(); -} - -template <class ELFT> -void MipsExecutableWriter<ELFT>::buildDynamicSymbolTable(const File &file) { - // MIPS ABI requires to add to dynsym even undefined symbols - // if they have a corresponding entries in a global part of GOT. - for (auto sec : this->_layout.sections()) - if (auto section = dyn_cast<AtomSection<ELFT>>(sec)) - for (const auto &atom : section->atoms()) { - if (_targetLayout.getGOTSection().hasGlobalGOTEntry(atom->_atom)) { - this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(), - atom->_virtualAddr, atom); - continue; - } - - const DefinedAtom *da = dyn_cast<const DefinedAtom>(atom->_atom); - if (!da) - continue; - - if (da->dynamicExport() != DefinedAtom::dynamicExportAlways && - !this->_ctx.isDynamicallyExportedSymbol(da->name()) && - !(this->_ctx.shouldExportDynamic() && - da->scope() == Atom::Scope::scopeGlobal)) - continue; - - this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(), - atom->_virtualAddr, atom); - } - - for (const UndefinedAtom *a : file.undefined()) - // FIXME (simon): Consider to move this check to the - // MipsELFUndefinedAtom class method. That allows to - // handle more complex coditions in the future. - if (_targetLayout.getGOTSection().hasGlobalGOTEntry(a)) - this->_dynamicSymbolTable->addSymbol(a, ELF::SHN_UNDEF); - - // Skip our immediate parent class method - // ExecutableWriter<ELFT>::buildDynamicSymbolTable because we replaced it - // with our own version. Call OutputELFWriter directly. - OutputELFWriter<ELFT>::buildDynamicSymbolTable(file); -} - -template <class ELFT> -void MipsExecutableWriter<ELFT>::createImplicitFiles( - std::vector<std::unique_ptr<File>> &result) { - ExecutableWriter<ELFT>::createImplicitFiles(result); - result.push_back(_writeHelper.createRuntimeFile()); -} - -template <class ELFT> -void MipsExecutableWriter<ELFT>::finalizeDefaultAtomValues() { - // Finalize the atom values that are part of the parent. - ExecutableWriter<ELFT>::finalizeDefaultAtomValues(); - _writeHelper.finalizeMipsRuntimeAtomValues(); -} - -template <class ELFT> void MipsExecutableWriter<ELFT>::createDefaultSections() { - ExecutableWriter<ELFT>::createDefaultSections(); - _reginfo = _writeHelper.createOptionsSection(this->_alloc); - if (_reginfo) - this->_layout.addSection(_reginfo.get()); - _abiFlags = _writeHelper.createAbiFlagsSection(this->_alloc); - if (_abiFlags) - this->_layout.addSection(_abiFlags.get()); -} - -template <class ELFT> -unique_bump_ptr<SymbolTable<ELFT>> -MipsExecutableWriter<ELFT>::createSymbolTable() { - return unique_bump_ptr<SymbolTable<ELFT>>( - new (this->_alloc) MipsSymbolTable<ELFT>(this->_ctx)); -} - -/// \brief create dynamic table -template <class ELFT> -unique_bump_ptr<DynamicTable<ELFT>> -MipsExecutableWriter<ELFT>::createDynamicTable() { - return unique_bump_ptr<DynamicTable<ELFT>>( - new (this->_alloc) MipsDynamicTable<ELFT>(this->_ctx, _targetLayout)); -} - -/// \brief create dynamic symbol table -template <class ELFT> -unique_bump_ptr<DynamicSymbolTable<ELFT>> -MipsExecutableWriter<ELFT>::createDynamicSymbolTable() { - return unique_bump_ptr<DynamicSymbolTable<ELFT>>(new ( - this->_alloc) MipsDynamicSymbolTable<ELFT>(this->_ctx, _targetLayout)); -} - -template class MipsExecutableWriter<ELF32BE>; -template class MipsExecutableWriter<ELF32LE>; -template class MipsExecutableWriter<ELF64BE>; -template class MipsExecutableWriter<ELF64LE>; - -} // elf -} // lld diff --git a/lib/ReaderWriter/ELF/Mips/MipsELFWriters.h b/lib/ReaderWriter/ELF/Mips/MipsELFWriters.h deleted file mode 100644 index 31b84f947c95..000000000000 --- a/lib/ReaderWriter/ELF/Mips/MipsELFWriters.h +++ /dev/null @@ -1,102 +0,0 @@ -//===- lib/ReaderWriter/ELF/Mips/MipsELFWriters.h -------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_WRITERS_H -#define LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_WRITERS_H - -#include "DynamicLibraryWriter.h" -#include "ExecutableWriter.h" -#include "MipsAbiInfoHandler.h" -#include "MipsLinkingContext.h" - -namespace lld { -namespace elf { - -template <class ELFT> class MipsTargetLayout; - -template <typename ELFT> class MipsELFWriter { -public: - MipsELFWriter(MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &targetLayout, - const MipsAbiInfoHandler<ELFT> &abiInfo); - - void setELFHeader(ELFHeader<ELFT> &elfHeader); - - void finalizeMipsRuntimeAtomValues(); - - std::unique_ptr<RuntimeFile<ELFT>> createRuntimeFile(); - unique_bump_ptr<Section<ELFT>> - createOptionsSection(llvm::BumpPtrAllocator &alloc); - unique_bump_ptr<Section<ELFT>> - createAbiFlagsSection(llvm::BumpPtrAllocator &alloc); - -private: - MipsLinkingContext &_ctx; - MipsTargetLayout<ELFT> &_targetLayout; - const MipsAbiInfoHandler<ELFT> &_abiInfo; - - void setAtomValue(StringRef name, uint64_t value); -}; - -template <class ELFT> -class MipsDynamicLibraryWriter : public DynamicLibraryWriter<ELFT> { -public: - MipsDynamicLibraryWriter(MipsLinkingContext &ctx, - MipsTargetLayout<ELFT> &layout, - const MipsAbiInfoHandler<ELFT> &abiInfo); - -protected: - // Add any runtime files and their atoms to the output - void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override; - - void finalizeDefaultAtomValues() override; - void createDefaultSections() override; - - std::error_code setELFHeader() override; - - unique_bump_ptr<SymbolTable<ELFT>> createSymbolTable() override; - unique_bump_ptr<DynamicTable<ELFT>> createDynamicTable() override; - unique_bump_ptr<DynamicSymbolTable<ELFT>> createDynamicSymbolTable() override; - -private: - MipsELFWriter<ELFT> _writeHelper; - MipsTargetLayout<ELFT> &_targetLayout; - unique_bump_ptr<Section<ELFT>> _reginfo; - unique_bump_ptr<Section<ELFT>> _abiFlags; -}; - -template <class ELFT> -class MipsExecutableWriter : public ExecutableWriter<ELFT> { -public: - MipsExecutableWriter(MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &layout, - const MipsAbiInfoHandler<ELFT> &abiInfo); - -protected: - void buildDynamicSymbolTable(const File &file) override; - - // Add any runtime files and their atoms to the output - void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override; - - void finalizeDefaultAtomValues() override; - void createDefaultSections() override; - std::error_code setELFHeader() override; - - unique_bump_ptr<SymbolTable<ELFT>> createSymbolTable() override; - unique_bump_ptr<DynamicTable<ELFT>> createDynamicTable() override; - unique_bump_ptr<DynamicSymbolTable<ELFT>> createDynamicSymbolTable() override; - -private: - MipsELFWriter<ELFT> _writeHelper; - MipsTargetLayout<ELFT> &_targetLayout; - unique_bump_ptr<Section<ELFT>> _reginfo; - unique_bump_ptr<Section<ELFT>> _abiFlags; -}; - -} // elf -} // lld - -#endif diff --git a/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp b/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp deleted file mode 100644 index b6cdd5c1487c..000000000000 --- a/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp +++ /dev/null @@ -1,164 +0,0 @@ -//===- lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp -------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Atoms.h" -#include "MipsCtorsOrderPass.h" -#include "MipsLinkingContext.h" -#include "MipsRelocationPass.h" -#include "MipsTargetHandler.h" - -using namespace lld; -using namespace lld::elf; - -std::unique_ptr<ELFLinkingContext> -elf::createMipsLinkingContext(llvm::Triple triple) { - if (triple.getArch() == llvm::Triple::mips || - triple.getArch() == llvm::Triple::mipsel || - triple.getArch() == llvm::Triple::mips64 || - triple.getArch() == llvm::Triple::mips64el) - return llvm::make_unique<MipsLinkingContext>(triple); - return nullptr; -} - -static std::unique_ptr<TargetHandler> createTarget(llvm::Triple triple, - MipsLinkingContext &ctx) { - switch (triple.getArch()) { - case llvm::Triple::mips: - return llvm::make_unique<MipsTargetHandler<ELF32BE>>(ctx); - case llvm::Triple::mipsel: - return llvm::make_unique<MipsTargetHandler<ELF32LE>>(ctx); - case llvm::Triple::mips64: - return llvm::make_unique<MipsTargetHandler<ELF64BE>>(ctx); - case llvm::Triple::mips64el: - return llvm::make_unique<MipsTargetHandler<ELF64LE>>(ctx); - default: - llvm_unreachable("Unhandled arch"); - } -} - -MipsLinkingContext::MipsLinkingContext(llvm::Triple triple) - : ELFLinkingContext(triple, createTarget(triple, *this)) {} - -uint64_t MipsLinkingContext::getBaseAddress() const { - if (_baseAddress != 0 || getOutputELFType() != llvm::ELF::ET_EXEC) - return _baseAddress; - switch (getAbi()) { - case MipsAbi::O32: - return 0x0400000; - case MipsAbi::N32: - return 0x10000000; - case MipsAbi::N64: - return 0x120000000; - } - llvm_unreachable("unknown MIPS ABI flag"); -} - -StringRef MipsLinkingContext::entrySymbolName() const { - if (_outputELFType == elf::ET_EXEC && _entrySymbolName.empty()) - return "__start"; - return _entrySymbolName; -} - -StringRef MipsLinkingContext::getDefaultInterpreter() const { - switch (getAbi()) { - case MipsAbi::O32: - return "/lib/ld.so.1"; - case MipsAbi::N32: - return "/lib32/ld.so.1"; - case MipsAbi::N64: - return "/lib64/ld.so.1"; - } - llvm_unreachable("unknown MIPS ABI flag"); -} - -void MipsLinkingContext::addPasses(PassManager &pm) { - auto pass = createMipsRelocationPass(*this); - if (pass) - pm.add(std::move(pass)); - ELFLinkingContext::addPasses(pm); - pm.add(llvm::make_unique<elf::MipsCtorsOrderPass>()); -} - -bool MipsLinkingContext::isDynamicRelocation(const Reference &r) const { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - assert(r.kindArch() == Reference::KindArch::Mips); - switch (r.kindValue()) { - case llvm::ELF::R_MIPS_COPY: - case llvm::ELF::R_MIPS_REL32: - return true; - case llvm::ELF::R_MIPS_TLS_DTPMOD32: - case llvm::ELF::R_MIPS_TLS_DTPREL32: - case llvm::ELF::R_MIPS_TLS_TPREL32: - case llvm::ELF::R_MIPS_TLS_DTPMOD64: - case llvm::ELF::R_MIPS_TLS_DTPREL64: - case llvm::ELF::R_MIPS_TLS_TPREL64: - return isDynamic(); - default: - return false; - } -} - -bool MipsLinkingContext::isCopyRelocation(const Reference &r) const { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - assert(r.kindArch() == Reference::KindArch::Mips); - if (r.kindValue() == llvm::ELF::R_MIPS_COPY) - return true; - return false; -} - -bool MipsLinkingContext::isPLTRelocation(const Reference &r) const { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - assert(r.kindArch() == Reference::KindArch::Mips); - switch (r.kindValue()) { - case llvm::ELF::R_MIPS_JUMP_SLOT: - return true; - default: - return false; - } -} - -bool MipsLinkingContext::isRelativeReloc(const Reference &r) const { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - assert(r.kindArch() == Reference::KindArch::Mips); - switch (r.kindValue()) { - case llvm::ELF::R_MIPS_REL32: - case llvm::ELF::R_MIPS_GPREL16: - case llvm::ELF::R_MIPS_GPREL32: - return true; - default: - return false; - } -} - -MipsAbi MipsLinkingContext::getAbi() const { - auto &handler = static_cast<MipsBaseTargetHandler &>(getTargetHandler()); - return handler.getAbi(); -} - -const Registry::KindStrings kindStrings[] = { -#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name), -#include "llvm/Support/ELFRelocs/Mips.def" -#undef ELF_RELOC - LLD_KIND_STRING_ENTRY(LLD_R_MIPS_GLOBAL_GOT), - LLD_KIND_STRING_ENTRY(LLD_R_MIPS_32_HI16), - LLD_KIND_STRING_ENTRY(LLD_R_MIPS_64_HI16), - LLD_KIND_STRING_ENTRY(LLD_R_MIPS_GLOBAL_26), - LLD_KIND_STRING_ENTRY(LLD_R_MIPS_STO_PLT), - LLD_KIND_STRING_ENTRY(LLD_R_MICROMIPS_GLOBAL_26_S1), - LLD_KIND_STRING_END -}; - -void MipsLinkingContext::registerRelocationNames(Registry ®istry) { - registry.addKindTable(Reference::KindNamespace::ELF, - Reference::KindArch::Mips, kindStrings); -} diff --git a/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h b/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h deleted file mode 100644 index 414d2c785e17..000000000000 --- a/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h +++ /dev/null @@ -1,56 +0,0 @@ -//===- lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h ---------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_LINKING_CONTEXT_H -#define LLD_READER_WRITER_ELF_MIPS_MIPS_LINKING_CONTEXT_H - -#include "MipsAbiInfoHandler.h" -#include "lld/ReaderWriter/ELFLinkingContext.h" - -namespace lld { -namespace elf { - -/// \brief Mips internal references. -enum { - /// \brief Do nothing but mark GOT entry as a global one. - LLD_R_MIPS_GLOBAL_GOT = 1024, - /// \brief Apply high 16 bits of symbol + addend. - LLD_R_MIPS_32_HI16 = 1025, - /// \brief The same as R_MIPS_26 but for global symbols. - LLD_R_MIPS_GLOBAL_26 = 1026, - /// \brief Represents a reference between PLT and dynamic symbol. - LLD_R_MIPS_STO_PLT = 1029, - /// \brief The same as R_MICROMIPS_26_S1 but for global symbols. - LLD_R_MICROMIPS_GLOBAL_26_S1 = 1030, - /// \brief Apply high 32+16 bits of symbol + addend. - LLD_R_MIPS_64_HI16 = 1031, -}; - -class MipsLinkingContext final : public ELFLinkingContext { -public: - MipsLinkingContext(llvm::Triple triple); - - void registerRelocationNames(Registry &r) override; - int getMachineType() const override { return llvm::ELF::EM_MIPS; } - uint64_t getBaseAddress() const override; - StringRef entrySymbolName() const override; - StringRef getDefaultInterpreter() const override; - void addPasses(PassManager &pm) override; - bool isRelaOutputFormat() const override { return false; } - bool isDynamicRelocation(const Reference &r) const override; - bool isCopyRelocation(const Reference &r) const override; - bool isPLTRelocation(const Reference &r) const override; - bool isRelativeReloc(const Reference &r) const override; - - MipsAbi getAbi() const; -}; - -} // elf -} // lld - -#endif diff --git a/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp b/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp deleted file mode 100644 index c55a7a4116e6..000000000000 --- a/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp +++ /dev/null @@ -1,687 +0,0 @@ -//===- lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp ----------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "MipsLinkingContext.h" -#include "MipsRelocationHandler.h" -#include "MipsTargetLayout.h" -#include "llvm/Support/Format.h" - -using namespace lld; -using namespace elf; -using namespace llvm::ELF; -using namespace llvm::support; - -namespace { -enum class CrossJumpMode { - None, // Not a jump or non-isa-cross jump - ToRegular, // cross isa jump to regular symbol - ToMicro, // cross isa jump to microMips symbol - ToMicroJalr// cross isa jump to microMips symbol referenced by R_MIPS_JALR -}; - -typedef std::function<std::error_code(int64_t, bool)> OverflowChecker; - -static std::error_code dummyCheck(int64_t, bool) { - return std::error_code(); -} - -template <int BITS> static std::error_code signedCheck(int64_t res, bool) { - if (llvm::isInt<BITS>(res)) - return std::error_code(); - return make_out_of_range_reloc_error(); -} - -template <int BITS> -static std::error_code gpDispCheck(int64_t res, bool isGpDisp) { - if (!isGpDisp || llvm::isInt<BITS>(res)) - return std::error_code(); - return make_out_of_range_reloc_error(); -} - -struct MipsRelocationParams { - uint8_t _size; // Relocations's size in bytes - uint64_t _mask; // Read/write mask of relocation - uint8_t _shift; // Relocation's addendum left shift size - bool _shuffle; // Relocation's addendum/result needs to be shuffled - OverflowChecker _overflow; // Check the relocation result -}; - -template <class ELFT> class RelocationHandler : public TargetRelocationHandler { -public: - RelocationHandler(MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &layout) - : _ctx(ctx), _targetLayout(layout) {} - - std::error_code applyRelocation(ELFWriter &writer, - llvm::FileOutputBuffer &buf, - const AtomLayout &atom, - const Reference &ref) const override; - -private: - MipsLinkingContext &_ctx; - MipsTargetLayout<ELFT> &_targetLayout; -}; -} - -static MipsRelocationParams getRelocationParams(uint32_t rType) { - switch (rType) { - case R_MIPS_NONE: - return {4, 0x0, 0, false, dummyCheck}; - case R_MIPS_64: - case R_MIPS_SUB: - return {8, 0xffffffffffffffffull, 0, false, dummyCheck}; - case R_MICROMIPS_SUB: - return {8, 0xffffffffffffffffull, 0, true, dummyCheck}; - case R_MIPS_32: - case R_MIPS_GPREL32: - case R_MIPS_REL32: - case R_MIPS_PC32: - case R_MIPS_EH: - return {4, 0xffffffff, 0, false, dummyCheck}; - case LLD_R_MIPS_32_HI16: - return {4, 0xffff0000, 0, false, dummyCheck}; - case LLD_R_MIPS_64_HI16: - return {8, 0xffffffffffff0000ull, 0, false, dummyCheck}; - case R_MIPS_26: - case LLD_R_MIPS_GLOBAL_26: - return {4, 0x3ffffff, 2, false, dummyCheck}; - case R_MIPS_PC16: - return {4, 0xffff, 2, false, signedCheck<18>}; - case R_MIPS_PC18_S3: - return {4, 0x3ffff, 3, false, signedCheck<21>}; - case R_MIPS_PC19_S2: - return {4, 0x7ffff, 2, false, signedCheck<21>}; - case R_MIPS_PC21_S2: - return {4, 0x1fffff, 2, false, signedCheck<23>}; - case R_MIPS_PC26_S2: - return {4, 0x3ffffff, 2, false, signedCheck<28>}; - case R_MIPS_HI16: - return {4, 0xffff, 0, false, gpDispCheck<16>}; - case R_MIPS_LO16: - case R_MIPS_HIGHER: - case R_MIPS_HIGHEST: - return {4, 0xffff, 0, false, dummyCheck}; - case R_MIPS_16: - case R_MIPS_PCHI16: - case R_MIPS_PCLO16: - case R_MIPS_GOT16: - case R_MIPS_CALL16: - case R_MIPS_GOT_DISP: - case R_MIPS_GOT_PAGE: - case R_MIPS_GOT_OFST: - case R_MIPS_GPREL16: - case R_MIPS_TLS_GD: - case R_MIPS_TLS_LDM: - case R_MIPS_TLS_GOTTPREL: - case R_MIPS_LITERAL: - return {4, 0xffff, 0, false, signedCheck<16>}; - case R_MIPS_GOT_HI16: - case R_MIPS_GOT_LO16: - case R_MIPS_CALL_HI16: - case R_MIPS_CALL_LO16: - case R_MIPS_TLS_DTPREL_HI16: - case R_MIPS_TLS_DTPREL_LO16: - case R_MIPS_TLS_TPREL_HI16: - case R_MIPS_TLS_TPREL_LO16: - return {4, 0xffff, 0, false, dummyCheck}; - case R_MICROMIPS_GPREL16: - case R_MICROMIPS_LITERAL: - return {4, 0xffff, 0, true, signedCheck<16>}; - case R_MICROMIPS_GPREL7_S2: - return {4, 0x7f, 2, false, signedCheck<9>}; - case R_MICROMIPS_GOT_HI16: - case R_MICROMIPS_GOT_LO16: - case R_MICROMIPS_CALL_HI16: - case R_MICROMIPS_CALL_LO16: - case R_MICROMIPS_TLS_DTPREL_HI16: - case R_MICROMIPS_TLS_DTPREL_LO16: - case R_MICROMIPS_TLS_TPREL_HI16: - case R_MICROMIPS_TLS_TPREL_LO16: - return {4, 0xffff, 0, true, dummyCheck}; - case R_MICROMIPS_26_S1: - case LLD_R_MICROMIPS_GLOBAL_26_S1: - return {4, 0x3ffffff, 1, true, dummyCheck}; - case R_MICROMIPS_HI16: - return {4, 0xffff, 0, true, gpDispCheck<16>}; - case R_MICROMIPS_LO16: - case R_MICROMIPS_HI0_LO16: - case R_MICROMIPS_HIGHER: - case R_MICROMIPS_HIGHEST: - return {4, 0xffff, 0, true, dummyCheck}; - case R_MICROMIPS_PC16_S1: - return {4, 0xffff, 1, true, signedCheck<17>}; - case R_MICROMIPS_PC7_S1: - return {4, 0x7f, 1, false, signedCheck<8>}; - case R_MICROMIPS_PC10_S1: - return {4, 0x3ff, 1, false, signedCheck<11>}; - case R_MICROMIPS_PC23_S2: - return {4, 0x7fffff, 2, true, signedCheck<25>}; - case R_MICROMIPS_PC18_S3: - return {4, 0x3ffff, 3, true, signedCheck<21>}; - case R_MICROMIPS_PC19_S2: - return {4, 0x7ffff, 2, true, signedCheck<21>}; - case R_MICROMIPS_PC21_S2: - return {4, 0x1fffff, 2, true, signedCheck<23>}; - case R_MICROMIPS_PC26_S2: - return {4, 0x3ffffff, 2, true, signedCheck<28>}; - case R_MICROMIPS_GOT16: - case R_MICROMIPS_CALL16: - case R_MICROMIPS_TLS_GD: - case R_MICROMIPS_TLS_LDM: - case R_MICROMIPS_TLS_GOTTPREL: - case R_MICROMIPS_GOT_DISP: - case R_MICROMIPS_GOT_PAGE: - case R_MICROMIPS_GOT_OFST: - return {4, 0xffff, 0, true, signedCheck<16>}; - case R_MIPS_JALR: - return {4, 0xffffffff, 0, false, dummyCheck}; - case R_MICROMIPS_JALR: - return {4, 0x0, 0, true, dummyCheck}; - case R_MIPS_JUMP_SLOT: - case R_MIPS_COPY: - case R_MIPS_TLS_DTPMOD32: - case R_MIPS_TLS_DTPREL32: - case R_MIPS_TLS_TPREL32: - return {4, 0xffffffff, 0, false, dummyCheck}; - case R_MIPS_TLS_DTPMOD64: - case R_MIPS_TLS_DTPREL64: - case R_MIPS_TLS_TPREL64: - return {8, 0xffffffffffffffffull, 0, false, dummyCheck}; - case LLD_R_MIPS_GLOBAL_GOT: - case LLD_R_MIPS_STO_PLT: - // Do nothing. - return {4, 0x0, 0, false, dummyCheck}; - default: - llvm_unreachable("Unknown relocation"); - } -} - -template <class ELFT> -static uint64_t relocRead(const MipsRelocationParams ¶ms, - const uint8_t *loc); - -static int64_t getHi16(int64_t value) { - return ((value + 0x8000) >> 16) & 0xffff; -} - -static int64_t getHigher16(int64_t value) { - return ((value + 0x80008000ull) >> 32) & 0xffff; -} - -static int64_t getHighest16(int64_t value) { - return ((value + 0x800080008000ull) >> 48) & 0xffff; -} - -static int64_t maskLow16(int64_t value) { - return (value + 0x8000) & ~0xffff; -} - -/// R_MIPS_GOT_OFST, R_MICROMIPS_GOT_OFST -/// rel16 offset of (S+A) from the page pointer (verify) -static int32_t relocGOTOfst(uint64_t S, int64_t A) { - int64_t page = maskLow16(S + A); - return S + A - page; -} - -/// \brief R_MIPS_PC16 -/// local/external: (S + A - P) >> 2 -static ErrorOr<int64_t> relocPc16(uint64_t P, uint64_t S, int64_t A) { - if ((S + A) & 3) - return make_unaligned_range_reloc_error(); - return S + A - P; -} - -/// \brief R_MIPS_PC18_S3, R_MICROMIPS_PC18_S3 -/// local/external: (S + A - P) >> 3 (P with cleared 3 less significant bits) -static ErrorOr<int64_t> relocPc18(uint64_t P, uint64_t S, int64_t A) { - if ((S + A) & 6) - return make_unaligned_range_reloc_error(); - return S + A - ((P | 7) ^ 7); -} - -/// \brief R_MIPS_PC19_S2, R_MICROMIPS_PC19_S2, R_MIPS_PC21_S2, -/// R_MICROMIPS_PC21_S2, R_MIPS_PC26_S2, R_MICROMIPS_PC26_S2 -/// local/external: (S + A - P) >> 2 -static ErrorOr<int64_t> relocPcS2(uint64_t P, uint64_t S, int64_t A) { - if ((S + A) & 2) - return make_unaligned_range_reloc_error(); - return S + A - P; -} - -template <class ELFT> -static ErrorOr<int64_t> relocJalr(uint64_t P, uint64_t S, bool isCrossJump, - uint8_t *location) { - uint64_t ins = relocRead<ELFT>(getRelocationParams(R_MIPS_JALR), location); - if (isCrossJump) - return ins; - int64_t off = S - P - 4; - if (!llvm::isInt<18>(off)) - return ins; - if (ins == 0x0320f809) // jalr t9 - return 0x04110000 | ((off >> 2) & 0xffff); - if (ins == 0x03200008) // jr t9 - return 0x10000000 | ((off >> 2) & 0xffff); - return ins; -} - -static int64_t relocRel32(uint64_t S, int64_t A, bool isLocal) { - // If output relocation format is REL and the input one is RELA, the only - // method to transfer the relocation addend from the input relocation - // to the output dynamic relocation is to save this addend to the location - // modified by R_MIPS_REL32. - return isLocal ? S + A : A; -} - -static std::error_code adjustJumpOpCode(uint64_t &ins, uint64_t tgt, - CrossJumpMode mode) { - if (mode == CrossJumpMode::None || mode == CrossJumpMode::ToMicroJalr) - return std::error_code(); - - bool toMicro = mode == CrossJumpMode::ToMicro; - uint32_t opNative = toMicro ? 0x03 : 0x3d; - uint32_t opCross = toMicro ? 0x1d : 0x3c; - - if ((tgt & 1) != toMicro) - return make_dynamic_error_code("Incorrect bit 0 for the jalx target"); - - if (tgt & 2) - return make_dynamic_error_code(Twine("The jalx target 0x") + - Twine::utohexstr(tgt) + - " is not word-aligned"); - uint8_t op = ins >> 26; - if (op != opNative && op != opCross) - return make_dynamic_error_code(Twine("Unsupported jump opcode (0x") + - Twine::utohexstr(op) + - ") for ISA modes cross call"); - - ins = (ins & ~(0x3f << 26)) | (opCross << 26); - return std::error_code(); -} - -static bool isMicroMipsAtom(const Atom *a) { - if (const auto *da = dyn_cast<DefinedAtom>(a)) - return da->codeModel() == DefinedAtom::codeMipsMicro || - da->codeModel() == DefinedAtom::codeMipsMicroPIC; - return false; -} - -static CrossJumpMode getCrossJumpMode(const Reference &ref) { - if (!isa<DefinedAtom>(ref.target())) - return CrossJumpMode::None; - bool isTgtMicro = isMicroMipsAtom(ref.target()); - switch (ref.kindValue()) { - case R_MIPS_JALR: - return isTgtMicro ? CrossJumpMode::ToMicroJalr : CrossJumpMode::None; - case R_MIPS_26: - case LLD_R_MIPS_GLOBAL_26: - return isTgtMicro ? CrossJumpMode::ToMicro : CrossJumpMode::None; - case R_MICROMIPS_26_S1: - case LLD_R_MICROMIPS_GLOBAL_26_S1: - return isTgtMicro ? CrossJumpMode::None : CrossJumpMode::ToRegular; - default: - return CrossJumpMode::None; - } -} - -template <class ELFT> -static ErrorOr<int64_t> -calculateRelocation(Reference::KindValue kind, Reference::Addend addend, - uint64_t tgtAddr, uint64_t relAddr, uint64_t gpAddr, - uint8_t *location, bool isGP, bool isCrossJump, - bool isDynamic, bool isLocalSym) { - switch (kind) { - case R_MIPS_NONE: - return 0; - case R_MIPS_16: - case R_MIPS_32: - case R_MIPS_64: - case R_MIPS_TLS_DTPREL_LO16: - case R_MIPS_TLS_TPREL_LO16: - case R_MICROMIPS_TLS_DTPREL_LO16: - case R_MICROMIPS_TLS_TPREL_LO16: - case LLD_R_MIPS_GLOBAL_26: - case LLD_R_MICROMIPS_GLOBAL_26_S1: - return tgtAddr + addend; - case R_MIPS_SUB: - case R_MICROMIPS_SUB: - return tgtAddr - addend; - case R_MIPS_26: - return tgtAddr + (addend | (relAddr & 0xf0000000)); - case R_MICROMIPS_26_S1: - return tgtAddr + (addend | (relAddr & 0xf8000000)); - case R_MIPS_HI16: - case R_MICROMIPS_HI16: - return getHi16(tgtAddr + addend - (isGP ? relAddr : 0)); - case R_MIPS_PCHI16: - return getHi16(tgtAddr + addend - relAddr); - case R_MIPS_LO16: - return tgtAddr + addend - (isGP ? relAddr - 4 : 0); - case R_MICROMIPS_LO16: - case R_MICROMIPS_HI0_LO16: - return tgtAddr + addend - (isGP ? relAddr - 3 : 0); - case R_MIPS_GOT_HI16: - case R_MIPS_CALL_HI16: - case R_MICROMIPS_GOT_HI16: - case R_MICROMIPS_CALL_HI16: - return getHi16(tgtAddr - gpAddr); - case R_MIPS_HIGHER: - case R_MICROMIPS_HIGHER: - return getHigher16(tgtAddr + addend); - case R_MIPS_HIGHEST: - case R_MICROMIPS_HIGHEST: - return getHighest16(tgtAddr + addend); - case R_MIPS_GOT_LO16: - case R_MIPS_CALL_LO16: - case R_MICROMIPS_GOT_LO16: - case R_MICROMIPS_CALL_LO16: - case R_MIPS_EH: - case R_MIPS_GOT16: - case R_MIPS_CALL16: - case R_MIPS_GOT_DISP: - case R_MIPS_GOT_PAGE: - case R_MICROMIPS_GOT_DISP: - case R_MICROMIPS_GOT_PAGE: - case R_MICROMIPS_GOT16: - case R_MICROMIPS_CALL16: - case R_MIPS_TLS_GD: - case R_MIPS_TLS_LDM: - case R_MIPS_TLS_GOTTPREL: - case R_MICROMIPS_TLS_GD: - case R_MICROMIPS_TLS_LDM: - case R_MICROMIPS_TLS_GOTTPREL: - return tgtAddr - gpAddr; - case R_MIPS_GPREL16: - case R_MIPS_GPREL32: - case R_MIPS_LITERAL: - case R_MICROMIPS_GPREL16: - case R_MICROMIPS_GPREL7_S2: - case R_MICROMIPS_LITERAL: - return tgtAddr + addend - gpAddr; - case R_MIPS_GOT_OFST: - case R_MICROMIPS_GOT_OFST: - return relocGOTOfst(tgtAddr, addend); - case R_MIPS_PC16: - return relocPc16(relAddr, tgtAddr, addend); - case R_MIPS_PC18_S3: - case R_MICROMIPS_PC18_S3: - return relocPc18(relAddr, tgtAddr, addend); - case R_MIPS_PC19_S2: - case R_MICROMIPS_PC19_S2: - case R_MIPS_PC21_S2: - case R_MICROMIPS_PC21_S2: - case R_MIPS_PC26_S2: - case R_MICROMIPS_PC26_S2: - return relocPcS2(relAddr, tgtAddr, addend); - case R_MIPS_PC32: - case R_MIPS_PCLO16: - case R_MICROMIPS_PC7_S1: - case R_MICROMIPS_PC10_S1: - case R_MICROMIPS_PC16_S1: - case R_MICROMIPS_PC23_S2: - return tgtAddr + addend - relAddr; - case R_MIPS_TLS_DTPREL_HI16: - case R_MIPS_TLS_TPREL_HI16: - case R_MICROMIPS_TLS_DTPREL_HI16: - case R_MICROMIPS_TLS_TPREL_HI16: - return getHi16(tgtAddr + addend); - case R_MIPS_JALR: - return relocJalr<ELFT>(relAddr, tgtAddr, isCrossJump, location); - case R_MICROMIPS_JALR: - // We do not do JALR optimization now. - return 0; - case R_MIPS_REL32: - return relocRel32(tgtAddr, addend, isLocalSym); - case R_MIPS_JUMP_SLOT: - case R_MIPS_COPY: - // Ignore runtime relocations. - return 0; - case R_MIPS_TLS_DTPMOD32: - case R_MIPS_TLS_DTPMOD64: - return isDynamic ? 0 : 1; - case R_MIPS_TLS_DTPREL32: - case R_MIPS_TLS_DTPREL64: - return isDynamic ? 0 : tgtAddr + addend - 0x8000; - case R_MIPS_TLS_TPREL32: - case R_MIPS_TLS_TPREL64: - return isDynamic ? 0 : tgtAddr + addend - 0x7000; - case LLD_R_MIPS_32_HI16: - case LLD_R_MIPS_64_HI16: - return maskLow16(tgtAddr + addend); - case LLD_R_MIPS_STO_PLT: - case LLD_R_MIPS_GLOBAL_GOT: - // Do nothing. - return 0; - default: - return make_unhandled_reloc_error(); - } -} - -template <class ELFT> -static uint64_t relocRead(const MipsRelocationParams ¶ms, - const uint8_t *loc) { - assert((params._size == 4 || params._size == 8) && "Unexpected size"); - uint64_t data = 0; - memcpy(&data, loc, params._size); - if (params._shuffle) { - using namespace endian; - auto p = reinterpret_cast<const uint8_t *>(&data); - uint32_t a = readNext<uint16_t, ELFT::TargetEndianness, unaligned>(p); - uint32_t b = read<uint16_t, ELFT::TargetEndianness, unaligned>(p); - write<uint32_t, ELFT::TargetEndianness, unaligned>(&data, a << 16 | b); - } - switch (params._size) { - case 4: - return endian::read<uint32_t, ELFT::TargetEndianness, unaligned>(&data); - case 8: - return endian::read<uint64_t, ELFT::TargetEndianness, unaligned>(&data); - default: - llvm_unreachable("Unexpected size"); - } -} - -template <class ELFT> -static void relocWrite(uint64_t data, const MipsRelocationParams ¶ms, - uint8_t *loc) { - switch (params._size) { - case 4: - endian::write<uint32_t, ELFT::TargetEndianness, unaligned>(loc, data); - break; - case 8: - endian::write<uint64_t, ELFT::TargetEndianness, unaligned>(loc, data); - break; - default: - llvm_unreachable("Unexpected size"); - } - if (params._shuffle) { - uint32_t v = endian::read<uint32_t, ELFT::TargetEndianness, unaligned>(loc); - uint16_t a = v >> 16; - uint16_t b = v & 0xffff; - endian::write<uint16_t, ELFT::TargetEndianness, unaligned>(loc, a); - endian::write<uint16_t, ELFT::TargetEndianness, unaligned>(loc + 2, b); - } -} - -static uint32_t getRelKind(const Reference &ref, size_t num) { - if (num == 0) - return ref.kindValue(); - if (num > 2) - return R_MIPS_NONE; - return (ref.tag() >> (8 * (num - 1))) & 0xff; -} - -static uint8_t getRelShift(Reference::KindValue kind, - const MipsRelocationParams ¶ms, - bool isCrossJump) { - uint8_t shift = params._shift; - if (isCrossJump && - (kind == R_MICROMIPS_26_S1 || kind == LLD_R_MICROMIPS_GLOBAL_26_S1)) - return 2; - return shift; -} - -static bool isLocalTarget(const Atom *a) { - if (auto *da = dyn_cast<DefinedAtom>(a)) - return da->scope() == Atom::scopeTranslationUnit; - return false; -} - -template <class ELFT> -std::error_code RelocationHandler<ELFT>::applyRelocation( - ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom, - const Reference &ref) const { - if (ref.kindNamespace() != Reference::KindNamespace::ELF) - return std::error_code(); - assert(ref.kindArch() == Reference::KindArch::Mips); - - uint64_t gpAddr = _targetLayout.getGPAddr(); - bool isGpDisp = ref.target()->name() == "_gp_disp"; - bool isLocalSym = isLocalTarget(ref.target()); - - uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset; - uint8_t *location = atomContent + ref.offsetInAtom(); - uint64_t tgtAddr = writer.addressOfAtom(ref.target()); - uint64_t relAddr = atom._virtualAddr + ref.offsetInAtom(); - - if (isMicroMipsAtom(ref.target())) - tgtAddr |= 1; - - CrossJumpMode jumpMode = getCrossJumpMode(ref); - bool isCrossJump = jumpMode != CrossJumpMode::None; - - uint64_t sym = tgtAddr; - ErrorOr<int64_t> res = ref.addend(); - Reference::KindValue lastRel = R_MIPS_NONE; - - for (size_t relNum = 0; relNum < 3; ++relNum) { - Reference::KindValue kind = getRelKind(ref, relNum); - if (kind == R_MIPS_NONE) - break; - auto params = getRelocationParams(kind); - res = calculateRelocation<ELFT>(kind, *res, sym, relAddr, gpAddr, location, - isGpDisp, isCrossJump, _ctx.isDynamic(), - isLocalSym); - if (auto ec = res.getError()) - return ec; - // Check result for the last relocation only. - if (getRelKind(ref, relNum + 1) == R_MIPS_NONE) { - if (auto ec = params._overflow(*res, isGpDisp)) - return ec; - } - res = *res >> getRelShift(kind, params, isCrossJump); - // FIXME (simon): Handle r_ssym value. - sym = 0; - isGpDisp = false; - isCrossJump = false; - lastRel = kind; - } - - auto params = getRelocationParams(lastRel); - uint64_t ins = relocRead<ELFT>(params, location); - if (auto ec = adjustJumpOpCode(ins, tgtAddr, jumpMode)) - return ec; - - ins = (ins & ~params._mask) | (*res & params._mask); - relocWrite<ELFT>(ins, params, location); - - return std::error_code(); -} - -namespace lld { -namespace elf { - -template <> -std::unique_ptr<TargetRelocationHandler> -createMipsRelocationHandler<ELF32BE>(MipsLinkingContext &ctx, - MipsTargetLayout<ELF32BE> &layout) { - return llvm::make_unique<RelocationHandler<ELF32BE>>(ctx, layout); -} - -template <> -std::unique_ptr<TargetRelocationHandler> -createMipsRelocationHandler<ELF32LE>(MipsLinkingContext &ctx, - MipsTargetLayout<ELF32LE> &layout) { - return llvm::make_unique<RelocationHandler<ELF32LE>>(ctx, layout); -} - -template <> -std::unique_ptr<TargetRelocationHandler> -createMipsRelocationHandler<ELF64BE>(MipsLinkingContext &ctx, - MipsTargetLayout<ELF64BE> &layout) { - return llvm::make_unique<RelocationHandler<ELF64BE>>(ctx, layout); -} - -template <> -std::unique_ptr<TargetRelocationHandler> -createMipsRelocationHandler<ELF64LE>(MipsLinkingContext &ctx, - MipsTargetLayout<ELF64LE> &layout) { - return llvm::make_unique<RelocationHandler<ELF64LE>>(ctx, layout); -} - -template <class ELFT> -Reference::Addend readMipsRelocAddend(Reference::KindValue kind, - const uint8_t *content) { - auto params = getRelocationParams(kind); - uint64_t ins = relocRead<ELFT>(params, content); - int64_t res = (ins & params._mask) << params._shift; - switch (kind) { - case R_MIPS_GPREL16: - case R_MICROMIPS_GPREL16: - case R_MIPS_PCLO16: - case R_MIPS_LITERAL: - case R_MICROMIPS_LITERAL: - return llvm::SignExtend32<16>(res); - case R_MIPS_PC16: - return llvm::SignExtend32<18>(res); - case R_MICROMIPS_GPREL7_S2: - return llvm::SignExtend32<9>(res); - case R_MICROMIPS_PC7_S1: - return llvm::SignExtend32<8>(res); - case R_MICROMIPS_PC10_S1: - return llvm::SignExtend32<11>(res); - case R_MIPS_16: - return llvm::SignExtend32<16>(res); - case R_MICROMIPS_PC16_S1: - return llvm::SignExtend32<17>(res); - case R_MIPS_PC18_S3: - case R_MIPS_PC19_S2: - case R_MICROMIPS_PC18_S3: - case R_MICROMIPS_PC19_S2: - return llvm::SignExtend32<21>(res); - case R_MIPS_PC21_S2: - case R_MICROMIPS_PC21_S2: - return llvm::SignExtend32<23>(res); - case R_MICROMIPS_PC23_S2: - return llvm::SignExtend32<25>(res); - case R_MICROMIPS_26_S1: - return llvm::SignExtend32<27>(res); - case R_MIPS_26: - case R_MIPS_PC26_S2: - case R_MICROMIPS_PC26_S2: - return llvm::SignExtend32<28>(res); - default: - // Nothing to do - break; - } - return res; -} - -template -Reference::Addend readMipsRelocAddend<ELF32BE>(Reference::KindValue kind, - const uint8_t *content); -template -Reference::Addend readMipsRelocAddend<ELF32LE>(Reference::KindValue kind, - const uint8_t *content); -template -Reference::Addend readMipsRelocAddend<ELF64BE>(Reference::KindValue kind, - const uint8_t *content); -template -Reference::Addend readMipsRelocAddend<ELF64LE>(Reference::KindValue kind, - const uint8_t *content); - -} // elf -} // lld diff --git a/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h b/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h deleted file mode 100644 index 62a7aee34496..000000000000 --- a/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h +++ /dev/null @@ -1,31 +0,0 @@ -//===- lld/ReaderWriter/ELF/Mips/MipsRelocationHandler.h ------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_RELOCATION_HANDLER_H -#define LLD_READER_WRITER_ELF_MIPS_MIPS_RELOCATION_HANDLER_H - -#include "lld/Core/Reference.h" - -namespace lld { -namespace elf { - -class MipsLinkingContext; -template<typename ELFT> class MipsTargetLayout; - -template <class ELFT> -std::unique_ptr<TargetRelocationHandler> -createMipsRelocationHandler(MipsLinkingContext &ctx, - MipsTargetLayout<ELFT> &layout); - -template <class ELFT> -Reference::Addend readMipsRelocAddend(Reference::KindValue kind, - const uint8_t *content); -} // elf -} // lld - -#endif diff --git a/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp b/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp deleted file mode 100644 index b47c7d2210db..000000000000 --- a/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp +++ /dev/null @@ -1,1415 +0,0 @@ -//===- lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp -------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "MipsELFFile.h" -#include "MipsLinkingContext.h" -#include "MipsRelocationPass.h" -#include "MipsTargetHandler.h" -#include "llvm/ADT/DenseSet.h" - -using namespace lld; -using namespace lld::elf; -using namespace llvm::ELF; - -// Lazy resolver -static const uint8_t mipsGot0AtomContent[] = { - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 -}; - -// Module pointer -static const uint8_t mipsGotModulePointerAtomContent[] = { - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x80 -}; - -// TLS GD Entry -static const uint8_t mipsGotTlsGdAtomContent[] = { - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 -}; - -// Regular big-endian PLT0 entry -static const uint8_t mipsBePlt0AtomContent[] = { - 0x3c, 0x1c, 0x00, 0x00, // lui $28, %hi(&GOTPLT[0]) - 0x8f, 0x99, 0x00, 0x00, // lw $25, %lo(&GOTPLT[0])($28) - 0x27, 0x9c, 0x00, 0x00, // addiu $28, $28, %lo(&GOTPLT[0]) - 0x03, 0x1c, 0xc0, 0x23, // subu $24, $24, $28 - 0x03, 0xe0, 0x78, 0x25, // move $15, $31 - 0x00, 0x18, 0xc0, 0x82, // srl $24, $24, 2 - 0x03, 0x20, 0xf8, 0x09, // jalr $25 - 0x27, 0x18, 0xff, 0xfe // subu $24, $24, 2 -}; - -// Regular little-endian PLT0 entry -static const uint8_t mipsLePlt0AtomContent[] = { - 0x00, 0x00, 0x1c, 0x3c, // lui $28, %hi(&GOTPLT[0]) - 0x00, 0x00, 0x99, 0x8f, // lw $25, %lo(&GOTPLT[0])($28) - 0x00, 0x00, 0x9c, 0x27, // addiu $28, $28, %lo(&GOTPLT[0]) - 0x23, 0xc0, 0x1c, 0x03, // subu $24, $24, $28 - 0x25, 0x78, 0xe0, 0x03, // move $15, $31 - 0x82, 0xc0, 0x18, 0x00, // srl $24, $24, 2 - 0x09, 0xf8, 0x20, 0x03, // jalr $25 - 0xfe, 0xff, 0x18, 0x27 // subu $24, $24, 2 -}; - -// N32 big-endian PLT0 entry -static const uint8_t mipsN32BePlt0AtomContent[] = { - 0x3c, 0x0e, 0x00, 0x00, // lui $14, %hi(&GOTPLT[0]) - 0x8d, 0xd9, 0x00, 0x00, // lw $25, %lo(&GOTPLT[0])($14) - 0x25, 0xce, 0x00, 0x00, // addiu $14, $14, %lo(&GOTPLT[0]) - 0x03, 0x0e, 0xc0, 0x23, // subu $24, $24, $14 - 0x03, 0xe0, 0x78, 0x25, // move $15, $31 - 0x00, 0x18, 0xc0, 0x82, // srl $24, $24, 2 - 0x03, 0x20, 0xf8, 0x09, // jalr $25 - 0x27, 0x18, 0xff, 0xfe // subu $24, $24, 2 -}; - -// N32 little-endian PLT0 entry -static const uint8_t mipsN32LePlt0AtomContent[] = { - 0x00, 0x00, 0x0e, 0x3c, // lui $14, %hi(&GOTPLT[0]) - 0x00, 0x00, 0xd9, 0x8d, // lw $25, %lo(&GOTPLT[0])($14) - 0x00, 0x00, 0xce, 0x25, // addiu $14, $14, %lo(&GOTPLT[0]) - 0x23, 0xc0, 0x0e, 0x03, // subu $24, $24, $14 - 0x25, 0x78, 0xe0, 0x03, // move $15, $31 - 0x82, 0xc0, 0x18, 0x00, // srl $24, $24, 2 - 0x09, 0xf8, 0x20, 0x03, // jalr $25 - 0xfe, 0xff, 0x18, 0x27 // subu $24, $24, 2 -}; - -// microMIPS big-endian PLT0 entry -static const uint8_t microMipsBePlt0AtomContent[] = { - 0x79, 0x80, 0x00, 0x00, // addiupc $3, (&GOTPLT[0]) - . - 0xff, 0x23, 0x00, 0x00, // lw $25, 0($3) - 0x05, 0x35, // subu $2, $2, $3 - 0x25, 0x25, // srl $2, $2, 2 - 0x33, 0x02, 0xff, 0xfe, // subu $24, $2, 2 - 0x0d, 0xff, // move $15, $31 - 0x45, 0xf9, // jalrs $25 - 0x0f, 0x83, // move $28, $3 - 0x0c, 0x00 // nop -}; - -// microMIPS little-endian PLT0 entry -static const uint8_t microMipsLePlt0AtomContent[] = { - 0x80, 0x79, 0x00, 0x00, // addiupc $3, (&GOTPLT[0]) - . - 0x23, 0xff, 0x00, 0x00, // lw $25, 0($3) - 0x35, 0x05, // subu $2, $2, $3 - 0x25, 0x25, // srl $2, $2, 2 - 0x02, 0x33, 0xfe, 0xff, // subu $24, $2, 2 - 0xff, 0x0d, // move $15, $31 - 0xf9, 0x45, // jalrs $25 - 0x83, 0x0f, // move $28, $3 - 0x00, 0x0c // nop -}; - -// Regular big-endian PLT entry -static const uint8_t mipsBePltAAtomContent[] = { - 0x3c, 0x0f, 0x00, 0x00, // lui $15, %hi(.got.plt entry) - 0x8d, 0xf9, 0x00, 0x00, // l[wd] $25, %lo(.got.plt entry)($15) - 0x03, 0x20, 0x00, 0x08, // jr $25 - 0x25, 0xf8, 0x00, 0x00 // addiu $24, $15, %lo(.got.plt entry) -}; - -// Regular little-endian PLT entry -static const uint8_t mipsLePltAAtomContent[] = { - 0x00, 0x00, 0x0f, 0x3c, // lui $15, %hi(.got.plt entry) - 0x00, 0x00, 0xf9, 0x8d, // l[wd] $25, %lo(.got.plt entry)($15) - 0x08, 0x00, 0x20, 0x03, // jr $25 - 0x00, 0x00, 0xf8, 0x25 // addiu $24, $15, %lo(.got.plt entry) -}; - -// microMIPS big-endian PLT entry -static const uint8_t microMipsBePltAAtomContent[] = { - 0x79, 0x00, 0x00, 0x00, // addiupc $2, (.got.plt entry) - . - 0xff, 0x22, 0x00, 0x00, // lw $25, 0($2) - 0x45, 0x99, // jr $25 - 0x0f, 0x02 // move $24, $2 -}; - -// microMIPS little-endian PLT entry -static const uint8_t microMipsLePltAAtomContent[] = { - 0x00, 0x79, 0x00, 0x00, // addiupc $2, (.got.plt entry) - . - 0x22, 0xff, 0x00, 0x00, // lw $25, 0($2) - 0x99, 0x45, // jr $25 - 0x02, 0x0f // move $24, $2 -}; - -// R6 big-endian PLT entry -static const uint8_t mipsR6BePltAAtomContent[] = { - 0x3c, 0x0f, 0x00, 0x00, // lui $15, %hi(.got.plt entry) - 0x8d, 0xf9, 0x00, 0x00, // l[wd] $25, %lo(.got.plt entry)($15) - 0x03, 0x20, 0x00, 0x09, // jr $25 - 0x25, 0xf8, 0x00, 0x00 // addiu $24, $15, %lo(.got.plt entry) -}; - -// R6 little-endian PLT entry -static const uint8_t mipsR6LePltAAtomContent[] = { - 0x00, 0x00, 0x0f, 0x3c, // lui $15, %hi(.got.plt entry) - 0x00, 0x00, 0xf9, 0x8d, // l[wd] $25, %lo(.got.plt entry)($15) - 0x09, 0x00, 0x20, 0x03, // jr $25 - 0x00, 0x00, 0xf8, 0x25 // addiu $24, $15, %lo(.got.plt entry) -}; - -// LA25 big-endian stub entry -static const uint8_t mipsBeLA25AtomContent[] = { - 0x3c, 0x19, 0x00, 0x00, // lui $25, %hi(func) - 0x08, 0x00, 0x00, 0x00, // j func - 0x27, 0x39, 0x00, 0x00, // addiu $25, $25, %lo(func) - 0x00, 0x00, 0x00, 0x00 // nop -}; - -// LA25 little-endian stub entry -static const uint8_t mipsLeLA25AtomContent[] = { - 0x00, 0x00, 0x19, 0x3c, // lui $25, %hi(func) - 0x00, 0x00, 0x00, 0x08, // j func - 0x00, 0x00, 0x39, 0x27, // addiu $25, $25, %lo(func) - 0x00, 0x00, 0x00, 0x00 // nop -}; - -// microMIPS LA25 big-endian stub entry -static const uint8_t microMipsBeLA25AtomContent[] = { - 0x41, 0xbe, 0x00, 0x00, // lui $25, %hi(func) - 0xd4, 0x00, 0x00, 0x00, // j func - 0x33, 0x39, 0x00, 0x00, // addiu $25, $25, %lo(func) - 0x00, 0x00, 0x00, 0x00 // nop -}; - -// microMIPS LA25 little-endian stub entry -static const uint8_t microMipsLeLA25AtomContent[] = { - 0xb9, 0x41, 0x00, 0x00, // lui $25, %hi(func) - 0x00, 0xd4, 0x00, 0x00, // j func - 0x39, 0x33, 0x00, 0x00, // addiu $25, $25, %lo(func) - 0x00, 0x00, 0x00, 0x00 // nop -}; - -namespace { - -/// \brief Abstract base class represent MIPS GOT entries. -class MipsGOTAtom : public GOTAtom { -public: - MipsGOTAtom(const File &f) : GOTAtom(f, ".got") {} - - Alignment alignment() const override { return 4; } -}; - -/// \brief MIPS GOT entry initialized by zero. -template <typename ELFT> class GOT0Atom : public MipsGOTAtom { -public: - GOT0Atom(const File &f) : MipsGOTAtom(f) {} - - ArrayRef<uint8_t> rawContent() const override; -}; - -template <> ArrayRef<uint8_t> GOT0Atom<ELF32BE>::rawContent() const { - return llvm::makeArrayRef(mipsGot0AtomContent).slice(4); -} -template <> ArrayRef<uint8_t> GOT0Atom<ELF32LE>::rawContent() const { - return llvm::makeArrayRef(mipsGot0AtomContent).slice(4); -} -template <> ArrayRef<uint8_t> GOT0Atom<ELF64BE>::rawContent() const { - return llvm::makeArrayRef(mipsGot0AtomContent); -} -template <> ArrayRef<uint8_t> GOT0Atom<ELF64LE>::rawContent() const { - return llvm::makeArrayRef(mipsGot0AtomContent); -} - -/// \brief MIPS GOT entry initialized by zero. -template <typename ELFT> class GOTModulePointerAtom : public MipsGOTAtom { -public: - GOTModulePointerAtom(const File &f) : MipsGOTAtom(f) {} - - ArrayRef<uint8_t> rawContent() const override; -}; - -template <> -ArrayRef<uint8_t> GOTModulePointerAtom<ELF32BE>::rawContent() const { - return llvm::makeArrayRef(mipsGotModulePointerAtomContent).slice(4); -} -template <> -ArrayRef<uint8_t> GOTModulePointerAtom<ELF32LE>::rawContent() const { - return llvm::makeArrayRef(mipsGotModulePointerAtomContent).slice(4); -} -template <> -ArrayRef<uint8_t> GOTModulePointerAtom<ELF64BE>::rawContent() const { - return llvm::makeArrayRef(mipsGotModulePointerAtomContent); -} -template <> -ArrayRef<uint8_t> GOTModulePointerAtom<ELF64LE>::rawContent() const { - return llvm::makeArrayRef(mipsGotModulePointerAtomContent); -} - -/// \brief MIPS GOT TLS GD entry. -template <typename ELFT> class GOTTLSGdAtom : public MipsGOTAtom { -public: - GOTTLSGdAtom(const File &f) : MipsGOTAtom(f) {} - - ArrayRef<uint8_t> rawContent() const override; -}; - -template <> ArrayRef<uint8_t> GOTTLSGdAtom<ELF32BE>::rawContent() const { - return llvm::makeArrayRef(mipsGotTlsGdAtomContent).slice(8); -} -template <> ArrayRef<uint8_t> GOTTLSGdAtom<ELF32LE>::rawContent() const { - return llvm::makeArrayRef(mipsGotTlsGdAtomContent).slice(8); -} -template <> ArrayRef<uint8_t> GOTTLSGdAtom<ELF64BE>::rawContent() const { - return llvm::makeArrayRef(mipsGotTlsGdAtomContent); -} -template <> ArrayRef<uint8_t> GOTTLSGdAtom<ELF64LE>::rawContent() const { - return llvm::makeArrayRef(mipsGotTlsGdAtomContent); -} - -class GOTPLTAtom : public GOTAtom { -public: - GOTPLTAtom(const File &f) : GOTAtom(f, ".got.plt") {} - GOTPLTAtom(const Atom *a, const File &f) : GOTAtom(f, ".got.plt") { - // Create dynamic relocation to adjust the .got.plt entry at runtime. - addReferenceELF_Mips(R_MIPS_JUMP_SLOT, 0, a, 0); - } - - /// Setup reference to assign initial value to the .got.plt entry. - void setPLT0(const PLTAtom *plt0) { - addReferenceELF_Mips(R_MIPS_32, 0, plt0, 0); - } - - Alignment alignment() const override { return 4; } - - ArrayRef<uint8_t> rawContent() const override { - return llvm::makeArrayRef(mipsGot0AtomContent).slice(4); - } -}; - -template <class ELFT> class PLT0Atom : public PLTAtom { -public: - PLT0Atom(const Atom *got, const File &f) : PLTAtom(f, ".plt") { - // Setup reference to fixup the PLT0 entry. - addReferenceELF_Mips(R_MIPS_HI16, 0, got, 0); - addReferenceELF_Mips(R_MIPS_LO16, 4, got, 0); - addReferenceELF_Mips(R_MIPS_LO16, 8, got, 0); - } - - ArrayRef<uint8_t> rawContent() const override { - llvm_unreachable("PLT0 is not applicable for this target"); - } -}; - -template <> ArrayRef<uint8_t> PLT0Atom<ELF32BE>::rawContent() const { - return llvm::makeArrayRef(mipsBePlt0AtomContent); -} -template <> ArrayRef<uint8_t> PLT0Atom<ELF32LE>::rawContent() const { - return llvm::makeArrayRef(mipsLePlt0AtomContent); -} - -template <class ELFT> class PLT0N32Atom : public PLTAtom { -public: - PLT0N32Atom(const Atom *got, const File &f) : PLTAtom(f, ".plt") { - // Setup reference to fixup the PLT0 entry. - addReferenceELF_Mips(R_MIPS_HI16, 0, got, 0); - addReferenceELF_Mips(R_MIPS_LO16, 4, got, 0); - addReferenceELF_Mips(R_MIPS_LO16, 8, got, 0); - } - - ArrayRef<uint8_t> rawContent() const override { - llvm_unreachable("PLT0 is not applicable for this target"); - } -}; - -template <> ArrayRef<uint8_t> PLT0N32Atom<ELF32BE>::rawContent() const { - return llvm::makeArrayRef(mipsN32BePlt0AtomContent); -} -template <> ArrayRef<uint8_t> PLT0N32Atom<ELF32LE>::rawContent() const { - return llvm::makeArrayRef(mipsN32LePlt0AtomContent); -} - -template <class ELFT> class PLT0MicroAtom : public PLTAtom { -public: - PLT0MicroAtom(const Atom *got, const File &f) : PLTAtom(f, ".plt") { - // Setup reference to fixup the PLT0 entry. - addReferenceELF_Mips(R_MICROMIPS_PC23_S2, 0, got, 0); - } - - CodeModel codeModel() const override { return codeMipsMicro; } - - ArrayRef<uint8_t> rawContent() const override { - llvm_unreachable("PLT0 is not applicable for this target"); - } -}; - -template <> ArrayRef<uint8_t> PLT0MicroAtom<ELF32BE>::rawContent() const { - return llvm::makeArrayRef(microMipsBePlt0AtomContent); -} -template <> ArrayRef<uint8_t> PLT0MicroAtom<ELF32LE>::rawContent() const { - return llvm::makeArrayRef(microMipsLePlt0AtomContent); -} - -class PLTAAtom : public PLTAtom { -public: - PLTAAtom(const GOTPLTAtom *got, const File &f) : PLTAtom(f, ".plt") { - // Setup reference to fixup the PLT entry. - addReferenceELF_Mips(R_MIPS_HI16, 0, got, 0); - addReferenceELF_Mips(R_MIPS_LO16, 4, got, 0); - addReferenceELF_Mips(R_MIPS_LO16, 12, got, 0); - } -}; - -template <class ELFT> class PLTARegAtom : public PLTAAtom { -public: - PLTARegAtom(const GOTPLTAtom *got, const File &f) : PLTAAtom(got, f) {} - - ArrayRef<uint8_t> rawContent() const override { - llvm_unreachable("PLT is not applicable for this target"); - } -}; - -template <> ArrayRef<uint8_t> PLTARegAtom<ELF32BE>::rawContent() const { - return llvm::makeArrayRef(mipsBePltAAtomContent); -} -template <> ArrayRef<uint8_t> PLTARegAtom<ELF32LE>::rawContent() const { - return llvm::makeArrayRef(mipsLePltAAtomContent); -} - -template <class ELFT> class PLTR6Atom : public PLTAAtom { -public: - PLTR6Atom(const GOTPLTAtom *got, const File &f) : PLTAAtom(got, f) {} - - ArrayRef<uint8_t> rawContent() const override { - llvm_unreachable("PLT is not applicable for this target"); - } -}; - -template <> ArrayRef<uint8_t> PLTR6Atom<ELF32BE>::rawContent() const { - return llvm::makeArrayRef(mipsR6BePltAAtomContent); -} -template <> ArrayRef<uint8_t> PLTR6Atom<ELF32LE>::rawContent() const { - return llvm::makeArrayRef(mipsR6LePltAAtomContent); -} - -template <class ELFT> class PLTMicroAtom : public PLTAtom { -public: - PLTMicroAtom(const GOTPLTAtom *got, const File &f) : PLTAtom(f, ".plt") { - // Setup reference to fixup the microMIPS PLT entry. - addReferenceELF_Mips(R_MICROMIPS_PC23_S2, 0, got, 0); - } - - Alignment alignment() const override { return 2; } - CodeModel codeModel() const override { return codeMipsMicro; } - - ArrayRef<uint8_t> rawContent() const override { - llvm_unreachable("PLT is not applicable for this target"); - } -}; - -template <> ArrayRef<uint8_t> PLTMicroAtom<ELF32BE>::rawContent() const { - return llvm::makeArrayRef(microMipsBePltAAtomContent); -} -template <> ArrayRef<uint8_t> PLTMicroAtom<ELF32LE>::rawContent() const { - return llvm::makeArrayRef(microMipsLePltAAtomContent); -} - -class LA25Atom : public PLTAtom { -public: - LA25Atom(const File &f) : PLTAtom(f, ".text") {} -}; - -template <typename ELFT> class LA25RegAtom : public LA25Atom { -public: - LA25RegAtom(const Atom *a, const File &f) : LA25Atom(f) { - // Setup reference to fixup the LA25 stub entry. - addReferenceELF_Mips(R_MIPS_HI16, 0, a, 0); - addReferenceELF_Mips(R_MIPS_26, 4, a, 0); - addReferenceELF_Mips(R_MIPS_LO16, 8, a, 0); - } - - ArrayRef<uint8_t> rawContent() const override { - llvm_unreachable("LA25 stubs are not applicable for this target"); - } -}; - -template <> ArrayRef<uint8_t> LA25RegAtom<ELF32BE>::rawContent() const { - return llvm::makeArrayRef(mipsBeLA25AtomContent); -} -template <> ArrayRef<uint8_t> LA25RegAtom<ELF32LE>::rawContent() const { - return llvm::makeArrayRef(mipsLeLA25AtomContent); -} - -template <typename ELFT> class LA25MicroAtom : public LA25Atom { -public: - LA25MicroAtom(const Atom *a, const File &f) : LA25Atom(f) { - // Setup reference to fixup the microMIPS LA25 stub entry. - addReferenceELF_Mips(R_MICROMIPS_HI16, 0, a, 0); - addReferenceELF_Mips(R_MICROMIPS_26_S1, 4, a, 0); - addReferenceELF_Mips(R_MICROMIPS_LO16, 8, a, 0); - } - - CodeModel codeModel() const override { return codeMipsMicro; } - - ArrayRef<uint8_t> rawContent() const override { - llvm_unreachable("LA25 stubs are not applicable for this target"); - } -}; - -template <> ArrayRef<uint8_t> LA25MicroAtom<ELF32BE>::rawContent() const { - return llvm::makeArrayRef(microMipsBeLA25AtomContent); -} -template <> ArrayRef<uint8_t> LA25MicroAtom<ELF32LE>::rawContent() const { - return llvm::makeArrayRef(microMipsLeLA25AtomContent); -} - -class MipsGlobalOffsetTableAtom : public GlobalOffsetTableAtom { -public: - MipsGlobalOffsetTableAtom(const File &f) : GlobalOffsetTableAtom(f) {} - - StringRef customSectionName() const override { return ".got"; } -}; - -template <typename ELFT> class MipsRldAtom : public SimpleELFDefinedAtom { -public: - MipsRldAtom(const File &f) : SimpleELFDefinedAtom(f) {} - - Scope scope() const override { return scopeGlobal; } - SectionChoice sectionChoice() const override { return sectionCustomRequired; } - StringRef customSectionName() const override { return ".rld_map"; } - ContentType contentType() const override { return typeData; } - uint64_t size() const override { return rawContent().size(); } - ContentPermissions permissions() const override { return permRW_; } - Alignment alignment() const override { return rawContent().size(); } - StringRef name() const override { return "__RLD_MAP"; } - ArrayRef<uint8_t> rawContent() const override { - return llvm::makeArrayRef(mipsGot0AtomContent) - .slice(ELFT::Is64Bits ? 0 : 4); - } -}; - -class RelocationPassFile : public SimpleFile { -public: - RelocationPassFile(const ELFLinkingContext &ctx) - : SimpleFile("RelocationPassFile") { - setOrdinal(ctx.getNextOrdinalAndIncrement()); - } - - llvm::BumpPtrAllocator _alloc; -}; - -template <typename ELFT> class RelocationPass : public Pass { -public: - RelocationPass(MipsLinkingContext &ctx); - - std::error_code perform(SimpleFile &mf) override; - -private: - /// \brief Reference to the linking context. - const MipsLinkingContext &_ctx; - - /// \brief Owner of all the Atoms created by this pass. - RelocationPassFile _file; - - /// \brief Map Atoms and addend to local GOT entries. - typedef std::pair<const Atom *, int64_t> LocalGotMapKeyT; - llvm::DenseMap<LocalGotMapKeyT, GOTAtom *> _gotLocalMap; - llvm::DenseMap<LocalGotMapKeyT, GOTAtom *> _gotLocalPageMap; - - /// \brief Map Atoms to global GOT entries. - llvm::DenseMap<const Atom *, GOTAtom *> _gotGlobalMap; - - /// \brief Map Atoms to TLS GOT entries. - llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSMap; - - /// \brief Map Atoms to TLS GD GOT entries. - llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSGdMap; - - /// \brief GOT entry for the R_xxxMIPS_TLS_LDM relocations. - GOTTLSGdAtom<ELFT> *_gotLDMEntry = nullptr; - - /// \brief the list of local GOT atoms. - std::vector<GOTAtom *> _localGotVector; - - /// \brief the list of global GOT atoms. - std::vector<GOTAtom *> _globalGotVector; - - /// \brief the list of TLS GOT atoms. - std::vector<GOTAtom *> _tlsGotVector; - - /// \brief Map Atoms to their GOTPLT entries. - llvm::DenseMap<const Atom *, GOTPLTAtom *> _gotpltMap; - - /// \brief Map Atoms to their PLT entries. - llvm::DenseMap<const Atom *, PLTAAtom *> _pltRegMap; - llvm::DenseMap<const Atom *, PLTMicroAtom<ELFT> *> _pltMicroMap; - - /// \brief Map Atoms to their Object entries. - llvm::DenseMap<const Atom *, ObjectAtom *> _objectMap; - - /// \brief Map Atoms to their LA25 entries. - llvm::DenseMap<const Atom *, LA25Atom *> _la25RegMap; - llvm::DenseMap<const Atom *, LA25Atom *> _la25MicroMap; - - /// \brief Atoms referenced by static relocations. - llvm::DenseSet<const Atom *> _hasStaticRelocations; - - /// \brief Atoms require pointers equality. - llvm::DenseSet<const Atom *> _requiresPtrEquality; - - /// \brief References which are candidates for converting - /// to the R_MIPS_REL32 relocation. - std::vector<Reference *> _rel32Candidates; - - /// \brief the list of PLT atoms. - std::vector<PLTAtom *> _pltRegVector; - std::vector<PLTAtom *> _pltMicroVector; - - /// \brief the list of GOTPLT atoms. - std::vector<GOTPLTAtom *> _gotpltVector; - - /// \brief the list of Object entries. - std::vector<ObjectAtom *> _objectVector; - - /// \brief the list of LA25 entries. - std::vector<LA25Atom *> _la25Vector; - - /// \brief Handle a specific reference. - void handleReference(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref); - - /// \brief Collect information about the reference to use it - /// later in the handleReference() routine. - std::error_code collectReferenceInfo(const MipsELFDefinedAtom<ELFT> &atom, - Reference &ref); - - /// \brief Check that the relocation is valid for the current linking mode. - std::error_code validateRelocation(const DefinedAtom &atom, - const Reference &ref) const; - - void handlePlain(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref); - void handleBranch(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref); - void handleGOT(Reference &ref); - - const GOTAtom *getLocalGOTEntry(const Reference &ref); - const GOTAtom *getLocalGOTPageEntry(const Reference &ref); - const GOTAtom *getGlobalGOTEntry(const Atom *a); - const GOTAtom *getTLSGOTEntry(const Atom *a, Reference::Addend addend); - const GOTAtom *getTLSGdGOTEntry(const Atom *a, Reference::Addend addend); - const GOTAtom *getTLSLdmGOTEntry(const Atom *a); - const GOTPLTAtom *getGOTPLTEntry(const Atom *a); - const PLTAtom *getPLTEntry(const Atom *a); - const PLTAtom *getPLTRegEntry(const Atom *a); - const PLTAtom *getPLTMicroEntry(const Atom *a); - const LA25Atom *getLA25RegEntry(const Atom *a); - const LA25Atom *getLA25MicroEntry(const Atom *a); - const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a); - - PLTAtom *createPLTHeader(bool isMicroMips); - - bool isLocal(const Atom *a) const; - bool isLocalCall(const Atom *a) const; - bool isDynamic(const Atom *atom) const; - bool requireLA25Stub(const MipsELFDefinedAtom<ELFT> &atom, - const Reference &ref) const; - bool requirePLTEntry(const Atom *a) const; - bool requireCopy(const Atom *a) const; - bool mightBeDynamic(const MipsELFDefinedAtom<ELFT> &atom, - Reference::KindValue refKind) const; - bool hasPLTEntry(const Atom *atom) const; - - /// \brief Linked files contain microMIPS code. - bool isMicroMips(); - /// \brief Linked files contain MIPS R6 code. - bool isMipsR6(); -}; - -template <typename ELFT> -RelocationPass<ELFT>::RelocationPass(MipsLinkingContext &ctx) - : _ctx(ctx), _file(ctx) { - _localGotVector.push_back(new (_file._alloc) GOT0Atom<ELFT>(_file)); - _localGotVector.push_back(new (_file._alloc) - GOTModulePointerAtom<ELFT>(_file)); -} - -template <typename ELFT> -std::error_code RelocationPass<ELFT>::perform(SimpleFile &mf) { - for (const auto &atom : mf.defined()) - for (const auto &ref : *atom) { - const auto &da = *cast<MipsELFDefinedAtom<ELFT>>(atom); - if (auto ec = collectReferenceInfo(da, const_cast<Reference &>(*ref))) - return ec; - } - - // Process all references. - for (const auto &atom : mf.defined()) - for (const auto &ref : *atom) - handleReference(*cast<MipsELFDefinedAtom<ELFT>>(atom), - const_cast<Reference &>(*ref)); - - // Create R_MIPS_REL32 relocations. - for (auto *ref : _rel32Candidates) { - bool forceRel = isLocal(ref->target()) && _ctx.getOutputELFType() == ET_DYN; - if (!forceRel && (!isDynamic(ref->target()) || hasPLTEntry(ref->target()))) - continue; - ref->setKindValue(R_MIPS_REL32); - if (ELFT::Is64Bits) - static_cast<MipsELFReference<ELFT> *>(ref)->setTag(R_MIPS_64); - if (!isLocalCall(ref->target())) - getGlobalGOTEntry(ref->target()); - } - - uint64_t ordinal = 0; - - if (_ctx.isDynamic() && _ctx.getOutputELFType() == ET_EXEC) { - auto rlda = new (_file._alloc) MipsRldAtom<ELFT>(_file); - rlda->setOrdinal(ordinal++); - mf.addAtom(*rlda); - } - - if (!_localGotVector.empty() || !_globalGotVector.empty() || - !_tlsGotVector.empty()) { - SimpleDefinedAtom *ga = new (_file._alloc) MipsGlobalOffsetTableAtom(_file); - ga->setOrdinal(ordinal++); - mf.addAtom(*ga); - } - - for (auto &got : _localGotVector) { - got->setOrdinal(ordinal++); - mf.addAtom(*got); - } - - for (auto &got : _globalGotVector) { - got->setOrdinal(ordinal++); - mf.addAtom(*got); - } - - for (auto &got : _tlsGotVector) { - got->setOrdinal(ordinal++); - mf.addAtom(*got); - } - - // Create and emit PLT0 entry. - PLTAtom *plt0Atom = nullptr; - if (!_pltRegVector.empty()) - plt0Atom = createPLTHeader(false); - else if (!_pltMicroVector.empty()) - plt0Atom = createPLTHeader(true); - - if (plt0Atom) { - plt0Atom->setOrdinal(ordinal++); - mf.addAtom(*plt0Atom); - } - - // Emit regular PLT entries firts. - for (auto &plt : _pltRegVector) { - plt->setOrdinal(ordinal++); - mf.addAtom(*plt); - } - - // microMIPS PLT entries come after regular ones. - for (auto &plt : _pltMicroVector) { - plt->setOrdinal(ordinal++); - mf.addAtom(*plt); - } - - // Assign PLT0 to GOTPLT entries. - assert(_gotpltMap.empty() || plt0Atom); - for (auto &a: _gotpltMap) - a.second->setPLT0(plt0Atom); - - for (auto &gotplt : _gotpltVector) { - gotplt->setOrdinal(ordinal++); - mf.addAtom(*gotplt); - } - - for (auto obj : _objectVector) { - obj->setOrdinal(ordinal++); - mf.addAtom(*obj); - } - - for (auto la25 : _la25Vector) { - la25->setOrdinal(ordinal++); - mf.addAtom(*la25); - } - - return std::error_code(); -} - -static bool isMicroMipsReloc(Reference::KindValue kind) { - return R_MICROMIPS_26_S1 <= kind && kind <= R_MICROMIPS_PC19_S2; -} - -static bool isHiLo16Reloc(Reference::KindValue kind) { - return kind == R_MIPS_HI16 || kind == R_MIPS_LO16 || kind == R_MIPS_PCHI16 || - kind == R_MIPS_PCLO16 || kind == R_MICROMIPS_HI16 || - kind == R_MICROMIPS_LO16 || kind == R_MICROMIPS_HI0_LO16; -} - -static bool isBranchReloc(Reference::KindValue kind) { - return kind == R_MIPS_26 || kind == R_MICROMIPS_26_S1 || - kind == R_MIPS_PC16 || kind == R_MIPS_PC21_S2 || - kind == R_MIPS_PC26_S2 || kind == R_MICROMIPS_PC7_S1 || - kind == R_MICROMIPS_PC10_S1 || kind == R_MICROMIPS_PC16_S1 || - kind == R_MICROMIPS_PC23_S2; -} - -static bool isGotReloc(Reference::KindValue kind) { - return kind == R_MIPS_GOT16 || kind == R_MICROMIPS_GOT16; -} - -static bool isAllGotReloc(Reference::KindValue kind) { - return isGotReloc(kind) || kind == R_MIPS_GOT_HI16 || - kind == R_MIPS_GOT_LO16 || kind == R_MICROMIPS_GOT_HI16 || - kind == R_MICROMIPS_GOT_LO16; -} - -static bool isCallReloc(Reference::KindValue kind) { - return kind == R_MIPS_CALL16 || kind == R_MICROMIPS_CALL16; -} - -static bool isAllCallReloc(Reference::KindValue kind) { - return isCallReloc(kind) || kind == R_MIPS_CALL_HI16 || - kind == R_MIPS_CALL_LO16 || kind == R_MICROMIPS_CALL_HI16 || - kind == R_MICROMIPS_CALL_LO16; -} - -static bool isGotDispReloc(Reference::KindValue kind) { - return kind == R_MIPS_GOT_DISP || kind == R_MICROMIPS_GOT_DISP; -} - -static bool isGotPageReloc(Reference::KindValue kind) { - return kind == R_MIPS_GOT_PAGE || kind == R_MICROMIPS_GOT_PAGE; -} - -static bool isTlsDtpReloc(Reference::KindValue kind) { - return kind == R_MIPS_TLS_DTPREL_HI16 || kind == R_MIPS_TLS_DTPREL_LO16 || - kind == R_MICROMIPS_TLS_DTPREL_HI16 || - kind == R_MICROMIPS_TLS_DTPREL_LO16; -} - -static bool isTlsTpReloc(Reference::KindValue kind) { - return kind == R_MIPS_TLS_TPREL_HI16 || kind == R_MIPS_TLS_TPREL_LO16 || - kind == R_MICROMIPS_TLS_TPREL_HI16 || - kind == R_MICROMIPS_TLS_TPREL_LO16; -} - -static bool isTlsGdReloc(Reference::KindValue kind) { - return kind == R_MIPS_TLS_GD || kind == R_MICROMIPS_TLS_GD; -} - -static bool isTlsLdmReloc(Reference::KindValue kind) { - return kind == R_MIPS_TLS_LDM || kind == R_MICROMIPS_TLS_LDM; -} - -static bool isTlsGotTpReloc(Reference::KindValue kind) { - return kind == R_MIPS_TLS_GOTTPREL || kind == R_MICROMIPS_TLS_GOTTPREL; -} - -static bool isGpRelReloc(Reference::KindValue kind) { - return kind == R_MIPS_GPREL32 || kind == R_MIPS_GPREL16 || - kind == R_MICROMIPS_GPREL16 || kind == R_MICROMIPS_GPREL7_S2 || - kind == R_MIPS_LITERAL || kind == R_MICROMIPS_LITERAL; -} - -template <typename ELFT> -void RelocationPass<ELFT>::handleReference(const MipsELFDefinedAtom<ELFT> &atom, - Reference &ref) { - if (!ref.target()) - return; - if (ref.kindNamespace() != Reference::KindNamespace::ELF) - return; - - assert(ref.kindArch() == Reference::KindArch::Mips); - Reference::KindValue kind = ref.kindValue(); - if (isHiLo16Reloc(kind) || kind == R_MIPS_32 || kind == R_MIPS_PC32) - handlePlain(atom, ref); - else if (isBranchReloc(kind)) - handleBranch(atom, ref); - else if (isAllGotReloc(kind) || isAllCallReloc(kind) || - isGotDispReloc(kind) || isGotPageReloc(kind) || kind == R_MIPS_EH) - handleGOT(ref); - else if (isTlsDtpReloc(kind)) - ref.setAddend(ref.addend() - atom.file().getDTPOffset()); - else if (isTlsTpReloc(kind)) - ref.setAddend(ref.addend() - atom.file().getTPOffset()); - else if (isTlsGdReloc(kind)) - ref.setTarget(getTLSGdGOTEntry(ref.target(), ref.addend())); - else if (isTlsLdmReloc(kind)) - ref.setTarget(getTLSLdmGOTEntry(ref.target())); - else if (isTlsGotTpReloc(kind)) - ref.setTarget(getTLSGOTEntry(ref.target(), ref.addend())); - else if (kind == R_MIPS_GPREL32 || (isLocal(ref.target()) && isGpRelReloc(kind))) - ref.setAddend(ref.addend() + atom.file().getGP0()); - else if (kind == R_MIPS_JALR) { - if (_ctx.getOutputELFType() != ET_EXEC || !isLocalCall(ref.target())) - ref.setKindValue(R_MIPS_NONE); - } -} - -template <typename ELFT> -static bool isConstrainSym(const MipsELFDefinedAtom<ELFT> &atom, - Reference::KindValue refKind) { - if ((atom.section()->sh_flags & SHF_ALLOC) == 0) - return false; - switch (refKind) { - case R_MIPS_NONE: - case R_MIPS_JALR: - case R_MICROMIPS_JALR: - case R_MIPS_GPREL16: - case R_MIPS_GPREL32: - case R_MICROMIPS_GPREL16: - case R_MICROMIPS_GPREL7_S2: - case R_MIPS_LITERAL: - case R_MICROMIPS_LITERAL: - return false; - default: - return true; - } -} - -template <typename ELFT> -std::error_code -RelocationPass<ELFT>::collectReferenceInfo(const MipsELFDefinedAtom<ELFT> &atom, - Reference &ref) { - if (!ref.target()) - return std::error_code(); - if (ref.kindNamespace() != Reference::KindNamespace::ELF) - return std::error_code(); - - auto refKind = ref.kindValue(); - if (refKind == R_MIPS_EH && this->_ctx.mipsPcRelEhRel()) - ref.setKindValue(R_MIPS_PC32); - - if (auto ec = validateRelocation(atom, ref)) - return ec; - - if (!isConstrainSym(atom, refKind)) - return std::error_code(); - - if (!mightBeDynamic(atom, refKind)) - _hasStaticRelocations.insert(ref.target()); - else if (refKind == R_MIPS_32 || refKind == R_MIPS_64) - _rel32Candidates.push_back(&ref); - - if (!isBranchReloc(refKind) && !isAllCallReloc(refKind) && - refKind != R_MIPS_EH) - _requiresPtrEquality.insert(ref.target()); - - return std::error_code(); -} - -static std::error_code -make_reject_for_shared_lib_reloc_error(const ELFLinkingContext &ctx, - const DefinedAtom &atom, - const Reference &ref) { - StringRef kindValStr = "unknown"; - ctx.registry().referenceKindToString(ref.kindNamespace(), ref.kindArch(), - ref.kindValue(), kindValStr); - - return make_dynamic_error_code(Twine(kindValStr) + " (" + - Twine(ref.kindValue()) + - ") relocation cannot be used " - "when making a shared object, recompile " + - atom.file().path() + " with -fPIC"); -} - -static std::error_code -make_local_call16_reloc_error(const ELFLinkingContext &ctx, - const DefinedAtom &atom, const Reference &ref) { - return make_dynamic_error_code("R_MIPS_CALL16 (11) relocation cannot be used " - "against local symbol " + - ref.target()->name() + " in file " + - atom.file().path()); -} - -template <typename ELFT> -std::error_code -RelocationPass<ELFT>::validateRelocation(const DefinedAtom &atom, - const Reference &ref) const { - if (!ref.target()) - return std::error_code(); - - if (isCallReloc(ref.kindValue()) && isLocal(ref.target())) - return make_local_call16_reloc_error(this->_ctx, atom, ref); - - if (this->_ctx.getOutputELFType() != ET_DYN) - return std::error_code(); - - switch (ref.kindValue()) { - case R_MIPS16_HI16: - case R_MIPS_HI16: - case R_MIPS_HIGHER: - case R_MIPS_HIGHEST: - case R_MICROMIPS_HI16: - case R_MICROMIPS_HIGHER: - case R_MICROMIPS_HIGHEST: - // For shared object we accepts "high" relocations - // against the "_gp_disp" symbol only. - if (ref.target()->name() != "_gp_disp") - return make_reject_for_shared_lib_reloc_error(this->_ctx, atom, ref); - break; - case R_MIPS16_26: - case R_MIPS_26: - case R_MICROMIPS_26_S1: - // These relocations are position dependent - // and not acceptable in a shared object. - return make_reject_for_shared_lib_reloc_error(this->_ctx, atom, ref); - default: - break; - } - return std::error_code(); -} - -template <typename ELFT> -bool RelocationPass<ELFT>::isLocal(const Atom *a) const { - if (auto *da = dyn_cast<DefinedAtom>(a)) - return da->scope() == Atom::scopeTranslationUnit; - return false; -} - -template <typename ELFT> -static bool isMipsReadonly(const MipsELFDefinedAtom<ELFT> &atom) { - auto secFlags = atom.section()->sh_flags; - auto secType = atom.section()->sh_type; - - if ((secFlags & SHF_ALLOC) == 0) - return false; - if (secType == SHT_NOBITS) - return false; - if ((secFlags & SHF_WRITE) != 0) - return false; - return true; -} - -template <typename ELFT> -bool RelocationPass<ELFT>::mightBeDynamic(const MipsELFDefinedAtom<ELFT> &atom, - Reference::KindValue refKind) const { - if (isAllGotReloc(refKind) || isAllCallReloc(refKind)) - return true; - - if (refKind != R_MIPS_32 && refKind != R_MIPS_64) - return false; - if ((atom.section()->sh_flags & SHF_ALLOC) == 0) - return false; - - if (_ctx.getOutputELFType() == ET_DYN) - return true; - if (!isMipsReadonly(atom)) - return true; - if (atom.isPIC()) - return true; - - return false; -} - -template <typename ELFT> -bool RelocationPass<ELFT>::hasPLTEntry(const Atom *atom) const { - return _pltRegMap.count(atom) || _pltMicroMap.count(atom); -} - -template <typename ELFT> bool RelocationPass<ELFT>::isMicroMips() { - TargetHandler &handler = this->_ctx.getTargetHandler(); - return static_cast<MipsTargetHandler<ELFT> &>(handler) - .getAbiInfoHandler() - .isMicroMips(); -} - -template <typename ELFT> bool RelocationPass<ELFT>::isMipsR6() { - TargetHandler &handler = this->_ctx.getTargetHandler(); - return static_cast<MipsTargetHandler<ELFT> &>(handler) - .getAbiInfoHandler() - .isMipsR6(); -} - -template <typename ELFT> -bool RelocationPass<ELFT>::requirePLTEntry(const Atom *a) const { - if (!_hasStaticRelocations.count(a)) - return false; - const auto *sa = dyn_cast<ELFDynamicAtom<ELFT>>(a); - if (sa && sa->type() != SharedLibraryAtom::Type::Code) - return false; - const auto *da = dyn_cast<ELFDefinedAtom<ELFT>>(a); - if (da && da->contentType() != DefinedAtom::typeCode) - return false; - if (isLocalCall(a)) - return false; - return true; -} - -template <typename ELFT> -bool RelocationPass<ELFT>::requireCopy(const Atom *a) const { - if (!_hasStaticRelocations.count(a)) - return false; - const auto *sa = dyn_cast<ELFDynamicAtom<ELFT>>(a); - return sa && sa->type() == SharedLibraryAtom::Type::Data; -} - -template <typename ELFT> -bool RelocationPass<ELFT>::isDynamic(const Atom *atom) const { - const auto *da = dyn_cast<const DefinedAtom>(atom); - if (da && da->dynamicExport() == DefinedAtom::dynamicExportAlways) - return true; - if (isa<SharedLibraryAtom>(atom)) - return true; - if (_ctx.getOutputELFType() != ET_DYN) - return false; - if (da && da->scope() != DefinedAtom::scopeTranslationUnit) - return true; - return isa<UndefinedAtom>(atom); -} - -template <typename ELFT> -static bool isMicroMips(const MipsELFDefinedAtom<ELFT> &atom) { - return atom.codeModel() == DefinedAtom::codeMipsMicro || - atom.codeModel() == DefinedAtom::codeMipsMicroPIC; -} - -template <typename ELFT> -const PLTAtom *RelocationPass<ELFT>::getPLTEntry(const Atom *a) { - // If file contains microMIPS code try to reuse compressed PLT entry... - if (isMicroMips()) { - auto microPLT = _pltMicroMap.find(a); - if (microPLT != _pltMicroMap.end()) - return microPLT->second; - } - - // ... then try to reuse a regular PLT entry ... - auto regPLT = _pltRegMap.find(a); - if (regPLT != _pltRegMap.end()) - return regPLT->second; - - // ... and finally prefer to create new compressed PLT entry. - return isMicroMips() ? getPLTMicroEntry(a) : getPLTRegEntry(a); -} - -template <typename ELFT> -void RelocationPass<ELFT>::handlePlain(const MipsELFDefinedAtom<ELFT> &atom, - Reference &ref) { - if (!isDynamic(ref.target())) - return; - - if (requirePLTEntry(ref.target())) - ref.setTarget(getPLTEntry(ref.target())); - else if (requireCopy(ref.target())) - ref.setTarget(getObjectEntry(cast<SharedLibraryAtom>(ref.target()))); -} - -template <typename ELFT> -void RelocationPass<ELFT>::handleBranch(const MipsELFDefinedAtom<ELFT> &atom, - Reference &ref) { - bool isMicro = isMicroMipsReloc(ref.kindValue()); - if (const auto *sla = dyn_cast<SharedLibraryAtom>(ref.target())) { - if (sla->type() == SharedLibraryAtom::Type::Code) - ref.setTarget(isMicro ? getPLTMicroEntry(sla) : getPLTRegEntry(sla)); - } else if (requireLA25Stub(atom, ref)) { - if (isMicro) - ref.setTarget(getLA25MicroEntry(ref.target())); - else - ref.setTarget(getLA25RegEntry(ref.target())); - } - - if (!isLocal(ref.target())) { - if (ref.kindValue() == R_MICROMIPS_26_S1) - ref.setKindValue(LLD_R_MICROMIPS_GLOBAL_26_S1); - else if (ref.kindValue() == R_MIPS_26) - ref.setKindValue(LLD_R_MIPS_GLOBAL_26); - } -} - -template <typename ELFT> void RelocationPass<ELFT>::handleGOT(Reference &ref) { - if (!isLocalCall(ref.target())) - ref.setTarget(getGlobalGOTEntry(ref.target())); - else if (isGotPageReloc(ref.kindValue())) - ref.setTarget(getLocalGOTPageEntry(ref)); - else if (isLocal(ref.target()) && - (isCallReloc(ref.kindValue()) || isGotReloc(ref.kindValue()))) - ref.setTarget(getLocalGOTPageEntry(ref)); - else - ref.setTarget(getLocalGOTEntry(ref)); -} - -template <typename ELFT> -bool RelocationPass<ELFT>::isLocalCall(const Atom *a) const { - Atom::Scope scope; - if (auto *da = dyn_cast<DefinedAtom>(a)) - scope = da->scope(); - else if (auto *aa = dyn_cast<AbsoluteAtom>(a)) - scope = aa->scope(); - else - return false; - - // Local and hidden symbols must be local. - if (scope == Atom::scopeTranslationUnit || scope == Atom::scopeLinkageUnit) - return true; - - // Calls to external symbols defined in an executable file resolved locally. - if (_ctx.getOutputELFType() == ET_EXEC) - return true; - - return false; -} - -template <typename ELFT> -bool RelocationPass<ELFT>::requireLA25Stub(const MipsELFDefinedAtom<ELFT> &atom, - const Reference &ref) const { - if (atom.file().isPIC()) - return false; - if (auto *da = dyn_cast<DefinedAtom>(ref.target())) - return static_cast<const MipsELFDefinedAtom<ELFT> *>(da)->isPIC(); - return false; -} - -template <typename ELFT> -const GOTAtom *RelocationPass<ELFT>::getLocalGOTEntry(const Reference &ref) { - const Atom *a = ref.target(); - LocalGotMapKeyT key(a, ref.addend()); - - auto got = _gotLocalMap.find(key); - if (got != _gotLocalMap.end()) - return got->second; - - auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file); - _gotLocalMap[key] = ga; - - _localGotVector.push_back(ga); - - Reference::KindValue relKind = ELFT::Is64Bits ? R_MIPS_64 : R_MIPS_32; - ga->addReferenceELF_Mips(relKind, 0, a, 0); - - return ga; -} - -template <typename ELFT> -const GOTAtom * -RelocationPass<ELFT>::getLocalGOTPageEntry(const Reference &ref) { - const Atom *a = ref.target(); - LocalGotMapKeyT key(a, ref.addend()); - - auto got = _gotLocalPageMap.find(key); - if (got != _gotLocalPageMap.end()) - return got->second; - - auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file); - _gotLocalPageMap[key] = ga; - - _localGotVector.push_back(ga); - - Reference::KindValue relKind = - ELFT::Is64Bits ? LLD_R_MIPS_64_HI16 : LLD_R_MIPS_32_HI16; - ga->addReferenceELF_Mips(relKind, 0, a, ref.addend()); - - return ga; -} - -template <typename ELFT> -const GOTAtom *RelocationPass<ELFT>::getGlobalGOTEntry(const Atom *a) { - auto got = _gotGlobalMap.find(a); - if (got != _gotGlobalMap.end()) - return got->second; - - auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file); - _gotGlobalMap[a] = ga; - - _globalGotVector.push_back(ga); - ga->addReferenceELF_Mips(LLD_R_MIPS_GLOBAL_GOT, 0, a, 0); - - if (const DefinedAtom *da = dyn_cast<DefinedAtom>(a)) - ga->addReferenceELF_Mips(R_MIPS_32, 0, da, 0); - - return ga; -} - -template <typename ELFT> -const GOTAtom *RelocationPass<ELFT>::getTLSGOTEntry(const Atom *a, - Reference::Addend addend) { - auto got = _gotTLSMap.find(a); - if (got != _gotTLSMap.end()) - return got->second; - - auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file); - _gotTLSMap[a] = ga; - - _tlsGotVector.push_back(ga); - Reference::KindValue relKind = - ELFT::Is64Bits ? R_MIPS_TLS_TPREL64 : R_MIPS_TLS_TPREL32; - ga->addReferenceELF_Mips(relKind, 0, a, addend); - - return ga; -} - -template <typename ELFT> -const GOTAtom * -RelocationPass<ELFT>::getTLSGdGOTEntry(const Atom *a, - Reference::Addend addend) { - auto got = _gotTLSGdMap.find(a); - if (got != _gotTLSGdMap.end()) - return got->second; - - auto ga = new (_file._alloc) GOTTLSGdAtom<ELFT>(_file); - _gotTLSGdMap[a] = ga; - - _tlsGotVector.push_back(ga); - if (ELFT::Is64Bits) { - ga->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD64, 0, a, addend); - ga->addReferenceELF_Mips(R_MIPS_TLS_DTPREL64, 8, a, addend); - } else { - ga->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD32, 0, a, addend); - ga->addReferenceELF_Mips(R_MIPS_TLS_DTPREL32, 4, a, addend); - } - - return ga; -} - -template <typename ELFT> -const GOTAtom *RelocationPass<ELFT>::getTLSLdmGOTEntry(const Atom *a) { - if (_gotLDMEntry) - return _gotLDMEntry; - - _gotLDMEntry = new (_file._alloc) GOTTLSGdAtom<ELFT>(_file); - _tlsGotVector.push_back(_gotLDMEntry); - if (ELFT::Is64Bits) - _gotLDMEntry->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD64, 0, _gotLDMEntry, 0); - else - _gotLDMEntry->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD32, 0, _gotLDMEntry, 0); - - return _gotLDMEntry; -} - -template <typename ELFT> -PLTAtom *RelocationPass<ELFT>::createPLTHeader(bool isMicroMips) { - auto ga1 = new (_file._alloc) GOTPLTAtom(_file); - _gotpltVector.insert(_gotpltVector.begin(), ga1); - auto ga0 = new (_file._alloc) GOTPLTAtom(_file); - _gotpltVector.insert(_gotpltVector.begin(), ga0); - - if (isMicroMips) - return new (_file._alloc) PLT0MicroAtom<ELFT>(ga0, _file); - if (_ctx.getAbi() == MipsAbi::N32) - return new (_file._alloc) PLT0N32Atom<ELFT>(ga0, _file); - return new (_file._alloc) PLT0Atom<ELFT>(ga0, _file); -} - -template <typename ELFT> -const GOTPLTAtom *RelocationPass<ELFT>::getGOTPLTEntry(const Atom *a) { - auto it = _gotpltMap.find(a); - if (it != _gotpltMap.end()) - return it->second; - - auto ga = new (_file._alloc) GOTPLTAtom(a, _file); - _gotpltMap[a] = ga; - _gotpltVector.push_back(ga); - return ga; -} - -template <typename ELFT> -const PLTAtom *RelocationPass<ELFT>::getPLTRegEntry(const Atom *a) { - auto plt = _pltRegMap.find(a); - if (plt != _pltRegMap.end()) - return plt->second; - - PLTAAtom *pa = nullptr; - if (isMipsR6()) - pa = new (_file._alloc) PLTR6Atom<ELFT>(getGOTPLTEntry(a), _file); - else - pa = new (_file._alloc) PLTARegAtom<ELFT>(getGOTPLTEntry(a), _file); - _pltRegMap[a] = pa; - _pltRegVector.push_back(pa); - - // Check that 'a' dynamic symbol table record should point to the PLT. - if (_hasStaticRelocations.count(a) && _requiresPtrEquality.count(a)) - pa->addReferenceELF_Mips(LLD_R_MIPS_STO_PLT, 0, a, 0); - - return pa; -} - -template <typename ELFT> -const PLTAtom *RelocationPass<ELFT>::getPLTMicroEntry(const Atom *a) { - auto plt = _pltMicroMap.find(a); - if (plt != _pltMicroMap.end()) - return plt->second; - - auto pa = new (_file._alloc) PLTMicroAtom<ELFT>(getGOTPLTEntry(a), _file); - _pltMicroMap[a] = pa; - _pltMicroVector.push_back(pa); - - // Check that 'a' dynamic symbol table record should point to the PLT. - if (_hasStaticRelocations.count(a) && _requiresPtrEquality.count(a)) - pa->addReferenceELF_Mips(LLD_R_MIPS_STO_PLT, 0, a, 0); - - return pa; -} - -template <typename ELFT> -const LA25Atom *RelocationPass<ELFT>::getLA25RegEntry(const Atom *a) { - auto la25 = _la25RegMap.find(a); - if (la25 != _la25RegMap.end()) - return la25->second; - - auto sa = new (_file._alloc) LA25RegAtom<ELFT>(a, _file); - _la25RegMap[a] = sa; - _la25Vector.push_back(sa); - - return sa; -} - -template <typename ELFT> -const LA25Atom *RelocationPass<ELFT>::getLA25MicroEntry(const Atom *a) { - auto la25 = _la25MicroMap.find(a); - if (la25 != _la25MicroMap.end()) - return la25->second; - - auto sa = new (_file._alloc) LA25MicroAtom<ELFT>(a, _file); - _la25MicroMap[a] = sa; - _la25Vector.push_back(sa); - - return sa; -} - -template <typename ELFT> -const ObjectAtom * -RelocationPass<ELFT>::getObjectEntry(const SharedLibraryAtom *a) { - auto obj = _objectMap.find(a); - if (obj != _objectMap.end()) - return obj->second; - - auto oa = new (_file._alloc) ObjectAtom(_file); - oa->addReferenceELF_Mips(R_MIPS_COPY, 0, oa, 0); - oa->_name = a->name(); - oa->_size = a->size(); - - _objectMap[a] = oa; - _objectVector.push_back(oa); - - return oa; -} - -} // end anon namespace - -static std::unique_ptr<Pass> createPass(MipsLinkingContext &ctx) { - switch (ctx.getTriple().getArch()) { - case llvm::Triple::mips: - return llvm::make_unique<RelocationPass<ELF32BE>>(ctx); - case llvm::Triple::mipsel: - return llvm::make_unique<RelocationPass<ELF32LE>>(ctx); - case llvm::Triple::mips64: - return llvm::make_unique<RelocationPass<ELF64BE>>(ctx); - case llvm::Triple::mips64el: - return llvm::make_unique<RelocationPass<ELF64LE>>(ctx); - default: - llvm_unreachable("Unhandled arch"); - } -} - -std::unique_ptr<Pass> -lld::elf::createMipsRelocationPass(MipsLinkingContext &ctx) { - switch (ctx.getOutputELFType()) { - case ET_EXEC: - case ET_DYN: - return createPass(ctx); - case ET_REL: - return nullptr; - default: - llvm_unreachable("Unhandled output file type"); - } -} diff --git a/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.h b/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.h deleted file mode 100644 index af343de5f027..000000000000 --- a/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.h +++ /dev/null @@ -1,25 +0,0 @@ -//===- lib/ReaderWriter/ELF/Mips/MipsRelocationPass.h ---------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_RELOCATION_PASS_H -#define LLD_READER_WRITER_ELF_MIPS_MIPS_RELOCATION_PASS_H - -#include <memory> - -namespace lld { -class Pass; - -namespace elf { -class MipsLinkingContext; - -std::unique_ptr<Pass> createMipsRelocationPass(MipsLinkingContext &ctx); - -} // end namespace elf -} // end namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.cpp b/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.cpp deleted file mode 100644 index 98cc059787ef..000000000000 --- a/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.cpp +++ /dev/null @@ -1,264 +0,0 @@ -//===- lib/ReaderWriter/ELF/Mips/MipsSectionChunks.cpp --------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "MipsLinkingContext.h" -#include "MipsSectionChunks.h" -#include "MipsTargetLayout.h" - -namespace lld { -namespace elf { - -template <class ELFT> -MipsReginfoSection<ELFT>::MipsReginfoSection( - const ELFLinkingContext &ctx, MipsTargetLayout<ELFT> &targetLayout, - const Elf_Mips_RegInfo ®info) - : Section<ELFT>(ctx, ".reginfo", "MipsReginfo"), _reginfo(reginfo), - _targetLayout(targetLayout) { - this->setOrder(MipsTargetLayout<ELFT>::ORDER_MIPS_REGINFO); - this->_entSize = sizeof(Elf_Mips_RegInfo); - this->_fsize = sizeof(Elf_Mips_RegInfo); - this->_msize = sizeof(Elf_Mips_RegInfo); - this->_alignment = 4; - this->_type = SHT_MIPS_REGINFO; - this->_flags = SHF_ALLOC; -} - -template <class ELFT> -void MipsReginfoSection<ELFT>::write(ELFWriter *writer, - TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) { - uint8_t *dest = buffer.getBufferStart() + this->fileOffset(); - std::memcpy(dest, &_reginfo, this->_fsize); -} - -template <class ELFT> void MipsReginfoSection<ELFT>::finalize() { - _reginfo.ri_gp_value = _targetLayout.getGPAddr(); - - if (this->_outputSection) - this->_outputSection->setType(this->_type); -} - -template class MipsReginfoSection<ELF32BE>; -template class MipsReginfoSection<ELF32LE>; -template class MipsReginfoSection<ELF64BE>; -template class MipsReginfoSection<ELF64LE>; - -template <class ELFT> -MipsOptionsSection<ELFT>::MipsOptionsSection( - const ELFLinkingContext &ctx, MipsTargetLayout<ELFT> &targetLayout, - const Elf_Mips_RegInfo ®info) - : Section<ELFT>(ctx, ".MIPS.options", "MipsOptions"), _reginfo(reginfo), - _targetLayout(targetLayout) { - this->setOrder(MipsTargetLayout<ELFT>::ORDER_MIPS_OPTIONS); - this->_entSize = 1; - this->_alignment = 8; - this->_fsize = llvm::RoundUpToAlignment( - sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo), this->_alignment); - this->_msize = this->_fsize; - this->_type = SHT_MIPS_OPTIONS; - this->_flags = SHF_ALLOC | SHF_MIPS_NOSTRIP; - - _header.kind = ODK_REGINFO; - _header.size = this->_fsize; - _header.section = 0; - _header.info = 0; -} - -template <class ELFT> -void MipsOptionsSection<ELFT>::write(ELFWriter *writer, - TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) { - uint8_t *dest = buffer.getBufferStart() + this->fileOffset(); - std::memset(dest, 0, this->_fsize); - std::memcpy(dest, &_header, sizeof(_header)); - std::memcpy(dest + sizeof(_header), &_reginfo, sizeof(_reginfo)); -} - -template <class ELFT> void MipsOptionsSection<ELFT>::finalize() { - _reginfo.ri_gp_value = _targetLayout.getGPAddr(); - - if (this->_outputSection) - this->_outputSection->setType(this->_type); -} - -template class MipsOptionsSection<ELF32BE>; -template class MipsOptionsSection<ELF32LE>; -template class MipsOptionsSection<ELF64BE>; -template class MipsOptionsSection<ELF64LE>; - -template <class ELFT> -MipsAbiFlagsSection<ELFT>::MipsAbiFlagsSection( - const ELFLinkingContext &ctx, MipsTargetLayout<ELFT> &targetLayout, - const Elf_Mips_ABIFlags &abiFlags) - : Section<ELFT>(ctx, ".MIPS.abiflags", "MipsAbiFlags"), _abiFlags(abiFlags), - _targetLayout(targetLayout) { - this->setOrder(MipsTargetLayout<ELFT>::ORDER_MIPS_ABI_FLAGS); - this->_alignment = 8; - this->_fsize = llvm::RoundUpToAlignment(sizeof(_abiFlags), this->_alignment); - this->_msize = this->_fsize; - this->_entSize = this->_fsize; - this->_type = SHT_MIPS_ABIFLAGS; - this->_flags = SHF_ALLOC; -} - -template <class ELFT> -void MipsAbiFlagsSection<ELFT>::write(ELFWriter *writer, - TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) { - uint8_t *dest = buffer.getBufferStart() + this->fileOffset(); - std::memcpy(dest, &_abiFlags, this->_fsize); -} - -template <class ELFT> void MipsAbiFlagsSection<ELFT>::finalize() { - if (this->_outputSection) - this->_outputSection->setType(this->_type); -} - -template class MipsAbiFlagsSection<ELF32BE>; -template class MipsAbiFlagsSection<ELF32LE>; -template class MipsAbiFlagsSection<ELF64BE>; -template class MipsAbiFlagsSection<ELF64LE>; - -template <class ELFT> -MipsGOTSection<ELFT>::MipsGOTSection(const MipsLinkingContext &ctx) - : AtomSection<ELFT>(ctx, ".got", DefinedAtom::typeGOT, DefinedAtom::permRW_, - MipsTargetLayout<ELFT>::ORDER_GOT), - _hasNonLocal(false), _localCount(0) { - this->_flags |= SHF_MIPS_GPREL; - this->_alignment = 4; -} - -template <class ELFT> -bool MipsGOTSection<ELFT>::compare(const Atom *a, const Atom *b) const { - auto ia = _posMap.find(a); - auto ib = _posMap.find(b); - - if (ia != _posMap.end() && ib != _posMap.end()) - return ia->second < ib->second; - - return ia == _posMap.end() && ib != _posMap.end(); -} - -template <class ELFT> -const AtomLayout *MipsGOTSection<ELFT>::appendAtom(const Atom *atom) { - const DefinedAtom *da = dyn_cast<DefinedAtom>(atom); - - if (atom->name() == "_GLOBAL_OFFSET_TABLE_") - return AtomSection<ELFT>::appendAtom(atom); - - for (const auto &r : *da) { - if (r->kindNamespace() != Reference::KindNamespace::ELF) - continue; - assert(r->kindArch() == Reference::KindArch::Mips); - switch (r->kindValue()) { - case LLD_R_MIPS_GLOBAL_GOT: - _hasNonLocal = true; - _posMap[r->target()] = _posMap.size(); - return AtomSection<ELFT>::appendAtom(atom); - case R_MIPS_TLS_TPREL32: - case R_MIPS_TLS_DTPREL32: - case R_MIPS_TLS_TPREL64: - case R_MIPS_TLS_DTPREL64: - _hasNonLocal = true; - _tlsMap[r->target()] = _tlsMap.size(); - return AtomSection<ELFT>::appendAtom(atom); - case R_MIPS_TLS_DTPMOD32: - case R_MIPS_TLS_DTPMOD64: - _hasNonLocal = true; - break; - } - } - - if (!_hasNonLocal) - ++_localCount; - - return AtomSection<ELFT>::appendAtom(atom); -} - -template class MipsGOTSection<ELF32BE>; -template class MipsGOTSection<ELF32LE>; -template class MipsGOTSection<ELF64BE>; -template class MipsGOTSection<ELF64LE>; - -template <class ELFT> -MipsPLTSection<ELFT>::MipsPLTSection(const MipsLinkingContext &ctx) - : AtomSection<ELFT>(ctx, ".plt", DefinedAtom::typeGOT, DefinedAtom::permR_X, - MipsTargetLayout<ELFT>::ORDER_PLT) {} - -template <class ELFT> -const AtomLayout *MipsPLTSection<ELFT>::findPLTLayout(const Atom *plt) const { - auto it = _pltLayoutMap.find(plt); - return it != _pltLayoutMap.end() ? it->second : nullptr; -} - -template <class ELFT> -const AtomLayout *MipsPLTSection<ELFT>::appendAtom(const Atom *atom) { - const auto *layout = AtomSection<ELFT>::appendAtom(atom); - - const DefinedAtom *da = cast<DefinedAtom>(atom); - - for (const auto &r : *da) { - if (r->kindNamespace() != Reference::KindNamespace::ELF) - continue; - assert(r->kindArch() == Reference::KindArch::Mips); - if (r->kindValue() == LLD_R_MIPS_STO_PLT) { - _pltLayoutMap[r->target()] = layout; - break; - } - } - - return layout; -} - -template class MipsPLTSection<ELF32BE>; -template class MipsPLTSection<ELF32LE>; -template class MipsPLTSection<ELF64BE>; -template class MipsPLTSection<ELF64LE>; - -template <class ELFT> static bool isMips64EL() { - return ELFT::Is64Bits && ELFT::TargetEndianness == llvm::support::little; -} - -template <class ELFT> -MipsRelocationTable<ELFT>::MipsRelocationTable(const ELFLinkingContext &ctx, - StringRef str, int32_t order) - : RelocationTable<ELFT>(ctx, str, order) {} - -template <class ELFT> -void MipsRelocationTable<ELFT>::writeRela(ELFWriter *writer, Elf_Rela &r, - const DefinedAtom &atom, - const Reference &ref) { - uint32_t rType = ref.kindValue() | (ref.tag() << 8); - r.setSymbolAndType(this->getSymbolIndex(ref.target()), rType, - isMips64EL<ELFT>()); - r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom(); - // The addend is used only by relative relocations - if (this->_ctx.isRelativeReloc(ref)) - r.r_addend = writer->addressOfAtom(ref.target()) + ref.addend(); - else - r.r_addend = 0; -} - -template <class ELFT> -void MipsRelocationTable<ELFT>::writeRel(ELFWriter *writer, Elf_Rel &r, - const DefinedAtom &atom, - const Reference &ref) { - uint32_t rType = ref.kindValue() | (ref.tag() << 8); - r.setSymbolAndType(this->getSymbolIndex(ref.target()), rType, - isMips64EL<ELFT>()); - r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom(); -} - -template class MipsRelocationTable<ELF32BE>; -template class MipsRelocationTable<ELF32LE>; -template class MipsRelocationTable<ELF64BE>; -template class MipsRelocationTable<ELF64LE>; - -} // elf -} // lld diff --git a/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h b/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h deleted file mode 100644 index e545f65dc419..000000000000 --- a/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h +++ /dev/null @@ -1,150 +0,0 @@ -//===- lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h ----------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_SECTION_CHUNKS_H -#define LLD_READER_WRITER_ELF_MIPS_MIPS_SECTION_CHUNKS_H - -#include "SectionChunks.h" - -namespace lld { -namespace elf { - -template <typename ELFT> class MipsTargetLayout; -class MipsLinkingContext; - -/// \brief Handle Mips .reginfo section -template <class ELFT> class MipsReginfoSection : public Section<ELFT> { -public: - typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo; - - MipsReginfoSection(const ELFLinkingContext &ctx, - MipsTargetLayout<ELFT> &targetLayout, - const Elf_Mips_RegInfo ®info); - - StringRef segmentKindToStr() const override { return "REGINFO"; } - bool hasOutputSegment() const override { return true; } - - void write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) override; - void finalize() override; - -private: - Elf_Mips_RegInfo _reginfo; - MipsTargetLayout<ELFT> &_targetLayout; -}; - -/// \brief Handle .MIPS.options section -template <class ELFT> class MipsOptionsSection : public Section<ELFT> { -public: - typedef llvm::object::Elf_Mips_Options<ELFT> Elf_Mips_Options; - typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo; - - MipsOptionsSection(const ELFLinkingContext &ctx, - MipsTargetLayout<ELFT> &targetLayout, - const Elf_Mips_RegInfo ®info); - - bool hasOutputSegment() const override { return true; } - - void write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) override; - void finalize() override; - -private: - Elf_Mips_Options _header; - Elf_Mips_RegInfo _reginfo; - MipsTargetLayout<ELFT> &_targetLayout; -}; - -/// \brief Handle .MIPS.abiflags section -template <class ELFT> class MipsAbiFlagsSection : public Section<ELFT> { -public: - typedef llvm::object::Elf_Mips_ABIFlags<ELFT> Elf_Mips_ABIFlags; - - MipsAbiFlagsSection(const ELFLinkingContext &ctx, - MipsTargetLayout<ELFT> &targetLayout, - const Elf_Mips_ABIFlags &abiFlags); - - bool hasOutputSegment() const override { return true; } - - void write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) override; - void finalize() override; - -private: - Elf_Mips_ABIFlags _abiFlags; - MipsTargetLayout<ELFT> &_targetLayout; -}; - -/// \brief Handle Mips GOT section -template <class ELFT> class MipsGOTSection : public AtomSection<ELFT> { -public: - MipsGOTSection(const MipsLinkingContext &ctx); - - /// \brief Number of local GOT entries. - std::size_t getLocalCount() const { return _localCount; } - - /// \brief Number of global GOT entries. - std::size_t getGlobalCount() const { return _posMap.size(); } - - /// \brief Does the atom have a global GOT entry? - bool hasGlobalGOTEntry(const Atom *a) const { - return _posMap.count(a) || _tlsMap.count(a); - } - - /// \brief Compare two atoms accordingly theirs positions in the GOT. - bool compare(const Atom *a, const Atom *b) const; - - const AtomLayout *appendAtom(const Atom *atom) override; - -private: - /// \brief True if the GOT contains non-local entries. - bool _hasNonLocal; - - /// \brief Number of local GOT entries. - std::size_t _localCount; - - /// \brief Map TLS Atoms to their GOT entry index. - llvm::DenseMap<const Atom *, std::size_t> _tlsMap; - - /// \brief Map Atoms to their GOT entry index. - llvm::DenseMap<const Atom *, std::size_t> _posMap; -}; - -/// \brief Handle Mips PLT section -template <class ELFT> class MipsPLTSection : public AtomSection<ELFT> { -public: - MipsPLTSection(const MipsLinkingContext &ctx); - - const AtomLayout *findPLTLayout(const Atom *plt) const; - - const AtomLayout *appendAtom(const Atom *atom) override; - -private: - /// \brief Map PLT Atoms to their layouts. - std::unordered_map<const Atom *, const AtomLayout *> _pltLayoutMap; -}; - -template <class ELFT> class MipsRelocationTable : public RelocationTable<ELFT> { - typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel; - typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela; - -public: - MipsRelocationTable(const ELFLinkingContext &ctx, StringRef str, - int32_t order); - -protected: - void writeRela(ELFWriter *writer, Elf_Rela &r, const DefinedAtom &atom, - const Reference &ref) override; - void writeRel(ELFWriter *writer, Elf_Rel &r, const DefinedAtom &atom, - const Reference &ref) override; -}; - -} // elf -} // lld - -#endif diff --git a/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp b/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp deleted file mode 100644 index 817e29444666..000000000000 --- a/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp +++ /dev/null @@ -1,166 +0,0 @@ -//===- lib/ReaderWriter/ELF/Mips/MipsTargetHandler32EL.cpp ----------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "ELFReader.h" -#include "MipsELFFile.h" -#include "MipsELFWriters.h" -#include "MipsTargetHandler.h" - -namespace lld { -namespace elf { - -template <class ELFT> -MipsTargetHandler<ELFT>::MipsTargetHandler(MipsLinkingContext &ctx) - : _ctx(ctx), _targetLayout(new MipsTargetLayout<ELFT>(ctx, _abiInfoHandler)), - _relocationHandler( - createMipsRelocationHandler<ELFT>(ctx, *_targetLayout)) {} - -template <class ELFT> -std::unique_ptr<Reader> MipsTargetHandler<ELFT>::getObjReader() { - return llvm::make_unique<ELFReader<MipsELFFile<ELFT>>>(_ctx); -} - -template <class ELFT> -std::unique_ptr<Reader> MipsTargetHandler<ELFT>::getDSOReader() { - return llvm::make_unique<ELFReader<DynamicFile<ELFT>>>(_ctx); -} - -template <class ELFT> -const TargetRelocationHandler & -MipsTargetHandler<ELFT>::getRelocationHandler() const { - return *_relocationHandler; -} - -template <class ELFT> -std::unique_ptr<Writer> MipsTargetHandler<ELFT>::getWriter() { - switch (_ctx.getOutputELFType()) { - case llvm::ELF::ET_EXEC: - return llvm::make_unique<MipsExecutableWriter<ELFT>>(_ctx, *_targetLayout, - _abiInfoHandler); - case llvm::ELF::ET_DYN: - return llvm::make_unique<MipsDynamicLibraryWriter<ELFT>>( - _ctx, *_targetLayout, _abiInfoHandler); - case llvm::ELF::ET_REL: - llvm_unreachable("TODO: support -r mode"); - default: - llvm_unreachable("unsupported output type"); - } -} - -template <class ELFT> MipsAbi MipsTargetHandler<ELFT>::getAbi() const { - return _abiInfoHandler.getAbi(); -} - -template class MipsTargetHandler<ELF32BE>; -template class MipsTargetHandler<ELF32LE>; -template class MipsTargetHandler<ELF64BE>; -template class MipsTargetHandler<ELF64LE>; - -template <class ELFT> -MipsSymbolTable<ELFT>::MipsSymbolTable(const ELFLinkingContext &ctx) - : SymbolTable<ELFT>(ctx, ".symtab", - TargetLayout<ELFT>::ORDER_SYMBOL_TABLE) {} - -template <class ELFT> -void MipsSymbolTable<ELFT>::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da, - int64_t addr) { - SymbolTable<ELFT>::addDefinedAtom(sym, da, addr); - - switch (da->codeModel()) { - case DefinedAtom::codeMipsMicro: - sym.st_other |= llvm::ELF::STO_MIPS_MICROMIPS; - break; - case DefinedAtom::codeMipsMicroPIC: - sym.st_other |= llvm::ELF::STO_MIPS_MICROMIPS | llvm::ELF::STO_MIPS_PIC; - break; - default: - break; - } -} - -template <class ELFT> void MipsSymbolTable<ELFT>::finalize(bool sort) { - SymbolTable<ELFT>::finalize(sort); - - for (auto &ste : this->_symbolTable) { - if (!ste._atom) - continue; - if (const auto *da = dyn_cast<DefinedAtom>(ste._atom)) { - if (da->codeModel() == DefinedAtom::codeMipsMicro || - da->codeModel() == DefinedAtom::codeMipsMicroPIC) { - // Adjust dynamic microMIPS symbol value. That allows a dynamic - // linker to recognize and handle this symbol correctly. - ste._symbol.st_value = ste._symbol.st_value | 1; - } - } - } -} - -template class MipsSymbolTable<ELF32BE>; -template class MipsSymbolTable<ELF32LE>; -template class MipsSymbolTable<ELF64BE>; -template class MipsSymbolTable<ELF64LE>; - -template <class ELFT> -MipsDynamicSymbolTable<ELFT>::MipsDynamicSymbolTable( - const ELFLinkingContext &ctx, MipsTargetLayout<ELFT> &layout) - : DynamicSymbolTable<ELFT>(ctx, layout, ".dynsym", - TargetLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS), - _targetLayout(layout) {} - -template <class ELFT> void MipsDynamicSymbolTable<ELFT>::sortSymbols() { - typedef typename DynamicSymbolTable<ELFT>::SymbolEntry SymbolEntry; - std::stable_sort(this->_symbolTable.begin(), this->_symbolTable.end(), - [this](const SymbolEntry &A, const SymbolEntry &B) { - if (A._symbol.getBinding() != STB_GLOBAL && - B._symbol.getBinding() != STB_GLOBAL) - return A._symbol.getBinding() < B._symbol.getBinding(); - - return _targetLayout.getGOTSection().compare(A._atom, - B._atom); - }); -} - -template <class ELFT> void MipsDynamicSymbolTable<ELFT>::finalize() { - DynamicSymbolTable<ELFT>::finalize(); - - const auto &pltSection = _targetLayout.getPLTSection(); - - for (auto &ste : this->_symbolTable) { - const Atom *a = ste._atom; - if (!a) - continue; - if (auto *layout = pltSection.findPLTLayout(a)) { - a = layout->_atom; - // Under some conditions a dynamic symbol table record should hold - // a symbol value of the corresponding PLT entry. For details look - // at the PLT entry creation code in the class MipsRelocationPass. - // Let's update atomLayout fields for such symbols. - assert(!ste._atomLayout); - ste._symbol.st_value = layout->_virtualAddr; - ste._symbol.st_other |= ELF::STO_MIPS_PLT; - } - - if (const auto *da = dyn_cast<DefinedAtom>(a)) { - if (da->codeModel() == DefinedAtom::codeMipsMicro || - da->codeModel() == DefinedAtom::codeMipsMicroPIC) { - // Adjust dynamic microMIPS symbol value. That allows a dynamic - // linker to recognize and handle this symbol correctly. - ste._symbol.st_value = ste._symbol.st_value | 1; - } - } - } -} - -template class MipsDynamicSymbolTable<ELF32BE>; -template class MipsDynamicSymbolTable<ELF32LE>; -template class MipsDynamicSymbolTable<ELF64BE>; -template class MipsDynamicSymbolTable<ELF64LE>; - -} -} diff --git a/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h b/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h deleted file mode 100644 index e4a35bdd323d..000000000000 --- a/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h +++ /dev/null @@ -1,73 +0,0 @@ -//===- lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h ----------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_TARGET_HANDLER_H -#define LLD_READER_WRITER_ELF_MIPS_MIPS_TARGET_HANDLER_H - -#include "MipsAbiInfoHandler.h" -#include "MipsLinkingContext.h" -#include "MipsTargetLayout.h" -#include "TargetHandler.h" - -namespace lld { -namespace elf { - -class MipsBaseTargetHandler : public TargetHandler { -public: - virtual MipsAbi getAbi() const = 0; -}; - -/// \brief TargetHandler for Mips -template <class ELFT> -class MipsTargetHandler final : public MipsBaseTargetHandler { -public: - MipsTargetHandler(MipsLinkingContext &ctx); - - MipsAbiInfoHandler<ELFT> &getAbiInfoHandler() { return _abiInfoHandler; } - - std::unique_ptr<Reader> getObjReader() override; - std::unique_ptr<Reader> getDSOReader() override; - const TargetRelocationHandler &getRelocationHandler() const override; - std::unique_ptr<Writer> getWriter() override; - MipsAbi getAbi() const override; - -private: - MipsLinkingContext &_ctx; - MipsAbiInfoHandler<ELFT> _abiInfoHandler; - std::unique_ptr<MipsTargetLayout<ELFT>> _targetLayout; - std::unique_ptr<TargetRelocationHandler> _relocationHandler; -}; - -template <class ELFT> class MipsSymbolTable : public SymbolTable<ELFT> { -public: - typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym; - - MipsSymbolTable(const ELFLinkingContext &ctx); - - void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da, - int64_t addr) override; - void finalize(bool sort) override; -}; - -template <class ELFT> -class MipsDynamicSymbolTable : public DynamicSymbolTable<ELFT> { -public: - MipsDynamicSymbolTable(const ELFLinkingContext &ctx, - MipsTargetLayout<ELFT> &layout); - - void sortSymbols() override; - void finalize() override; - -private: - MipsTargetLayout<ELFT> &_targetLayout; -}; - -} // end namespace elf -} // end namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.cpp b/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.cpp deleted file mode 100644 index 710f8320a8b9..000000000000 --- a/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.cpp +++ /dev/null @@ -1,111 +0,0 @@ -//===- lib/ReaderWriter/ELF/Mips/MipsTargetLayout.cpp ---------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "MipsLinkingContext.h" -#include "MipsTargetLayout.h" - -namespace lld { -namespace elf { - -template <class ELFT> -MipsTargetLayout<ELFT>::MipsTargetLayout(MipsLinkingContext &ctx, - MipsAbiInfoHandler<ELFT> &abi) - : TargetLayout<ELFT>(ctx), _abiInfo(abi), - _gotSection(new (this->_allocator) MipsGOTSection<ELFT>(ctx)), - _pltSection(new (this->_allocator) MipsPLTSection<ELFT>(ctx)) {} - -template <class ELFT> -AtomSection<ELFT> *MipsTargetLayout<ELFT>::createSection( - StringRef name, int32_t type, DefinedAtom::ContentPermissions permissions, - typename TargetLayout<ELFT>::SectionOrder order) { - if (type == DefinedAtom::typeGOT && name == ".got") - return _gotSection; - if (type == DefinedAtom::typeStub && name == ".plt") - return _pltSection; - return TargetLayout<ELFT>::createSection(name, type, permissions, order); -} - -template <class ELFT> -typename TargetLayout<ELFT>::SegmentType -MipsTargetLayout<ELFT>::getSegmentType(const Section<ELFT> *section) const { - switch (section->order()) { - case ORDER_MIPS_REGINFO: - return _abiInfo.hasMipsAbiSection() ? llvm::ELF::PT_LOAD - : llvm::ELF::PT_MIPS_REGINFO; - case ORDER_MIPS_OPTIONS: - return llvm::ELF::PT_LOAD; - case ORDER_MIPS_ABI_FLAGS: - return llvm::ELF::PT_MIPS_ABIFLAGS; - default: - return TargetLayout<ELFT>::getSegmentType(section); - } -} - -template <class ELFT> uint64_t MipsTargetLayout<ELFT>::getGPAddr() { - std::call_once(_gpOnce, [this]() { - if (AtomLayout *a = this->findAbsoluteAtom("_gp")) - _gpAddr = a->_virtualAddr; - }); - return _gpAddr; -} - -template <class ELFT> -typename TargetLayout<ELFT>::SectionOrder -MipsTargetLayout<ELFT>::getSectionOrder(StringRef name, int32_t contentType, - int32_t contentPermissions) { - if ((contentType == DefinedAtom::typeStub) && (name.startswith(".text"))) - return TargetLayout<ELFT>::ORDER_TEXT; - - return TargetLayout<ELFT>::getSectionOrder(name, contentType, - contentPermissions); -} - -template <class ELFT> -unique_bump_ptr<RelocationTable<ELFT>> -MipsTargetLayout<ELFT>::createRelocationTable(StringRef name, int32_t order) { - return unique_bump_ptr<RelocationTable<ELFT>>(new ( - this->_allocator) MipsRelocationTable<ELFT>(this->_ctx, name, order)); -} - -template <class ELFT> -uint64_t MipsTargetLayout<ELFT>::getLookupSectionFlags( - const OutputSection<ELFT> *os) const { - uint64_t flags = TargetLayout<ELFT>::getLookupSectionFlags(os); - return flags & ~llvm::ELF::SHF_MIPS_NOSTRIP; -} - -template <class ELFT> void MipsTargetLayout<ELFT>::sortSegments() { - using namespace llvm::ELF; - TargetLayout<ELFT>::sortSegments(); - // Move PT_MIPS_ABIFLAGS or PT_MIPS_REGINFO right after PT_INTERP. - auto abiIt = - std::find_if(this->_segments.begin(), this->_segments.end(), - [](const Segment<ELFT> *s) { - auto typ = s->segmentType(); - return typ == PT_MIPS_ABIFLAGS || typ == PT_MIPS_REGINFO; - }); - if (abiIt == this->_segments.end()) - return; - Segment<ELFT> *abiSeg = *abiIt; - this->_segments.erase(abiIt); - auto outIt = std::find_if(this->_segments.begin(), this->_segments.end(), - [](const Segment<ELFT> *s) { - auto typ = s->segmentType(); - return typ != PT_PHDR && typ != PT_INTERP; - }); - this->_segments.insert(outIt, abiSeg); -} - -template class MipsTargetLayout<ELF32BE>; -template class MipsTargetLayout<ELF32LE>; -template class MipsTargetLayout<ELF64BE>; -template class MipsTargetLayout<ELF64LE>; - -} // end namespace elf -} // end namespace lld diff --git a/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.h b/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.h deleted file mode 100644 index 08855438d20e..000000000000 --- a/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.h +++ /dev/null @@ -1,71 +0,0 @@ -//===- lib/ReaderWriter/ELF/Mips/MipsTargetLayout.h -----------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_TARGET_LAYOUT_H -#define LLD_READER_WRITER_ELF_MIPS_MIPS_TARGET_LAYOUT_H - -#include "MipsAbiInfoHandler.h" -#include "MipsSectionChunks.h" -#include "TargetLayout.h" - -namespace lld { -namespace elf { - -class MipsLinkingContext; - -/// \brief TargetLayout for Mips -template <class ELFT> class MipsTargetLayout final : public TargetLayout<ELFT> { -public: - enum MipsSectionOrder { - ORDER_MIPS_ABI_FLAGS = TargetLayout<ELFT>::ORDER_RO_NOTE + 1, - ORDER_MIPS_REGINFO, - ORDER_MIPS_OPTIONS, - }; - - MipsTargetLayout(MipsLinkingContext &ctx, MipsAbiInfoHandler<ELFT> &abi); - - const MipsGOTSection<ELFT> &getGOTSection() const { return *_gotSection; } - const MipsPLTSection<ELFT> &getPLTSection() const { return *_pltSection; } - - AtomSection<ELFT> * - createSection(StringRef name, int32_t type, - DefinedAtom::ContentPermissions permissions, - typename TargetLayout<ELFT>::SectionOrder order) override; - - typename TargetLayout<ELFT>::SegmentType - getSegmentType(const Section<ELFT> *section) const override; - - /// \brief GP offset relative to .got section. - uint64_t getGPOffset() const { return 0x7FF0; } - - /// \brief Get '_gp' symbol address. - uint64_t getGPAddr(); - - /// \brief Return the section order for a input section - typename TargetLayout<ELFT>::SectionOrder - getSectionOrder(StringRef name, int32_t contentType, - int32_t contentPermissions) override; - -protected: - unique_bump_ptr<RelocationTable<ELFT>> - createRelocationTable(StringRef name, int32_t order) override; - uint64_t getLookupSectionFlags(const OutputSection<ELFT> *os) const override; - void sortSegments() override; - -private: - MipsAbiInfoHandler<ELFT> &_abiInfo; - MipsGOTSection<ELFT> *_gotSection; - MipsPLTSection<ELFT> *_pltSection; - uint64_t _gpAddr = 0; - std::once_flag _gpOnce; -}; - -} // end namespace elf -} // end namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/OrderPass.h b/lib/ReaderWriter/ELF/OrderPass.h deleted file mode 100644 index 11f88056c8c4..000000000000 --- a/lib/ReaderWriter/ELF/OrderPass.h +++ /dev/null @@ -1,31 +0,0 @@ -//===- lib/ReaderWriter/ELF/OrderPass.h -----------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_ORDER_PASS_H -#define LLD_READER_WRITER_ELF_ORDER_PASS_H - -#include "lld/Core/Parallel.h" -#include <limits> - -namespace lld { -namespace elf { - -/// \brief This pass sorts atoms by file and atom ordinals. -class OrderPass : public Pass { -public: - std::error_code perform(SimpleFile &file) override { - parallel_sort(file.definedAtoms().begin(), file.definedAtoms().end(), - DefinedAtom::compareByPosition); - return std::error_code(); - } -}; -} -} - -#endif diff --git a/lib/ReaderWriter/ELF/OutputELFWriter.cpp b/lib/ReaderWriter/ELF/OutputELFWriter.cpp deleted file mode 100644 index 4f8b0eac655f..000000000000 --- a/lib/ReaderWriter/ELF/OutputELFWriter.cpp +++ /dev/null @@ -1,514 +0,0 @@ -//===- lib/ReaderWriter/ELF/OutputELFWriter.cpp --------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "OutputELFWriter.h" -#include "lld/Core/SharedLibraryFile.h" -#include "lld/Core/Simple.h" -#include "lld/ReaderWriter/ELFLinkingContext.h" -#include "llvm/Support/Path.h" - -namespace lld { -namespace elf { - -namespace { - -template <class ELFT> class SymbolFile : public RuntimeFile<ELFT> { -public: - SymbolFile(ELFLinkingContext &ctx) - : RuntimeFile<ELFT>(ctx, "Dynamic absolute symbols") {} - - void addUndefinedAtom(StringRef) override { - llvm_unreachable("Cannot add undefined atoms to resolve undefined symbols"); - } - - bool hasAtoms() const { return this->absolute().size(); } -}; - -template <class ELFT> -class DynamicSymbolFile : public SimpleArchiveLibraryFile { - typedef std::function<void(StringRef, RuntimeFile<ELFT> &)> Resolver; - -public: - DynamicSymbolFile(ELFLinkingContext &ctx, Resolver resolver) - : SimpleArchiveLibraryFile("Dynamically added runtime symbols"), - _ctx(ctx), _resolver(resolver) {} - - File *find(StringRef sym, bool dataSymbolOnly) override { - if (!_file) - _file.reset(new (_alloc) SymbolFile<ELFT>(_ctx)); - - assert(!_file->hasAtoms() && "The file shouldn't have atoms yet"); - _resolver(sym, *_file); - - if (!_file->hasAtoms()) - return nullptr; - - // If atoms were added - return the file but also store it for later - // destruction. - File *result = _file.get(); - _returnedFiles.push_back(std::move(_file)); - return result; - } - -private: - ELFLinkingContext &_ctx; - Resolver _resolver; - - // The allocator should go before bump pointers because of - // reversed destruction order. - llvm::BumpPtrAllocator _alloc; - unique_bump_ptr<SymbolFile<ELFT>> _file; - std::vector<unique_bump_ptr<SymbolFile<ELFT>>> _returnedFiles; -}; - -} // end anon namespace - -template <class ELFT> -OutputELFWriter<ELFT>::OutputELFWriter(ELFLinkingContext &ctx, - TargetLayout<ELFT> &layout) - : _ctx(ctx), _targetHandler(ctx.getTargetHandler()), _layout(layout) {} - -template <class ELFT> -void OutputELFWriter<ELFT>::buildChunks(const File &file) { - ScopedTask task(getDefaultDomain(), "buildChunks"); - for (const DefinedAtom *definedAtom : file.defined()) { - DefinedAtom::ContentType contentType = definedAtom->contentType(); - // Dont add COMDAT group atoms and GNU linkonce atoms, as they are used for - // symbol resolution. - // TODO: handle partial linking. - if (contentType == DefinedAtom::typeGroupComdat || - contentType == DefinedAtom::typeGnuLinkOnce) - continue; - _layout.addAtom(definedAtom); - } - for (const AbsoluteAtom *absoluteAtom : file.absolute()) - _layout.addAtom(absoluteAtom); -} - -template <class ELFT> -void OutputELFWriter<ELFT>::buildStaticSymbolTable(const File &file) { - ScopedTask task(getDefaultDomain(), "buildStaticSymbolTable"); - for (auto sec : _layout.sections()) - if (auto section = dyn_cast<AtomSection<ELFT>>(sec)) - for (const auto &atom : section->atoms()) - _symtab->addSymbol(atom->_atom, section->ordinal(), atom->_virtualAddr); - for (auto &atom : _layout.absoluteAtoms()) - _symtab->addSymbol(atom->_atom, ELF::SHN_ABS, atom->_virtualAddr); - for (const UndefinedAtom *a : file.undefined()) - _symtab->addSymbol(a, ELF::SHN_UNDEF); -} - -// Returns the DSO name for a given input file if it's a shared library -// file and not marked as --as-needed. -template <class ELFT> -StringRef OutputELFWriter<ELFT>::maybeGetSOName(Node *node) { - if (auto *fnode = dyn_cast<FileNode>(node)) - if (!fnode->asNeeded()) - if (auto *file = dyn_cast<SharedLibraryFile>(fnode->getFile())) - return file->getDSOName(); - return ""; -} - -template <class ELFT> -void OutputELFWriter<ELFT>::buildDynamicSymbolTable(const File &file) { - ScopedTask task(getDefaultDomain(), "buildDynamicSymbolTable"); - for (const auto &sla : file.sharedLibrary()) { - if (isDynSymEntryRequired(sla)) { - _dynamicSymbolTable->addSymbol(sla, ELF::SHN_UNDEF); - _soNeeded.insert(sla->loadName()); - continue; - } - if (isNeededTagRequired(sla)) - _soNeeded.insert(sla->loadName()); - } - for (const std::unique_ptr<Node> &node : _ctx.getNodes()) { - StringRef soname = maybeGetSOName(node.get()); - if (!soname.empty()) - _soNeeded.insert(soname); - } - // Never mark the dynamic linker as DT_NEEDED - _soNeeded.erase(sys::path::filename(_ctx.getInterpreter())); - for (const auto &loadName : _soNeeded) - _dynamicTable->addEntry(DT_NEEDED, - _dynamicStringTable->addString(loadName.getKey())); - const auto &rpathList = _ctx.getRpathList(); - if (!rpathList.empty()) { - auto rpath = - new (_alloc) std::string(join(rpathList.begin(), rpathList.end(), ":")); - _dynamicTable->addEntry(_ctx.getEnableNewDtags() ? DT_RUNPATH : DT_RPATH, - _dynamicStringTable->addString(*rpath)); - } - StringRef soname = _ctx.sharedObjectName(); - if (!soname.empty() && _ctx.getOutputELFType() == llvm::ELF::ET_DYN) - _dynamicTable->addEntry(DT_SONAME, _dynamicStringTable->addString(soname)); - - // Add DT_FLAGS/DT_FLAGS_1 entries if necessary. - uint32_t dtflags = 0, dt1flags = 0; - if (_ctx.getDTFlag(ELFLinkingContext::DTFlag::DT_NOW)) { - dtflags |= DF_BIND_NOW; - dt1flags |= DF_1_NOW; - } - if (_ctx.getDTFlag(ELFLinkingContext::DTFlag::DT_ORIGIN)) { - dtflags |= DF_ORIGIN; - dt1flags |= DF_1_ORIGIN; - } - if (dtflags != 0) - _dynamicTable->addEntry(DT_FLAGS, dtflags); - if (dt1flags != 0) - _dynamicTable->addEntry(DT_FLAGS_1, dt1flags); - - // The dynamic symbol table need to be sorted earlier because the hash - // table needs to be built using the dynamic symbol table. It would be - // late to sort the symbols due to that in finalize. In the dynamic symbol - // table finalize, we call the symbol table finalize and we don't want to - // sort again - _dynamicSymbolTable->sortSymbols(); - - // Add the dynamic symbols into the hash table - _dynamicSymbolTable->addSymbolsToHashTable(); -} - -template <class ELFT> -void OutputELFWriter<ELFT>::buildAtomToAddressMap(const File &file) { - ScopedTask task(getDefaultDomain(), "buildAtomToAddressMap"); - int64_t totalAbsAtoms = _layout.absoluteAtoms().size(); - int64_t totalUndefinedAtoms = file.undefined().size(); - int64_t totalDefinedAtoms = 0; - for (auto sec : _layout.sections()) - if (auto section = dyn_cast<AtomSection<ELFT>>(sec)) { - totalDefinedAtoms += section->atoms().size(); - for (const auto &atom : section->atoms()) - _atomToAddressMap[atom->_atom] = atom->_virtualAddr; - } - // build the atomToAddressMap that contains absolute symbols too - for (auto &atom : _layout.absoluteAtoms()) - _atomToAddressMap[atom->_atom] = atom->_virtualAddr; - - // Set the total number of atoms in the symbol table, so that appropriate - // resizing of the string table can be done. - // There's no such thing as symbol table if we're stripping all the symbols - if (!_ctx.stripSymbols()) - _symtab->setNumEntries(totalDefinedAtoms + totalAbsAtoms + - totalUndefinedAtoms); -} - -template <class ELFT> void OutputELFWriter<ELFT>::buildSectionHeaderTable() { - ScopedTask task(getDefaultDomain(), "buildSectionHeaderTable"); - for (auto outputSection : _layout.outputSections()) { - if (outputSection->kind() != Chunk<ELFT>::Kind::ELFSection && - outputSection->kind() != Chunk<ELFT>::Kind::AtomSection) - continue; - if (outputSection->hasSegment()) - _shdrtab->appendSection(outputSection); - } -} - -template <class ELFT> -void OutputELFWriter<ELFT>::assignSectionsWithNoSegments() { - ScopedTask task(getDefaultDomain(), "assignSectionsWithNoSegments"); - for (auto outputSection : _layout.outputSections()) { - if (outputSection->kind() != Chunk<ELFT>::Kind::ELFSection && - outputSection->kind() != Chunk<ELFT>::Kind::AtomSection) - continue; - if (!outputSection->hasSegment()) - _shdrtab->appendSection(outputSection); - } - _layout.assignFileOffsetsForMiscSections(); - for (auto sec : _layout.sections()) - if (auto section = dyn_cast<Section<ELFT>>(sec)) - if (!TargetLayout<ELFT>::hasOutputSegment(section)) - _shdrtab->updateSection(section); -} - -template <class ELFT> -void OutputELFWriter<ELFT>::createImplicitFiles( - std::vector<std::unique_ptr<File>> &result) { - // Add the virtual archive to resolve undefined symbols. - // The file will be added later in the linking context. - auto callback = [this](StringRef sym, RuntimeFile<ELFT> &file) { - processUndefinedSymbol(sym, file); - }; - _ctx.setUndefinesResolver( - llvm::make_unique<DynamicSymbolFile<ELFT>>(_ctx, std::move(callback))); - // Add script defined symbols - auto file = - llvm::make_unique<RuntimeFile<ELFT>>(_ctx, "Linker script runtime"); - for (auto &sym : this->_ctx.linkerScriptSema().getScriptDefinedSymbols()) - file->addAbsoluteAtom(sym.getKey()); - result.push_back(std::move(file)); -} - -template <class ELFT> void OutputELFWriter<ELFT>::finalizeDefaultAtomValues() { - const llvm::StringSet<> &symbols = - _ctx.linkerScriptSema().getScriptDefinedSymbols(); - for (auto &sym : symbols) { - uint64_t res = - _ctx.linkerScriptSema().getLinkerScriptExprValue(sym.getKey()); - AtomLayout *a = _layout.findAbsoluteAtom(sym.getKey()); - assert(a); - a->_virtualAddr = res; - } - // If there is a section named XXX, and XXX is a valid C identifier, - // and there are undefined or weak __start_XXX/__stop_XXX symbols, - // set the symbols values to the begin/end of the XXX section - // correspondingly. - for (const auto &name : _ctx.cidentSectionNames()) - updateScopeAtomValues((Twine("__start_") + name.getKey()).str(), - (Twine("__stop_") + name.getKey()).str(), - name.getKey()); -} - -template <class ELFT> void OutputELFWriter<ELFT>::createDefaultSections() { - _elfHeader.reset(new (_alloc) ELFHeader<ELFT>(_ctx)); - _programHeader.reset(new (_alloc) ProgramHeader<ELFT>(_ctx)); - _layout.setHeader(_elfHeader.get()); - _layout.setProgramHeader(_programHeader.get()); - - // Don't create .symtab and .strtab sections if we're going to - // strip all the symbols. - if (!_ctx.stripSymbols()) { - _symtab = this->createSymbolTable(); - _strtab.reset(new (_alloc) StringTable<ELFT>( - _ctx, ".strtab", TargetLayout<ELFT>::ORDER_STRING_TABLE)); - _layout.addSection(_symtab.get()); - _layout.addSection(_strtab.get()); - _symtab->setStringSection(_strtab.get()); - } - - _shstrtab.reset(new (_alloc) StringTable<ELFT>( - _ctx, ".shstrtab", TargetLayout<ELFT>::ORDER_SECTION_STRINGS)); - _shdrtab.reset(new (_alloc) SectionHeader<ELFT>( - _ctx, TargetLayout<ELFT>::ORDER_SECTION_HEADERS)); - _layout.addSection(_shstrtab.get()); - _shdrtab->setStringSection(_shstrtab.get()); - _layout.addSection(_shdrtab.get()); - - for (auto sec : _layout.sections()) { - // TODO: use findOutputSection - auto section = dyn_cast<Section<ELFT>>(sec); - if (!section || section->outputSectionName() != ".eh_frame") - continue; - _ehFrameHeader.reset(new (_alloc) EHFrameHeader<ELFT>( - _ctx, ".eh_frame_hdr", _layout, TargetLayout<ELFT>::ORDER_EH_FRAMEHDR)); - _layout.addSection(_ehFrameHeader.get()); - break; - } - - if (_ctx.isDynamic()) { - _dynamicTable = createDynamicTable(); - _dynamicStringTable.reset(new (_alloc) StringTable<ELFT>( - _ctx, ".dynstr", TargetLayout<ELFT>::ORDER_DYNAMIC_STRINGS, true)); - _dynamicSymbolTable = createDynamicSymbolTable(); - _hashTable.reset(new (_alloc) HashSection<ELFT>( - _ctx, ".hash", TargetLayout<ELFT>::ORDER_HASH)); - // Set the hash table in the dynamic symbol table so that the entries in the - // hash table can be created - _dynamicSymbolTable->setHashTable(_hashTable.get()); - _hashTable->setSymbolTable(_dynamicSymbolTable.get()); - _layout.addSection(_dynamicTable.get()); - _layout.addSection(_dynamicStringTable.get()); - _layout.addSection(_dynamicSymbolTable.get()); - _layout.addSection(_hashTable.get()); - _dynamicSymbolTable->setStringSection(_dynamicStringTable.get()); - _dynamicTable->setSymbolTable(_dynamicSymbolTable.get()); - _dynamicTable->setHashTable(_hashTable.get()); - if (_layout.hasDynamicRelocationTable()) - _layout.getDynamicRelocationTable()->setSymbolTable( - _dynamicSymbolTable.get()); - if (_layout.hasPLTRelocationTable()) - _layout.getPLTRelocationTable()->setSymbolTable( - _dynamicSymbolTable.get()); - } -} - -template <class ELFT> -unique_bump_ptr<SymbolTable<ELFT>> OutputELFWriter<ELFT>::createSymbolTable() { - return unique_bump_ptr<SymbolTable<ELFT>>(new (_alloc) SymbolTable<ELFT>( - this->_ctx, ".symtab", TargetLayout<ELFT>::ORDER_SYMBOL_TABLE)); -} - -/// \brief create dynamic table -template <class ELFT> -unique_bump_ptr<DynamicTable<ELFT>> -OutputELFWriter<ELFT>::createDynamicTable() { - return unique_bump_ptr<DynamicTable<ELFT>>(new (_alloc) DynamicTable<ELFT>( - this->_ctx, _layout, ".dynamic", TargetLayout<ELFT>::ORDER_DYNAMIC)); -} - -/// \brief create dynamic symbol table -template <class ELFT> -unique_bump_ptr<DynamicSymbolTable<ELFT>> -OutputELFWriter<ELFT>::createDynamicSymbolTable() { - return unique_bump_ptr<DynamicSymbolTable<ELFT>>( - new (_alloc) - DynamicSymbolTable<ELFT>(this->_ctx, _layout, ".dynsym", - TargetLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS)); -} - -template <class ELFT> -std::error_code OutputELFWriter<ELFT>::buildOutput(const File &file) { - ScopedTask buildTask(getDefaultDomain(), "ELF Writer buildOutput"); - buildChunks(file); - - // Create the default sections like the symbol table, string table, and the - // section string table - createDefaultSections(); - - // Set the Layout - _layout.assignSectionsToSegments(); - - // Create the dynamic table entries - if (_ctx.isDynamic()) { - _dynamicTable->createDefaultEntries(); - buildDynamicSymbolTable(file); - } - - // Call the preFlight callbacks to modify the sections and the atoms - // contained in them, in anyway the targets may want - _layout.doPreFlight(); - - _layout.assignVirtualAddress(); - - // Finalize the default value of symbols that the linker adds - finalizeDefaultAtomValues(); - - // Build the Atom To Address map for applying relocations - buildAtomToAddressMap(file); - - // Create symbol table and section string table - // Do it only if -s is not specified. - if (!_ctx.stripSymbols()) - buildStaticSymbolTable(file); - - // Finalize the layout by calling the finalize() functions - _layout.finalize(); - - // build Section Header table - buildSectionHeaderTable(); - - // assign Offsets and virtual addresses - // for sections with no segments - assignSectionsWithNoSegments(); - - if (_ctx.isDynamic()) - _dynamicTable->updateDynamicTable(); - - return std::error_code(); -} - -template <class ELFT> std::error_code OutputELFWriter<ELFT>::setELFHeader() { - _elfHeader->e_type(_ctx.getOutputELFType()); - _elfHeader->e_machine(_ctx.getOutputMachine()); - _elfHeader->e_ident(ELF::EI_VERSION, 1); - _elfHeader->e_ident(ELF::EI_OSABI, 0); - _elfHeader->e_version(1); - _elfHeader->e_phoff(_programHeader->fileOffset()); - _elfHeader->e_shoff(_shdrtab->fileOffset()); - _elfHeader->e_phentsize(_programHeader->entsize()); - _elfHeader->e_phnum(_programHeader->numHeaders()); - _elfHeader->e_shentsize(_shdrtab->entsize()); - _elfHeader->e_shnum(_shdrtab->numHeaders()); - _elfHeader->e_shstrndx(_shstrtab->ordinal()); - if (const auto *al = _layout.findAtomLayoutByName(_ctx.entrySymbolName())) - _elfHeader->e_entry(al->_virtualAddr); - else - _elfHeader->e_entry(0); - - return std::error_code(); -} - -template <class ELFT> uint64_t OutputELFWriter<ELFT>::outputFileSize() const { - return _shdrtab->fileOffset() + _shdrtab->fileSize(); -} - -template <class ELFT> -std::error_code OutputELFWriter<ELFT>::writeOutput(const File &file, - StringRef path) { - - ScopedTask createOutputTask(getDefaultDomain(), "ELF Writer Create Output"); - ErrorOr<std::unique_ptr<FileOutputBuffer>> bufferOrErr = - FileOutputBuffer::create(path, outputFileSize(), - FileOutputBuffer::F_executable); - if (std::error_code ec = bufferOrErr.getError()) - return ec; - std::unique_ptr<FileOutputBuffer> &buffer = *bufferOrErr; - createOutputTask.end(); - - ScopedTask writeTask(getDefaultDomain(), "ELF Writer write to memory"); - - // HACK: We have to write out the header and program header here even though - // they are a member of a segment because only sections are written in the - // following loop. - - // Finalize ELF Header / Program Headers. - _elfHeader->finalize(); - _programHeader->finalize(); - - _elfHeader->write(this, _layout, *buffer); - _programHeader->write(this, _layout, *buffer); - - auto sections = _layout.sections(); - parallel_for_each( - sections.begin(), sections.end(), - [&](Chunk<ELFT> *section) { section->write(this, _layout, *buffer); }); - writeTask.end(); - - ScopedTask commitTask(getDefaultDomain(), "ELF Writer commit to disk"); - return buffer->commit(); -} - -template <class ELFT> -std::error_code OutputELFWriter<ELFT>::writeFile(const File &file, - StringRef path) { - if (std::error_code ec = buildOutput(file)) - return ec; - if (std::error_code ec = setELFHeader()) - return ec; - return writeOutput(file, path); -} - -template <class ELFT> -void OutputELFWriter<ELFT>::processUndefinedSymbol( - StringRef symName, RuntimeFile<ELFT> &file) const { - if (symName.startswith("__start_")) { - if (_ctx.cidentSectionNames().count(symName.drop_front(8))) - file.addAbsoluteAtom(symName); - } else if (symName.startswith("__stop_")) { - if (_ctx.cidentSectionNames().count(symName.drop_front(7))) - file.addAbsoluteAtom(symName); - } -} - -template <class ELFT> -void OutputELFWriter<ELFT>::updateScopeAtomValues(StringRef sym, - StringRef sec) { - updateScopeAtomValues(("__" + sym + "_start").str().c_str(), - ("__" + sym + "_end").str().c_str(), sec); -} - -template <class ELFT> -void OutputELFWriter<ELFT>::updateScopeAtomValues(StringRef start, - StringRef end, - StringRef sec) { - AtomLayout *s = _layout.findAbsoluteAtom(start); - AtomLayout *e = _layout.findAbsoluteAtom(end); - const OutputSection<ELFT> *section = _layout.findOutputSection(sec); - if (s) - s->_virtualAddr = section ? section->virtualAddr() : 0; - if (e) - e->_virtualAddr = section ? section->virtualAddr() + section->memSize() : 0; -} - -template class OutputELFWriter<ELF32LE>; -template class OutputELFWriter<ELF32BE>; -template class OutputELFWriter<ELF64LE>; -template class OutputELFWriter<ELF64BE>; - -} // namespace elf -} // namespace lld diff --git a/lib/ReaderWriter/ELF/OutputELFWriter.h b/lib/ReaderWriter/ELF/OutputELFWriter.h deleted file mode 100644 index bb3901010634..000000000000 --- a/lib/ReaderWriter/ELF/OutputELFWriter.h +++ /dev/null @@ -1,153 +0,0 @@ -//===- lib/ReaderWriter/ELF/OutputELFWriter.h ----------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_OUTPUT_WRITER_H -#define LLD_READER_WRITER_ELF_OUTPUT_WRITER_H - -#include "ELFFile.h" -#include "TargetLayout.h" -#include "lld/Core/Writer.h" -#include "llvm/ADT/StringSet.h" - -namespace lld { -class ELFLinkingContext; - -namespace elf { -using namespace llvm; -using namespace llvm::object; - -// OutputELFWriter Class -// -/// \brief This acts as the base class for all the ELF writers that are output -/// for emitting an ELF output file. This class also acts as a common class for -/// creating static and dynamic executables. All the function in this class -/// can be overridden and an appropriate writer be created -template<class ELFT> -class OutputELFWriter : public ELFWriter { -public: - typedef Elf_Shdr_Impl<ELFT> Elf_Shdr; - typedef Elf_Sym_Impl<ELFT> Elf_Sym; - typedef Elf_Dyn_Impl<ELFT> Elf_Dyn; - - OutputELFWriter(ELFLinkingContext &ctx, TargetLayout<ELFT> &layout); - -protected: - // build the sections that need to be created - virtual void createDefaultSections(); - - // Build all the output sections - void buildChunks(const File &file) override; - - // Build the output file - virtual std::error_code buildOutput(const File &file); - - // Setup the ELF header. - virtual std::error_code setELFHeader(); - - // Write the file to the path specified - std::error_code writeFile(const File &File, StringRef path) override; - - // Write to the output file. - virtual std::error_code writeOutput(const File &file, StringRef path); - - // Get the size of the output file that the linker would emit. - virtual uint64_t outputFileSize() const; - - // Build the atom to address map, this has to be called - // before applying relocations - virtual void buildAtomToAddressMap(const File &file); - - // Build the symbol table for static linking - virtual void buildStaticSymbolTable(const File &file); - - // Build the dynamic symbol table for dynamic linking - virtual void buildDynamicSymbolTable(const File &file); - - // Build the section header table - virtual void buildSectionHeaderTable(); - - // Assign sections that have no segments such as the symbol table, - // section header table, string table etc - virtual void assignSectionsWithNoSegments(); - - // Add any runtime files and their atoms to the output - void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override; - - // Finalize the default atom values - virtual void finalizeDefaultAtomValues(); - - // This is called by the write section to apply relocations - uint64_t addressOfAtom(const Atom *atom) override { - auto addr = _atomToAddressMap.find(atom); - return addr == _atomToAddressMap.end() ? 0 : addr->second; - } - - // This is a hook for creating default dynamic entries - virtual void createDefaultDynamicEntries() {} - - /// \brief Create symbol table. - virtual unique_bump_ptr<SymbolTable<ELFT>> createSymbolTable(); - - /// \brief create dynamic table. - virtual unique_bump_ptr<DynamicTable<ELFT>> createDynamicTable(); - - /// \brief create dynamic symbol table. - virtual unique_bump_ptr<DynamicSymbolTable<ELFT>> - createDynamicSymbolTable(); - - /// \brief Create entry in the dynamic symbols table for this atom. - virtual bool isDynSymEntryRequired(const SharedLibraryAtom *sla) const { - return _layout.isReferencedByDefinedAtom(sla); - } - - /// \brief Create DT_NEEDED dynamic tage for the shared library. - virtual bool isNeededTagRequired(const SharedLibraryAtom *sla) const { - return false; - } - - /// \brief Process undefined symbols that left after resolution step. - virtual void processUndefinedSymbol(StringRef symName, - RuntimeFile<ELFT> &file) const; - - /// \brief Assign addresses to atoms marking section's start and end. - void updateScopeAtomValues(StringRef sym, StringRef sec); - - llvm::BumpPtrAllocator _alloc; - - ELFLinkingContext &_ctx; - TargetHandler &_targetHandler; - - typedef llvm::DenseMap<const Atom *, uint64_t> AtomToAddress; - AtomToAddress _atomToAddressMap; - TargetLayout<ELFT> &_layout; - unique_bump_ptr<ELFHeader<ELFT>> _elfHeader; - unique_bump_ptr<ProgramHeader<ELFT>> _programHeader; - unique_bump_ptr<SymbolTable<ELFT>> _symtab; - unique_bump_ptr<StringTable<ELFT>> _strtab; - unique_bump_ptr<StringTable<ELFT>> _shstrtab; - unique_bump_ptr<SectionHeader<ELFT>> _shdrtab; - unique_bump_ptr<EHFrameHeader<ELFT>> _ehFrameHeader; - /// \name Dynamic sections. - /// @{ - unique_bump_ptr<DynamicTable<ELFT>> _dynamicTable; - unique_bump_ptr<DynamicSymbolTable<ELFT>> _dynamicSymbolTable; - unique_bump_ptr<StringTable<ELFT>> _dynamicStringTable; - unique_bump_ptr<HashSection<ELFT>> _hashTable; - llvm::StringSet<> _soNeeded; - /// @} - -private: - static StringRef maybeGetSOName(Node *node); - void updateScopeAtomValues(StringRef start, StringRef end, StringRef sec); -}; - -} // namespace elf -} // namespace lld - -#endif // LLD_READER_WRITER_ELF_OUTPUT_WRITER_H diff --git a/lib/ReaderWriter/ELF/Reader.cpp b/lib/ReaderWriter/ELF/Reader.cpp deleted file mode 100644 index 801f1abaed7a..000000000000 --- a/lib/ReaderWriter/ELF/Reader.cpp +++ /dev/null @@ -1,43 +0,0 @@ -//===- lib/ReaderWriter/ELF/Reader.cpp ------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Defines the ELF Reader and all helper sub classes to consume an ELF -/// file and produces atoms out of it. -/// -//===----------------------------------------------------------------------===// - -#include "ELFReader.h" -#include <map> -#include <vector> - -using llvm::support::endianness; -using namespace llvm::object; - -namespace lld { - -// This dynamic registration of a handler causes support for all ELF -// architectures to be pulled into the linker. If we want to support making a -// linker that only supports one ELF architecture, we'd need to change this -// to have a different registration method for each architecture. -void Registry::addSupportELFObjects(ELFLinkingContext &ctx) { - - // Tell registry about the ELF object file parser. - add(ctx.getTargetHandler().getObjReader()); - - // Tell registry about the relocation name to number mapping for this arch. - ctx.registerRelocationNames(*this); -} - -void Registry::addSupportELFDynamicSharedObjects(ELFLinkingContext &ctx) { - // Tell registry about the ELF dynamic shared library file parser. - add(ctx.getTargetHandler().getDSOReader()); -} - -} // end namespace lld diff --git a/lib/ReaderWriter/ELF/SectionChunks.cpp b/lib/ReaderWriter/ELF/SectionChunks.cpp deleted file mode 100644 index 520fbe24af3b..000000000000 --- a/lib/ReaderWriter/ELF/SectionChunks.cpp +++ /dev/null @@ -1,996 +0,0 @@ -//===- lib/ReaderWriter/ELF/SectionChunks.h -------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "SectionChunks.h" -#include "TargetLayout.h" -#include "lld/Core/Parallel.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/Support/Dwarf.h" - -namespace lld { -namespace elf { - -template <class ELFT> -Section<ELFT>::Section(const ELFLinkingContext &ctx, StringRef sectionName, - StringRef chunkName, typename Chunk<ELFT>::Kind k) - : Chunk<ELFT>(chunkName, k, ctx), _inputSectionName(sectionName), - _outputSectionName(sectionName) {} - -template <class ELFT> int Section<ELFT>::getContentType() const { - if (_flags & llvm::ELF::SHF_EXECINSTR) - return Chunk<ELFT>::ContentType::Code; - else if (_flags & llvm::ELF::SHF_WRITE) - return Chunk<ELFT>::ContentType::Data; - else if (_flags & llvm::ELF::SHF_ALLOC) - return Chunk<ELFT>::ContentType::Code; - else - return Chunk<ELFT>::ContentType::Unknown; -} - -template <class ELFT> -AtomSection<ELFT>::AtomSection(const ELFLinkingContext &ctx, - StringRef sectionName, int32_t contentType, - int32_t permissions, int32_t order) - : Section<ELFT>(ctx, sectionName, "AtomSection", - Chunk<ELFT>::Kind::AtomSection), - _contentType(contentType), _contentPermissions(permissions) { - this->setOrder(order); - - switch (contentType) { - case DefinedAtom::typeCode: - case DefinedAtom::typeDataFast: - case DefinedAtom::typeData: - case DefinedAtom::typeConstant: - case DefinedAtom::typeGOT: - case DefinedAtom::typeStub: - case DefinedAtom::typeResolver: - case DefinedAtom::typeThreadData: - this->_type = SHT_PROGBITS; - break; - - case DefinedAtom::typeThreadZeroFill: - case DefinedAtom::typeZeroFillFast: - case DefinedAtom::typeZeroFill: - this->_type = SHT_NOBITS; - break; - - case DefinedAtom::typeRONote: - case DefinedAtom::typeRWNote: - this->_type = SHT_NOTE; - break; - - case DefinedAtom::typeNoAlloc: - this->_type = SHT_PROGBITS; - this->_isLoadedInMemory = false; - break; - } - - switch (permissions) { - case DefinedAtom::permR__: - this->_flags = SHF_ALLOC; - break; - case DefinedAtom::permR_X: - this->_flags = SHF_ALLOC | SHF_EXECINSTR; - break; - case DefinedAtom::permRW_: - case DefinedAtom::permRW_L: - this->_flags = SHF_ALLOC | SHF_WRITE; - if (_contentType == DefinedAtom::typeThreadData || - _contentType == DefinedAtom::typeThreadZeroFill) - this->_flags |= SHF_TLS; - break; - case DefinedAtom::permRWX: - this->_flags = SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR; - break; - case DefinedAtom::perm___: - this->_flags = 0; - break; - } -} - -template <class ELFT> -void AtomSection<ELFT>::assignVirtualAddress(uint64_t addr) { - parallel_for_each(_atoms.begin(), _atoms.end(), [&](AtomLayout *ai) { - ai->_virtualAddr = addr + ai->_fileOffset; - }); -} - -template <class ELFT> -void AtomSection<ELFT>::assignFileOffsets(uint64_t offset) { - parallel_for_each(_atoms.begin(), _atoms.end(), [&](AtomLayout *ai) { - ai->_fileOffset = offset + ai->_fileOffset; - }); -} - -template <class ELFT> -const AtomLayout * -AtomSection<ELFT>::findAtomLayoutByName(StringRef name) const { - for (auto ai : _atoms) - if (ai->_atom->name() == name) - return ai; - return nullptr; -} - -template <class ELFT> -std::string AtomSection<ELFT>::formatError(const std::string &errorStr, - const AtomLayout &atom, - const Reference &ref) const { - StringRef kindValStr; - if (!this->_ctx.registry().referenceKindToString( - ref.kindNamespace(), ref.kindArch(), ref.kindValue(), kindValStr)) { - kindValStr = "unknown"; - } - - return - (Twine(errorStr) + " in file " + atom._atom->file().path() + - ": reference from " + atom._atom->name() + "+" + - Twine(ref.offsetInAtom()) + " to " + ref.target()->name() + "+" + - Twine(ref.addend()) + " of type " + Twine(ref.kindValue()) + " (" + - kindValStr + ")\n") - .str(); -} - -/// Align the offset to the required modulus defined by the atom alignment -template <class ELFT> -uint64_t AtomSection<ELFT>::alignOffset(uint64_t offset, - DefinedAtom::Alignment &atomAlign) { - uint64_t requiredModulus = atomAlign.modulus; - uint64_t alignment = atomAlign.value; - uint64_t currentModulus = (offset % alignment); - uint64_t retOffset = offset; - if (currentModulus != requiredModulus) { - if (requiredModulus > currentModulus) - retOffset += requiredModulus - currentModulus; - else - retOffset += alignment + requiredModulus - currentModulus; - } - return retOffset; -} - -// \brief Append an atom to a Section. The atom gets pushed into a vector -// contains the atom, the atom file offset, the atom virtual address -// the atom file offset is aligned appropriately as set by the Reader -template <class ELFT> -const AtomLayout *AtomSection<ELFT>::appendAtom(const Atom *atom) { - const DefinedAtom *definedAtom = cast<DefinedAtom>(atom); - - DefinedAtom::Alignment atomAlign = definedAtom->alignment(); - uint64_t alignment = atomAlign.value; - // Align the atom to the required modulus/ align the file offset and the - // memory offset separately this is required so that BSS symbols are handled - // properly as the BSS symbols only occupy memory size and not file size - uint64_t fOffset = alignOffset(this->fileSize(), atomAlign); - uint64_t mOffset = alignOffset(this->memSize(), atomAlign); - switch (definedAtom->contentType()) { - case DefinedAtom::typeCode: - case DefinedAtom::typeConstant: - case DefinedAtom::typeData: - case DefinedAtom::typeDataFast: - case DefinedAtom::typeZeroFillFast: - case DefinedAtom::typeGOT: - case DefinedAtom::typeStub: - case DefinedAtom::typeResolver: - case DefinedAtom::typeThreadData: - case DefinedAtom::typeRONote: - case DefinedAtom::typeRWNote: - _atoms.push_back(new (_alloc) AtomLayout(atom, fOffset, 0)); - this->_fsize = fOffset + definedAtom->size(); - this->_msize = mOffset + definedAtom->size(); - DEBUG_WITH_TYPE("Section", llvm::dbgs() - << "[" << this->name() << " " << this << "] " - << "Adding atom: " << atom->name() << "@" - << fOffset << "\n"); - break; - case DefinedAtom::typeNoAlloc: - _atoms.push_back(new (_alloc) AtomLayout(atom, fOffset, 0)); - this->_fsize = fOffset + definedAtom->size(); - DEBUG_WITH_TYPE("Section", llvm::dbgs() - << "[" << this->name() << " " << this << "] " - << "Adding atom: " << atom->name() << "@" - << fOffset << "\n"); - break; - case DefinedAtom::typeThreadZeroFill: - case DefinedAtom::typeZeroFill: - _atoms.push_back(new (_alloc) AtomLayout(atom, mOffset, 0)); - this->_msize = mOffset + definedAtom->size(); - break; - default: - llvm::dbgs() << definedAtom->contentType() << "\n"; - llvm_unreachable("Uexpected content type."); - } - // Set the section alignment to the largest alignment - // std::max doesn't support uint64_t - if (this->_alignment < alignment) - this->_alignment = alignment; - - if (_atoms.size()) - return _atoms.back(); - return nullptr; -} - -/// \brief convert the segment type to a String for diagnostics -/// and printing purposes -template <class ELFT> StringRef Section<ELFT>::segmentKindToStr() const { - switch (_segmentType) { - case llvm::ELF::PT_DYNAMIC: - return "DYNAMIC"; - case llvm::ELF::PT_INTERP: - return "INTERP"; - case llvm::ELF::PT_LOAD: - return "LOAD"; - case llvm::ELF::PT_GNU_EH_FRAME: - return "EH_FRAME"; - case llvm::ELF::PT_GNU_RELRO: - return "GNU_RELRO"; - case llvm::ELF::PT_NOTE: - return "NOTE"; - case llvm::ELF::PT_NULL: - return "NULL"; - case llvm::ELF::PT_TLS: - return "TLS"; - default: - return "UNKNOWN"; - } -} - -/// \brief Write the section and the atom contents to the buffer -template <class ELFT> -void AtomSection<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) { - uint8_t *chunkBuffer = buffer.getBufferStart(); - bool success = true; - - // parallel_for_each() doesn't have deterministic order. To guarantee - // deterministic error output, collect errors in this vector and sort it - // by atom file offset before printing all errors. - std::vector<std::pair<size_t, std::string>> errors; - parallel_for_each(_atoms.begin(), _atoms.end(), [&](AtomLayout *ai) { - DEBUG_WITH_TYPE("Section", llvm::dbgs() - << "Writing atom: " << ai->_atom->name() - << " | " << ai->_fileOffset << "\n"); - const DefinedAtom *definedAtom = cast<DefinedAtom>(ai->_atom); - if (!definedAtom->occupiesDiskSpace()) - return; - // Copy raw content of atom to file buffer. - ArrayRef<uint8_t> content = definedAtom->rawContent(); - uint64_t contentSize = content.size(); - if (contentSize == 0) - return; - uint8_t *atomContent = chunkBuffer + ai->_fileOffset; - std::memcpy(atomContent, content.data(), contentSize); - const TargetRelocationHandler &relHandler = - this->_ctx.getTargetHandler().getRelocationHandler(); - for (const auto ref : *definedAtom) { - if (std::error_code ec = - relHandler.applyRelocation(*writer, buffer, *ai, *ref)) { - std::lock_guard<std::mutex> lock(_outputMutex); - errors.push_back(std::make_pair(ai->_fileOffset, - formatError(ec.message(), *ai, *ref))); - success = false; - } - } - }); - if (!success) { - std::sort(errors.begin(), errors.end()); - for (auto &&error : errors) - llvm::errs() << error.second; - llvm::report_fatal_error("relocating output"); - } -} - -template <class ELFT> -void OutputSection<ELFT>::appendSection(Section<ELFT> *section) { - if (section->alignment() > _alignment) - _alignment = section->alignment(); - assert(!_link && "Section already has a link!"); - _link = section->getLink(); - _shInfo = section->getInfo(); - _entSize = section->getEntSize(); - _type = section->getType(); - if (_flags < section->getFlags()) - _flags = section->getFlags(); - section->setOutputSection(this, (_sections.size() == 0)); - _kind = section->kind(); - _sections.push_back(section); -} - -template <class ELFT> -StringTable<ELFT>::StringTable(const ELFLinkingContext &ctx, const char *str, - int32_t order, bool dynamic) - : Section<ELFT>(ctx, str, "StringTable") { - // the string table has a NULL entry for which - // add an empty string - _strings.push_back(""); - this->_fsize = 1; - this->_alignment = 1; - this->setOrder(order); - this->_type = SHT_STRTAB; - if (dynamic) { - this->_flags = SHF_ALLOC; - this->_msize = this->_fsize; - } -} - -template <class ELFT> uint64_t StringTable<ELFT>::addString(StringRef symname) { - if (symname.empty()) - return 0; - StringMapTIter stringIter = _stringMap.find(symname); - if (stringIter == _stringMap.end()) { - _strings.push_back(symname); - uint64_t offset = this->_fsize; - this->_fsize += symname.size() + 1; - if (this->_flags & SHF_ALLOC) - this->_msize = this->_fsize; - _stringMap[symname] = offset; - return offset; - } - return stringIter->second; -} - -template <class ELFT> -void StringTable<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &, - llvm::FileOutputBuffer &buffer) { - uint8_t *chunkBuffer = buffer.getBufferStart(); - uint8_t *dest = chunkBuffer + this->fileOffset(); - for (auto si : _strings) { - memcpy(dest, si.data(), si.size()); - dest += si.size(); - memcpy(dest, "", 1); - dest += 1; - } -} - -/// ELF Symbol Table -template <class ELFT> -SymbolTable<ELFT>::SymbolTable(const ELFLinkingContext &ctx, const char *str, - int32_t order) - : Section<ELFT>(ctx, str, "SymbolTable") { - this->setOrder(order); - Elf_Sym symbol; - std::memset(&symbol, 0, sizeof(Elf_Sym)); - _symbolTable.push_back(SymbolEntry(nullptr, symbol, nullptr)); - this->_entSize = sizeof(Elf_Sym); - this->_fsize = sizeof(Elf_Sym); - this->_alignment = sizeof(Elf_Addr); - this->_type = SHT_SYMTAB; -} - -template <class ELFT> -void SymbolTable<ELFT>::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da, - int64_t addr) { - unsigned char binding = 0, type = 0; - sym.st_size = da->size(); - DefinedAtom::ContentType ct; - switch (ct = da->contentType()) { - case DefinedAtom::typeCode: - case DefinedAtom::typeStub: - sym.st_value = addr; - type = llvm::ELF::STT_FUNC; - break; - case DefinedAtom::typeResolver: - sym.st_value = addr; - type = llvm::ELF::STT_GNU_IFUNC; - break; - case DefinedAtom::typeDataFast: - case DefinedAtom::typeData: - case DefinedAtom::typeConstant: - sym.st_value = addr; - type = llvm::ELF::STT_OBJECT; - break; - case DefinedAtom::typeGOT: - sym.st_value = addr; - type = llvm::ELF::STT_NOTYPE; - break; - case DefinedAtom::typeZeroFill: - case DefinedAtom::typeZeroFillFast: - type = llvm::ELF::STT_OBJECT; - sym.st_value = addr; - break; - case DefinedAtom::typeThreadData: - case DefinedAtom::typeThreadZeroFill: - type = llvm::ELF::STT_TLS; - sym.st_value = addr; - break; - default: - type = llvm::ELF::STT_NOTYPE; - } - if (da->customSectionName() == da->name()) - type = llvm::ELF::STT_SECTION; - - if (da->scope() == DefinedAtom::scopeTranslationUnit) - binding = llvm::ELF::STB_LOCAL; - else - binding = llvm::ELF::STB_GLOBAL; - - sym.setBindingAndType(binding, type); -} - -template <class ELFT> -void SymbolTable<ELFT>::addAbsoluteAtom(Elf_Sym &sym, const AbsoluteAtom *aa, - int64_t addr) { - unsigned char binding = 0, type = 0; - type = llvm::ELF::STT_OBJECT; - sym.st_shndx = llvm::ELF::SHN_ABS; - switch (aa->scope()) { - case AbsoluteAtom::scopeLinkageUnit: - sym.setVisibility(llvm::ELF::STV_HIDDEN); - binding = llvm::ELF::STB_LOCAL; - break; - case AbsoluteAtom::scopeTranslationUnit: - binding = llvm::ELF::STB_LOCAL; - break; - case AbsoluteAtom::scopeGlobal: - binding = llvm::ELF::STB_GLOBAL; - break; - } - sym.st_value = addr; - sym.setBindingAndType(binding, type); -} - -template <class ELFT> -void SymbolTable<ELFT>::addSharedLibAtom(Elf_Sym &sym, - const SharedLibraryAtom *aa) { - unsigned char binding = 0, type = 0; - if (aa->type() == SharedLibraryAtom::Type::Data) { - type = llvm::ELF::STT_OBJECT; - sym.st_size = aa->size(); - } else - type = llvm::ELF::STT_FUNC; - sym.st_shndx = llvm::ELF::SHN_UNDEF; - binding = llvm::ELF::STB_GLOBAL; - sym.setBindingAndType(binding, type); -} - -template <class ELFT> -void SymbolTable<ELFT>::addUndefinedAtom(Elf_Sym &sym, - const UndefinedAtom *ua) { - unsigned char binding = 0, type = 0; - sym.st_value = 0; - type = llvm::ELF::STT_NOTYPE; - if (ua->canBeNull()) - binding = llvm::ELF::STB_WEAK; - else - binding = llvm::ELF::STB_GLOBAL; - sym.setBindingAndType(binding, type); -} - -/// Add a symbol to the symbol Table, definedAtoms which get added to the symbol -/// section don't have their virtual addresses set at the time of adding the -/// symbol to the symbol table(Example: dynamic symbols), the addresses needs -/// to be updated in the table before writing the dynamic symbol table -/// information -template <class ELFT> -void SymbolTable<ELFT>::addSymbol(const Atom *atom, int32_t sectionIndex, - uint64_t addr, const AtomLayout *atomLayout) { - Elf_Sym symbol; - - if (atom->name().empty()) - return; - - symbol.st_name = _stringSection->addString(atom->name()); - symbol.st_size = 0; - symbol.st_shndx = sectionIndex; - symbol.st_value = 0; - symbol.st_other = 0; - symbol.setVisibility(llvm::ELF::STV_DEFAULT); - - // Add all the atoms - if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(atom)) - addDefinedAtom(symbol, da, addr); - else if (const AbsoluteAtom *aa = dyn_cast<const AbsoluteAtom>(atom)) - addAbsoluteAtom(symbol, aa, addr); - else if (isa<const SharedLibraryAtom>(atom)) - addSharedLibAtom(symbol, dyn_cast<SharedLibraryAtom>(atom)); - else - addUndefinedAtom(symbol, dyn_cast<UndefinedAtom>(atom)); - - // If --discard-all is on, don't add to the symbol table - // symbols with local binding. - if (this->_ctx.discardLocals() && symbol.getBinding() == llvm::ELF::STB_LOCAL) - return; - - // Temporary locals are all the symbols which name starts with .L. - // This is defined by the ELF standard. - if (this->_ctx.discardTempLocals() && atom->name().startswith(".L")) - return; - - _symbolTable.push_back(SymbolEntry(atom, symbol, atomLayout)); - this->_fsize += sizeof(Elf_Sym); - if (this->_flags & SHF_ALLOC) - this->_msize = this->_fsize; -} - -template <class ELFT> void SymbolTable<ELFT>::finalize(bool sort) { - // sh_info should be one greater than last symbol with STB_LOCAL binding - // we sort the symbol table to keep all local symbols at the beginning - if (sort) - sortSymbols(); - - uint16_t shInfo = 0; - for (const auto &i : _symbolTable) { - if (i._symbol.getBinding() != llvm::ELF::STB_LOCAL) - break; - shInfo++; - } - this->_info = shInfo; - this->_link = _stringSection->ordinal(); - if (this->_outputSection) { - this->_outputSection->setInfo(this->_info); - this->_outputSection->setLink(this->_link); - } -} - -template <class ELFT> -void SymbolTable<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &, - llvm::FileOutputBuffer &buffer) { - uint8_t *chunkBuffer = buffer.getBufferStart(); - uint8_t *dest = chunkBuffer + this->fileOffset(); - for (const auto &sti : _symbolTable) { - memcpy(dest, &sti._symbol, sizeof(Elf_Sym)); - dest += sizeof(Elf_Sym); - } -} - -template <class ELFT> -DynamicSymbolTable<ELFT>::DynamicSymbolTable(const ELFLinkingContext &ctx, - TargetLayout<ELFT> &layout, - const char *str, int32_t order) - : SymbolTable<ELFT>(ctx, str, order), _layout(layout) { - this->_type = SHT_DYNSYM; - this->_flags = SHF_ALLOC; - this->_msize = this->_fsize; -} - -template <class ELFT> void DynamicSymbolTable<ELFT>::addSymbolsToHashTable() { - int index = 0; - for (auto &ste : this->_symbolTable) { - if (!ste._atom) - _hashTable->addSymbol("", index); - else - _hashTable->addSymbol(ste._atom->name(), index); - ++index; - } -} - -template <class ELFT> void DynamicSymbolTable<ELFT>::finalize() { - // Defined symbols which have been added into the dynamic symbol table - // don't have their addresses known until addresses have been assigned - // so let's update the symbol values after they have got assigned - for (auto &ste : this->_symbolTable) { - const AtomLayout *atomLayout = ste._atomLayout; - if (!atomLayout) - continue; - ste._symbol.st_value = atomLayout->_virtualAddr; - } - - // Don't sort the symbols - SymbolTable<ELFT>::finalize(false); -} - -template <class ELFT> -RelocationTable<ELFT>::RelocationTable(const ELFLinkingContext &ctx, - StringRef str, int32_t order) - : Section<ELFT>(ctx, str, "RelocationTable") { - this->setOrder(order); - this->_flags = SHF_ALLOC; - // Set the alignment properly depending on the target architecture - this->_alignment = ELFT::Is64Bits ? 8 : 4; - if (ctx.isRelaOutputFormat()) { - this->_entSize = sizeof(Elf_Rela); - this->_type = SHT_RELA; - } else { - this->_entSize = sizeof(Elf_Rel); - this->_type = SHT_REL; - } -} - -template <class ELFT> -uint32_t RelocationTable<ELFT>::addRelocation(const DefinedAtom &da, - const Reference &r) { - _relocs.emplace_back(&da, &r); - this->_fsize = _relocs.size() * this->_entSize; - this->_msize = this->_fsize; - return _relocs.size() - 1; -} - -template <class ELFT> -bool RelocationTable<ELFT>::getRelocationIndex(const Reference &r, - uint32_t &res) { - auto rel = std::find_if( - _relocs.begin(), _relocs.end(), - [&](const std::pair<const DefinedAtom *, const Reference *> &p) { - if (p.second == &r) - return true; - return false; - }); - if (rel == _relocs.end()) - return false; - res = std::distance(_relocs.begin(), rel); - return true; -} - -template <class ELFT> -bool RelocationTable<ELFT>::canModifyReadonlySection() const { - for (const auto &rel : _relocs) { - const DefinedAtom *atom = rel.first; - if ((atom->permissions() & DefinedAtom::permRW_) != DefinedAtom::permRW_) - return true; - } - return false; -} - -template <class ELFT> void RelocationTable<ELFT>::finalize() { - this->_link = _symbolTable ? _symbolTable->ordinal() : 0; - if (this->_outputSection) - this->_outputSection->setLink(this->_link); -} - -template <class ELFT> -void RelocationTable<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) { - uint8_t *chunkBuffer = buffer.getBufferStart(); - uint8_t *dest = chunkBuffer + this->fileOffset(); - for (const auto &rel : _relocs) { - if (this->_ctx.isRelaOutputFormat()) { - auto &r = *reinterpret_cast<Elf_Rela *>(dest); - writeRela(writer, r, *rel.first, *rel.second); - DEBUG_WITH_TYPE("ELFRelocationTable", - llvm::dbgs() - << rel.second->kindValue() << " relocation at " - << rel.first->name() << "@" << r.r_offset << " to " - << rel.second->target()->name() << "@" << r.r_addend - << "\n";); - } else { - auto &r = *reinterpret_cast<Elf_Rel *>(dest); - writeRel(writer, r, *rel.first, *rel.second); - DEBUG_WITH_TYPE("ELFRelocationTable", - llvm::dbgs() << rel.second->kindValue() - << " relocation at " << rel.first->name() - << "@" << r.r_offset << " to " - << rel.second->target()->name() << "\n";); - } - dest += this->_entSize; - } -} - -template <class ELFT> -void RelocationTable<ELFT>::writeRela(ELFWriter *writer, Elf_Rela &r, - const DefinedAtom &atom, - const Reference &ref) { - r.setSymbolAndType(getSymbolIndex(ref.target()), ref.kindValue(), false); - r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom(); - // The addend is used only by relative relocations - if (this->_ctx.isRelativeReloc(ref)) - r.r_addend = writer->addressOfAtom(ref.target()) + ref.addend(); - else - r.r_addend = 0; -} - -template <class ELFT> -void RelocationTable<ELFT>::writeRel(ELFWriter *writer, Elf_Rel &r, - const DefinedAtom &atom, - const Reference &ref) { - r.setSymbolAndType(getSymbolIndex(ref.target()), ref.kindValue(), false); - r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom(); -} - -template <class ELFT> -uint32_t RelocationTable<ELFT>::getSymbolIndex(const Atom *a) { - return _symbolTable ? _symbolTable->getSymbolTableIndex(a) - : (uint32_t)STN_UNDEF; -} - -template <class ELFT> -DynamicTable<ELFT>::DynamicTable(const ELFLinkingContext &ctx, - TargetLayout<ELFT> &layout, StringRef str, - int32_t order) - : Section<ELFT>(ctx, str, "DynamicSection"), _layout(layout) { - this->setOrder(order); - this->_entSize = sizeof(Elf_Dyn); - this->_alignment = ELFT::Is64Bits ? 8 : 4; - // Reserve space for the DT_NULL entry. - this->_fsize = sizeof(Elf_Dyn); - this->_msize = sizeof(Elf_Dyn); - this->_type = SHT_DYNAMIC; - this->_flags = SHF_ALLOC; -} - -template <class ELFT> -std::size_t DynamicTable<ELFT>::addEntry(int64_t tag, uint64_t val) { - Elf_Dyn dyn; - dyn.d_tag = tag; - dyn.d_un.d_val = val; - _entries.push_back(dyn); - this->_fsize = (_entries.size() * sizeof(Elf_Dyn)) + sizeof(Elf_Dyn); - this->_msize = this->_fsize; - return _entries.size() - 1; -} - -template <class ELFT> -void DynamicTable<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) { - uint8_t *chunkBuffer = buffer.getBufferStart(); - uint8_t *dest = chunkBuffer + this->fileOffset(); - // Add the null entry. - Elf_Dyn d; - d.d_tag = 0; - d.d_un.d_val = 0; - _entries.push_back(d); - std::memcpy(dest, _entries.data(), this->_fsize); -} - -template <class ELFT> void DynamicTable<ELFT>::createDefaultEntries() { - bool isRela = this->_ctx.isRelaOutputFormat(); - _dt_hash = addEntry(DT_HASH, 0); - _dt_strtab = addEntry(DT_STRTAB, 0); - _dt_symtab = addEntry(DT_SYMTAB, 0); - _dt_strsz = addEntry(DT_STRSZ, 0); - _dt_syment = addEntry(DT_SYMENT, 0); - if (_layout.hasDynamicRelocationTable()) { - _dt_rela = addEntry(isRela ? DT_RELA : DT_REL, 0); - _dt_relasz = addEntry(isRela ? DT_RELASZ : DT_RELSZ, 0); - _dt_relaent = addEntry(isRela ? DT_RELAENT : DT_RELENT, 0); - if (_layout.getDynamicRelocationTable()->canModifyReadonlySection()) - _dt_textrel = addEntry(DT_TEXTREL, 0); - } - if (_layout.hasPLTRelocationTable()) { - _dt_pltrelsz = addEntry(DT_PLTRELSZ, 0); - _dt_pltgot = addEntry(getGotPltTag(), 0); - _dt_pltrel = addEntry(DT_PLTREL, isRela ? DT_RELA : DT_REL); - _dt_jmprel = addEntry(DT_JMPREL, 0); - } -} - -template <class ELFT> void DynamicTable<ELFT>::doPreFlight() { - auto initArray = _layout.findOutputSection(".init_array"); - auto finiArray = _layout.findOutputSection(".fini_array"); - if (initArray) { - _dt_init_array = addEntry(DT_INIT_ARRAY, 0); - _dt_init_arraysz = addEntry(DT_INIT_ARRAYSZ, 0); - } - if (finiArray) { - _dt_fini_array = addEntry(DT_FINI_ARRAY, 0); - _dt_fini_arraysz = addEntry(DT_FINI_ARRAYSZ, 0); - } - if (getInitAtomLayout()) - _dt_init = addEntry(DT_INIT, 0); - if (getFiniAtomLayout()) - _dt_fini = addEntry(DT_FINI, 0); -} - -template <class ELFT> void DynamicTable<ELFT>::finalize() { - StringTable<ELFT> *dynamicStringTable = _dynamicSymbolTable->getStringTable(); - this->_link = dynamicStringTable->ordinal(); - if (this->_outputSection) { - this->_outputSection->setType(this->_type); - this->_outputSection->setInfo(this->_info); - this->_outputSection->setLink(this->_link); - } -} - -template <class ELFT> void DynamicTable<ELFT>::updateDynamicTable() { - StringTable<ELFT> *dynamicStringTable = _dynamicSymbolTable->getStringTable(); - _entries[_dt_hash].d_un.d_val = _hashTable->virtualAddr(); - _entries[_dt_strtab].d_un.d_val = dynamicStringTable->virtualAddr(); - _entries[_dt_symtab].d_un.d_val = _dynamicSymbolTable->virtualAddr(); - _entries[_dt_strsz].d_un.d_val = dynamicStringTable->memSize(); - _entries[_dt_syment].d_un.d_val = _dynamicSymbolTable->getEntSize(); - auto initArray = _layout.findOutputSection(".init_array"); - if (initArray) { - _entries[_dt_init_array].d_un.d_val = initArray->virtualAddr(); - _entries[_dt_init_arraysz].d_un.d_val = initArray->memSize(); - } - auto finiArray = _layout.findOutputSection(".fini_array"); - if (finiArray) { - _entries[_dt_fini_array].d_un.d_val = finiArray->virtualAddr(); - _entries[_dt_fini_arraysz].d_un.d_val = finiArray->memSize(); - } - if (const auto *al = getInitAtomLayout()) - _entries[_dt_init].d_un.d_val = getAtomVirtualAddress(al); - if (const auto *al = getFiniAtomLayout()) - _entries[_dt_fini].d_un.d_val = getAtomVirtualAddress(al); - if (_layout.hasDynamicRelocationTable()) { - auto relaTbl = _layout.getDynamicRelocationTable(); - _entries[_dt_rela].d_un.d_val = relaTbl->virtualAddr(); - _entries[_dt_relasz].d_un.d_val = relaTbl->memSize(); - _entries[_dt_relaent].d_un.d_val = relaTbl->getEntSize(); - } - if (_layout.hasPLTRelocationTable()) { - auto relaTbl = _layout.getPLTRelocationTable(); - _entries[_dt_jmprel].d_un.d_val = relaTbl->virtualAddr(); - _entries[_dt_pltrelsz].d_un.d_val = relaTbl->memSize(); - auto gotplt = _layout.findOutputSection(".got.plt"); - _entries[_dt_pltgot].d_un.d_val = gotplt->virtualAddr(); - } -} - -template <class ELFT> -const AtomLayout *DynamicTable<ELFT>::getInitAtomLayout() { - auto al = _layout.findAtomLayoutByName(this->_ctx.initFunction()); - if (al && isa<DefinedAtom>(al->_atom)) - return al; - return nullptr; -} - -template <class ELFT> -const AtomLayout *DynamicTable<ELFT>::getFiniAtomLayout() { - auto al = _layout.findAtomLayoutByName(this->_ctx.finiFunction()); - if (al && isa<DefinedAtom>(al->_atom)) - return al; - return nullptr; -} - -template <class ELFT> -InterpSection<ELFT>::InterpSection(const ELFLinkingContext &ctx, StringRef str, - int32_t order, StringRef interp) - : Section<ELFT>(ctx, str, "Dynamic:Interp"), _interp(interp) { - this->setOrder(order); - this->_alignment = 1; - // + 1 for null term. - this->_fsize = interp.size() + 1; - this->_msize = this->_fsize; - this->_type = SHT_PROGBITS; - this->_flags = SHF_ALLOC; -} - -template <class ELFT> -void InterpSection<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) { - uint8_t *chunkBuffer = buffer.getBufferStart(); - uint8_t *dest = chunkBuffer + this->fileOffset(); - std::memcpy(dest, _interp.data(), _interp.size()); -} - -template <class ELFT> -HashSection<ELFT>::HashSection(const ELFLinkingContext &ctx, StringRef name, - int32_t order) - : Section<ELFT>(ctx, name, "Dynamic:Hash") { - this->setOrder(order); - this->_entSize = 4; - this->_type = SHT_HASH; - this->_flags = SHF_ALLOC; - this->_alignment = ELFT::Is64Bits ? 8 : 4; - this->_fsize = 0; - this->_msize = 0; -} - -template <class ELFT> -void HashSection<ELFT>::addSymbol(StringRef name, uint32_t index) { - SymbolTableEntry ste; - ste._name = name; - ste._index = index; - _entries.push_back(ste); -} - -/// \brief Set the dynamic symbol table -template <class ELFT> -void HashSection<ELFT>::setSymbolTable( - const DynamicSymbolTable<ELFT> *symbolTable) { - _symbolTable = symbolTable; -} - -template <class ELFT> void HashSection<ELFT>::doPreFlight() { - // The number of buckets to use for a certain number of symbols. - // If there are less than 3 symbols, 1 bucket will be used. If - // there are less than 17 symbols, 3 buckets will be used, and so - // forth. The bucket numbers are defined by GNU ld. We use the - // same rules here so we generate hash sections with the same - // size as those generated by GNU ld. - uint32_t hashBuckets[] = {1, 3, 17, 37, 67, 97, 131, - 197, 263, 521, 1031, 2053, 4099, 8209, - 16411, 32771, 65537, 131101, 262147}; - int hashBucketsCount = sizeof(hashBuckets) / sizeof(uint32_t); - - unsigned int bucketsCount = 0; - unsigned int dynSymCount = _entries.size(); - - // Get the number of buckes that we want to use - for (int i = 0; i < hashBucketsCount; ++i) { - if (dynSymCount < hashBuckets[i]) - break; - bucketsCount = hashBuckets[i]; - } - _buckets.resize(bucketsCount); - _chains.resize(_entries.size()); - - // Create the hash table for the dynamic linker - for (auto ai : _entries) { - unsigned int dynsymIndex = ai._index; - unsigned int bucketpos = llvm::object::elf_hash(ai._name) % bucketsCount; - _chains[dynsymIndex] = _buckets[bucketpos]; - _buckets[bucketpos] = dynsymIndex; - } - - this->_fsize = (2 + _chains.size() + _buckets.size()) * sizeof(uint32_t); - this->_msize = this->_fsize; -} - -template <class ELFT> void HashSection<ELFT>::finalize() { - this->_link = _symbolTable ? _symbolTable->ordinal() : 0; - if (this->_outputSection) - this->_outputSection->setLink(this->_link); -} - -template <class ELFT> -void HashSection<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) { - uint8_t *chunkBuffer = buffer.getBufferStart(); - uint8_t *dest = chunkBuffer + this->fileOffset(); - Elf_Word bucketChainCounts[2]; - bucketChainCounts[0] = _buckets.size(); - bucketChainCounts[1] = _chains.size(); - std::memcpy(dest, bucketChainCounts, sizeof(bucketChainCounts)); - dest += sizeof(bucketChainCounts); - // write bucket values - std::memcpy(dest, _buckets.data(), _buckets.size() * sizeof(Elf_Word)); - dest += _buckets.size() * sizeof(Elf_Word); - // write chain values - std::memcpy(dest, _chains.data(), _chains.size() * sizeof(Elf_Word)); -} - -template <class ELFT> -EHFrameHeader<ELFT>::EHFrameHeader(const ELFLinkingContext &ctx, StringRef name, - TargetLayout<ELFT> &layout, int32_t order) - : Section<ELFT>(ctx, name, "EHFrameHeader"), _layout(layout) { - this->setOrder(order); - this->_entSize = 0; - this->_type = SHT_PROGBITS; - this->_flags = SHF_ALLOC; - this->_alignment = ELFT::Is64Bits ? 8 : 4; - // Minimum size for empty .eh_frame_hdr. - this->_fsize = 1 + 1 + 1 + 1 + 4; - this->_msize = this->_fsize; -} - -template <class ELFT> void EHFrameHeader<ELFT>::doPreFlight() { - // TODO: Generate a proper binary search table. -} - -template <class ELFT> void EHFrameHeader<ELFT>::finalize() { - OutputSection<ELFT> *s = _layout.findOutputSection(".eh_frame"); - OutputSection<ELFT> *h = _layout.findOutputSection(".eh_frame_hdr"); - if (s && h) - _ehFrameOffset = s->virtualAddr() - (h->virtualAddr() + 4); -} - -template <class ELFT> -void EHFrameHeader<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) { - uint8_t *chunkBuffer = buffer.getBufferStart(); - uint8_t *dest = chunkBuffer + this->fileOffset(); - int pos = 0; - dest[pos++] = 1; // version - dest[pos++] = llvm::dwarf::DW_EH_PE_pcrel | - llvm::dwarf::DW_EH_PE_sdata4; // eh_frame_ptr_enc - dest[pos++] = llvm::dwarf::DW_EH_PE_omit; // fde_count_enc - dest[pos++] = llvm::dwarf::DW_EH_PE_omit; // table_enc - *reinterpret_cast<typename llvm::object::ELFFile<ELFT>::Elf_Sword *>( - dest + pos) = _ehFrameOffset; -} - -#define INSTANTIATE(klass) \ - template class klass<ELF32LE>; \ - template class klass<ELF32BE>; \ - template class klass<ELF64LE>; \ - template class klass<ELF64BE> - -INSTANTIATE(AtomSection); -INSTANTIATE(DynamicSymbolTable); -INSTANTIATE(DynamicTable); -INSTANTIATE(EHFrameHeader); -INSTANTIATE(HashSection); -INSTANTIATE(InterpSection); -INSTANTIATE(OutputSection); -INSTANTIATE(RelocationTable); -INSTANTIATE(Section); -INSTANTIATE(StringTable); -INSTANTIATE(SymbolTable); - -} // end namespace elf -} // end namespace lld diff --git a/lib/ReaderWriter/ELF/SectionChunks.h b/lib/ReaderWriter/ELF/SectionChunks.h deleted file mode 100644 index b10ba05237ff..000000000000 --- a/lib/ReaderWriter/ELF/SectionChunks.h +++ /dev/null @@ -1,616 +0,0 @@ -//===- lib/ReaderWriter/ELF/SectionChunks.h -------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_SECTION_CHUNKS_H -#define LLD_READER_WRITER_ELF_SECTION_CHUNKS_H - -#include "Chunk.h" -#include "TargetHandler.h" -#include "Writer.h" -#include "lld/Core/DefinedAtom.h" -#include "lld/Core/range.h" -#include "lld/ReaderWriter/AtomLayout.h" -#include "lld/ReaderWriter/ELFLinkingContext.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Object/ELF.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/ELF.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/FileOutputBuffer.h" -#include <memory> -#include <mutex> - -namespace lld { -namespace elf { -template <class> class OutputSection; -using namespace llvm::ELF; -template <class ELFT> class Segment; -template <class ELFT> class TargetLayout; - -/// \brief An ELF section. -template <class ELFT> class Section : public Chunk<ELFT> { -public: - Section(const ELFLinkingContext &ctx, StringRef sectionName, - StringRef chunkName, - typename Chunk<ELFT>::Kind k = Chunk<ELFT>::Kind::ELFSection); - - /// \brief Modify the section contents before assigning virtual addresses - // or assigning file offsets - - /// \brief Finalize the section contents before writing - - /// \brief Does this section have an output segment. - virtual bool hasOutputSegment() const { return false; } - - /// Return if the section is a loadable section that occupies memory - virtual bool isLoadableSection() const { return false; } - - /// \brief Assign file offsets starting at offset. - virtual void assignFileOffsets(uint64_t offset) {} - - /// \brief Assign virtual addresses starting at addr. - virtual void assignVirtualAddress(uint64_t addr) {} - - uint64_t getFlags() const { return _flags; } - uint64_t getEntSize() const { return _entSize; } - uint32_t getType() const { return _type; } - uint32_t getLink() const { return _link; } - uint32_t getInfo() const { return _info; } - - typename TargetLayout<ELFT>::SegmentType getSegmentType() const { - return _segmentType; - } - - /// \brief Return the type of content that the section contains - int getContentType() const override; - - /// \brief convert the segment type to a String for diagnostics and printing - /// purposes - virtual StringRef segmentKindToStr() const; - - /// \brief Records the segmentType, that this section belongs to - void - setSegmentType(const typename TargetLayout<ELFT>::SegmentType segmentType) { - this->_segmentType = segmentType; - } - - virtual const AtomLayout *findAtomLayoutByName(StringRef) const { - return nullptr; - } - - const OutputSection<ELFT> *getOutputSection() const { - return _outputSection; - } - - void setOutputSection(OutputSection<ELFT> *os, bool isFirst = false) { - _outputSection = os; - _isFirstSectionInOutputSection = isFirst; - } - - static bool classof(const Chunk<ELFT> *c) { - return c->kind() == Chunk<ELFT>::Kind::ELFSection || - c->kind() == Chunk<ELFT>::Kind::AtomSection; - } - - uint64_t alignment() const override { - return _isFirstSectionInOutputSection ? _outputSection->alignment() - : this->_alignment; - } - - virtual StringRef inputSectionName() const { return _inputSectionName; } - - virtual StringRef outputSectionName() const { return _outputSectionName; } - - virtual void setOutputSectionName(StringRef outputSectionName) { - _outputSectionName = outputSectionName; - } - - void setArchiveNameOrPath(StringRef name) { _archivePath = name; } - - void setMemberNameOrPath(StringRef name) { _memberPath = name; } - - StringRef archivePath() { return _archivePath; } - - StringRef memberPath() { return _memberPath; } - -protected: - /// \brief OutputSection this Section is a member of, or nullptr. - OutputSection<ELFT> *_outputSection = nullptr; - /// \brief ELF SHF_* flags. - uint64_t _flags = 0; - /// \brief The size of each entity. - uint64_t _entSize = 0; - /// \brief ELF SHT_* type. - uint32_t _type = 0; - /// \brief sh_link field. - uint32_t _link = 0; - /// \brief the sh_info field. - uint32_t _info = 0; - /// \brief Is this the first section in the output section. - bool _isFirstSectionInOutputSection = false; - /// \brief the output ELF segment type of this section. - typename TargetLayout<ELFT>::SegmentType _segmentType = SHT_NULL; - /// \brief Input section name. - StringRef _inputSectionName; - /// \brief Output section name. - StringRef _outputSectionName; - StringRef _archivePath; - StringRef _memberPath; -}; - -/// \brief A section containing atoms. -template <class ELFT> class AtomSection : public Section<ELFT> { -public: - AtomSection(const ELFLinkingContext &ctx, StringRef sectionName, - int32_t contentType, int32_t permissions, int32_t order); - - /// Align the offset to the required modulus defined by the atom alignment - uint64_t alignOffset(uint64_t offset, DefinedAtom::Alignment &atomAlign); - - /// Return if the section is a loadable section that occupies memory - bool isLoadableSection() const override { return _isLoadedInMemory; } - - // \brief Append an atom to a Section. The atom gets pushed into a vector - // contains the atom, the atom file offset, the atom virtual address - // the atom file offset is aligned appropriately as set by the Reader - virtual const AtomLayout *appendAtom(const Atom *atom); - - /// \brief Set the virtual address of each Atom in the Section. This - /// routine gets called after the linker fixes up the virtual address - /// of the section - void assignVirtualAddress(uint64_t addr) override; - - /// \brief Set the file offset of each Atom in the section. This routine - /// gets called after the linker fixes up the section offset - void assignFileOffsets(uint64_t offset) override; - - /// \brief Find the Atom address given a name, this is needed to properly - /// apply relocation. The section class calls this to find the atom address - /// to fix the relocation - const AtomLayout *findAtomLayoutByName(StringRef name) const override; - - /// \brief Return the raw flags, we need this to sort segments - int64_t atomflags() const { return _contentPermissions; } - - /// Atom Iterators - typedef typename std::vector<AtomLayout *>::iterator atom_iter; - - range<atom_iter> atoms() { return _atoms; } - - void write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) override; - - static bool classof(const Chunk<ELFT> *c) { - return c->kind() == Chunk<ELFT>::Kind::AtomSection; - } - -protected: - llvm::BumpPtrAllocator _alloc; - int32_t _contentType; - int32_t _contentPermissions; - bool _isLoadedInMemory = true; - std::vector<AtomLayout *> _atoms; - mutable std::mutex _outputMutex; - - std::string formatError(const std::string &errorStr, const AtomLayout &atom, - const Reference &ref) const; -}; - -/// \brief A OutputSection represents a set of sections grouped by the same -/// name. The output file that gets written by the linker has sections grouped -/// by similar names -template <class ELFT> class OutputSection { -public: - // Iterators - typedef typename std::vector<Section<ELFT> *>::iterator SectionIter; - - OutputSection(StringRef name) : _name(name) {} - - // Appends a section into the list of sections that are part of this Output - // Section - void appendSection(Section<ELFT> *c); - - // Set the OutputSection is associated with a segment - void setHasSegment() { _hasSegment = true; } - - /// Sets the ordinal - void setOrdinal(uint64_t ordinal) { _ordinal = ordinal; } - - /// Sets the Memory size - void setMemSize(uint64_t memsz) { _memSize = memsz; } - - /// Sets the size fo the output Section. - void setSize(uint64_t fsiz) { _size = fsiz; } - - // The offset of the first section contained in the output section is - // contained here. - void setFileOffset(uint64_t foffset) { _fileOffset = foffset; } - - // Sets the starting address of the section - void setAddr(uint64_t addr) { _virtualAddr = addr; } - - // Is the section loadable? - bool isLoadableSection() const { return _isLoadableSection; } - - // Set section Loadable - void setLoadableSection(bool isLoadable) { - _isLoadableSection = isLoadable; - } - - void setLink(uint64_t link) { _link = link; } - void setInfo(uint64_t info) { _shInfo = info; } - void setFlag(uint64_t flags) { _flags = flags; } - void setType(int64_t type) { _type = type; } - range<SectionIter> sections() { return _sections; } - - // The below functions returns the properties of the OutputSection. - bool hasSegment() const { return _hasSegment; } - StringRef name() const { return _name; } - int64_t shinfo() const { return _shInfo; } - uint64_t alignment() const { return _alignment; } - int64_t link() const { return _link; } - int64_t type() const { return _type; } - uint64_t virtualAddr() const { return _virtualAddr; } - int64_t ordinal() const { return _ordinal; } - int64_t kind() const { return _kind; } - uint64_t fileSize() const { return _size; } - int64_t entsize() const { return _entSize; } - uint64_t fileOffset() const { return _fileOffset; } - uint64_t flags() const { return _flags; } - uint64_t memSize() const { return _memSize; } - -private: - StringRef _name; - bool _hasSegment = false; - uint64_t _ordinal = 0; - uint64_t _flags = 0; - uint64_t _size = 0; - uint64_t _memSize = 0; - uint64_t _fileOffset = 0; - uint64_t _virtualAddr = 0; - int64_t _shInfo = 0; - int64_t _entSize = 0; - int64_t _link = 0; - uint64_t _alignment = 1; - int64_t _kind = 0; - int64_t _type = 0; - bool _isLoadableSection = false; - std::vector<Section<ELFT> *> _sections; -}; - -/// \brief The class represents the ELF String Table -template <class ELFT> class StringTable : public Section<ELFT> { -public: - StringTable(const ELFLinkingContext &, const char *str, int32_t order, - bool dynamic = false); - - uint64_t addString(StringRef symname); - - void write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) override; - - void setNumEntries(int64_t numEntries) { _stringMap.resize(numEntries); } - -private: - std::vector<StringRef> _strings; - - struct StringRefMappingInfo { - static StringRef getEmptyKey() { return StringRef(); } - static StringRef getTombstoneKey() { return StringRef(" ", 1); } - static unsigned getHashValue(StringRef const val) { - return llvm::HashString(val); - } - static bool isEqual(StringRef const lhs, StringRef const rhs) { - return lhs.equals(rhs); - } - }; - typedef typename llvm::DenseMap<StringRef, uint64_t, StringRefMappingInfo> - StringMapT; - typedef typename StringMapT::iterator StringMapTIter; - StringMapT _stringMap; -}; - -/// \brief The SymbolTable class represents the symbol table in a ELF file -template <class ELFT> class SymbolTable : public Section<ELFT> { - typedef - typename llvm::object::ELFDataTypeTypedefHelper<ELFT>::Elf_Addr Elf_Addr; - -public: - typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym; - - SymbolTable(const ELFLinkingContext &ctx, const char *str, int32_t order); - - /// \brief set the number of entries that would exist in the symbol - /// table for the current link - void setNumEntries(int64_t numEntries) const { - if (_stringSection) - _stringSection->setNumEntries(numEntries); - } - - /// \brief return number of entries - std::size_t size() const { return _symbolTable.size(); } - - void addSymbol(const Atom *atom, int32_t sectionIndex, uint64_t addr = 0, - const AtomLayout *layout = nullptr); - - /// \brief Get the symbol table index for an Atom. If it's not in the symbol - /// table, return STN_UNDEF. - uint32_t getSymbolTableIndex(const Atom *a) const { - for (size_t i = 0, e = _symbolTable.size(); i < e; ++i) - if (_symbolTable[i]._atom == a) - return i; - return STN_UNDEF; - } - - void finalize() override { finalize(true); } - - virtual void sortSymbols() { - std::stable_sort(_symbolTable.begin(), _symbolTable.end(), - [](const SymbolEntry &A, const SymbolEntry &B) { - return A._symbol.getBinding() < B._symbol.getBinding(); - }); - } - - virtual void addAbsoluteAtom(Elf_Sym &sym, const AbsoluteAtom *aa, - int64_t addr); - - virtual void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da, - int64_t addr); - - virtual void addUndefinedAtom(Elf_Sym &sym, const UndefinedAtom *ua); - - virtual void addSharedLibAtom(Elf_Sym &sym, const SharedLibraryAtom *sla); - - virtual void finalize(bool sort); - - void write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) override; - - void setStringSection(StringTable<ELFT> *s) { _stringSection = s; } - - StringTable<ELFT> *getStringTable() const { return _stringSection; } - -protected: - struct SymbolEntry { - SymbolEntry(const Atom *a, const Elf_Sym &sym, const AtomLayout *layout) - : _atom(a), _atomLayout(layout), _symbol(sym) {} - - const Atom *_atom; - const AtomLayout *_atomLayout; - Elf_Sym _symbol; - }; - - llvm::BumpPtrAllocator _symbolAllocate; - StringTable<ELFT> *_stringSection; - std::vector<SymbolEntry> _symbolTable; -}; - -template <class ELFT> class HashSection; - -template <class ELFT> class DynamicSymbolTable : public SymbolTable<ELFT> { -public: - DynamicSymbolTable(const ELFLinkingContext &ctx, TargetLayout<ELFT> &layout, - const char *str, int32_t order); - - // Set the dynamic hash table for symbols to be added into - void setHashTable(HashSection<ELFT> *hashTable) { _hashTable = hashTable; } - - // Add all the dynamic symbos to the hash table - void addSymbolsToHashTable(); - - void finalize() override; - -protected: - HashSection<ELFT> *_hashTable = nullptr; - TargetLayout<ELFT> &_layout; -}; - -template <class ELFT> class RelocationTable : public Section<ELFT> { -public: - typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel; - typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela; - - RelocationTable(const ELFLinkingContext &ctx, StringRef str, int32_t order); - - /// \returns the index of the relocation added. - uint32_t addRelocation(const DefinedAtom &da, const Reference &r); - - bool getRelocationIndex(const Reference &r, uint32_t &res); - - void setSymbolTable(const DynamicSymbolTable<ELFT> *symbolTable) { - _symbolTable = symbolTable; - } - - /// \brief Check if any relocation modifies a read-only section. - bool canModifyReadonlySection() const; - - void finalize() override; - - void write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) override; - -protected: - const DynamicSymbolTable<ELFT> *_symbolTable = nullptr; - - virtual void writeRela(ELFWriter *writer, Elf_Rela &r, - const DefinedAtom &atom, const Reference &ref); - virtual void writeRel(ELFWriter *writer, Elf_Rel &r, const DefinedAtom &atom, - const Reference &ref); - uint32_t getSymbolIndex(const Atom *a); - -private: - std::vector<std::pair<const DefinedAtom *, const Reference *>> _relocs; -}; - -template <class ELFT> class HashSection; - -template <class ELFT> class DynamicTable : public Section<ELFT> { -public: - typedef llvm::object::Elf_Dyn_Impl<ELFT> Elf_Dyn; - typedef std::vector<Elf_Dyn> EntriesT; - - DynamicTable(const ELFLinkingContext &ctx, TargetLayout<ELFT> &layout, - StringRef str, int32_t order); - - range<typename EntriesT::iterator> entries() { return _entries; } - - /// \returns the index of the entry. - std::size_t addEntry(int64_t tag, uint64_t val); - - void write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) override; - - virtual void createDefaultEntries(); - void doPreFlight() override; - - /// \brief Dynamic table tag for .got.plt section referencing. - /// Usually but not always targets use DT_PLTGOT for that. - virtual int64_t getGotPltTag() { return DT_PLTGOT; } - - void finalize() override; - - void setSymbolTable(DynamicSymbolTable<ELFT> *dynsym) { - _dynamicSymbolTable = dynsym; - } - - const DynamicSymbolTable<ELFT> *getSymbolTable() const { - return _dynamicSymbolTable; - } - - void setHashTable(HashSection<ELFT> *hsh) { _hashTable = hsh; } - - virtual void updateDynamicTable(); - -protected: - EntriesT _entries; - - /// \brief Return a virtual address (maybe adjusted) for the atom layout - /// Some targets like microMIPS and ARM Thumb use the last bit - /// of a symbol's value to mark 'compressed' code. This function allows - /// to adjust a virtal address before using it in the dynamic table tag. - virtual uint64_t getAtomVirtualAddress(const AtomLayout *al) const { - return al->_virtualAddr; - } - -private: - std::size_t _dt_hash; - std::size_t _dt_strtab; - std::size_t _dt_symtab; - std::size_t _dt_rela; - std::size_t _dt_relasz; - std::size_t _dt_relaent; - std::size_t _dt_strsz; - std::size_t _dt_syment; - std::size_t _dt_pltrelsz; - std::size_t _dt_pltgot; - std::size_t _dt_pltrel; - std::size_t _dt_jmprel; - std::size_t _dt_init_array; - std::size_t _dt_init_arraysz; - std::size_t _dt_fini_array; - std::size_t _dt_fini_arraysz; - std::size_t _dt_textrel; - std::size_t _dt_init; - std::size_t _dt_fini; - TargetLayout<ELFT> &_layout; - DynamicSymbolTable<ELFT> *_dynamicSymbolTable; - HashSection<ELFT> *_hashTable; - - const AtomLayout *getInitAtomLayout(); - - const AtomLayout *getFiniAtomLayout(); -}; - -template <class ELFT> class InterpSection : public Section<ELFT> { -public: - InterpSection(const ELFLinkingContext &ctx, StringRef str, int32_t order, - StringRef interp); - - void write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) override; - -private: - StringRef _interp; -}; - -/// The hash table in the dynamic linker is organized into -/// -/// [ nbuckets ] -/// [ nchains ] -/// [ buckets[0] ] -/// ......................... -/// [ buckets[nbuckets-1] ] -/// [ chains[0] ] -/// ......................... -/// [ chains[nchains - 1] ] -/// -/// nbuckets - total number of hash buckets -/// nchains is equal to the number of dynamic symbols. -/// -/// The symbol is searched by the dynamic linker using the below approach. -/// * Calculate the hash of the symbol that needs to be searched -/// * Take the value from the buckets[hash % nbuckets] as the index of symbol -/// * Compare the symbol's name, if true return, if false, look through the -/// * array since there was a collision -template <class ELFT> class HashSection : public Section<ELFT> { - struct SymbolTableEntry { - StringRef _name; - uint32_t _index; - }; - -public: - HashSection(const ELFLinkingContext &ctx, StringRef name, int32_t order); - - /// \brief add the dynamic symbol into the table so that the - /// hash could be calculated - void addSymbol(StringRef name, uint32_t index); - - /// \brief Set the dynamic symbol table - void setSymbolTable(const DynamicSymbolTable<ELFT> *symbolTable); - - // The size of the section has to be determined so that fileoffsets - // may be properly assigned. Let's calculate the buckets and the chains - // and fill the chains and the buckets hash table used by the dynamic - // linker and update the filesize and memory size accordingly - void doPreFlight() override; - - void finalize() override; - - void write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) override; - -private: - typedef - typename llvm::object::ELFDataTypeTypedefHelper<ELFT>::Elf_Word Elf_Word; - - std::vector<SymbolTableEntry> _entries; - std::vector<Elf_Word> _buckets; - std::vector<Elf_Word> _chains; - const DynamicSymbolTable<ELFT> *_symbolTable = nullptr; -}; - -template <class ELFT> class EHFrameHeader : public Section<ELFT> { -public: - EHFrameHeader(const ELFLinkingContext &ctx, StringRef name, - TargetLayout<ELFT> &layout, int32_t order); - void doPreFlight() override; - void finalize() override; - void write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) override; - -private: - int32_t _ehFrameOffset = 0; - TargetLayout<ELFT> &_layout; -}; - -} // end namespace elf -} // end namespace lld - -#endif // LLD_READER_WRITER_ELF_SECTION_CHUNKS_H diff --git a/lib/ReaderWriter/ELF/SegmentChunks.cpp b/lib/ReaderWriter/ELF/SegmentChunks.cpp deleted file mode 100644 index 99449f7d45aa..000000000000 --- a/lib/ReaderWriter/ELF/SegmentChunks.cpp +++ /dev/null @@ -1,519 +0,0 @@ -//===- lib/ReaderWriter/ELF/SegmentChunks.h -------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "SegmentChunks.h" -#include "TargetLayout.h" - -namespace lld { -namespace elf { - -template <class ELFT> -bool SegmentSlice<ELFT>::compare_slices(SegmentSlice<ELFT> *a, - SegmentSlice<ELFT> *b) { - return a->startSection() < b->startSection(); -} - -template <class ELFT> -Segment<ELFT>::Segment(const ELFLinkingContext &ctx, StringRef name, - const typename TargetLayout<ELFT>::SegmentType type) - : Chunk<ELFT>(name, Chunk<ELFT>::Kind::ELFSegment, ctx), _segmentType(type), - _flags(0), _atomflags(0), _segmentFlags(false) { - this->_alignment = 1; - this->_fsize = 0; - _outputMagic = ctx.getOutputMagic(); -} - -// This function actually is used, but not in all instantiations of Segment. -LLVM_ATTRIBUTE_UNUSED -static DefinedAtom::ContentPermissions toAtomPerms(uint64_t flags) { - switch (flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR)) { - case SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR: - return DefinedAtom::permRWX; - case SHF_ALLOC | SHF_EXECINSTR: - return DefinedAtom::permR_X; - case SHF_ALLOC: - return DefinedAtom::permR__; - case SHF_ALLOC | SHF_WRITE: - return DefinedAtom::permRW_; - default: - return DefinedAtom::permUnknown; - } -} - -// This function actually is used, but not in all instantiations of Segment. -LLVM_ATTRIBUTE_UNUSED -static DefinedAtom::ContentPermissions toAtomPermsSegment(uint64_t flags) { - switch (flags & (llvm::ELF::PF_R | llvm::ELF::PF_W | llvm::ELF::PF_X)) { - case llvm::ELF::PF_R | llvm::ELF::PF_W | llvm::ELF::PF_X: - return DefinedAtom::permRWX; - case llvm::ELF::PF_R | llvm::ELF::PF_X: - return DefinedAtom::permR_X; - case llvm::ELF::PF_R: - return DefinedAtom::permR__; - case llvm::ELF::PF_R | llvm::ELF::PF_W: - return DefinedAtom::permRW_; - default: - return DefinedAtom::permUnknown; - } -} - -template <class ELFT> void Segment<ELFT>::append(Chunk<ELFT> *chunk) { - _sections.push_back(chunk); - Section<ELFT> *section = dyn_cast<Section<ELFT>>(chunk); - if (!section) - return; - if (this->_alignment < section->alignment()) - this->_alignment = section->alignment(); - - if (_segmentFlags) - return; - if (_flags < section->getFlags()) - _flags |= section->getFlags(); - if (_atomflags < toAtomPerms(_flags)) - _atomflags = toAtomPerms(_flags); -} - -template <class ELFT> -bool Segment<ELFT>::compareSegments(Segment<ELFT> *sega, Segment<ELFT> *segb) { - int64_t type1 = sega->segmentType(); - int64_t type2 = segb->segmentType(); - - if (type1 == type2) - return sega->atomflags() < segb->atomflags(); - - // The single PT_PHDR segment is required to precede any loadable - // segment. We simply make it always first. - if (type1 == llvm::ELF::PT_PHDR) - return true; - if (type2 == llvm::ELF::PT_PHDR) - return false; - - // The single PT_INTERP segment is required to precede any loadable - // segment. We simply make it always second. - if (type1 == llvm::ELF::PT_INTERP) - return true; - if (type2 == llvm::ELF::PT_INTERP) - return false; - - // We then put PT_LOAD segments before any other segments. - if (type1 == llvm::ELF::PT_LOAD) - return true; - if (type2 == llvm::ELF::PT_LOAD) - return false; - - // We put the PT_GNU_RELRO segment last, because that is where the - // dynamic linker expects to find it - if (type1 == llvm::ELF::PT_GNU_RELRO) - return false; - if (type2 == llvm::ELF::PT_GNU_RELRO) - return true; - - // We put the PT_TLS segment last except for the PT_GNU_RELRO - // segment, because that is where the dynamic linker expects to find - if (type1 == llvm::ELF::PT_TLS) - return false; - if (type2 == llvm::ELF::PT_TLS) - return true; - - // Otherwise compare the types to establish an arbitrary ordering. - // FIXME: Should figure out if we should just make all other types compare - // equal, but if so, we should probably do the same for atom flags and change - // users of this to use stable_sort. - return type1 < type2; -} - -template <class ELFT> -void Segment<ELFT>::assignFileOffsets(uint64_t startOffset) { - uint64_t fileOffset = startOffset; - uint64_t curSliceFileOffset = fileOffset; - bool isDataPageAlignedForNMagic = false; - bool alignSegments = this->_ctx.alignSegments(); - uint64_t p_align = this->_ctx.getPageSize(); - uint64_t lastVirtualAddress = 0; - - this->setFileOffset(startOffset); - bool changeOffset = false; - uint64_t newOffset = 0; - for (auto &slice : slices()) { - bool isFirstSection = true; - for (auto section : slice->sections()) { - // Handle linker script expressions, which may change the offset - if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(section)) { - if (!isFirstSection) { - changeOffset = true; - newOffset = fileOffset + expr->virtualAddr() - lastVirtualAddress; - } - continue; - } - if (changeOffset) { - changeOffset = false; - fileOffset = newOffset; - } - // Align fileoffset to the alignment of the section. - fileOffset = llvm::RoundUpToAlignment(fileOffset, section->alignment()); - // If the linker outputmagic is set to OutputMagic::NMAGIC, align the Data - // to a page boundary - if (isFirstSection && - _outputMagic != ELFLinkingContext::OutputMagic::NMAGIC && - _outputMagic != ELFLinkingContext::OutputMagic::OMAGIC) { - // Align to a page only if the output is not - // OutputMagic::NMAGIC/OutputMagic::OMAGIC - if (alignSegments) - fileOffset = llvm::RoundUpToAlignment(fileOffset, p_align); - // Align according to ELF spec. - // in p75, http://www.sco.com/developers/devspecs/gabi41.pdf - uint64_t virtualAddress = slice->virtualAddr(); - Section<ELFT> *sect = dyn_cast<Section<ELFT>>(section); - if (sect && sect->isLoadableSection() && - ((virtualAddress & (p_align - 1)) != (fileOffset & (p_align - 1)))) - fileOffset = llvm::RoundUpToAlignment(fileOffset, p_align) + - (virtualAddress % p_align); - } else if (!isDataPageAlignedForNMagic && needAlign(section)) { - fileOffset = - llvm::RoundUpToAlignment(fileOffset, this->_ctx.getPageSize()); - isDataPageAlignedForNMagic = true; - } - if (isFirstSection) { - slice->setFileOffset(fileOffset); - isFirstSection = false; - curSliceFileOffset = fileOffset; - } - section->setFileOffset(fileOffset); - fileOffset += section->fileSize(); - lastVirtualAddress = section->virtualAddr() + section->memSize(); - } - changeOffset = false; - slice->setFileSize(fileOffset - curSliceFileOffset); - } - this->setFileSize(fileOffset - startOffset); -} - -/// \brief Assign virtual addresses to the slices -template <class ELFT> void Segment<ELFT>::assignVirtualAddress(uint64_t addr) { - int startSection = 0; - int currSection = 0; - SectionIter startSectionIter; - - // slice align is set to the max alignment of the chunks that are - // contained in the slice - uint64_t sliceAlign = 0; - // Current slice size - uint64_t curSliceSize = 0; - // Current Slice File Offset - uint64_t curSliceAddress = 0; - - startSectionIter = _sections.begin(); - startSection = 0; - bool isDataPageAlignedForNMagic = false; - uint64_t startAddr = addr; - SegmentSlice<ELFT> *slice = nullptr; - uint64_t tlsStartAddr = 0; - bool alignSegments = this->_ctx.alignSegments(); - StringRef prevOutputSectionName = StringRef(); - uint64_t tbssMemsize = 0; - - // If this is first section in the segment, page align the section start - // address. The linker needs to align the data section to a page boundary - // only if NMAGIC is set. - auto si = _sections.begin(); - if (si != _sections.end()) { - if (alignSegments && - _outputMagic != ELFLinkingContext::OutputMagic::NMAGIC && - _outputMagic != ELFLinkingContext::OutputMagic::OMAGIC) { - // Align to a page only if the output is not - // OutputMagic::NMAGIC/OutputMagic::OMAGIC - startAddr = llvm::RoundUpToAlignment(startAddr, this->_ctx.getPageSize()); - } else if (needAlign(*si)) { - // If the linker outputmagic is set to OutputMagic::NMAGIC, align the - // Data to a page boundary. - startAddr = llvm::RoundUpToAlignment(startAddr, this->_ctx.getPageSize()); - isDataPageAlignedForNMagic = true; - } - // align the startOffset to the section alignment - uint64_t newAddr = llvm::RoundUpToAlignment(startAddr, (*si)->alignment()); - // Handle linker script expressions, which *may update newAddr* if the - // expression assigns to "." - if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(*si)) - expr->evalExpr(newAddr); - curSliceAddress = newAddr; - sliceAlign = (*si)->alignment(); - (*si)->setVirtualAddr(curSliceAddress); - - // Handle TLS. - if (auto section = dyn_cast<Section<ELFT>>(*si)) { - if (section->getSegmentType() == llvm::ELF::PT_TLS) { - tlsStartAddr = - llvm::RoundUpToAlignment(tlsStartAddr, (*si)->alignment()); - section->assignVirtualAddress(tlsStartAddr); - tlsStartAddr += (*si)->memSize(); - } else { - section->assignVirtualAddress(newAddr); - } - } - // TBSS section is special in that it doesn't contribute to memory of any - // segment. If we see a tbss section, don't add memory size to addr The - // fileOffset is automatically taken care of since TBSS section does not - // end up using file size - if ((*si)->order() != TargetLayout<ELFT>::ORDER_TBSS) { - curSliceSize = (*si)->memSize(); - tbssMemsize = 0; - } else { - tbssMemsize = (*si)->memSize(); - } - ++currSection; - ++si; - } - - uint64_t scriptAddr = 0; - bool forceScriptAddr = false; - for (auto e = _sections.end(); si != e; ++si) { - uint64_t curAddr = curSliceAddress + curSliceSize; - if (!isDataPageAlignedForNMagic && needAlign(*si)) { - // If the linker outputmagic is set to OutputMagic::NMAGIC, align the - // Data - // to a page boundary - curAddr = llvm::RoundUpToAlignment(curAddr, this->_ctx.getPageSize()); - isDataPageAlignedForNMagic = true; - } - uint64_t newAddr = llvm::RoundUpToAlignment( - forceScriptAddr ? scriptAddr : curAddr, (*si)->alignment()); - forceScriptAddr = false; - - // Handle linker script expressions, which may force an address change if - // the expression assigns to "." - if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(*si)) { - uint64_t oldAddr = newAddr; - expr->evalExpr(newAddr); - if (oldAddr != newAddr) { - forceScriptAddr = true; - scriptAddr = newAddr; - } - (*si)->setVirtualAddr(newAddr); - continue; - } - Section<ELFT> *sec = dyn_cast<Section<ELFT>>(*si); - StringRef curOutputSectionName = - sec ? sec->outputSectionName() : (*si)->name(); - bool autoCreateSlice = true; - if (curOutputSectionName == prevOutputSectionName) - autoCreateSlice = false; - // If the newAddress computed is more than a page away, let's create - // a separate segment, so that memory is not used up while running. - // Dont create a slice, if the new section falls in the same output - // section as the previous section. - if (autoCreateSlice && ((newAddr - curAddr) > this->_ctx.getPageSize()) && - (_outputMagic != ELFLinkingContext::OutputMagic::NMAGIC && - _outputMagic != ELFLinkingContext::OutputMagic::OMAGIC)) { - auto sliceIter = - std::find_if(_segmentSlices.begin(), _segmentSlices.end(), - [startSection](SegmentSlice<ELFT> *s) -> bool { - return s->startSection() == startSection; - }); - if (sliceIter == _segmentSlices.end()) { - slice = new (_segmentAllocate.Allocate<SegmentSlice<ELFT>>()) - SegmentSlice<ELFT>(); - _segmentSlices.push_back(slice); - } else { - slice = *sliceIter; - } - slice->setStart(startSection); - slice->setSections(make_range(startSectionIter, si)); - slice->setMemSize(curSliceSize); - slice->setAlign(sliceAlign); - slice->setVirtualAddr(curSliceAddress); - // Start new slice - curSliceAddress = newAddr; - if ((*si)->order() == TargetLayout<ELFT>::ORDER_TBSS) - curSliceAddress += tbssMemsize; - (*si)->setVirtualAddr(curSliceAddress); - startSectionIter = si; - startSection = currSection; - if (auto section = dyn_cast<Section<ELFT>>(*si)) - section->assignVirtualAddress(newAddr); - curSliceSize = newAddr - curSliceAddress + (*si)->memSize(); - sliceAlign = (*si)->alignment(); - } else { - if (sliceAlign < (*si)->alignment()) - sliceAlign = (*si)->alignment(); - if ((*si)->order() == TargetLayout<ELFT>::ORDER_TBSS) - newAddr += tbssMemsize; - (*si)->setVirtualAddr(newAddr); - // Handle TLS. - if (auto section = dyn_cast<Section<ELFT>>(*si)) { - if (section->getSegmentType() == llvm::ELF::PT_TLS) { - tlsStartAddr = - llvm::RoundUpToAlignment(tlsStartAddr, (*si)->alignment()); - section->assignVirtualAddress(tlsStartAddr); - tlsStartAddr += (*si)->memSize(); - } else { - section->assignVirtualAddress(newAddr); - } - } - // TBSS section is special in that it doesn't contribute to memory of - // any segment. If we see a tbss section, don't add memory size to addr - // The fileOffset is automatically taken care of since TBSS section does - // not end up using file size. - if ((*si)->order() != TargetLayout<ELFT>::ORDER_TBSS) { - curSliceSize = newAddr - curSliceAddress + (*si)->memSize(); - tbssMemsize = 0; - } else { - // Although TBSS section does not contribute to memory of any segment, - // we still need to keep track its total size to correct write it - // down. Since it is done based on curSliceAddress, we need to add - // add it to virtual address. - tbssMemsize = (*si)->memSize(); - } - } - prevOutputSectionName = curOutputSectionName; - ++currSection; - } - - auto sliceIter = std::find_if(_segmentSlices.begin(), _segmentSlices.end(), - [startSection](SegmentSlice<ELFT> *s) -> bool { - return s->startSection() == startSection; - }); - if (sliceIter == _segmentSlices.end()) { - slice = new (_segmentAllocate.Allocate<SegmentSlice<ELFT>>()) - SegmentSlice<ELFT>(); - _segmentSlices.push_back(slice); - } else { - slice = *sliceIter; - } - - slice->setStart(startSection); - slice->setVirtualAddr(curSliceAddress); - slice->setMemSize(curSliceSize); - slice->setSections(make_range(startSectionIter, _sections.end())); - slice->setAlign(sliceAlign); - - // Set the segment memory size and the virtual address. - this->setMemSize(curSliceAddress - startAddr + curSliceSize); - this->setVirtualAddr(startAddr); - std::stable_sort(_segmentSlices.begin(), _segmentSlices.end(), - SegmentSlice<ELFT>::compare_slices); -} - -// Write the Segment -template <class ELFT> -void Segment<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) { - for (auto slice : slices()) - for (auto section : slice->sections()) - section->write(writer, layout, buffer); -} - -template <class ELFT> int64_t Segment<ELFT>::flags() const { - if (_segmentFlags) - return (int64_t)_flags; - - int64_t fl = 0; - if (_flags & llvm::ELF::SHF_ALLOC) - fl |= llvm::ELF::PF_R; - if (_flags & llvm::ELF::SHF_WRITE) - fl |= llvm::ELF::PF_W; - if (_flags & llvm::ELF::SHF_EXECINSTR) - fl |= llvm::ELF::PF_X; - return fl; -} - -template <class ELFT> void Segment<ELFT>::setSegmentFlags(uint64_t flags) { - assert(!_segmentFlags && "Segment flags have already been set"); - _segmentFlags = true; - _flags = flags; - _atomflags = toAtomPermsSegment(flags); -} - -template <class ELFT> void Segment<ELFT>::finalize() { - // We want to finalize the segment values for now only for non loadable - // segments, since those values are not set in the Layout - if (_segmentType == llvm::ELF::PT_LOAD) - return; - // The size is the difference of the - // last section to the first section, especially for TLS because - // the TLS segment contains both .tdata/.tbss - this->setFileOffset(_sections.front()->fileOffset()); - this->setVirtualAddr(_sections.front()->virtualAddr()); - size_t startFileOffset = _sections.front()->fileOffset(); - size_t startAddr = _sections.front()->virtualAddr(); - for (auto ai : _sections) { - this->_fsize = ai->fileOffset() + ai->fileSize() - startFileOffset; - this->_msize = ai->virtualAddr() + ai->memSize() - startAddr; - } -} - -template <class ELFT> int Segment<ELFT>::getContentType() const { - int64_t fl = flags(); - switch (_segmentType) { - case llvm::ELF::PT_LOAD: { - if (fl && llvm::ELF::PF_X) - return Chunk<ELFT>::ContentType::Code; - if (fl && llvm::ELF::PF_W) - return Chunk<ELFT>::ContentType::Data; - } - case llvm::ELF::PT_TLS: - return Chunk<ELFT>::ContentType::TLS; - case llvm::ELF::PT_NOTE: - return Chunk<ELFT>::ContentType::Note; - default: - return Chunk<ELFT>::ContentType::Unknown; - } -} - -template <class ELFT> int64_t Segment<ELFT>::atomflags() const { - switch (_atomflags) { - case DefinedAtom::permUnknown: - return permUnknown; - case DefinedAtom::permRWX: - return permRWX; - case DefinedAtom::permR_X: - return permRX; - case DefinedAtom::permR__: - return permR; - case DefinedAtom::permRW_L: - return permRWL; - case DefinedAtom::permRW_: - return permRW; - case DefinedAtom::perm___: - default: - return permNonAccess; - } -} - -/// \brief Check if the chunk needs to be aligned -template <class ELFT> bool Segment<ELFT>::needAlign(Chunk<ELFT> *chunk) const { - if (chunk->getContentType() == Chunk<ELFT>::ContentType::Data && - _outputMagic == ELFLinkingContext::OutputMagic::NMAGIC) - return true; - return false; -} - -template <class ELFT> void ProgramHeaderSegment<ELFT>::finalize() { - // If the segment is of type Program Header, then the values fileOffset - // and the fileSize need to be picked up from the last section, the first - // section points to the ELF header and the second chunk points to the - // actual program headers - this->setFileOffset(this->_sections.back()->fileOffset()); - this->setVirtualAddr(this->_sections.back()->virtualAddr()); - this->_fsize = this->_sections.back()->fileSize(); - this->_msize = this->_sections.back()->memSize(); -} - -#define INSTANTIATE(klass) \ - template class klass<ELF32LE>; \ - template class klass<ELF32BE>; \ - template class klass<ELF64LE>; \ - template class klass<ELF64BE> - -INSTANTIATE(ExpressionChunk); -INSTANTIATE(ProgramHeaderSegment); -INSTANTIATE(Segment); -INSTANTIATE(SegmentSlice); - -} // end namespace elf -} // end namespace lld diff --git a/lib/ReaderWriter/ELF/SegmentChunks.h b/lib/ReaderWriter/ELF/SegmentChunks.h deleted file mode 100644 index b444f44c04eb..000000000000 --- a/lib/ReaderWriter/ELF/SegmentChunks.h +++ /dev/null @@ -1,246 +0,0 @@ -//===- lib/ReaderWriter/ELF/SegmentChunks.h -------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_SEGMENT_CHUNKS_H -#define LLD_READER_WRITER_ELF_SEGMENT_CHUNKS_H - -#include "Chunk.h" -#include "SectionChunks.h" -#include "Writer.h" -#include "lld/Core/range.h" -#include "lld/Core/Writer.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Object/ELF.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/ELF.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/FileOutputBuffer.h" -#include <memory> - -namespace lld { -namespace elf { - -template <typename ELFT> class TargetLayout; - -/// \brief A segment can be divided into segment slices -/// depending on how the segments can be split -template<class ELFT> -class SegmentSlice { -public: - typedef typename std::vector<Chunk<ELFT> *>::iterator SectionIter; - - /// Set the start of the slice. - void setStart(int32_t s) { _startSection = s; } - - // Set the segment slice start and end iterators. This is used to walk through - // the sections that are part of the Segment slice - void setSections(range<SectionIter> sections) { _sections = sections; } - - // Return the fileOffset of the slice - uint64_t fileOffset() const { return _offset; } - void setFileOffset(uint64_t offset) { _offset = offset; } - - // Return the size of the slice - uint64_t fileSize() const { return _fsize; } - void setFileSize(uint64_t filesz) { _fsize = filesz; } - - // Return the start of the slice - int32_t startSection() const { return _startSection; } - - // Return the start address of the slice - uint64_t virtualAddr() const { return _addr; } - - // Return the memory size of the slice - uint64_t memSize() const { return _memSize; } - - // Return the alignment of the slice - uint64_t alignment() const { return _alignment; } - - void setMemSize(uint64_t memsz) { _memSize = memsz; } - - void setVirtualAddr(uint64_t addr) { _addr = addr; } - - void setAlign(uint64_t align) { _alignment = align; } - - static bool compare_slices(SegmentSlice<ELFT> *a, SegmentSlice<ELFT> *b); - - range<SectionIter> sections() { return _sections; } - -private: - range<SectionIter> _sections; - int32_t _startSection; - uint64_t _addr; - uint64_t _offset; - uint64_t _alignment; - uint64_t _fsize; - uint64_t _memSize; -}; - -/// \brief A segment contains a set of sections, that have similar properties -// the sections are already separated based on different flags and properties -// the segment is just a way to concatenate sections to segments -template<class ELFT> -class Segment : public Chunk<ELFT> { -public: - typedef typename std::vector<SegmentSlice<ELFT> *>::iterator SliceIter; - typedef typename std::vector<Chunk<ELFT> *>::iterator SectionIter; - - Segment(const ELFLinkingContext &ctx, StringRef name, - const typename TargetLayout<ELFT>::SegmentType type); - - /// \brief the Order of segments that appear in the output file - enum SegmentOrder { - permUnknown, - permRWX, - permRX, - permR, - permRWL, - permRW, - permNonAccess - }; - - /// append a section to a segment - virtual void append(Chunk<ELFT> *chunk); - - /// Sort segments depending on the property - /// If we have a Program Header segment, it should appear first - /// If we have a INTERP segment, that should appear after the Program Header - /// All Loadable segments appear next in this order - /// All Read Write Execute segments follow - /// All Read Execute segments appear next - /// All Read only segments appear first - /// All Write execute segments follow - static bool compareSegments(Segment<ELFT> *sega, Segment<ELFT> *segb); - - /// \brief Start assigning file offset to the segment chunks The fileoffset - /// needs to be page at the start of the segment and in addition the - /// fileoffset needs to be aligned to the max section alignment within the - /// segment. This is required so that the ELF property p_poffset % p_align = - /// p_vaddr mod p_align holds true. - /// The algorithm starts off by assigning the startOffset thats passed in as - /// parameter to the first section in the segment, if the difference between - /// the newly computed offset is greater than a page, then we create a segment - /// slice, as it would be a waste of virtual memory just to be filled with - /// zeroes - void assignFileOffsets(uint64_t startOffset); - - /// \brief Assign virtual addresses to the slices - void assignVirtualAddress(uint64_t addr); - - // Write the Segment - void write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) override; - - int64_t flags() const; - - // Set segment flags directly. - void setSegmentFlags(uint64_t flags); - - /// Prepend a generic chunk to the segment. - void prepend(Chunk<ELFT> *c) { - _sections.insert(_sections.begin(), c); - } - - /// Finalize the segment, before we want to write the segment header - /// information - void finalize() override; - - // For LLVM RTTI - static bool classof(const Chunk<ELFT> *c) { - return c->kind() == Chunk<ELFT>::Kind::ELFSegment; - } - - // Getters - int32_t sectionCount() const { return _sections.size(); } - - /// \brief, this function returns the type of segment (PT_*) - typename TargetLayout<ELFT>::SegmentType segmentType() const { - return _segmentType; - } - - /// \brief return the segment type depending on the content, - /// If the content corresponds to Code, this will return Segment::Code - /// If the content corresponds to Data, this will return Segment::Data - /// If the content corresponds to TLS, this will return Segment::TLS - int getContentType() const override; - - int pageSize() const { return this->_ctx.getPageSize(); } - int rawflags() const { return _atomflags; } - int64_t atomflags() const; - int64_t numSlices() const { return _segmentSlices.size(); } - range<SliceIter> slices() { return _segmentSlices; } - Chunk<ELFT> *firstSection() { return _sections[0]; } - -private: - /// \brief Check if the chunk needs to be aligned - bool needAlign(Chunk<ELFT> *chunk) const; - - // Cached value of outputMagic - ELFLinkingContext::OutputMagic _outputMagic; - -protected: - /// \brief Section or some other chunk type. - std::vector<Chunk<ELFT> *> _sections; - std::vector<SegmentSlice<ELFT> *> _segmentSlices; - typename TargetLayout<ELFT>::SegmentType _segmentType; - uint64_t _flags; - int64_t _atomflags; - bool _segmentFlags; - llvm::BumpPtrAllocator _segmentAllocate; -}; - -/// This chunk represents a linker script expression that needs to be calculated -/// at the time the virtual addresses for the parent segment are being assigned. -template <class ELFT> class ExpressionChunk : public Chunk<ELFT> { -public: - ExpressionChunk(ELFLinkingContext &ctx, const script::SymbolAssignment *expr) - : Chunk<ELFT>(StringRef(), Chunk<ELFT>::Kind::Expression, ctx), - _expr(expr), _linkerScriptSema(ctx.linkerScriptSema()) { - this->_alignment = 1; - } - - static bool classof(const Chunk<ELFT> *c) { - return c->kind() == Chunk<ELFT>::Kind::Expression; - } - - int getContentType() const override { - return Chunk<ELFT>::ContentType::Unknown; - } - - void write(ELFWriter *, TargetLayout<ELFT> &, - llvm::FileOutputBuffer &) override {} - - std::error_code evalExpr(uint64_t &curPos) { - return _linkerScriptSema.evalExpr(_expr, curPos); - } - -private: - const script::SymbolAssignment *_expr; - script::Sema &_linkerScriptSema; -}; - -/// \brief A Program Header segment contains a set of chunks instead of sections -/// The segment doesn't contain any slice -template <class ELFT> class ProgramHeaderSegment : public Segment<ELFT> { -public: - ProgramHeaderSegment(const ELFLinkingContext &ctx) - : Segment<ELFT>(ctx, "PHDR", llvm::ELF::PT_PHDR) { - this->_alignment = 8; - this->_flags = (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR); - } - - /// Finalize the segment, before we want to write the segment header - /// information - void finalize() override; -}; - -} // end namespace elf -} // end namespace lld - -#endif // LLD_READER_WRITER_ELF_SEGMENT_CHUNKS_H diff --git a/lib/ReaderWriter/ELF/TODO.txt b/lib/ReaderWriter/ELF/TODO.txt deleted file mode 100644 index 90c334b781ba..000000000000 --- a/lib/ReaderWriter/ELF/TODO.txt +++ /dev/null @@ -1,18 +0,0 @@ -lib/ReaderWriter/ELF -~~~~~~~~~~~~~~~~~~~~ - -- Implement processing of DT_NEEDED elements including -rpath-link / - -rpath processing. - -- _GLOBAL_OFFSET_TABLE should be hidden and normally dropped from the output. - -- Merge SHT_NOTE sections only if applicable. - -- Do not create __got_* / __plt_* symbol table entries by default. - -- Weak references to symbols defined in a DSO should remain weak. - -- Fix section flags as they appear in input (update content permissions) - -- Check for errors in the ELFReader when creating atoms for LinkOnce - sections/Group sections. Add tests to account for the change when it happens. diff --git a/lib/ReaderWriter/ELF/TargetHandler.h b/lib/ReaderWriter/ELF/TargetHandler.h deleted file mode 100644 index 406ac670fc83..000000000000 --- a/lib/ReaderWriter/ELF/TargetHandler.h +++ /dev/null @@ -1,35 +0,0 @@ -//===- lib/ReaderWriter/ELF/TargetHandler.h -------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_TARGET_HANDLER_H -#define LLD_READER_WRITER_ELF_TARGET_HANDLER_H - -#include "lld/Core/Error.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Support/ErrorHandling.h" - -namespace lld { -namespace elf { - -inline std::error_code make_unhandled_reloc_error() { - return make_dynamic_error_code("Unhandled reference type"); -} - -inline std::error_code make_out_of_range_reloc_error() { - return make_dynamic_error_code("Relocation out of range"); -} - -inline std::error_code make_unaligned_range_reloc_error() { - return make_dynamic_error_code("Relocation not aligned"); -} - -} // end namespace elf -} // end namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/TargetLayout.cpp b/lib/ReaderWriter/ELF/TargetLayout.cpp deleted file mode 100644 index 09c49f62d64f..000000000000 --- a/lib/ReaderWriter/ELF/TargetLayout.cpp +++ /dev/null @@ -1,747 +0,0 @@ -//===- lib/ReaderWriter/ELF/TargetLayout.cpp ------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "TargetLayout.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/Errc.h" - -namespace lld { -namespace elf { - -template <class ELFT> -typename TargetLayout<ELFT>::SectionOrder -TargetLayout<ELFT>::getSectionOrder(StringRef name, int32_t contentType, - int32_t contentPermissions) { - switch (contentType) { - case DefinedAtom::typeResolver: - case DefinedAtom::typeCode: - return llvm::StringSwitch<typename TargetLayout<ELFT>::SectionOrder>(name) - .StartsWith(".eh_frame_hdr", ORDER_EH_FRAMEHDR) - .StartsWith(".eh_frame", ORDER_EH_FRAME) - .StartsWith(".init", ORDER_INIT) - .StartsWith(".fini", ORDER_FINI) - .StartsWith(".hash", ORDER_HASH) - .Default(ORDER_TEXT); - - case DefinedAtom::typeConstant: - return ORDER_RODATA; - - case DefinedAtom::typeData: - case DefinedAtom::typeDataFast: - return llvm::StringSwitch<typename TargetLayout<ELFT>::SectionOrder>(name) - .StartsWith(".init_array", ORDER_INIT_ARRAY) - .StartsWith(".fini_array", ORDER_FINI_ARRAY) - .StartsWith(".dynamic", ORDER_DYNAMIC) - .StartsWith(".ctors", ORDER_CTORS) - .StartsWith(".dtors", ORDER_DTORS) - .Default(ORDER_DATA); - - case DefinedAtom::typeZeroFill: - case DefinedAtom::typeZeroFillFast: - return ORDER_BSS; - - case DefinedAtom::typeGOT: - return llvm::StringSwitch<typename TargetLayout<ELFT>::SectionOrder>(name) - .StartsWith(".got.plt", ORDER_GOT_PLT) - .Default(ORDER_GOT); - - case DefinedAtom::typeStub: - return ORDER_PLT; - - case DefinedAtom::typeRONote: - return ORDER_RO_NOTE; - - case DefinedAtom::typeRWNote: - return ORDER_RW_NOTE; - - case DefinedAtom::typeNoAlloc: - return ORDER_NOALLOC; - - case DefinedAtom::typeThreadData: - return ORDER_TDATA; - case DefinedAtom::typeThreadZeroFill: - return ORDER_TBSS; - default: - // If we get passed in a section push it to OTHER - if (contentPermissions == DefinedAtom::perm___) - return ORDER_OTHER; - - return ORDER_NOT_DEFINED; - } -} - -/// \brief This maps the input sections to the output section names -template <class ELFT> -StringRef TargetLayout<ELFT>::getInputSectionName(const DefinedAtom *da) const { - if (da->sectionChoice() == DefinedAtom::sectionBasedOnContent) { - switch (da->contentType()) { - case DefinedAtom::typeCode: - return ".text"; - case DefinedAtom::typeData: - return ".data"; - case DefinedAtom::typeConstant: - return ".rodata"; - case DefinedAtom::typeZeroFill: - return ".bss"; - case DefinedAtom::typeThreadData: - return ".tdata"; - case DefinedAtom::typeThreadZeroFill: - return ".tbss"; - default: - break; - } - } - return da->customSectionName(); -} - -/// \brief This maps the input sections to the output section names. -template <class ELFT> -StringRef -TargetLayout<ELFT>::getOutputSectionName(StringRef archivePath, - StringRef memberPath, - StringRef inputSectionName) const { - StringRef outputSectionName; - if (_linkerScriptSema.hasLayoutCommands()) { - script::Sema::SectionKey key = {archivePath, memberPath, inputSectionName}; - outputSectionName = _linkerScriptSema.getOutputSection(key); - if (!outputSectionName.empty()) - return outputSectionName; - } - return llvm::StringSwitch<StringRef>(inputSectionName) - .StartsWith(".text", ".text") - .StartsWith(".ctors", ".ctors") - .StartsWith(".dtors", ".dtors") - .StartsWith(".rodata", ".rodata") - .StartsWith(".gcc_except_table", ".gcc_except_table") - .StartsWith(".data.rel.ro", ".data.rel.ro") - .StartsWith(".data.rel.local", ".data.rel.local") - .StartsWith(".data", ".data") - .StartsWith(".tdata", ".tdata") - .StartsWith(".tbss", ".tbss") - .StartsWith(".init_array", ".init_array") - .StartsWith(".fini_array", ".fini_array") - .Default(inputSectionName); -} - -/// \brief Gets the segment for a output section -template <class ELFT> -typename TargetLayout<ELFT>::SegmentType -TargetLayout<ELFT>::getSegmentType(const Section<ELFT> *section) const { - switch (section->order()) { - case ORDER_INTERP: - return llvm::ELF::PT_INTERP; - - case ORDER_TEXT: - case ORDER_HASH: - case ORDER_DYNAMIC_SYMBOLS: - case ORDER_DYNAMIC_STRINGS: - case ORDER_DYNAMIC_RELOCS: - case ORDER_DYNAMIC_PLT_RELOCS: - case ORDER_REL: - case ORDER_INIT: - case ORDER_PLT: - case ORDER_FINI: - case ORDER_RODATA: - case ORDER_EH_FRAME: - case ORDER_CTORS: - case ORDER_DTORS: - return llvm::ELF::PT_LOAD; - - case ORDER_RO_NOTE: - case ORDER_RW_NOTE: - return llvm::ELF::PT_NOTE; - - case ORDER_DYNAMIC: - return llvm::ELF::PT_DYNAMIC; - - case ORDER_EH_FRAMEHDR: - return llvm::ELF::PT_GNU_EH_FRAME; - - case ORDER_GOT: - case ORDER_GOT_PLT: - case ORDER_DATA: - case ORDER_BSS: - case ORDER_INIT_ARRAY: - case ORDER_FINI_ARRAY: - return llvm::ELF::PT_LOAD; - - case ORDER_TDATA: - case ORDER_TBSS: - return llvm::ELF::PT_TLS; - - default: - return llvm::ELF::PT_NULL; - } -} - -template <class ELFT> -bool TargetLayout<ELFT>::hasOutputSegment(Section<ELFT> *section) { - switch (section->order()) { - case ORDER_INTERP: - case ORDER_HASH: - case ORDER_DYNAMIC_SYMBOLS: - case ORDER_DYNAMIC_STRINGS: - case ORDER_DYNAMIC_RELOCS: - case ORDER_DYNAMIC_PLT_RELOCS: - case ORDER_REL: - case ORDER_INIT: - case ORDER_PLT: - case ORDER_TEXT: - case ORDER_FINI: - case ORDER_RODATA: - case ORDER_EH_FRAME: - case ORDER_EH_FRAMEHDR: - case ORDER_TDATA: - case ORDER_TBSS: - case ORDER_RO_NOTE: - case ORDER_RW_NOTE: - case ORDER_DYNAMIC: - case ORDER_CTORS: - case ORDER_DTORS: - case ORDER_GOT: - case ORDER_GOT_PLT: - case ORDER_DATA: - case ORDER_INIT_ARRAY: - case ORDER_FINI_ARRAY: - case ORDER_BSS: - case ORDER_NOALLOC: - return true; - default: - return section->hasOutputSegment(); - } -} - -template <class ELFT> -AtomSection<ELFT> * -TargetLayout<ELFT>::createSection(StringRef sectionName, int32_t contentType, - DefinedAtom::ContentPermissions permissions, - SectionOrder sectionOrder) { - return new (_allocator) AtomSection<ELFT>(_ctx, sectionName, contentType, - permissions, sectionOrder); -} - -template <class ELFT> -AtomSection<ELFT> * -TargetLayout<ELFT>::getSection(StringRef sectionName, int32_t contentType, - DefinedAtom::ContentPermissions permissions, - const DefinedAtom *da) { - const SectionKey sectionKey(sectionName, permissions, da->file().path()); - SectionOrder sectionOrder = - getSectionOrder(sectionName, contentType, permissions); - auto sec = _sectionMap.find(sectionKey); - if (sec != _sectionMap.end()) - return sec->second; - AtomSection<ELFT> *newSec = - createSection(sectionName, contentType, permissions, sectionOrder); - - newSec->setOutputSectionName(getOutputSectionName( - da->file().archivePath(), da->file().memberPath(), sectionName)); - newSec->setOrder(sectionOrder); - newSec->setArchiveNameOrPath(da->file().archivePath()); - newSec->setMemberNameOrPath(da->file().memberPath()); - _sections.push_back(newSec); - _sectionMap.insert(std::make_pair(sectionKey, newSec)); - return newSec; -} - -template <class ELFT> -ErrorOr<const AtomLayout *> TargetLayout<ELFT>::addAtom(const Atom *atom) { - if (const DefinedAtom *definedAtom = dyn_cast<DefinedAtom>(atom)) { - // HACK: Ignore undefined atoms. We need to adjust the interface so that - // undefined atoms can still be included in the output symbol table for - // -noinhibit-exec. - if (definedAtom->contentType() == DefinedAtom::typeUnknown) - return make_error_code(llvm::errc::invalid_argument); - const DefinedAtom::ContentPermissions permissions = - definedAtom->permissions(); - const DefinedAtom::ContentType contentType = definedAtom->contentType(); - - StringRef sectionName = getInputSectionName(definedAtom); - AtomSection<ELFT> *section = - getSection(sectionName, contentType, permissions, definedAtom); - - // Add runtime relocations to the .rela section. - for (const auto &reloc : *definedAtom) { - bool isLocalReloc = true; - if (_ctx.isDynamicRelocation(*reloc)) { - getDynamicRelocationTable()->addRelocation(*definedAtom, *reloc); - isLocalReloc = false; - } else if (_ctx.isPLTRelocation(*reloc)) { - getPLTRelocationTable()->addRelocation(*definedAtom, *reloc); - isLocalReloc = false; - } - - if (!reloc->target()) - continue; - - // Ignore undefined atoms that are not target of dynamic relocations - if (isa<UndefinedAtom>(reloc->target()) && isLocalReloc) - continue; - - if (_ctx.isCopyRelocation(*reloc)) { - _copiedDynSymNames.insert(definedAtom->name()); - continue; - } - - _referencedDynAtoms.insert(reloc->target()); - } - return section->appendAtom(atom); - } - - const AbsoluteAtom *absoluteAtom = cast<AbsoluteAtom>(atom); - // Absolute atoms are not part of any section, they are global for the whole - // link - _absoluteAtoms.push_back( - new (_allocator) AtomLayout(absoluteAtom, 0, absoluteAtom->value())); - return _absoluteAtoms.back(); -} - -/// Output sections with the same name into a OutputSection -template <class ELFT> void TargetLayout<ELFT>::createOutputSections() { - OutputSection<ELFT> *outputSection; - - for (auto &si : _sections) { - Section<ELFT> *section = dyn_cast<Section<ELFT>>(si); - if (!section) - continue; - const std::pair<StringRef, OutputSection<ELFT> *> currentOutputSection( - section->outputSectionName(), nullptr); - std::pair<typename OutputSectionMapT::iterator, bool> outputSectionInsert( - _outputSectionMap.insert(currentOutputSection)); - if (!outputSectionInsert.second) { - outputSection = outputSectionInsert.first->second; - } else { - outputSection = new (_allocator.Allocate<OutputSection<ELFT>>()) - OutputSection<ELFT>(section->outputSectionName()); - _outputSections.push_back(outputSection); - outputSectionInsert.first->second = outputSection; - } - outputSection->appendSection(section); - } -} - -template <class ELFT> -std::vector<typename TargetLayout<ELFT>::SegmentKey> -TargetLayout<ELFT>::getSegmentsForSection(const OutputSection<ELFT> *os, - const Section<ELFT> *sec) const { - std::vector<SegmentKey> segKeys; - auto phdrs = _linkerScriptSema.getPHDRsForOutputSection(os->name()); - if (!phdrs.empty()) { - if (phdrs.size() == 1 && phdrs[0]->isNone()) { - segKeys.emplace_back("NONE", llvm::ELF::PT_NULL, 0, false); - return segKeys; - } - - for (auto phdr : phdrs) { - segKeys.emplace_back(phdr->name(), phdr->type(), phdr->flags(), true); - } - return segKeys; - } - - uint64_t flags = getLookupSectionFlags(os); - int64_t segmentType = getSegmentType(sec); - StringRef segmentName = sec->segmentKindToStr(); - - // We need a separate segment for sections that don't have - // the segment type to be PT_LOAD - if (segmentType != llvm::ELF::PT_LOAD) - segKeys.emplace_back(segmentName, segmentType, flags, false); - - if (segmentType == llvm::ELF::PT_NULL) - return segKeys; - - // If the output magic is set to OutputMagic::NMAGIC or - // OutputMagic::OMAGIC, Place the data alongside text in one single - // segment - ELFLinkingContext::OutputMagic outputMagic = _ctx.getOutputMagic(); - if (outputMagic == ELFLinkingContext::OutputMagic::NMAGIC || - outputMagic == ELFLinkingContext::OutputMagic::OMAGIC) - flags = - llvm::ELF::SHF_EXECINSTR | llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE; - - segKeys.emplace_back("LOAD", llvm::ELF::PT_LOAD, flags, false); - return segKeys; -} - -template <class ELFT> -uint64_t -TargetLayout<ELFT>::getLookupSectionFlags(const OutputSection<ELFT> *os) const { - uint64_t flags = os->flags(); - if (!(flags & llvm::ELF::SHF_WRITE) && _ctx.mergeRODataToTextSegment()) - flags &= ~llvm::ELF::SHF_EXECINSTR; - - // Merge string sections into Data segment itself - flags &= ~(llvm::ELF::SHF_STRINGS | llvm::ELF::SHF_MERGE); - - // Merge the TLS section into the DATA segment itself - flags &= ~(llvm::ELF::SHF_TLS); - return flags; -} - -template <class ELFT> void TargetLayout<ELFT>::assignSectionsToSegments() { - ScopedTask task(getDefaultDomain(), "assignSectionsToSegments"); - // sort the sections by their order as defined by the layout - sortInputSections(); - - // Create output sections. - createOutputSections(); - - // Finalize output section layout. - finalizeOutputSectionLayout(); - - // Set the ordinal after sorting the sections - int ordinal = 1; - for (auto osi : _outputSections) { - osi->setOrdinal(ordinal); - for (auto ai : osi->sections()) { - ai->setOrdinal(ordinal); - } - ++ordinal; - } - for (auto osi : _outputSections) { - for (auto section : osi->sections()) { - if (!hasOutputSegment(section)) - continue; - - osi->setLoadableSection(section->isLoadableSection()); - osi->setHasSegment(); - - auto segKeys = getSegmentsForSection(osi, section); - assert(!segKeys.empty() && "Must always be at least one segment"); - section->setSegmentType(segKeys[0]._type); - - for (auto key : segKeys) { - // Try to find non-load (real) segment type if possible - if (key._type != llvm::ELF::PT_LOAD) - section->setSegmentType(key._type); - - const std::pair<SegmentKey, Segment<ELFT> *> currentSegment(key, - nullptr); - std::pair<typename SegmentMapT::iterator, bool> segmentInsert( - _segmentMap.insert(currentSegment)); - Segment<ELFT> *segment; - if (!segmentInsert.second) { - segment = segmentInsert.first->second; - } else { - segment = new (_allocator) Segment<ELFT>(_ctx, key._name, key._type); - if (key._segmentFlags) - segment->setSegmentFlags(key._flags); - segmentInsert.first->second = segment; - _segments.push_back(segment); - } - if (key._type == llvm::ELF::PT_LOAD) { - // Insert chunks with linker script expressions that occur at this - // point, just before appending a new input section - addExtraChunksToSegment(segment, section->archivePath(), - section->memberPath(), - section->inputSectionName()); - } - segment->append(section); - } - } - } - - // Default values if no linker script is available - bool hasProgramSegment = _ctx.isDynamic() && !_ctx.isDynamicLibrary(); - bool hasElfHeader = true; - bool hasProgramHeader = true; - uint64_t segmentFlags = 0; - - // Check if linker script has PHDRS and program segment defined - if (_linkerScriptSema.hasPHDRs()) { - if (auto p = _linkerScriptSema.getProgramPHDR()) { - hasProgramSegment = true; - hasElfHeader = p->hasFileHdr(); - hasProgramHeader = p->hasPHDRs(); - segmentFlags = p->flags(); - } else { - hasProgramSegment = false; - hasElfHeader = false; - hasProgramHeader = false; - } - } - - if (hasProgramSegment) { - Segment<ELFT> *segment = new (_allocator) ProgramHeaderSegment<ELFT>(_ctx); - _segments.push_back(segment); - if (segmentFlags) - segment->setSegmentFlags(segmentFlags); - if (hasElfHeader) - segment->append(_elfHeader); - if (hasProgramHeader) - segment->append(_programHeader); - } -} - -template <class ELFT> void TargetLayout<ELFT>::sortSegments() { - std::sort(_segments.begin(), _segments.end(), Segment<ELFT>::compareSegments); -} - -template <class ELFT> void TargetLayout<ELFT>::assignVirtualAddress() { - if (_segments.empty()) - return; - - sortSegments(); - - uint64_t baseAddress = _ctx.getBaseAddress(); - - // HACK: This is a super dirty hack. The elf header and program header are - // not part of a section, but we need them to be loaded at the base address - // so that AT_PHDR is set correctly by the loader and so they are accessible - // at runtime. To do this we simply prepend them to the first loadable Segment - // and let the layout logic take care of it. - Segment<ELFT> *firstLoadSegment = nullptr; - for (auto si : _segments) { - if (si->segmentType() == llvm::ELF::PT_LOAD) { - firstLoadSegment = si; - si->firstSection()->setAlign(si->alignment()); - break; - } - } - assert(firstLoadSegment != nullptr && "No loadable segment!"); - firstLoadSegment->prepend(_programHeader); - firstLoadSegment->prepend(_elfHeader); - bool newSegmentHeaderAdded = true; - bool virtualAddressAssigned = false; - bool fileOffsetAssigned = false; - while (true) { - for (auto si : _segments) { - si->finalize(); - // Don't add PT_NULL segments into the program header - if (si->segmentType() != llvm::ELF::PT_NULL) - newSegmentHeaderAdded = _programHeader->addSegment(si); - } - if (!newSegmentHeaderAdded && virtualAddressAssigned) - break; - uint64_t address = baseAddress; - // start assigning virtual addresses - for (auto &si : _segments) { - if ((si->segmentType() != llvm::ELF::PT_LOAD) && - (si->segmentType() != llvm::ELF::PT_NULL)) - continue; - - if (si->segmentType() == llvm::ELF::PT_NULL) { - si->assignVirtualAddress(0 /*non loadable*/); - } else { - if (virtualAddressAssigned && (address != baseAddress) && - (address == si->virtualAddr())) - break; - si->assignVirtualAddress(address); - } - address = si->virtualAddr() + si->memSize(); - } - uint64_t baseFileOffset = 0; - uint64_t fileoffset = baseFileOffset; - for (auto &si : _segments) { - if ((si->segmentType() != llvm::ELF::PT_LOAD) && - (si->segmentType() != llvm::ELF::PT_NULL)) - continue; - if (fileOffsetAssigned && (fileoffset != baseFileOffset) && - (fileoffset == si->fileOffset())) - break; - si->assignFileOffsets(fileoffset); - fileoffset = si->fileOffset() + si->fileSize(); - } - virtualAddressAssigned = true; - fileOffsetAssigned = true; - _programHeader->resetProgramHeaders(); - } - Section<ELFT> *section; - // Fix the offsets of all the atoms within a section - for (auto &si : _sections) { - section = dyn_cast<Section<ELFT>>(si); - if (section && TargetLayout<ELFT>::hasOutputSegment(section)) - section->assignFileOffsets(section->fileOffset()); - } - // Set the size of the merged Sections - for (auto osi : _outputSections) { - uint64_t sectionfileoffset = 0; - uint64_t startFileOffset = 0; - uint64_t sectionsize = 0; - bool isFirstSection = true; - for (auto si : osi->sections()) { - if (isFirstSection) { - startFileOffset = si->fileOffset(); - isFirstSection = false; - } - sectionfileoffset = si->fileOffset(); - sectionsize = si->fileSize(); - } - sectionsize = (sectionfileoffset - startFileOffset) + sectionsize; - osi->setFileOffset(startFileOffset); - osi->setSize(sectionsize); - } - // Set the virtual addr of the merged Sections - for (auto osi : _outputSections) { - uint64_t sectionstartaddr = 0; - uint64_t startaddr = 0; - uint64_t sectionsize = 0; - bool isFirstSection = true; - for (auto si : osi->sections()) { - if (isFirstSection) { - startaddr = si->virtualAddr(); - isFirstSection = false; - } - sectionstartaddr = si->virtualAddr(); - sectionsize = si->memSize(); - } - sectionsize = (sectionstartaddr - startaddr) + sectionsize; - osi->setMemSize(sectionsize); - osi->setAddr(startaddr); - } -} - -template <class ELFT> -void TargetLayout<ELFT>::assignFileOffsetsForMiscSections() { - uint64_t fileoffset = 0; - uint64_t size = 0; - for (auto si : _segments) { - // Don't calculate offsets from non loadable segments - if ((si->segmentType() != llvm::ELF::PT_LOAD) && - (si->segmentType() != llvm::ELF::PT_NULL)) - continue; - fileoffset = si->fileOffset(); - size = si->fileSize(); - } - fileoffset = fileoffset + size; - Section<ELFT> *section; - for (auto si : _sections) { - section = dyn_cast<Section<ELFT>>(si); - if (section && TargetLayout<ELFT>::hasOutputSegment(section)) - continue; - fileoffset = llvm::RoundUpToAlignment(fileoffset, si->alignment()); - si->setFileOffset(fileoffset); - si->setVirtualAddr(0); - fileoffset += si->fileSize(); - } -} - -template <class ELFT> void TargetLayout<ELFT>::sortInputSections() { - // First, sort according to default layout's order - std::stable_sort( - _sections.begin(), _sections.end(), - [](Chunk<ELFT> *A, Chunk<ELFT> *B) { return A->order() < B->order(); }); - - if (!_linkerScriptSema.hasLayoutCommands()) - return; - - // Sort the sections by their order as defined by the linker script - std::stable_sort( - this->_sections.begin(), this->_sections.end(), - [this](Chunk<ELFT> *A, Chunk<ELFT> *B) { - auto *a = dyn_cast<Section<ELFT>>(A); - auto *b = dyn_cast<Section<ELFT>>(B); - - if (a == nullptr) - return false; - if (b == nullptr) - return true; - - return _linkerScriptSema.less( - {a->archivePath(), a->memberPath(), a->inputSectionName()}, - {b->archivePath(), b->memberPath(), b->inputSectionName()}); - }); - // Now try to arrange sections with no mapping rules to sections with - // similar content - auto p = this->_sections.begin(); - // Find first section that has no assigned rule id - while (p != this->_sections.end()) { - auto *sect = dyn_cast<AtomSection<ELFT>>(*p); - if (!sect) - break; - - if (!_linkerScriptSema.hasMapping({sect->archivePath(), sect->memberPath(), - sect->inputSectionName()})) - break; - - ++p; - } - // For all sections that have no assigned rule id, try to move them near a - // section with similar contents - if (p != this->_sections.begin()) { - for (; p != this->_sections.end(); ++p) { - auto q = p; - --q; - while (q != this->_sections.begin() && - (*q)->getContentType() != (*p)->getContentType()) - --q; - if ((*q)->getContentType() != (*p)->getContentType()) - continue; - ++q; - for (auto i = p; i != q;) { - auto next = i--; - std::iter_swap(i, next); - } - } - } -} - -template <class ELFT> -const AtomLayout * -TargetLayout<ELFT>::findAtomLayoutByName(StringRef name) const { - for (auto sec : _sections) - if (auto section = dyn_cast<Section<ELFT>>(sec)) - if (auto *al = section->findAtomLayoutByName(name)) - return al; - return nullptr; -} - -template <class ELFT> -void TargetLayout<ELFT>::addExtraChunksToSegment(Segment<ELFT> *segment, - StringRef archivePath, - StringRef memberPath, - StringRef sectionName) { - if (!_linkerScriptSema.hasLayoutCommands()) - return; - std::vector<const script::SymbolAssignment *> exprs = - _linkerScriptSema.getExprs({archivePath, memberPath, sectionName}); - for (auto expr : exprs) { - auto expChunk = - new (this->_allocator) ExpressionChunk<ELFT>(this->_ctx, expr); - segment->append(expChunk); - } -} - -template <class ELFT> -RelocationTable<ELFT> *TargetLayout<ELFT>::getDynamicRelocationTable() { - if (!_dynamicRelocationTable) { - _dynamicRelocationTable = createRelocationTable( - _ctx.isRelaOutputFormat() ? ".rela.dyn" : ".rel.dyn", - ORDER_DYNAMIC_RELOCS); - addSection(_dynamicRelocationTable.get()); - } - return _dynamicRelocationTable.get(); -} - -template <class ELFT> -RelocationTable<ELFT> *TargetLayout<ELFT>::getPLTRelocationTable() { - if (!_pltRelocationTable) { - _pltRelocationTable = createRelocationTable( - _ctx.isRelaOutputFormat() ? ".rela.plt" : ".rel.plt", - ORDER_DYNAMIC_PLT_RELOCS); - addSection(_pltRelocationTable.get()); - } - return _pltRelocationTable.get(); -} - -template <class ELFT> uint64_t TargetLayout<ELFT>::getTLSSize() const { - for (const auto &phdr : *_programHeader) - if (phdr->p_type == llvm::ELF::PT_TLS) - return phdr->p_memsz; - return 0; -} - -template class TargetLayout<ELF32LE>; -template class TargetLayout<ELF32BE>; -template class TargetLayout<ELF64LE>; -template class TargetLayout<ELF64BE>; - -} // end namespace elf -} // end namespace lld diff --git a/lib/ReaderWriter/ELF/TargetLayout.h b/lib/ReaderWriter/ELF/TargetLayout.h deleted file mode 100644 index 52512f8e279e..000000000000 --- a/lib/ReaderWriter/ELF/TargetLayout.h +++ /dev/null @@ -1,327 +0,0 @@ -//===- lib/ReaderWriter/ELF/TargetLayout.h --------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_DEFAULT_LAYOUT_H -#define LLD_READER_WRITER_ELF_DEFAULT_LAYOUT_H - -#include "Atoms.h" -#include "HeaderChunks.h" -#include "SectionChunks.h" -#include "SegmentChunks.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" -#include <unordered_map> - -namespace lld { -namespace elf { - -/// \brief The TargetLayout class is used by the Writer to arrange -/// sections and segments in the order determined by the target ELF -/// format. The writer creates a single instance of the TargetLayout -/// class -template <class ELFT> class TargetLayout { -public: - typedef uint32_t SectionOrder; - typedef uint32_t SegmentType; - - // The order in which the sections appear in the output file - // If its determined, that the layout needs to change - // just changing the order of enumerations would essentially - // change the layout in the output file - // Change the enumerations so that Target can override and stick - // a section anywhere it wants to - enum DefaultSectionOrder { - ORDER_NOT_DEFINED = 0, - ORDER_INTERP = 10, - ORDER_RO_NOTE = 15, - ORDER_HASH = 30, - ORDER_DYNAMIC_SYMBOLS = 40, - ORDER_DYNAMIC_STRINGS = 50, - ORDER_DYNAMIC_RELOCS = 52, - ORDER_DYNAMIC_PLT_RELOCS = 54, - ORDER_INIT = 60, - ORDER_PLT = 70, - ORDER_TEXT = 80, - ORDER_FINI = 90, - ORDER_REL = 95, - ORDER_RODATA = 100, - ORDER_EH_FRAME = 110, - ORDER_EH_FRAMEHDR = 120, - ORDER_TDATA = 124, - ORDER_TBSS = 128, - ORDER_CTORS = 130, - ORDER_DTORS = 140, - ORDER_INIT_ARRAY = 150, - ORDER_FINI_ARRAY = 160, - ORDER_DYNAMIC = 170, - ORDER_GOT = 180, - ORDER_GOT_PLT = 190, - ORDER_DATA = 200, - ORDER_RW_NOTE = 205, - ORDER_BSS = 210, - ORDER_NOALLOC = 215, - ORDER_OTHER = 220, - ORDER_SECTION_STRINGS = 230, - ORDER_SYMBOL_TABLE = 240, - ORDER_STRING_TABLE = 250, - ORDER_SECTION_HEADERS = 260 - }; - -public: - - // The Key used for creating Sections - // The sections are created using - // SectionName, contentPermissions - struct SectionKey { - SectionKey(StringRef name, DefinedAtom::ContentPermissions perm, - StringRef path) - : _name(name), _perm(perm), _path(path) {} - - // Data members - StringRef _name; - DefinedAtom::ContentPermissions _perm; - StringRef _path; - }; - - struct SectionKeyHash { - int64_t operator()(const SectionKey &k) const { - return llvm::hash_combine(k._name, k._perm, k._path); - } - }; - - struct SectionKeyEq { - bool operator()(const SectionKey &lhs, const SectionKey &rhs) const { - return ((lhs._name == rhs._name) && (lhs._perm == rhs._perm) && - (lhs._path == rhs._path)); - } - }; - - typedef typename std::vector<Chunk<ELFT> *>::iterator ChunkIter; - typedef typename std::vector<Segment<ELFT> *>::iterator SegmentIter; - - // Properties used during segment creation - struct SegmentKey { - SegmentKey(StringRef name, int64_t type, uint64_t flags, bool segFlags) - : _name(name), _type(type), _flags(flags), - _segmentFlags(segFlags && flags != 0) {} - StringRef _name = ""; - int64_t _type = 0; - uint64_t _flags = 0; - bool _segmentFlags = false; - }; - - struct SegmentKeyHash { - int64_t operator()(const SegmentKey &k) const { - return llvm::hash_combine(k._name, k._type, k._flags); - } - }; - - struct SegmentKeyEq { - bool operator()(const SegmentKey &lhs, const SegmentKey &rhs) const { - return ((lhs._name == rhs._name) && (lhs._type == rhs._type) && - (lhs._flags == rhs._flags)); - } - }; - - // Output Sections contain the map of Section names to a vector of sections, - // that have been merged to form a single section - typedef llvm::StringMap<OutputSection<ELFT> *> OutputSectionMapT; - typedef - typename std::vector<OutputSection<ELFT> *>::iterator OutputSectionIter; - - typedef std::unordered_map<SectionKey, AtomSection<ELFT> *, SectionKeyHash, - SectionKeyEq> SectionMapT; - typedef std::unordered_map<SegmentKey, Segment<ELFT> *, SegmentKeyHash, - SegmentKeyEq> SegmentMapT; - - typedef typename std::vector<AtomLayout *>::iterator AbsoluteAtomIterT; - - typedef llvm::DenseSet<const Atom *> AtomSetT; - - TargetLayout(ELFLinkingContext &ctx) - : _ctx(ctx), _linkerScriptSema(ctx.linkerScriptSema()) {} - - virtual ~TargetLayout() = default; - - /// \brief Return the section order for a input section - virtual SectionOrder getSectionOrder(StringRef name, int32_t contentType, - int32_t contentPermissions); - - /// \brief Return the name of the input section by decoding the input - /// sectionChoice. - virtual StringRef getInputSectionName(const DefinedAtom *da) const; - - /// \brief Return the name of the output section from the input section. - virtual StringRef getOutputSectionName(StringRef archivePath, - StringRef memberPath, - StringRef inputSectionName) const; - - /// \brief Gets or creates a section. - AtomSection<ELFT> * - getSection(StringRef name, int32_t contentType, - DefinedAtom::ContentPermissions contentPermissions, - const DefinedAtom *da); - - /// \brief Gets the segment for a output section - virtual SegmentType getSegmentType(const Section<ELFT> *section) const; - - /// \brief Returns true/false depending on whether the section has a Output - // segment or not - static bool hasOutputSegment(Section<ELFT> *section); - - /// \brief Append the Atom to the layout and create appropriate sections. - /// \returns A reference to the atom layout or an error. The atom layout will - /// be updated as linking progresses. - virtual ErrorOr<const AtomLayout *> addAtom(const Atom *atom); - - /// \brief Find an output Section given a section name. - OutputSection<ELFT> *findOutputSection(StringRef name) { - auto iter = _outputSectionMap.find(name); - if (iter == _outputSectionMap.end()) - return nullptr; - return iter->second; - } - - /// \brief find a absolute atom given a name - AtomLayout *findAbsoluteAtom(StringRef name) { - auto iter = std::find_if( - _absoluteAtoms.begin(), _absoluteAtoms.end(), - [=](const AtomLayout *a) { return a->_atom->name() == name; }); - if (iter == _absoluteAtoms.end()) - return nullptr; - return *iter; - } - - // Output sections with the same name into a OutputSection - void createOutputSections(); - - // Query for segments based on output and input sections - std::vector<SegmentKey> getSegmentsForSection(const OutputSection<ELFT> *os, - const Section<ELFT> *sec) const; - - /// \brief Sort the sections by their order as defined by the layout, - /// preparing all sections to be assigned to a segment. - virtual void sortInputSections(); - - /// \brief Add extra chunks to a segment just before including the input - /// section given by <archivePath, memberPath, sectionName>. This - /// is used to add linker script expressions before each section. - virtual void addExtraChunksToSegment(Segment<ELFT> *segment, - StringRef archivePath, - StringRef memberPath, - StringRef sectionName); - - /// \brief associates a section to a segment - virtual void assignSectionsToSegments(); - - /// \brief associates a virtual address to the segment, section, and the atom - virtual void assignVirtualAddress(); - - void assignFileOffsetsForMiscSections(); - - range<AbsoluteAtomIterT> absoluteAtoms() { return _absoluteAtoms; } - - void addSection(Chunk<ELFT> *c) { _sections.push_back(c); } - - void finalize() { - ScopedTask task(getDefaultDomain(), "Finalize layout"); - for (auto &si : _sections) - si->finalize(); - } - - void doPreFlight() { - for (auto &si : _sections) - si->doPreFlight(); - } - - /// \brief find the Atom in the current layout - virtual const AtomLayout *findAtomLayoutByName(StringRef name) const; - - void setHeader(ELFHeader<ELFT> *elfHeader) { _elfHeader = elfHeader; } - - void setProgramHeader(ProgramHeader<ELFT> *p) { - _programHeader = p; - } - - range<OutputSectionIter> outputSections() { return _outputSections; } - - range<ChunkIter> sections() { return _sections; } - - range<SegmentIter> segments() { return _segments; } - - ELFHeader<ELFT> *getHeader() { return _elfHeader; } - - bool hasDynamicRelocationTable() const { return !!_dynamicRelocationTable; } - - bool hasPLTRelocationTable() const { return !!_pltRelocationTable; } - - /// \brief Get or create the dynamic relocation table. All relocations in this - /// table are processed at startup. - RelocationTable<ELFT> *getDynamicRelocationTable(); - - /// \brief Get or create the PLT relocation table. Referenced by DT_JMPREL. - RelocationTable<ELFT> *getPLTRelocationTable(); - - uint64_t getTLSSize() const; - - bool isReferencedByDefinedAtom(const Atom *a) const { - return _referencedDynAtoms.count(a); - } - - bool isCopied(const SharedLibraryAtom *sla) const { - return _copiedDynSymNames.count(sla->name()); - } - -protected: - /// \brief TargetLayouts may use these functions to reorder the input sections - /// in a order defined by their ABI. - virtual void finalizeOutputSectionLayout() {} - - /// \brief Allocate a new section. - virtual AtomSection<ELFT> *createSection( - StringRef name, int32_t contentType, - DefinedAtom::ContentPermissions contentPermissions, - SectionOrder sectionOrder); - - /// \brief Create a new relocation table. - virtual unique_bump_ptr<RelocationTable<ELFT>> - createRelocationTable(StringRef name, int32_t order) { - return unique_bump_ptr<RelocationTable<ELFT>>( - new (_allocator) RelocationTable<ELFT>(_ctx, name, order)); - } - - virtual uint64_t getLookupSectionFlags(const OutputSection<ELFT> *os) const; - - /// \brief Sort segements stored in the _segments - virtual void sortSegments(); - -protected: - llvm::BumpPtrAllocator _allocator; - SectionMapT _sectionMap; - OutputSectionMapT _outputSectionMap; - SegmentMapT _segmentMap; - std::vector<Chunk<ELFT> *> _sections; - std::vector<Segment<ELFT> *> _segments; - std::vector<OutputSection<ELFT> *> _outputSections; - ELFHeader<ELFT> *_elfHeader; - ProgramHeader<ELFT> *_programHeader; - unique_bump_ptr<RelocationTable<ELFT>> _dynamicRelocationTable; - unique_bump_ptr<RelocationTable<ELFT>> _pltRelocationTable; - std::vector<AtomLayout *> _absoluteAtoms; - AtomSetT _referencedDynAtoms; - llvm::StringSet<> _copiedDynSymNames; - ELFLinkingContext &_ctx; - script::Sema &_linkerScriptSema; -}; - -} // end namespace elf -} // end namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/Writer.cpp b/lib/ReaderWriter/ELF/Writer.cpp deleted file mode 100644 index 1c5d9766e9c5..000000000000 --- a/lib/ReaderWriter/ELF/Writer.cpp +++ /dev/null @@ -1,23 +0,0 @@ -//===- lib/ReaderWriter/ELF/WriterELF.cpp ---------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lld/Core/Writer.h" -#include "DynamicLibraryWriter.h" -#include "ExecutableWriter.h" - -using namespace llvm; -using namespace llvm::object; - -namespace lld { - -std::unique_ptr<Writer> createWriterELF(const ELFLinkingContext &ctx) { - return ctx.getTargetHandler().getWriter(); -} - -} // namespace lld diff --git a/lib/ReaderWriter/ELF/Writer.h b/lib/ReaderWriter/ELF/Writer.h deleted file mode 100644 index 8b3e8f90638a..000000000000 --- a/lib/ReaderWriter/ELF/Writer.h +++ /dev/null @@ -1,35 +0,0 @@ -//===- lib/ReaderWriter/ELF/Writer.h --------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_WRITER_H -#define LLD_READER_WRITER_ELF_WRITER_H - -#include "lld/Core/File.h" -#include "lld/Core/Writer.h" - -namespace lld { -namespace elf { -/// \brief The Writer class is a base class for the linker to write -/// various kinds of ELF files. -class ELFWriter : public Writer { -public: - /// \brief builds the chunks that needs to be written to the output - /// ELF file - virtual void buildChunks(const File &file) = 0; - - /// \brief Writes the chunks into the output file specified by path - std::error_code writeFile(const File &file, StringRef path) override = 0; - - /// \brief Get the virtual address of \p atom after layout. - virtual uint64_t addressOfAtom(const Atom *atom) = 0; -}; -} // end namespace elf -} // end namespace lld - -#endif // LLD_READER_WRITER_ELF_WRITER_H diff --git a/lib/ReaderWriter/ELF/X86/CMakeLists.txt b/lib/ReaderWriter/ELF/X86/CMakeLists.txt deleted file mode 100644 index 5e3fe64dc15d..000000000000 --- a/lib/ReaderWriter/ELF/X86/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -add_lld_library(lldX86ELFTarget - X86LinkingContext.cpp - X86TargetHandler.cpp - X86RelocationHandler.cpp - LINK_LIBS - lldELF - lldReaderWriter - lldCore - LLVMObject - LLVMSupport - ) diff --git a/lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h b/lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h deleted file mode 100644 index dd2184d7201e..000000000000 --- a/lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h +++ /dev/null @@ -1,44 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h -----------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef X86_X86_DYNAMIC_LIBRARY_WRITER_H -#define X86_X86_DYNAMIC_LIBRARY_WRITER_H - -#include "DynamicLibraryWriter.h" -#include "X86LinkingContext.h" - -namespace lld { -namespace elf { - -class X86DynamicLibraryWriter : public DynamicLibraryWriter<ELF32LE> { -public: - X86DynamicLibraryWriter(X86LinkingContext &ctx, - TargetLayout<ELF32LE> &layout); - -protected: - // Add any runtime files and their atoms to the output - void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override; -}; - -X86DynamicLibraryWriter::X86DynamicLibraryWriter(X86LinkingContext &ctx, - TargetLayout<ELF32LE> &layout) - : DynamicLibraryWriter(ctx, layout) {} - -void X86DynamicLibraryWriter::createImplicitFiles( - std::vector<std::unique_ptr<File>> &result) { - DynamicLibraryWriter::createImplicitFiles(result); - auto gotFile = llvm::make_unique<SimpleFile>("GOTFile"); - gotFile->addAtom(*new (gotFile->allocator()) GlobalOffsetTableAtom(*gotFile)); - gotFile->addAtom(*new (gotFile->allocator()) DynamicAtom(*gotFile)); - result.push_back(std::move(gotFile)); -} - -} // namespace elf -} // namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h b/lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h deleted file mode 100644 index 70aabde3ad2c..000000000000 --- a/lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h +++ /dev/null @@ -1,39 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h ---------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef X86_X86_EXECUTABLE_WRITER_H -#define X86_X86_EXECUTABLE_WRITER_H - -#include "ExecutableWriter.h" -#include "X86LinkingContext.h" - -namespace lld { -namespace elf { - -class X86ExecutableWriter : public ExecutableWriter<ELF32LE> { -public: - X86ExecutableWriter(X86LinkingContext &ctx, TargetLayout<ELF32LE> &layout); - -protected: - // Add any runtime files and their atoms to the output - void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override; -}; - -X86ExecutableWriter::X86ExecutableWriter(X86LinkingContext &ctx, - TargetLayout<ELF32LE> &layout) - : ExecutableWriter(ctx, layout) {} - -void X86ExecutableWriter::createImplicitFiles( - std::vector<std::unique_ptr<File>> &result) { - ExecutableWriter::createImplicitFiles(result); -} - -} // namespace elf -} // namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp b/lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp deleted file mode 100644 index dc45efc390fd..000000000000 --- a/lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp +++ /dev/null @@ -1,39 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp ---------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "X86LinkingContext.h" -#include "X86TargetHandler.h" -#include "lld/Core/LLVM.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/ErrorOr.h" - -using namespace lld; -using namespace lld::elf; - -std::unique_ptr<ELFLinkingContext> -elf::createX86LinkingContext(llvm::Triple triple) { - if (triple.getArch() == llvm::Triple::x86) - return llvm::make_unique<X86LinkingContext>(triple); - return nullptr; -} - -X86LinkingContext::X86LinkingContext(llvm::Triple triple) - : ELFLinkingContext(triple, llvm::make_unique<X86TargetHandler>(*this)) {} - -static const Registry::KindStrings kindStrings[] = { -#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name), -#include "llvm/Support/ELFRelocs/i386.def" -#undef ELF_RELOC - LLD_KIND_STRING_END -}; - -void X86LinkingContext::registerRelocationNames(Registry ®istry) { - registry.addKindTable(Reference::KindNamespace::ELF, Reference::KindArch::x86, - kindStrings); -} diff --git a/lib/ReaderWriter/ELF/X86/X86LinkingContext.h b/lib/ReaderWriter/ELF/X86/X86LinkingContext.h deleted file mode 100644 index f6ab3e980d7d..000000000000 --- a/lib/ReaderWriter/ELF/X86/X86LinkingContext.h +++ /dev/null @@ -1,44 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86/X86LinkingContext.h -----------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_X86_TARGETINFO_H -#define LLD_READER_WRITER_ELF_X86_TARGETINFO_H - -#include "lld/ReaderWriter/ELFLinkingContext.h" -#include "llvm/Object/ELF.h" -#include "llvm/Support/ELF.h" - -namespace lld { -namespace elf { -class X86LinkingContext final : public ELFLinkingContext { -public: - static std::unique_ptr<ELFLinkingContext> create(llvm::Triple); - int getMachineType() const override { return llvm::ELF::EM_386; } - X86LinkingContext(llvm::Triple); - void registerRelocationNames(Registry &r) override; - - /// \brief X86 has only two relative relocation - /// a) for supporting IFUNC relocs - R_386_IRELATIVE - /// b) for supporting relative relocs - R_386_RELATIVE - bool isRelativeReloc(const Reference &r) const override { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - assert(r.kindArch() == Reference::KindArch::x86); - switch (r.kindValue()) { - case llvm::ELF::R_386_IRELATIVE: - case llvm::ELF::R_386_RELATIVE: - return true; - default: - return false; - } - } -}; -} // end namespace elf -} // end namespace lld -#endif diff --git a/lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp b/lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp deleted file mode 100644 index 15774bc33123..000000000000 --- a/lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp +++ /dev/null @@ -1,54 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp ------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "X86LinkingContext.h" -#include "X86TargetHandler.h" -#include "llvm/Support/Endian.h" - -using namespace lld; -using namespace lld::elf; -using namespace llvm::support::endian; - -/// \brief R_386_32 - word32: S + A -static int reloc32(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) { - int32_t result = (uint32_t)(S + A); - write32le(location, result | read32le(location)); - return 0; -} - -/// \brief R_386_PC32 - word32: S + A - P -static int relocPC32(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) { - uint32_t result = (uint32_t)(S + A - P); - write32le(location, result + read32le(location)); - return 0; -} - -std::error_code X86TargetRelocationHandler::applyRelocation( - ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom, - const Reference &ref) const { - uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset; - uint8_t *loc = atomContent + ref.offsetInAtom(); - uint64_t target = writer.addressOfAtom(ref.target()); - uint64_t reloc = atom._virtualAddr + ref.offsetInAtom(); - - if (ref.kindNamespace() != Reference::KindNamespace::ELF) - return std::error_code(); - assert(ref.kindArch() == Reference::KindArch::x86); - switch (ref.kindValue()) { - case R_386_32: - reloc32(loc, reloc, target, ref.addend()); - break; - case R_386_PC32: - relocPC32(loc, reloc, target, ref.addend()); - break; - default: - return make_unhandled_reloc_error(); - } - return std::error_code(); -} diff --git a/lib/ReaderWriter/ELF/X86/X86RelocationHandler.h b/lib/ReaderWriter/ELF/X86/X86RelocationHandler.h deleted file mode 100644 index 1131635c6735..000000000000 --- a/lib/ReaderWriter/ELF/X86/X86RelocationHandler.h +++ /dev/null @@ -1,28 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86/X86RelocationHandler.h --------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef X86_X86_RELOCATION_HANDLER_H -#define X86_X86_RELOCATION_HANDLER_H - -#include "lld/ReaderWriter/ELFLinkingContext.h" - -namespace lld { -namespace elf { - -class X86TargetRelocationHandler final : public TargetRelocationHandler { -public: - std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &, - const AtomLayout &, - const Reference &) const override; -}; - -} // end namespace elf -} // end namespace lld - -#endif // X86_X86_RELOCATION_HANDLER_H diff --git a/lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp b/lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp deleted file mode 100644 index c01ed7258f1c..000000000000 --- a/lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp +++ /dev/null @@ -1,36 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp ----------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "X86TargetHandler.h" -#include "X86DynamicLibraryWriter.h" -#include "X86ExecutableWriter.h" -#include "X86LinkingContext.h" -#include "X86RelocationHandler.h" - -using namespace lld; -using namespace elf; - -using namespace llvm::ELF; - -std::unique_ptr<Writer> X86TargetHandler::getWriter() { - switch (_ctx.getOutputELFType()) { - case llvm::ELF::ET_EXEC: - return llvm::make_unique<X86ExecutableWriter>(_ctx, *_targetLayout); - case llvm::ELF::ET_DYN: - return llvm::make_unique<X86DynamicLibraryWriter>(_ctx, *_targetLayout); - case llvm::ELF::ET_REL: - llvm_unreachable("TODO: support -r mode"); - default: - llvm_unreachable("unsupported output type"); - } -} - -X86TargetHandler::X86TargetHandler(X86LinkingContext &ctx) - : _ctx(ctx), _targetLayout(new TargetLayout<ELF32LE>(ctx)), - _relocationHandler(new X86TargetRelocationHandler()) {} diff --git a/lib/ReaderWriter/ELF/X86/X86TargetHandler.h b/lib/ReaderWriter/ELF/X86/X86TargetHandler.h deleted file mode 100644 index fecf9abfc678..000000000000 --- a/lib/ReaderWriter/ELF/X86/X86TargetHandler.h +++ /dev/null @@ -1,48 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86/X86TargetHandler.h ------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_X86_TARGET_HANDLER_H -#define LLD_READER_WRITER_ELF_X86_TARGET_HANDLER_H - -#include "TargetLayout.h" -#include "ELFReader.h" -#include "X86RelocationHandler.h" - -namespace lld { -namespace elf { - -class X86LinkingContext; - -class X86TargetHandler final : public TargetHandler { -public: - X86TargetHandler(X86LinkingContext &ctx); - - const TargetRelocationHandler &getRelocationHandler() const override { - return *_relocationHandler; - } - - std::unique_ptr<Reader> getObjReader() override { - return llvm::make_unique<ELFReader<ELFFile<ELF32LE>>>(_ctx); - } - - std::unique_ptr<Reader> getDSOReader() override { - return llvm::make_unique<ELFReader<DynamicFile<ELF32LE>>>(_ctx); - } - - std::unique_ptr<Writer> getWriter() override; - -protected: - X86LinkingContext &_ctx; - std::unique_ptr<TargetLayout<ELF32LE>> _targetLayout; - std::unique_ptr<X86TargetRelocationHandler> _relocationHandler; -}; -} // end namespace elf -} // end namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt b/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt deleted file mode 100644 index 61f4b4b524e8..000000000000 --- a/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -add_lld_library(lldX86_64ELFTarget - X86_64LinkingContext.cpp - X86_64TargetHandler.cpp - X86_64RelocationHandler.cpp - X86_64RelocationPass.cpp - X86_64SectionChunks.cpp - LINK_LIBS - lldELF - lldReaderWriter - lldCore - LLVMObject - LLVMSupport - ) - -include_directories(.) - -add_subdirectory(ExampleSubTarget) diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/CMakeLists.txt b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/CMakeLists.txt deleted file mode 100644 index 700b2550b119..000000000000 --- a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -add_lld_library(lldExampleSubTarget - ExampleLinkingContext.cpp - ExampleTargetHandler.cpp - LINK_LIBS - lldX86_64ELFTarget - lldELF - lldReaderWriter - lldCore - LLVMObject - LLVMSupport - ) diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.cpp b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.cpp deleted file mode 100644 index cb3e819aff6b..000000000000 --- a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.cpp +++ /dev/null @@ -1,35 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86_64/ExampleTarget/ExampleLinkingContext.cpp ----===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "ExampleLinkingContext.h" -#include "ExampleTargetHandler.h" - -using namespace lld; -using namespace elf; - -std::unique_ptr<ELFLinkingContext> -elf::createExampleLinkingContext(llvm::Triple triple) { - if (triple.getVendorName() == "example") - return llvm::make_unique<ExampleLinkingContext>(triple); - return nullptr; -} - -ExampleLinkingContext::ExampleLinkingContext(llvm::Triple triple) - : X86_64LinkingContext(triple, std::unique_ptr<TargetHandler>( - new ExampleTargetHandler(*this))) { - _outputELFType = llvm::ELF::ET_LOPROC; -} - -StringRef ExampleLinkingContext::entrySymbolName() const { - return "_start"; -} - -void ExampleLinkingContext::addPasses(PassManager &p) { - ELFLinkingContext::addPasses(p); -} diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.h b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.h deleted file mode 100644 index 5bb11cd35b41..000000000000 --- a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.h +++ /dev/null @@ -1,31 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86_64/ExampleTarget/ExampleLinkingContext.h --===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_X86_64_EXAMPLE_TARGET_EXAMPLE_LINKING_CONTEXT -#define LLD_READER_WRITER_ELF_X86_64_EXAMPLE_TARGET_EXAMPLE_LINKING_CONTEXT - -#include "X86_64LinkingContext.h" -#include "X86_64TargetHandler.h" - -namespace lld { -namespace elf { - -class ExampleLinkingContext final : public X86_64LinkingContext { -public: - static std::unique_ptr<ELFLinkingContext> create(llvm::Triple); - ExampleLinkingContext(llvm::Triple triple); - - StringRef entrySymbolName() const override; - void addPasses(PassManager &) override; -}; - -} // end namespace elf -} // end namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.cpp b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.cpp deleted file mode 100644 index 89ec6671f3a0..000000000000 --- a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.cpp +++ /dev/null @@ -1,22 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86_64/ExampleTarget/ExampleTargetHandler.cpp -===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "ExampleTargetHandler.h" -#include "X86_64ExecutableWriter.h" -#include "ExampleLinkingContext.h" - -using namespace lld; -using namespace elf; - -ExampleTargetHandler::ExampleTargetHandler(ExampleLinkingContext &c) - : X86_64TargetHandler(c), _ctx(c) {} - -std::unique_ptr<Writer> ExampleTargetHandler::getWriter() { - return llvm::make_unique<X86_64ExecutableWriter>(_ctx, *_targetLayout); -} diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.h b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.h deleted file mode 100644 index 46eade5864f9..000000000000 --- a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.h +++ /dev/null @@ -1,31 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86_64/ExampleTarget/ExampleTargetHandler.h ---===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_X86_64_EXAMPLE_TARGET_EXAMPLE_TARGET_HANDLER_H -#define LLD_READER_WRITER_ELF_X86_64_EXAMPLE_TARGET_EXAMPLE_TARGET_HANDLER_H - -#include "X86_64TargetHandler.h" - -namespace lld { -namespace elf { -class ExampleLinkingContext; - -class ExampleTargetHandler final : public X86_64TargetHandler { -public: - ExampleTargetHandler(ExampleLinkingContext &c); - - std::unique_ptr<Writer> getWriter() override; - -private: - ExampleLinkingContext &_ctx; -}; -} // end namespace elf -} // end namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/X86_64/TODO.rst b/lib/ReaderWriter/ELF/X86_64/TODO.rst deleted file mode 100644 index a2411a00d1ea..000000000000 --- a/lib/ReaderWriter/ELF/X86_64/TODO.rst +++ /dev/null @@ -1,46 +0,0 @@ -ELF x86-64 -~~~~~~~~~~ - -Unimplemented Features -###################### - -* Code models other than the small code model -* TLS strength reduction - -Unimplemented Relocations -######################### - -All of these relocations are defined in: -http://www.x86-64.org/documentation/abi.pdf - -Trivial Relocs -<<<<<<<<<<<<<< - -These are very simple relocation calculations to implement. -See lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp - -* R_X86_64_8 -* R_X86_64_PC8 -* R_X86_64_SIZE32 -* R_X86_64_SIZE64 -* R_X86_64_GOTPC32 (this relocation requires there to be a __GLOBAL_OFFSET_TABLE__) - -Global Offset Table Relocs -<<<<<<<<<<<<<<<<<<<<<<<<<< - -* R_X86_64_GOTOFF32 -* R_X86_64_GOTOFF64 - -Global Dynamic Thread Local Storage Relocs -<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - -These relocations take more effort to implement, but some of them are done. -Their implementation lives in lib/ReaderWriter/ELF/X86_64/{X86_64RelocationPass.cpp,X86_64RelocationHandler.cpp}. - -Documentation on these relocations can be found in: -http://www.akkadia.org/drepper/tls.pdf -http://www.fsfla.org/~lxoliva/writeups/TLS/RFC-TLSDESC-x86.txt - -* R_X86_64_GOTPC32_TLSDESC -* R_X86_64_TLSDESC_CALL -* R_X86_64_TLSDESC diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h b/lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h deleted file mode 100644 index f84f85223bfb..000000000000 --- a/lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h +++ /dev/null @@ -1,45 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86/X86_64DynamicLibraryWriter.h ---------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef X86_64_DYNAMIC_LIBRARY_WRITER_H -#define X86_64_DYNAMIC_LIBRARY_WRITER_H - -#include "DynamicLibraryWriter.h" -#include "X86_64LinkingContext.h" -#include "X86_64TargetHandler.h" - -namespace lld { -namespace elf { - -class X86_64DynamicLibraryWriter : public DynamicLibraryWriter<ELF64LE> { -public: - X86_64DynamicLibraryWriter(X86_64LinkingContext &ctx, - X86_64TargetLayout &layout); - -protected: - // Add any runtime files and their atoms to the output - void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override; -}; - -X86_64DynamicLibraryWriter::X86_64DynamicLibraryWriter( - X86_64LinkingContext &ctx, X86_64TargetLayout &layout) - : DynamicLibraryWriter(ctx, layout) {} - -void X86_64DynamicLibraryWriter::createImplicitFiles( - std::vector<std::unique_ptr<File>> &result) { - DynamicLibraryWriter::createImplicitFiles(result); - auto gotFile = llvm::make_unique<SimpleFile>("GOTFile"); - gotFile->addAtom(*new (gotFile->allocator()) GlobalOffsetTableAtom(*gotFile)); - gotFile->addAtom(*new (gotFile->allocator()) DynamicAtom(*gotFile)); - result.push_back(std::move(gotFile)); -} - -} // namespace elf -} // namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h b/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h deleted file mode 100644 index 930a2de2a9e8..000000000000 --- a/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h +++ /dev/null @@ -1,57 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86/X86_64ExecutableWriter.h ------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef X86_64_EXECUTABLE_WRITER_H -#define X86_64_EXECUTABLE_WRITER_H - -#include "ExecutableWriter.h" -#include "X86_64LinkingContext.h" - -namespace lld { -namespace elf { - -class X86_64ExecutableWriter : public ExecutableWriter<ELF64LE> { -public: - X86_64ExecutableWriter(X86_64LinkingContext &ctx, X86_64TargetLayout &layout) - : ExecutableWriter(ctx, layout), _targetLayout(layout) {} - -protected: - // Add any runtime files and their atoms to the output - void - createImplicitFiles(std::vector<std::unique_ptr<File>> &result) override { - ExecutableWriter::createImplicitFiles(result); - auto gotFile = llvm::make_unique<SimpleFile>("GOTFile"); - gotFile->addAtom(*new (gotFile->allocator()) - GlobalOffsetTableAtom(*gotFile)); - if (this->_ctx.isDynamic()) - gotFile->addAtom(*new (gotFile->allocator()) DynamicAtom(*gotFile)); - result.push_back(std::move(gotFile)); - } - - void buildDynamicSymbolTable(const File &file) override { - for (auto sec : this->_layout.sections()) { - if (auto section = dyn_cast<AtomSection<ELF64LE>>(sec)) { - for (const auto &atom : section->atoms()) { - if (_targetLayout.getGOTSection().hasGlobalGOTEntry(atom->_atom)) { - this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(), - atom->_virtualAddr, atom); - } - } - } - } - - ExecutableWriter<ELF64LE>::buildDynamicSymbolTable(file); - } - - X86_64TargetLayout &_targetLayout; -}; - -} // namespace elf -} // namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp b/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp deleted file mode 100644 index 0dcd6ac6fbed..000000000000 --- a/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp +++ /dev/null @@ -1,50 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp ---------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "X86_64LinkingContext.h" -#include "X86_64RelocationPass.h" -#include "X86_64TargetHandler.h" - -using namespace lld; -using namespace lld::elf; - -X86_64LinkingContext::X86_64LinkingContext( - llvm::Triple triple, std::unique_ptr<TargetHandler> handler) - : ELFLinkingContext(triple, std::move(handler)) {} - -X86_64LinkingContext::X86_64LinkingContext(llvm::Triple triple) - : X86_64LinkingContext(triple, - llvm::make_unique<X86_64TargetHandler>(*this)) {} - -void X86_64LinkingContext::addPasses(PassManager &pm) { - auto pass = createX86_64RelocationPass(*this); - if (pass) - pm.add(std::move(pass)); - ELFLinkingContext::addPasses(pm); -} - -std::unique_ptr<ELFLinkingContext> -elf::createX86_64LinkingContext(llvm::Triple triple) { - if (triple.getArch() == llvm::Triple::x86_64) - return llvm::make_unique<X86_64LinkingContext>(triple); - return nullptr; -} - -static const Registry::KindStrings kindStrings[] = { -#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name), -#include "llvm/Support/ELFRelocs/x86_64.def" -#undef ELF_RELOC - LLD_KIND_STRING_ENTRY(LLD_R_X86_64_GOTRELINDEX), - LLD_KIND_STRING_END -}; - -void X86_64LinkingContext::registerRelocationNames(Registry ®istry) { - registry.addKindTable(Reference::KindNamespace::ELF, - Reference::KindArch::x86_64, kindStrings); -} diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h b/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h deleted file mode 100644 index a5a7b3d21f4e..000000000000 --- a/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h +++ /dev/null @@ -1,103 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h -----------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_X86_64_X86_64_LINKING_CONTEXT_H -#define LLD_READER_WRITER_ELF_X86_64_X86_64_LINKING_CONTEXT_H - -#include "lld/ReaderWriter/ELFLinkingContext.h" -#include "llvm/Object/ELF.h" -#include "llvm/Support/ELF.h" - -namespace lld { -namespace elf { - -/// \brief x86-64 internal references. -enum { - /// \brief The 32 bit index of the relocation in the got this reference refers - /// to. - LLD_R_X86_64_GOTRELINDEX = 1024, -}; - -class X86_64LinkingContext : public ELFLinkingContext { -protected: - X86_64LinkingContext(llvm::Triple, std::unique_ptr<TargetHandler>); - -public: - static std::unique_ptr<ELFLinkingContext> create(llvm::Triple); - int getMachineType() const override { return llvm::ELF::EM_X86_64; } - X86_64LinkingContext(llvm::Triple); - - void addPasses(PassManager &) override; - void registerRelocationNames(Registry &r) override; - - uint64_t getBaseAddress() const override { - if (_baseAddress == 0) - return 0x400000; - return _baseAddress; - } - - bool isDynamicRelocation(const Reference &r) const override { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - assert(r.kindArch() == Reference::KindArch::x86_64); - switch (r.kindValue()) { - case llvm::ELF::R_X86_64_RELATIVE: - case llvm::ELF::R_X86_64_GLOB_DAT: - case llvm::ELF::R_X86_64_COPY: - case llvm::ELF::R_X86_64_DTPMOD64: - case llvm::ELF::R_X86_64_DTPOFF64: - case llvm::ELF::R_X86_64_TPOFF64: - return true; - default: - return false; - } - } - - bool isCopyRelocation(const Reference &r) const override { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - assert(r.kindArch() == Reference::KindArch::x86_64); - if (r.kindValue() == llvm::ELF::R_X86_64_COPY) - return true; - return false; - } - - bool isPLTRelocation(const Reference &r) const override { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - assert(r.kindArch() == Reference::KindArch::x86_64); - switch (r.kindValue()) { - case llvm::ELF::R_X86_64_JUMP_SLOT: - case llvm::ELF::R_X86_64_IRELATIVE: - return true; - default: - return false; - } - } - - /// \brief X86_64 has two relative relocations - /// a) for supporting IFUNC - R_X86_64_IRELATIVE - /// b) for supporting relative relocs - R_X86_64_RELATIVE - bool isRelativeReloc(const Reference &r) const override { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - assert(r.kindArch() == Reference::KindArch::x86_64); - switch (r.kindValue()) { - case llvm::ELF::R_X86_64_IRELATIVE: - case llvm::ELF::R_X86_64_RELATIVE: - return true; - default: - return false; - } - } -}; -} // end namespace elf -} // end namespace lld - -#endif diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp deleted file mode 100644 index d56983d1e382..000000000000 --- a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp +++ /dev/null @@ -1,147 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp ------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "X86_64LinkingContext.h" -#include "X86_64TargetHandler.h" -#include "llvm/Support/Endian.h" - -using namespace lld; -using namespace lld::elf; -using namespace llvm::support::endian; - -/// \brief R_X86_64_64 - word64: S + A -static void reloc64(uint8_t *location, uint64_t P, uint64_t S, int64_t A) { - uint64_t result = S + A; - write64le(location, result | read64le(location)); -} - -/// \brief R_X86_64_PC32 - word32: S + A - P -static void relocPC32(uint8_t *location, uint64_t P, uint64_t S, int64_t A) { - uint32_t result = (uint32_t)(S + A - P); - write32le(location, result + read32le(location)); -} - -/// \brief R_X86_64_32 - word32: S + A -static void reloc32(uint8_t *location, uint64_t P, uint64_t S, int64_t A) { - int32_t result = (uint32_t)(S + A); - write32le(location, result | read32le(location)); - // TODO: Make sure that the result zero extends to the 64bit value. -} - -/// \brief R_X86_64_32S - word32: S + A -static void reloc32S(uint8_t *location, uint64_t P, uint64_t S, int64_t A) { - int32_t result = (int32_t)(S + A); - write32le(location, result | read32le(location)); - // TODO: Make sure that the result sign extends to the 64bit value. -} - -/// \brief R_X86_64_16 - word16: S + A -static void reloc16(uint8_t *location, uint64_t P, uint64_t S, int64_t A) { - uint16_t result = (uint16_t)(S + A); - write16le(location, result | read16le(location)); - // TODO: Check for overflow. -} - -/// \brief R_X86_64_PC16 - word16: S + A - P -static void relocPC16(uint8_t *location, uint64_t P, uint64_t S, int64_t A) { - uint16_t result = (uint16_t)(S + A - P); - write16le(location, result | read16le(location)); - // TODO: Check for overflow. -} - -/// \brief R_X86_64_PC64 - word64: S + A - P -static void relocPC64(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) { - int64_t result = (uint64_t)(S + A - P); - write64le(location, result | read64le(location)); -} - -std::error_code X86_64TargetRelocationHandler::applyRelocation( - ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom, - const Reference &ref) const { - uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset; - uint8_t *loc = atomContent + ref.offsetInAtom(); - uint64_t target = writer.addressOfAtom(ref.target()); - uint64_t reloc = atom._virtualAddr + ref.offsetInAtom(); - - if (ref.kindNamespace() != Reference::KindNamespace::ELF) - return std::error_code(); - assert(ref.kindArch() == Reference::KindArch::x86_64); - switch (ref.kindValue()) { - case R_X86_64_NONE: - break; - case R_X86_64_64: - reloc64(loc, reloc, target, ref.addend()); - break; - case R_X86_64_PC32: - case R_X86_64_GOTPCREL: - relocPC32(loc, reloc, target, ref.addend()); - break; - case R_X86_64_32: - reloc32(loc, reloc, target, ref.addend()); - break; - case R_X86_64_32S: - reloc32S(loc, reloc, target, ref.addend()); - break; - case R_X86_64_16: - reloc16(loc, reloc, target, ref.addend()); - break; - case R_X86_64_PC16: - relocPC16(loc, reloc, target, ref.addend()); - break; - case R_X86_64_DTPOFF32: - case R_X86_64_TPOFF32: - _tlsSize = _layout.getTLSSize(); - write32le(loc, target - _tlsSize); - break; - case R_X86_64_GOTTPOFF: - relocPC32(loc, reloc, target, ref.addend()); - break; - case R_X86_64_TLSGD: { - relocPC32(loc, reloc, target, ref.addend()); - break; - } - case R_X86_64_TLSLD: { - // Rewrite to move %fs:0 into %rax. Technically we should verify that the - // next relocation is a PC32 to __tls_get_addr... - static uint8_t instr[] = { 0x66, 0x66, 0x66, 0x64, 0x48, 0x8b, 0x04, 0x25, - 0x00, 0x00, 0x00, 0x00 }; - std::memcpy(loc - 3, instr, sizeof(instr)); - break; - } - case R_X86_64_PC64: - relocPC64(loc, reloc, target, ref.addend()); - break; - case LLD_R_X86_64_GOTRELINDEX: { - const DefinedAtom *target = cast<const DefinedAtom>(ref.target()); - for (const Reference *r : *target) { - if (r->kindValue() == R_X86_64_JUMP_SLOT) { - uint32_t index; - if (!_layout.getPLTRelocationTable()->getRelocationIndex(*r, index)) - llvm_unreachable("Relocation doesn't exist"); - reloc32(loc, 0, index, 0); - break; - } - } - break; - } - // Runtime only relocations. Ignore here. - case R_X86_64_RELATIVE: - case R_X86_64_IRELATIVE: - case R_X86_64_JUMP_SLOT: - case R_X86_64_GLOB_DAT: - case R_X86_64_DTPMOD64: - case R_X86_64_DTPOFF64: - case R_X86_64_TPOFF64: - break; - default: - return make_unhandled_reloc_error(); - } - - return std::error_code(); -} diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h deleted file mode 100644 index 26382804549b..000000000000 --- a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h +++ /dev/null @@ -1,37 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h --------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef X86_64_RELOCATION_HANDLER_H -#define X86_64_RELOCATION_HANDLER_H - -#include "lld/ReaderWriter/ELFLinkingContext.h" - -namespace lld { -namespace elf { -class X86_64TargetLayout; - -class X86_64TargetRelocationHandler final : public TargetRelocationHandler { -public: - X86_64TargetRelocationHandler(X86_64TargetLayout &layout) - : _tlsSize(0), _layout(layout) {} - - std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &, - const AtomLayout &, - const Reference &) const override; - -private: - // Cached size of the TLS segment. - mutable uint64_t _tlsSize; - X86_64TargetLayout &_layout; -}; - -} // end namespace elf -} // end namespace lld - -#endif // X86_64_RELOCATION_HANDLER_H diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp deleted file mode 100644 index a2f10dc08a4e..000000000000 --- a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp +++ /dev/null @@ -1,513 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp ---------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Defines the relocation processing pass for x86-64. This includes -/// GOT and PLT entries, TLS, COPY, and ifunc. -/// -/// This is based on section 4.4.1 of the AMD64 ABI (no stable URL as of Oct, -/// 2013). -/// -/// This also includes aditional behaivor that gnu-ld and gold implement but -/// which is not specified anywhere. -/// -//===----------------------------------------------------------------------===// - -#include "X86_64RelocationPass.h" -#include "Atoms.h" -#include "X86_64LinkingContext.h" -#include "lld/Core/Simple.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/STLExtras.h" - -using namespace lld; -using namespace lld::elf; -using namespace llvm::ELF; - -// .got values -static const uint8_t x86_64GotAtomContent[8] = {0}; - -// .plt value (entry 0) -static const uint8_t x86_64Plt0AtomContent[16] = { - 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOT+8(%rip) - 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOT+16(%rip) - 0x90, 0x90, 0x90, 0x90 // nopnopnop -}; - -// .plt values (other entries) -static const uint8_t x86_64PltAtomContent[16] = { - 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *gotatom(%rip) - 0x68, 0x00, 0x00, 0x00, 0x00, // pushq reloc-index - 0xe9, 0x00, 0x00, 0x00, 0x00 // jmpq plt[-1] -}; - -// TLS GD Entry -static const uint8_t x86_64GotTlsGdAtomContent[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - -namespace { -/// \brief Atoms that are used by X86_64 dynamic linking -class X86_64GOTAtom : public GOTAtom { -public: - X86_64GOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {} - - ArrayRef<uint8_t> rawContent() const override { - return ArrayRef<uint8_t>(x86_64GotAtomContent, 8); - } -}; - -/// \brief X86_64 GOT TLS GD entry. -class GOTTLSGdAtom : public X86_64GOTAtom { -public: - GOTTLSGdAtom(const File &f, StringRef secName) : X86_64GOTAtom(f, secName) {} - - ArrayRef<uint8_t> rawContent() const override { - return llvm::makeArrayRef(x86_64GotTlsGdAtomContent); - } -}; - -class X86_64PLT0Atom : public PLT0Atom { -public: - X86_64PLT0Atom(const File &f) : PLT0Atom(f) {} - ArrayRef<uint8_t> rawContent() const override { - return ArrayRef<uint8_t>(x86_64Plt0AtomContent, 16); - } -}; - -class X86_64PLTAtom : public PLTAtom { -public: - X86_64PLTAtom(const File &f, StringRef secName) : PLTAtom(f, secName) {} - - ArrayRef<uint8_t> rawContent() const override { - return ArrayRef<uint8_t>(x86_64PltAtomContent, 16); - } -}; - -class ELFPassFile : public SimpleFile { -public: - ELFPassFile(const ELFLinkingContext &eti) : SimpleFile("ELFPassFile") { - setOrdinal(eti.getNextOrdinalAndIncrement()); - } - - llvm::BumpPtrAllocator _alloc; -}; - -/// \brief CRTP base for handling relocations. -template <class Derived> class RelocationPass : public Pass { - /// \brief Handle a specific reference. - void handleReference(const DefinedAtom &atom, const Reference &ref) { - if (ref.kindNamespace() != Reference::KindNamespace::ELF) - return; - assert(ref.kindArch() == Reference::KindArch::x86_64); - switch (ref.kindValue()) { - case R_X86_64_16: - case R_X86_64_32: - case R_X86_64_32S: - case R_X86_64_64: - case R_X86_64_PC16: - case R_X86_64_PC32: - case R_X86_64_PC64: - static_cast<Derived *>(this)->handlePlain(ref); - break; - case R_X86_64_PLT32: - static_cast<Derived *>(this)->handlePLT32(ref); - break; - case R_X86_64_GOT32: - case R_X86_64_GOTPC32: - case R_X86_64_GOTPCREL: - case R_X86_64_GOTOFF64: - static_cast<Derived *>(this)->handleGOT(ref); - break; - case R_X86_64_GOTTPOFF: // GOT Thread Pointer Offset - static_cast<Derived *>(this)->handleGOTTPOFF(ref); - break; - case R_X86_64_TLSGD: - static_cast<Derived *>(this)->handleTLSGd(ref); - break; - } - } - -protected: - /// \brief get the PLT entry for a given IFUNC Atom. - /// - /// If the entry does not exist. Both the GOT and PLT entry is created. - const PLTAtom *getIFUNCPLTEntry(const DefinedAtom *da) { - auto plt = _pltMap.find(da); - if (plt != _pltMap.end()) - return plt->second; - auto ga = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt"); - ga->addReferenceELF_x86_64(R_X86_64_IRELATIVE, 0, da, 0); - auto pa = new (_file._alloc) X86_64PLTAtom(_file, ".plt"); - pa->addReferenceELF_x86_64(R_X86_64_PC32, 2, ga, -4); -#ifndef NDEBUG - ga->_name = "__got_ifunc_"; - ga->_name += da->name(); - pa->_name = "__plt_ifunc_"; - pa->_name += da->name(); -#endif - _gotMap[da] = ga; - _pltMap[da] = pa; - _gotVector.push_back(ga); - _pltVector.push_back(pa); - return pa; - } - - /// \brief Redirect the call to the PLT stub for the target IFUNC. - /// - /// This create a PLT and GOT entry for the IFUNC if one does not exist. The - /// GOT entry and a IRELATIVE relocation to the original target resolver. - std::error_code handleIFUNC(const Reference &ref) { - auto target = dyn_cast_or_null<const DefinedAtom>(ref.target()); - if (target && target->contentType() == DefinedAtom::typeResolver) - const_cast<Reference &>(ref).setTarget(getIFUNCPLTEntry(target)); - return std::error_code(); - } - - /// \brief Create a GOT entry for the TP offset of a TLS atom. - const GOTAtom *getGOTTPOFF(const Atom *atom) { - auto got = _gotMap.find(atom); - if (got == _gotMap.end()) { - auto g = new (_file._alloc) X86_64GOTAtom(_file, ".got"); - g->addReferenceELF_x86_64(R_X86_64_TPOFF64, 0, atom, 0); -#ifndef NDEBUG - g->_name = "__got_tls_"; - g->_name += atom->name(); -#endif - _gotMap[atom] = g; - _gotVector.push_back(g); - return g; - } - return got->second; - } - - /// \brief Create a TPOFF64 GOT entry. - std::error_code handleGOTTPOFF(const Reference &ref) { - if (isa<DefinedAtom>(ref.target())) { - const_cast<Reference &>(ref).setTarget(getGOTTPOFF(ref.target())); - } - return std::error_code(); - } - - /// \brief Create a TLS GOT entry with DTPMOD64/DTPOFF64 dynamic relocations. - void handleTLSGd(const Reference &ref) { - const_cast<Reference &>(ref).setTarget(getTLSGdGOTEntry(ref.target())); - } - - /// \brief Create a GOT entry containing 0. - const GOTAtom *getNullGOT() { - if (!_null) { - _null = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt"); -#ifndef NDEBUG - _null->_name = "__got_null"; -#endif - } - return _null; - } - - const GOTAtom *getGOT(const DefinedAtom *da) { - auto got = _gotMap.find(da); - if (got == _gotMap.end()) { - auto g = new (_file._alloc) X86_64GOTAtom(_file, ".got"); - g->addReferenceELF_x86_64(R_X86_64_64, 0, da, 0); -#ifndef NDEBUG - g->_name = "__got_"; - g->_name += da->name(); -#endif - _gotMap[da] = g; - _gotVector.push_back(g); - return g; - } - return got->second; - } - - const GOTAtom *getTLSGdGOTEntry(const Atom *a) { - auto got = _gotTLSGdMap.find(a); - if (got != _gotTLSGdMap.end()) - return got->second; - - auto ga = new (_file._alloc) GOTTLSGdAtom(_file, ".got"); - _gotTLSGdMap[a] = ga; - - _tlsGotVector.push_back(ga); - ga->addReferenceELF_x86_64(R_X86_64_DTPMOD64, 0, a, 0); - ga->addReferenceELF_x86_64(R_X86_64_DTPOFF64, 8, a, 0); - - return ga; - } - -public: - RelocationPass(const ELFLinkingContext &ctx) : _file(ctx), _ctx(ctx) {} - - /// \brief Do the pass. - /// - /// The goal here is to first process each reference individually. Each call - /// to handleReference may modify the reference itself and/or create new - /// atoms which must be stored in one of the maps below. - /// - /// After all references are handled, the atoms created during that are all - /// added to mf. - std::error_code perform(SimpleFile &mf) override { - ScopedTask task(getDefaultDomain(), "X86-64 GOT/PLT Pass"); - // Process all references. - for (const auto &atom : mf.defined()) - for (const auto &ref : *atom) - handleReference(*atom, *ref); - - // Add all created atoms to the link. - uint64_t ordinal = 0; - if (_plt0) { - _plt0->setOrdinal(ordinal++); - mf.addAtom(*_plt0); - } - for (auto &plt : _pltVector) { - plt->setOrdinal(ordinal++); - mf.addAtom(*plt); - } - if (_null) { - _null->setOrdinal(ordinal++); - mf.addAtom(*_null); - } - if (_plt0) { - _got0->setOrdinal(ordinal++); - _got1->setOrdinal(ordinal++); - mf.addAtom(*_got0); - mf.addAtom(*_got1); - } - for (auto &got : _gotVector) { - got->setOrdinal(ordinal++); - mf.addAtom(*got); - } - for (auto &got : _tlsGotVector) { - got->setOrdinal(ordinal++); - mf.addAtom(*got); - } - for (auto obj : _objectVector) { - obj->setOrdinal(ordinal++); - mf.addAtom(*obj); - } - return std::error_code(); - } - -protected: - /// \brief Owner of all the Atoms created by this pass. - ELFPassFile _file; - const ELFLinkingContext &_ctx; - - /// \brief Map Atoms to their GOT entries. - llvm::DenseMap<const Atom *, GOTAtom *> _gotMap; - - /// \brief Map Atoms to their PLT entries. - llvm::DenseMap<const Atom *, PLTAtom *> _pltMap; - - /// \brief Map Atoms to TLS GD GOT entries. - llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSGdMap; - - /// \brief Map Atoms to their Object entries. - llvm::DenseMap<const Atom *, ObjectAtom *> _objectMap; - - /// \brief the list of GOT/PLT atoms - std::vector<GOTAtom *> _gotVector; - std::vector<PLTAtom *> _pltVector; - std::vector<ObjectAtom *> _objectVector; - - /// \brief the list of TLS GOT atoms. - std::vector<GOTAtom *> _tlsGotVector; - - /// \brief GOT entry that is always 0. Used for undefined weaks. - GOTAtom *_null = nullptr; - - /// \brief The got and plt entries for .PLT0. This is used to call into the - /// dynamic linker for symbol resolution. - /// @{ - PLT0Atom *_plt0 = nullptr; - GOTAtom *_got0 = nullptr; - GOTAtom *_got1 = nullptr; - /// @} -}; - -/// This implements the static relocation model. Meaning GOT and PLT entries are -/// not created for references that can be directly resolved. These are -/// converted to a direct relocation. For entries that do require a GOT or PLT -/// entry, that entry is statically bound. -/// -/// TLS always assumes module 1 and attempts to remove indirection. -class StaticRelocationPass final - : public RelocationPass<StaticRelocationPass> { -public: - StaticRelocationPass(const elf::X86_64LinkingContext &ctx) - : RelocationPass(ctx) {} - - std::error_code handlePlain(const Reference &ref) { return handleIFUNC(ref); } - - std::error_code handlePLT32(const Reference &ref) { - // __tls_get_addr is handled elsewhere. - if (ref.target() && ref.target()->name() == "__tls_get_addr") { - const_cast<Reference &>(ref).setKindValue(R_X86_64_NONE); - return std::error_code(); - } - // Static code doesn't need PLTs. - const_cast<Reference &>(ref).setKindValue(R_X86_64_PC32); - // Handle IFUNC. - if (const DefinedAtom *da = - dyn_cast_or_null<const DefinedAtom>(ref.target())) - if (da->contentType() == DefinedAtom::typeResolver) - return handleIFUNC(ref); - return std::error_code(); - } - - std::error_code handleGOT(const Reference &ref) { - if (isa<UndefinedAtom>(ref.target())) - const_cast<Reference &>(ref).setTarget(getNullGOT()); - else if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(ref.target())) - const_cast<Reference &>(ref).setTarget(getGOT(da)); - return std::error_code(); - } -}; - -class DynamicRelocationPass final - : public RelocationPass<DynamicRelocationPass> { -public: - DynamicRelocationPass(const elf::X86_64LinkingContext &ctx) - : RelocationPass(ctx) {} - - const PLT0Atom *getPLT0() { - if (_plt0) - return _plt0; - // Fill in the null entry. - getNullGOT(); - _plt0 = new (_file._alloc) X86_64PLT0Atom(_file); - _got0 = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt"); - _got1 = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt"); - _plt0->addReferenceELF_x86_64(R_X86_64_PC32, 2, _got0, -4); - _plt0->addReferenceELF_x86_64(R_X86_64_PC32, 8, _got1, -4); -#ifndef NDEBUG - _got0->_name = "__got0"; - _got1->_name = "__got1"; -#endif - return _plt0; - } - - const PLTAtom *getPLTEntry(const Atom *a) { - auto plt = _pltMap.find(a); - if (plt != _pltMap.end()) - return plt->second; - auto ga = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt"); - ga->addReferenceELF_x86_64(R_X86_64_JUMP_SLOT, 0, a, 0); - auto pa = new (_file._alloc) X86_64PLTAtom(_file, ".plt"); - pa->addReferenceELF_x86_64(R_X86_64_PC32, 2, ga, -4); - pa->addReferenceELF_x86_64(LLD_R_X86_64_GOTRELINDEX, 7, ga, 0); - pa->addReferenceELF_x86_64(R_X86_64_PC32, 12, getPLT0(), -4); - // Set the starting address of the got entry to the second instruction in - // the plt entry. - ga->addReferenceELF_x86_64(R_X86_64_64, 0, pa, 6); -#ifndef NDEBUG - ga->_name = "__got_"; - ga->_name += a->name(); - pa->_name = "__plt_"; - pa->_name += a->name(); -#endif - _gotMap[a] = ga; - _pltMap[a] = pa; - _gotVector.push_back(ga); - _pltVector.push_back(pa); - return pa; - } - - const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a) { - auto obj = _objectMap.find(a); - if (obj != _objectMap.end()) - return obj->second; - - auto oa = new (_file._alloc) ObjectAtom(_file); - // This needs to point to the atom that we just created. - oa->addReferenceELF_x86_64(R_X86_64_COPY, 0, oa, 0); - - oa->_name = a->name(); - oa->_size = a->size(); - - _objectMap[a] = oa; - _objectVector.push_back(oa); - return oa; - } - - std::error_code handlePlain(const Reference &ref) { - if (!ref.target()) - return std::error_code(); - if (auto sla = dyn_cast<SharedLibraryAtom>(ref.target())) { - if (sla->type() == SharedLibraryAtom::Type::Data) - const_cast<Reference &>(ref).setTarget(getObjectEntry(sla)); - else if (sla->type() == SharedLibraryAtom::Type::Code) - const_cast<Reference &>(ref).setTarget(getPLTEntry(sla)); - } else - return handleIFUNC(ref); - return std::error_code(); - } - - std::error_code handlePLT32(const Reference &ref) { - // Turn this into a PC32 to the PLT entry. - const_cast<Reference &>(ref).setKindValue(R_X86_64_PC32); - // Handle IFUNC. - if (const DefinedAtom *da = - dyn_cast_or_null<const DefinedAtom>(ref.target())) - if (da->contentType() == DefinedAtom::typeResolver) - return handleIFUNC(ref); - // If it is undefined at link time, push the work to the dynamic linker by - // creating a PLT entry - if (isa<SharedLibraryAtom>(ref.target()) || - isa<UndefinedAtom>(ref.target())) - const_cast<Reference &>(ref).setTarget(getPLTEntry(ref.target())); - return std::error_code(); - } - - const GOTAtom *getSharedGOT(const Atom *a) { - auto got = _gotMap.find(a); - if (got == _gotMap.end()) { - auto g = new (_file._alloc) X86_64GOTAtom(_file, ".got"); - g->addReferenceELF_x86_64(R_X86_64_GLOB_DAT, 0, a, 0); -#ifndef NDEBUG - g->_name = "__got_"; - g->_name += a->name(); -#endif - _gotMap[a] = g; - _gotVector.push_back(g); - return g; - } - return got->second; - } - - std::error_code handleGOT(const Reference &ref) { - if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(ref.target())) - const_cast<Reference &>(ref).setTarget(getGOT(da)); - // Handle undefined atoms in the same way as shared lib atoms: to be - // resolved at run time. - else if (isa<SharedLibraryAtom>(ref.target()) || - isa<UndefinedAtom>(ref.target())) - const_cast<Reference &>(ref).setTarget(getSharedGOT(ref.target())); - return std::error_code(); - } -}; -} // end anon namespace - -std::unique_ptr<Pass> -lld::elf::createX86_64RelocationPass(const X86_64LinkingContext &ctx) { - switch (ctx.getOutputELFType()) { - case llvm::ELF::ET_EXEC: - if (ctx.isDynamic()) - return llvm::make_unique<DynamicRelocationPass>(ctx); - return llvm::make_unique<StaticRelocationPass>(ctx); - case llvm::ELF::ET_DYN: - return llvm::make_unique<DynamicRelocationPass>(ctx); - case llvm::ELF::ET_REL: - return nullptr; - default: - llvm_unreachable("Unhandled output file type"); - } -} diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h deleted file mode 100644 index 1635b5e5f57b..000000000000 --- a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h +++ /dev/null @@ -1,32 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h -----------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Declares the relocation processing pass for x86-64. This includes -/// GOT and PLT entries, TLS, COPY, and ifunc. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_X86_64_X86_64_RELOCATION_PASS_H -#define LLD_READER_WRITER_ELF_X86_64_X86_64_RELOCATION_PASS_H - -#include <memory> - -namespace lld { -class Pass; -namespace elf { -class X86_64LinkingContext; - -/// \brief Create x86-64 relocation pass for the given linking context. -std::unique_ptr<Pass> -createX86_64RelocationPass(const X86_64LinkingContext &); -} -} - -#endif diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.cpp b/lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.cpp deleted file mode 100644 index 28eb3e4244b6..000000000000 --- a/lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.cpp +++ /dev/null @@ -1,37 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.cpp --------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "X86_64SectionChunks.h" -#include "TargetLayout.h" - -namespace lld { -namespace elf { - -X86_64GOTSection::X86_64GOTSection(const ELFLinkingContext &ctx) - : AtomSection<ELF64LE>(ctx, ".got", DefinedAtom::typeGOT, DefinedAtom::permRW_, - TargetLayout<ELF64LE>::ORDER_GOT) { - this->_alignment = 8; -} - -const AtomLayout *X86_64GOTSection::appendAtom(const Atom *atom) { - const DefinedAtom *da = dyn_cast<DefinedAtom>(atom); - - for (const auto &r : *da) { - if (r->kindNamespace() != Reference::KindNamespace::ELF) - continue; - assert(r->kindArch() == Reference::KindArch::x86_64); - if (r->kindValue() == R_X86_64_TPOFF64) - _tlsMap[r->target()] = _tlsMap.size(); - } - - return AtomSection<ELF64LE>::appendAtom(atom); -} - -} // elf -} // lld diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.h b/lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.h deleted file mode 100644 index 5208491eee55..000000000000 --- a/lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.h +++ /dev/null @@ -1,36 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.h ----------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_X86_64_X86_64_SECTION_CHUNKS_H -#define LLD_READER_WRITER_ELF_X86_64_X86_64_SECTION_CHUNKS_H - -#include "TargetLayout.h" - -namespace lld { -namespace elf { - -class X86_64GOTSection : public AtomSection<ELF64LE> { -public: - X86_64GOTSection(const ELFLinkingContext &ctx); - - bool hasGlobalGOTEntry(const Atom *a) const { - return _tlsMap.count(a); - } - - const AtomLayout *appendAtom(const Atom *atom) override; - -private: - /// \brief Map TLS Atoms to their GOT entry index. - llvm::DenseMap<const Atom *, std::size_t> _tlsMap; -}; - -} // elf -} // lld - -#endif diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp b/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp deleted file mode 100644 index 599077ac33c5..000000000000 --- a/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp +++ /dev/null @@ -1,34 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp ----------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Atoms.h" -#include "X86_64DynamicLibraryWriter.h" -#include "X86_64ExecutableWriter.h" -#include "X86_64LinkingContext.h" -#include "X86_64TargetHandler.h" - -using namespace lld; -using namespace elf; - -X86_64TargetHandler::X86_64TargetHandler(X86_64LinkingContext &ctx) - : _ctx(ctx), _targetLayout(new X86_64TargetLayout(ctx)), - _relocationHandler(new X86_64TargetRelocationHandler(*_targetLayout)) {} - -std::unique_ptr<Writer> X86_64TargetHandler::getWriter() { - switch (this->_ctx.getOutputELFType()) { - case llvm::ELF::ET_EXEC: - return llvm::make_unique<X86_64ExecutableWriter>(_ctx, *_targetLayout); - case llvm::ELF::ET_DYN: - return llvm::make_unique<X86_64DynamicLibraryWriter>(_ctx, *_targetLayout); - case llvm::ELF::ET_REL: - llvm_unreachable("TODO: support -r mode"); - default: - llvm_unreachable("unsupported output type"); - } -} diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h b/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h deleted file mode 100644 index 6e3e58f8aed6..000000000000 --- a/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h +++ /dev/null @@ -1,104 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h ------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_X86_64_X86_64_TARGET_HANDLER_H -#define LLD_READER_WRITER_ELF_X86_64_X86_64_TARGET_HANDLER_H - -#include "ELFReader.h" -#include "TargetLayout.h" -#include "X86_64LinkingContext.h" -#include "X86_64RelocationHandler.h" -#include "X86_64SectionChunks.h" -#include "lld/Core/Simple.h" - -namespace lld { -namespace elf { - - -class X86_64TargetLayout : public TargetLayout<ELF64LE> { -public: - X86_64TargetLayout(X86_64LinkingContext &ctx) : TargetLayout(ctx), - _gotSection(new (this->_allocator) X86_64GOTSection(ctx)) {} - - AtomSection<ELF64LE> * - createSection(StringRef name, int32_t type, - DefinedAtom::ContentPermissions permissions, - TargetLayout<ELF64LE>::SectionOrder order) override { - if (type == DefinedAtom::typeGOT && name == ".got") - return _gotSection; - return TargetLayout<ELF64LE>::createSection(name, type, permissions, order); - } - - void finalizeOutputSectionLayout() override { - sortOutputSectionByPriority<ELF64LE>(".init_array"); - sortOutputSectionByPriority<ELF64LE>(".fini_array"); - } - - const X86_64GOTSection &getGOTSection() const { return *_gotSection; } - -private: - uint32_t getPriority(StringRef sectionName) const { - StringRef priority = sectionName.drop_front().rsplit('.').second; - uint32_t prio; - if (priority.getAsInteger(10, prio)) - return std::numeric_limits<uint32_t>::max(); - return prio; - } - - template <typename T> void sortOutputSectionByPriority(StringRef prefix) { - OutputSection<T> *section = findOutputSection(prefix); - if (!section) - return; - auto sections = section->sections(); - std::sort(sections.begin(), sections.end(), - [&](Chunk<T> *lhs, Chunk<T> *rhs) { - Section<T> *lhsSection = dyn_cast<Section<T>>(lhs); - Section<T> *rhsSection = dyn_cast<Section<T>>(rhs); - if (!lhsSection || !rhsSection) - return false; - StringRef lhsName = lhsSection->inputSectionName(); - StringRef rhsName = rhsSection->inputSectionName(); - if (!lhsName.startswith(prefix) || !rhsName.startswith(prefix)) - return false; - return getPriority(lhsName) < getPriority(rhsName); - }); - } - -private: - X86_64GOTSection *_gotSection; -}; - -class X86_64TargetHandler : public TargetHandler { -public: - X86_64TargetHandler(X86_64LinkingContext &ctx); - - const TargetRelocationHandler &getRelocationHandler() const override { - return *_relocationHandler; - } - - std::unique_ptr<Reader> getObjReader() override { - return llvm::make_unique<ELFReader<ELFFile<ELF64LE>>>(_ctx); - } - - std::unique_ptr<Reader> getDSOReader() override { - return llvm::make_unique<ELFReader<DynamicFile<ELF64LE>>>(_ctx); - } - - std::unique_ptr<Writer> getWriter() override; - -protected: - X86_64LinkingContext &_ctx; - std::unique_ptr<X86_64TargetLayout> _targetLayout; - std::unique_ptr<X86_64TargetRelocationHandler> _relocationHandler; -}; - -} // end namespace elf -} // end namespace lld - -#endif diff --git a/lib/ReaderWriter/FileArchive.cpp b/lib/ReaderWriter/FileArchive.cpp index a09923f57d07..eb7e7fb1837b 100644 --- a/lib/ReaderWriter/FileArchive.cpp +++ b/lib/ReaderWriter/FileArchive.cpp @@ -8,27 +8,28 @@ //===----------------------------------------------------------------------===// #include "lld/Core/ArchiveLibraryFile.h" +#include "lld/Core/File.h" #include "lld/Core/LLVM.h" -#include "lld/Core/LinkingContext.h" -#include "lld/Core/Parallel.h" -#include "lld/Driver/Driver.h" -#include "llvm/ADT/Hashing.h" +#include "lld/Core/Reader.h" #include "llvm/ADT/StringRef.h" #include "llvm/Object/Archive.h" -#include "llvm/Object/ObjectFile.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Format.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Object/Error.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/raw_ostream.h" #include <memory> -#include <mutex> #include <set> +#include <string> +#include <system_error> #include <unordered_map> +#include <utility> +#include <vector> using llvm::object::Archive; -using llvm::object::ObjectFile; -using llvm::object::SymbolRef; -using llvm::object::symbol_iterator; -using llvm::object::object_error; namespace lld { @@ -44,39 +45,23 @@ public: /// \brief Check if any member of the archive contains an Atom with the /// specified name and return the File object for that member, or nullptr. - File *find(StringRef name, bool dataSymbolOnly) override { + File *find(StringRef name) override { auto member = _symbolMemberMap.find(name); if (member == _symbolMemberMap.end()) return nullptr; - Archive::child_iterator ci = member->second; - if (ci->getError()) - return nullptr; + Archive::Child c = member->second; // Don't return a member already returned - ErrorOr<StringRef> buf = (*ci)->getBuffer(); + ErrorOr<StringRef> buf = c.getBuffer(); if (!buf) return nullptr; const char *memberStart = buf->data(); if (_membersInstantiated.count(memberStart)) return nullptr; - if (dataSymbolOnly && !isDataSymbol(ci, name)) - return nullptr; - _membersInstantiated.insert(memberStart); - // Check if a file is preloaded. - { - std::lock_guard<std::mutex> lock(_mutex); - auto it = _preloaded.find(memberStart); - if (it != _preloaded.end()) { - std::unique_ptr<Future<File *>> &p = it->second; - Future<File *> *future = p.get(); - return future->get(); - } - } - std::unique_ptr<File> result; - if (instantiateMember(ci, result)) + if (instantiateMember(c, result)) return nullptr; File *file = result.get(); @@ -86,97 +71,68 @@ public: return file; } - // Instantiate a member file containing a given symbol name. - void preload(TaskGroup &group, StringRef name) override { - auto member = _symbolMemberMap.find(name); - if (member == _symbolMemberMap.end()) - return; - Archive::child_iterator ci = member->second; - if (ci->getError()) - return; - - // Do nothing if a member is already instantiated. - ErrorOr<StringRef> buf = (*ci)->getBuffer(); - if (!buf) - return; - const char *memberStart = buf->data(); - if (_membersInstantiated.count(memberStart)) - return; - - std::lock_guard<std::mutex> lock(_mutex); - if (_preloaded.find(memberStart) != _preloaded.end()) - return; - - // Instantiate the member - auto *future = new Future<File *>(); - _preloaded[memberStart] = std::unique_ptr<Future<File *>>(future); - - group.spawn([=] { - std::unique_ptr<File> result; - std::error_code ec = instantiateMember(ci, result); - future->set(ec ? nullptr : result.release()); - }); - } - /// \brief parse each member std::error_code parseAllMembers(std::vector<std::unique_ptr<File>> &result) override { if (std::error_code ec = parse()) return ec; - for (auto mf = _archive->child_begin(), me = _archive->child_end(); + llvm::Error err; + for (auto mf = _archive->child_begin(err), me = _archive->child_end(); mf != me; ++mf) { std::unique_ptr<File> file; - if (std::error_code ec = instantiateMember(mf, file)) + if (std::error_code ec = instantiateMember(*mf, file)) { + // err is Success (or we wouldn't be in the loop body) but we can't + // return without testing or consuming it. + consumeError(std::move(err)); return ec; + } result.push_back(std::move(file)); } + if (err) + return errorToErrorCode(std::move(err)); return std::error_code(); } - const AtomVector<DefinedAtom> &defined() const override { + const AtomRange<DefinedAtom> defined() const override { return _noDefinedAtoms; } - const AtomVector<UndefinedAtom> &undefined() const override { + const AtomRange<UndefinedAtom> undefined() const override { return _noUndefinedAtoms; } - const AtomVector<SharedLibraryAtom> &sharedLibrary() const override { + const AtomRange<SharedLibraryAtom> sharedLibrary() const override { return _noSharedLibraryAtoms; } - const AtomVector<AbsoluteAtom> &absolute() const override { + const AtomRange<AbsoluteAtom> absolute() const override { return _noAbsoluteAtoms; } - /// Returns a set of all defined symbols in the archive. - std::set<StringRef> getDefinedSymbols() override { - parse(); - std::set<StringRef> ret; - for (const auto &e : _symbolMemberMap) - ret.insert(e.first); - return ret; + void clearAtoms() override { + _noDefinedAtoms.clear(); + _noUndefinedAtoms.clear(); + _noSharedLibraryAtoms.clear(); + _noAbsoluteAtoms.clear(); } protected: std::error_code doParse() override { // Make Archive object which will be owned by FileArchive object. + llvm::Error Err; + _archive.reset(new Archive(_mb->getMemBufferRef(), Err)); + if (Err) + return errorToErrorCode(std::move(Err)); std::error_code ec; - _archive.reset(new Archive(_mb->getMemBufferRef(), ec)); - if (ec) - return ec; if ((ec = buildTableOfContents())) return ec; return std::error_code(); } private: - std::error_code instantiateMember(Archive::child_iterator cOrErr, + std::error_code instantiateMember(Archive::Child member, std::unique_ptr<File> &result) const { - if (std::error_code ec = cOrErr->getError()) - return ec; - Archive::child_iterator member = cOrErr->get(); - ErrorOr<llvm::MemoryBufferRef> mbOrErr = (*member)->getMemoryBufferRef(); + ErrorOr<llvm::MemoryBufferRef> mbOrErr = member.getMemoryBufferRef(); if (std::error_code ec = mbOrErr.getError()) return ec; llvm::MemoryBufferRef mb = mbOrErr.get(); @@ -204,64 +160,27 @@ private: return std::error_code(); } - // Parses the given memory buffer as an object file, and returns true - // code if the given symbol is a data symbol. If the symbol is not a data - // symbol or does not exist, returns false. - bool isDataSymbol(Archive::child_iterator cOrErr, StringRef symbol) const { - if (cOrErr->getError()) - return false; - Archive::child_iterator member = cOrErr->get(); - ErrorOr<llvm::MemoryBufferRef> buf = (*member)->getMemoryBufferRef(); - if (buf.getError()) - return false; - std::unique_ptr<MemoryBuffer> mb(MemoryBuffer::getMemBuffer( - buf.get().getBuffer(), buf.get().getBufferIdentifier(), false)); - - auto objOrErr(ObjectFile::createObjectFile(mb->getMemBufferRef())); - if (objOrErr.getError()) - return false; - std::unique_ptr<ObjectFile> obj = std::move(objOrErr.get()); - - for (SymbolRef sym : obj->symbols()) { - // Skip until we find the symbol. - ErrorOr<StringRef> name = sym.getName(); - if (!name) - return false; - if (*name != symbol) - continue; - uint32_t flags = sym.getFlags(); - if (flags <= SymbolRef::SF_Undefined) - continue; - - // Returns true if it's a data symbol. - SymbolRef::Type type = sym.getType(); - if (type == SymbolRef::ST_Data) - return true; - } - return false; - } - std::error_code buildTableOfContents() { DEBUG_WITH_TYPE("FileArchive", llvm::dbgs() << "Table of contents for archive '" << _archive->getFileName() << "':\n"); for (const Archive::Symbol &sym : _archive->symbols()) { StringRef name = sym.getName(); - ErrorOr<Archive::child_iterator> memberOrErr = sym.getMember(); + ErrorOr<Archive::Child> memberOrErr = sym.getMember(); if (std::error_code ec = memberOrErr.getError()) return ec; - Archive::child_iterator member = memberOrErr.get(); + Archive::Child member = memberOrErr.get(); DEBUG_WITH_TYPE("FileArchive", llvm::dbgs() << llvm::format("0x%08llX ", - (*member)->getBuffer()->data()) + member.getBuffer()->data()) << "'" << name << "'\n"); _symbolMemberMap.insert(std::make_pair(name, member)); } return std::error_code(); } - typedef std::unordered_map<StringRef, Archive::child_iterator> MemberMap; + typedef std::unordered_map<StringRef, Archive::Child> MemberMap; typedef std::set<const char *> InstantiatedSet; std::shared_ptr<MemoryBuffer> _mb; @@ -271,9 +190,7 @@ private: InstantiatedSet _membersInstantiated; bool _logLoading; std::vector<std::unique_ptr<MemoryBuffer>> _memberBuffers; - std::map<const char *, std::unique_ptr<Future<File *>>> _preloaded; - std::mutex _mutex; - FileVector _filesReturned; + std::vector<std::unique_ptr<File>> _filesReturned; }; class ArchiveReader : public Reader { @@ -302,4 +219,4 @@ void Registry::addSupportArchives(bool logLoading) { add(std::unique_ptr<Reader>(new ArchiveReader(logLoading))); } -} // end namespace lld +} // namespace lld diff --git a/lib/ReaderWriter/LinkerScript.cpp b/lib/ReaderWriter/LinkerScript.cpp deleted file mode 100644 index 67822dc48fe6..000000000000 --- a/lib/ReaderWriter/LinkerScript.cpp +++ /dev/null @@ -1,2895 +0,0 @@ -//===- ReaderWriter/LinkerScript.cpp ----------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Linker script parser. -/// -//===----------------------------------------------------------------------===// - -#include "lld/ReaderWriter/LinkerScript.h" - -#include "llvm/ADT/APInt.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/ELF.h" - -namespace lld { -namespace script { -void Token::dump(raw_ostream &os) const { - switch (_kind) { -#define CASE(name) \ - case Token::name: \ - os << #name ": "; \ - break; - CASE(unknown) - CASE(eof) - CASE(exclaim) - CASE(exclaimequal) - CASE(amp) - CASE(ampequal) - CASE(l_paren) - CASE(r_paren) - CASE(star) - CASE(starequal) - CASE(plus) - CASE(plusequal) - CASE(comma) - CASE(minus) - CASE(minusequal) - CASE(slash) - CASE(slashequal) - CASE(number) - CASE(colon) - CASE(semicolon) - CASE(less) - CASE(lessequal) - CASE(lessless) - CASE(lesslessequal) - CASE(equal) - CASE(equalequal) - CASE(greater) - CASE(greaterequal) - CASE(greatergreater) - CASE(greatergreaterequal) - CASE(question) - CASE(identifier) - CASE(libname) - CASE(kw_align) - CASE(kw_align_with_input) - CASE(kw_as_needed) - CASE(kw_at) - CASE(kw_discard) - CASE(kw_entry) - CASE(kw_exclude_file) - CASE(kw_extern) - CASE(kw_filehdr) - CASE(kw_fill) - CASE(kw_flags) - CASE(kw_group) - CASE(kw_hidden) - CASE(kw_input) - CASE(kw_keep) - CASE(kw_length) - CASE(kw_memory) - CASE(kw_origin) - CASE(kw_phdrs) - CASE(kw_provide) - CASE(kw_provide_hidden) - CASE(kw_only_if_ro) - CASE(kw_only_if_rw) - CASE(kw_output) - CASE(kw_output_arch) - CASE(kw_output_format) - CASE(kw_overlay) - CASE(kw_search_dir) - CASE(kw_sections) - CASE(kw_sort_by_alignment) - CASE(kw_sort_by_init_priority) - CASE(kw_sort_by_name) - CASE(kw_sort_none) - CASE(kw_subalign) - CASE(l_brace) - CASE(pipe) - CASE(pipeequal) - CASE(r_brace) - CASE(tilde) -#undef CASE - } - os << _range << "\n"; -} - -static llvm::ErrorOr<uint64_t> parseDecimal(StringRef str) { - uint64_t res = 0; - for (auto &c : str) { - res *= 10; - if (c < '0' || c > '9') - return llvm::ErrorOr<uint64_t>(make_error_code(llvm::errc::io_error)); - res += c - '0'; - } - return res; -} - -static llvm::ErrorOr<uint64_t> parseOctal(StringRef str) { - uint64_t res = 0; - for (auto &c : str) { - res <<= 3; - if (c < '0' || c > '7') - return llvm::ErrorOr<uint64_t>(make_error_code(llvm::errc::io_error)); - res += c - '0'; - } - return res; -} - -static llvm::ErrorOr<uint64_t> parseBinary(StringRef str) { - uint64_t res = 0; - for (auto &c : str) { - res <<= 1; - if (c != '0' && c != '1') - return llvm::ErrorOr<uint64_t>(make_error_code(llvm::errc::io_error)); - res += c - '0'; - } - return res; -} - -static llvm::ErrorOr<uint64_t> parseHex(StringRef str) { - uint64_t res = 0; - for (auto &c : str) { - res <<= 4; - if (c >= '0' && c <= '9') - res += c - '0'; - else if (c >= 'a' && c <= 'f') - res += c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - res += c - 'A' + 10; - else - return llvm::ErrorOr<uint64_t>(make_error_code(llvm::errc::io_error)); - } - return res; -} - -static bool parseHexToByteStream(StringRef str, std::string &buf) { - unsigned char byte = 0; - bool dumpByte = str.size() % 2; - for (auto &c : str) { - byte <<= 4; - if (c >= '0' && c <= '9') - byte += c - '0'; - else if (c >= 'a' && c <= 'f') - byte += c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - byte += c - 'A' + 10; - else - return false; - if (!dumpByte) { - dumpByte = true; - continue; - } - buf.push_back(byte); - byte = 0; - dumpByte = false; - } - return !dumpByte; -} - -static void dumpByteStream(raw_ostream &os, StringRef stream) { - os << "0x"; - for (auto &c : stream) { - unsigned char firstNibble = c >> 4 & 0xF; - if (firstNibble > 9) - os << (char) ('A' + firstNibble - 10); - else - os << (char) ('0' + firstNibble); - unsigned char secondNibble = c & 0xF; - if (secondNibble > 9) - os << (char) ('A' + secondNibble - 10); - else - os << (char) ('0' + secondNibble); - } -} - -static llvm::ErrorOr<uint64_t> parseNum(StringRef str) { - unsigned multiplier = 1; - enum NumKind { decimal, hex, octal, binary }; - NumKind kind = llvm::StringSwitch<NumKind>(str) - .StartsWith("0x", hex) - .StartsWith("0X", hex) - .StartsWith("0", octal) - .Default(decimal); - - // Parse scale - if (str.endswith("K")) { - multiplier = 1 << 10; - str = str.drop_back(); - } else if (str.endswith("M")) { - multiplier = 1 << 20; - str = str.drop_back(); - } - - // Parse type - if (str.endswith_lower("o")) { - kind = octal; - str = str.drop_back(); - } else if (str.endswith_lower("h")) { - kind = hex; - str = str.drop_back(); - } else if (str.endswith_lower("d")) { - kind = decimal; - str = str.drop_back(); - } else if (str.endswith_lower("b")) { - kind = binary; - str = str.drop_back(); - } - - llvm::ErrorOr<uint64_t> res(0); - switch (kind) { - case hex: - if (str.startswith_lower("0x")) - str = str.drop_front(2); - res = parseHex(str); - break; - case octal: - res = parseOctal(str); - break; - case decimal: - res = parseDecimal(str); - break; - case binary: - res = parseBinary(str); - break; - } - if (res.getError()) - return res; - - *res = *res * multiplier; - return res; -} - -bool Lexer::canStartNumber(char c) const { - return '0' <= c && c <= '9'; -} - -bool Lexer::canContinueNumber(char c) const { - // [xX] = hex marker, [hHoO] = type suffix, [MK] = scale suffix. - return strchr("0123456789ABCDEFabcdefxXhHoOMK", c); -} - -bool Lexer::canStartName(char c) const { - return strchr( - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_.$/\\*", c); -} - -bool Lexer::canContinueName(char c) const { - return strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" - "0123456789_.$/\\~=+[]*?-:", c); -} - -/// Helper function to split a StringRef in two at the nth character. -/// The StringRef s is updated, while the function returns the n first -/// characters. -static StringRef drop(StringRef &s, int n) { - StringRef res = s.substr(0, n); - s = s.drop_front(n); - return res; -} - -void Lexer::lex(Token &tok) { - skipWhitespace(); - if (_buffer.empty()) { - tok = Token(_buffer, Token::eof); - return; - } - switch (_buffer[0]) { - case 0: - tok = Token(drop(_buffer, 1), Token::eof); - return; - case '(': - tok = Token(drop(_buffer, 1), Token::l_paren); - return; - case ')': - tok = Token(drop(_buffer, 1), Token::r_paren); - return; - case '{': - tok = Token(drop(_buffer, 1), Token::l_brace); - return; - case '}': - tok = Token(drop(_buffer, 1), Token::r_brace); - return; - case '=': - if (_buffer.startswith("==")) { - tok = Token(drop(_buffer, 2), Token::equalequal); - return; - } - tok = Token(drop(_buffer, 1), Token::equal); - return; - case '!': - if (_buffer.startswith("!=")) { - tok = Token(drop(_buffer, 2), Token::exclaimequal); - return; - } - tok = Token(drop(_buffer, 1), Token::exclaim); - return; - case ',': - tok = Token(drop(_buffer, 1), Token::comma); - return; - case ';': - tok = Token(drop(_buffer, 1), Token::semicolon); - return; - case ':': - tok = Token(drop(_buffer, 1), Token::colon); - return; - case '&': - if (_buffer.startswith("&=")) { - tok = Token(drop(_buffer, 2), Token::ampequal); - return; - } - tok = Token(drop(_buffer, 1), Token::amp); - return; - case '|': - if (_buffer.startswith("|=")) { - tok = Token(drop(_buffer, 2), Token::pipeequal); - return; - } - tok = Token(drop(_buffer, 1), Token::pipe); - return; - case '+': - if (_buffer.startswith("+=")) { - tok = Token(drop(_buffer, 2), Token::plusequal); - return; - } - tok = Token(drop(_buffer, 1), Token::plus); - return; - case '-': { - if (_buffer.startswith("-=")) { - tok = Token(drop(_buffer, 2), Token::minusequal); - return; - } - if (!_buffer.startswith("-l")) { - tok = Token(drop(_buffer, 1), Token::minus); - return; - } - // -l<lib name> - _buffer = _buffer.drop_front(2); - StringRef::size_type start = 0; - if (_buffer[start] == ':') - ++start; - if (!canStartName(_buffer[start])) - // Create 'unknown' token. - break; - auto libNameEnd = std::find_if(_buffer.begin() + start + 1, _buffer.end(), - [=](char c) { return !canContinueName(c); }); - StringRef::size_type libNameLen = - std::distance(_buffer.begin(), libNameEnd); - tok = Token(_buffer.substr(0, libNameLen), Token::libname); - _buffer = _buffer.drop_front(libNameLen); - return; - } - case '<': - if (_buffer.startswith("<<=")) { - tok = Token(drop(_buffer, 3), Token::lesslessequal); - return; - } - if (_buffer.startswith("<<")) { - tok = Token(drop(_buffer, 2), Token::lessless); - return; - } - if (_buffer.startswith("<=")) { - tok = Token(drop(_buffer, 2), Token::lessequal); - return; - } - tok = Token(drop(_buffer, 1), Token::less); - return; - case '>': - if (_buffer.startswith(">>=")) { - tok = Token(drop(_buffer, 3), Token::greatergreaterequal); - return; - } - if (_buffer.startswith(">>")) { - tok = Token(drop(_buffer, 2), Token::greatergreater); - return; - } - if (_buffer.startswith(">=")) { - tok = Token(drop(_buffer, 2), Token::greaterequal); - return; - } - tok = Token(drop(_buffer, 1), Token::greater); - return; - case '~': - tok = Token(drop(_buffer, 1), Token::tilde); - return; - case '\"': case '\'': { - // Handle quoted strings. They are treated as identifiers for - // simplicity. - char c = _buffer[0]; - _buffer = _buffer.drop_front(); - auto quotedStringEnd = _buffer.find(c); - if (quotedStringEnd == StringRef::npos || quotedStringEnd == 0) - break; - StringRef word = _buffer.substr(0, quotedStringEnd); - tok = Token(word, Token::identifier); - _buffer = _buffer.drop_front(quotedStringEnd + 1); - return; - } - default: - // Handle literal numbers - if (canStartNumber(_buffer[0])) { - auto endIter = std::find_if(_buffer.begin(), _buffer.end(), [=](char c) { - return !canContinueNumber(c); - }); - StringRef::size_type end = endIter == _buffer.end() - ? StringRef::npos - : std::distance(_buffer.begin(), endIter); - if (end == StringRef::npos || end == 0) - break; - StringRef word = _buffer.substr(0, end); - tok = Token(word, Token::number); - _buffer = _buffer.drop_front(end); - return; - } - // Handle slashes '/', which can be either an operator inside an expression - // or the beginning of an identifier - if (_buffer.startswith("/=")) { - tok = Token(drop(_buffer, 2), Token::slashequal); - return; - } - if (_buffer[0] == '/' && _buffer.size() > 1 && - !canContinueName(_buffer[1])) { - tok = Token(drop(_buffer, 1), Token::slash); - return; - } - // Handle stars '*' - if (_buffer.startswith("*=")) { - tok = Token(drop(_buffer, 2), Token::starequal); - return; - } - if (_buffer[0] == '*' && _buffer.size() > 1 && - !canContinueName(_buffer[1])) { - tok = Token(drop(_buffer, 1), Token::star); - return; - } - // Handle questions '?' - if (_buffer[0] == '?' && _buffer.size() > 1 && - !canContinueName(_buffer[1])) { - tok = Token(drop(_buffer, 1), Token::question); - return; - } - // keyword or identifier. - if (!canStartName(_buffer[0])) - break; - auto endIter = std::find_if(_buffer.begin() + 1, _buffer.end(), - [=](char c) { return !canContinueName(c); }); - StringRef::size_type end = endIter == _buffer.end() - ? StringRef::npos - : std::distance(_buffer.begin(), endIter); - if (end == StringRef::npos || end == 0) - break; - StringRef word = _buffer.substr(0, end); - Token::Kind kind = - llvm::StringSwitch<Token::Kind>(word) - .Case("ALIGN", Token::kw_align) - .Case("ALIGN_WITH_INPUT", Token::kw_align_with_input) - .Case("AS_NEEDED", Token::kw_as_needed) - .Case("AT", Token::kw_at) - .Case("ENTRY", Token::kw_entry) - .Case("EXCLUDE_FILE", Token::kw_exclude_file) - .Case("EXTERN", Token::kw_extern) - .Case("FILEHDR", Token::kw_filehdr) - .Case("FILL", Token::kw_fill) - .Case("FLAGS", Token::kw_flags) - .Case("GROUP", Token::kw_group) - .Case("HIDDEN", Token::kw_hidden) - .Case("INPUT", Token::kw_input) - .Case("KEEP", Token::kw_keep) - .Case("LENGTH", Token::kw_length) - .Case("l", Token::kw_length) - .Case("len", Token::kw_length) - .Case("MEMORY", Token::kw_memory) - .Case("ONLY_IF_RO", Token::kw_only_if_ro) - .Case("ONLY_IF_RW", Token::kw_only_if_rw) - .Case("ORIGIN", Token::kw_origin) - .Case("o", Token::kw_origin) - .Case("org", Token::kw_origin) - .Case("OUTPUT", Token::kw_output) - .Case("OUTPUT_ARCH", Token::kw_output_arch) - .Case("OUTPUT_FORMAT", Token::kw_output_format) - .Case("OVERLAY", Token::kw_overlay) - .Case("PHDRS", Token::kw_phdrs) - .Case("PROVIDE", Token::kw_provide) - .Case("PROVIDE_HIDDEN", Token::kw_provide_hidden) - .Case("SEARCH_DIR", Token::kw_search_dir) - .Case("SECTIONS", Token::kw_sections) - .Case("SORT", Token::kw_sort_by_name) - .Case("SORT_BY_ALIGNMENT", Token::kw_sort_by_alignment) - .Case("SORT_BY_INIT_PRIORITY", Token::kw_sort_by_init_priority) - .Case("SORT_BY_NAME", Token::kw_sort_by_name) - .Case("SORT_NONE", Token::kw_sort_none) - .Case("SUBALIGN", Token::kw_subalign) - .Case("/DISCARD/", Token::kw_discard) - .Default(Token::identifier); - tok = Token(word, kind); - _buffer = _buffer.drop_front(end); - return; - } - tok = Token(drop(_buffer, 1), Token::unknown); -} - -void Lexer::skipWhitespace() { - while (true) { - if (_buffer.empty()) - return; - switch (_buffer[0]) { - case ' ': - case '\r': - case '\n': - case '\t': - _buffer = _buffer.drop_front(); - break; - // Potential comment. - case '/': - if (_buffer.size() <= 1 || _buffer[1] != '*') - return; - // Skip starting /* - _buffer = _buffer.drop_front(2); - // If the next char is also a /, it's not the end. - if (!_buffer.empty() && _buffer[0] == '/') - _buffer = _buffer.drop_front(); - - // Scan for /'s. We're done if it is preceded by a *. - while (true) { - if (_buffer.empty()) - break; - _buffer = _buffer.drop_front(); - if (_buffer.data()[-1] == '/' && _buffer.data()[-2] == '*') - break; - } - break; - default: - return; - } - } -} - -// Constant functions -void Constant::dump(raw_ostream &os) const { os << _num; } - -ErrorOr<int64_t> Constant::evalExpr(const SymbolTableTy &symbolTable) const { - return _num; -} - -// Symbol functions -void Symbol::dump(raw_ostream &os) const { os << _name; } - -ErrorOr<int64_t> Symbol::evalExpr(const SymbolTableTy &symbolTable) const { - auto it = symbolTable.find(_name); - if (it == symbolTable.end()) - return LinkerScriptReaderError::unknown_symbol_in_expr; - return it->second; -} - -// FunctionCall functions -void FunctionCall::dump(raw_ostream &os) const { - os << _name << "("; - for (unsigned i = 0, e = _args.size(); i != e; ++i) { - if (i) - os << ", "; - _args[i]->dump(os); - } - os << ")"; -} - -ErrorOr<int64_t> -FunctionCall::evalExpr(const SymbolTableTy &symbolTable) const { - return LinkerScriptReaderError::unrecognized_function_in_expr; -} - -// Unary functions -void Unary::dump(raw_ostream &os) const { - os << "("; - if (_op == Unary::Minus) - os << "-"; - else - os << "~"; - _child->dump(os); - os << ")"; -} - -ErrorOr<int64_t> Unary::evalExpr(const SymbolTableTy &symbolTable) const { - auto child = _child->evalExpr(symbolTable); - if (child.getError()) - return child.getError(); - - int64_t childRes = *child; - switch (_op) { - case Unary::Minus: - return -childRes; - case Unary::Not: - return ~childRes; - } - - llvm_unreachable(""); -} - -// BinOp functions -void BinOp::dump(raw_ostream &os) const { - os << "("; - _lhs->dump(os); - os << " "; - switch (_op) { - case Sum: - os << "+"; - break; - case Sub: - os << "-"; - break; - case Mul: - os << "*"; - break; - case Div: - os << "/"; - break; - case Shl: - os << "<<"; - break; - case Shr: - os << ">>"; - break; - case And: - os << "&"; - break; - case Or: - os << "|"; - break; - case CompareEqual: - os << "=="; - break; - case CompareDifferent: - os << "!="; - break; - case CompareLess: - os << "<"; - break; - case CompareGreater: - os << ">"; - break; - case CompareLessEqual: - os << "<="; - break; - case CompareGreaterEqual: - os << ">="; - break; - } - os << " "; - _rhs->dump(os); - os << ")"; -} - -ErrorOr<int64_t> BinOp::evalExpr(const SymbolTableTy &symbolTable) const { - auto lhs = _lhs->evalExpr(symbolTable); - if (lhs.getError()) - return lhs.getError(); - auto rhs = _rhs->evalExpr(symbolTable); - if (rhs.getError()) - return rhs.getError(); - - int64_t lhsRes = *lhs; - int64_t rhsRes = *rhs; - - switch(_op) { - case And: return lhsRes & rhsRes; - case CompareDifferent: return lhsRes != rhsRes; - case CompareEqual: return lhsRes == rhsRes; - case CompareGreater: return lhsRes > rhsRes; - case CompareGreaterEqual: return lhsRes >= rhsRes; - case CompareLess: return lhsRes < rhsRes; - case CompareLessEqual: return lhsRes <= rhsRes; - case Div: return lhsRes / rhsRes; - case Mul: return lhsRes * rhsRes; - case Or: return lhsRes | rhsRes; - case Shl: return lhsRes << rhsRes; - case Shr: return lhsRes >> rhsRes; - case Sub: return lhsRes - rhsRes; - case Sum: return lhsRes + rhsRes; - } - - llvm_unreachable(""); -} - -// TernaryConditional functions -void TernaryConditional::dump(raw_ostream &os) const { - _conditional->dump(os); - os << " ? "; - _trueExpr->dump(os); - os << " : "; - _falseExpr->dump(os); -} - -ErrorOr<int64_t> -TernaryConditional::evalExpr(const SymbolTableTy &symbolTable) const { - auto conditional = _conditional->evalExpr(symbolTable); - if (conditional.getError()) - return conditional.getError(); - if (*conditional) - return _trueExpr->evalExpr(symbolTable); - return _falseExpr->evalExpr(symbolTable); -} - -// SymbolAssignment functions -void SymbolAssignment::dump(raw_ostream &os) const { - int numParen = 0; - - if (_assignmentVisibility != Default) { - switch (_assignmentVisibility) { - case Hidden: - os << "HIDDEN("; - break; - case Provide: - os << "PROVIDE("; - break; - case ProvideHidden: - os << "PROVIDE_HIDDEN("; - break; - default: - llvm_unreachable("Unknown visibility"); - } - ++numParen; - } - - os << _symbol << " "; - switch (_assignmentKind) { - case Simple: - os << "="; - break; - case Sum: - os << "+="; - break; - case Sub: - os << "-="; - break; - case Mul: - os << "*="; - break; - case Div: - os << "/="; - break; - case Shl: - os << "<<="; - break; - case Shr: - os << ">>="; - break; - case And: - os << "&="; - break; - case Or: - os << "|="; - break; - } - - os << " "; - _expression->dump(os); - if (numParen) - os << ")"; - os << ";"; -} - -static int dumpSortDirectives(raw_ostream &os, WildcardSortMode sortMode) { - switch (sortMode) { - case WildcardSortMode::NA: - return 0; - case WildcardSortMode::ByName: - os << "SORT_BY_NAME("; - return 1; - case WildcardSortMode::ByAlignment: - os << "SORT_BY_ALIGNMENT("; - return 1; - case WildcardSortMode::ByInitPriority: - os << "SORT_BY_INIT_PRIORITY("; - return 1; - case WildcardSortMode::ByNameAndAlignment: - os << "SORT_BY_NAME(SORT_BY_ALIGNMENT("; - return 2; - case WildcardSortMode::ByAlignmentAndName: - os << "SORT_BY_ALIGNMENT(SORT_BY_NAME("; - return 2; - case WildcardSortMode::None: - os << "SORT_NONE("; - return 1; - } - return 0; -} - -// InputSectionName functions -void InputSectionName::dump(raw_ostream &os) const { - os << _name; -} - -// InputSectionSortedGroup functions -static void dumpInputSections(raw_ostream &os, - llvm::ArrayRef<const InputSection *> secs) { - bool excludeFile = false; - bool first = true; - - for (auto &secName : secs) { - if (!first) - os << " "; - first = false; - // Coalesce multiple input sections marked with EXCLUDE_FILE in the same - // EXCLUDE_FILE() group - if (auto inputSec = dyn_cast<InputSectionName>(secName)) { - if (!excludeFile && inputSec->hasExcludeFile()) { - excludeFile = true; - os << "EXCLUDE_FILE("; - } else if (excludeFile && !inputSec->hasExcludeFile()) { - excludeFile = false; - os << ") "; - } - } - secName->dump(os); - } - - if (excludeFile) - os << ")"; -} - -void InputSectionSortedGroup::dump(raw_ostream &os) const { - int numParen = dumpSortDirectives(os, _sortMode); - dumpInputSections(os, _sections); - for (int i = 0; i < numParen; ++i) - os << ")"; -} - -// InputSectionsCmd functions -void InputSectionsCmd::dump(raw_ostream &os) const { - if (_keep) - os << "KEEP("; - - int numParen = dumpSortDirectives(os, _fileSortMode); - os << _memberName; - for (int i = 0; i < numParen; ++i) - os << ")"; - - if (_archiveName.size() > 0) { - os << ":"; - numParen = dumpSortDirectives(os, _archiveSortMode); - os << _archiveName; - for (int i = 0; i < numParen; ++i) - os << ")"; - } - - if (_sections.size() > 0) { - os << "("; - dumpInputSections(os, _sections); - os << ")"; - } - - if (_keep) - os << ")"; -} - -void FillCmd::dump(raw_ostream &os) const { - os << "FILL("; - dumpByteStream(os, StringRef((const char *)_bytes.begin(), _bytes.size())); - os << ")"; -} - -// OutputSectionDescription functions -void OutputSectionDescription::dump(raw_ostream &os) const { - if (_discard) - os << "/DISCARD/"; - else - os << _sectionName; - - if (_address) { - os << " "; - _address->dump(os); - } - os << " :\n"; - - if (_at) { - os << " AT("; - _at->dump(os); - os << ")\n"; - } - - if (_align) { - os << " ALIGN("; - _align->dump(os); - os << ")\n"; - } else if (_alignWithInput) { - os << " ALIGN_WITH_INPUT\n"; - } - - if (_subAlign) { - os << " SUBALIGN("; - _subAlign->dump(os); - os << ")\n"; - } - - switch (_constraint) { - case C_None: - break; - case C_OnlyIfRO: - os << "ONLY_IF_RO"; - break; - case C_OnlyIfRW: - os << "ONLY_IF_RW"; - break; - } - - os << " {\n"; - for (auto &command : _outputSectionCommands) { - os << " "; - command->dump(os); - os << "\n"; - } - os << " }"; - - for (auto && phdr : _phdrs) - os << " : " << phdr; - - if (_fillStream.size() > 0) { - os << " ="; - dumpByteStream(os, _fillStream); - } else if (_fillExpr) { - os << " ="; - _fillExpr->dump(os); - } -} - -// Special header that discards output sections assigned to it. -static const PHDR PHDR_NONE("NONE", 0, false, false, nullptr, 0); - -bool PHDR::isNone() const { - return this == &PHDR_NONE; -} - -void PHDR::dump(raw_ostream &os) const { - os << _name << " " << _type; - if (_includeFileHdr) - os << " FILEHDR"; - if (_includePHDRs) - os << " PHDRS"; - if (_at) { - os << " AT ("; - _at->dump(os); - os << ")"; - } - if (_flags) - os << " FLAGS (" << _flags << ")"; - os << ";\n"; -} - -void PHDRS::dump(raw_ostream &os) const { - os << "PHDRS\n{\n"; - for (auto &&phdr : _phdrs) { - phdr->dump(os); - } - os << "}\n"; -} - -// Sections functions -void Sections::dump(raw_ostream &os) const { - os << "SECTIONS\n{\n"; - for (auto &command : _sectionsCommands) { - command->dump(os); - os << "\n"; - } - os << "}\n"; -} - -// Memory functions -void MemoryBlock::dump(raw_ostream &os) const { - os << _name; - - if (!_attr.empty()) - os << " (" << _attr << ")"; - - os << " : "; - - os << "ORIGIN = "; - _origin->dump(os); - os << ", "; - - os << "LENGTH = "; - _length->dump(os); -} - -void Memory::dump(raw_ostream &os) const { - os << "MEMORY\n{\n"; - for (auto &block : _blocks) { - block->dump(os); - os << "\n"; - } - os << "}\n"; -} - -// Extern functions -void Extern::dump(raw_ostream &os) const { - os << "EXTERN("; - for (unsigned i = 0, e = _symbols.size(); i != e; ++i) { - if (i) - os << " "; - os << _symbols[i]; - } - os << ")\n"; -} - -// Parser functions -std::error_code Parser::parse() { - // Get the first token. - _lex.lex(_tok); - // Parse top level commands. - while (true) { - switch (_tok._kind) { - case Token::eof: - return std::error_code(); - case Token::semicolon: - consumeToken(); - break; - case Token::kw_output: { - auto output = parseOutput(); - if (!output) - return LinkerScriptReaderError::parse_error; - _script._commands.push_back(output); - break; - } - case Token::kw_output_format: { - auto outputFormat = parseOutputFormat(); - if (!outputFormat) - return LinkerScriptReaderError::parse_error; - _script._commands.push_back(outputFormat); - break; - } - case Token::kw_output_arch: { - auto outputArch = parseOutputArch(); - if (!outputArch) - return LinkerScriptReaderError::parse_error; - _script._commands.push_back(outputArch); - break; - } - case Token::kw_input: { - Input *input = parsePathList<Input>(); - if (!input) - return LinkerScriptReaderError::parse_error; - _script._commands.push_back(input); - break; - } - case Token::kw_group: { - Group *group = parsePathList<Group>(); - if (!group) - return LinkerScriptReaderError::parse_error; - _script._commands.push_back(group); - break; - } - case Token::kw_as_needed: - // Not allowed at top level. - error(_tok, "AS_NEEDED not allowed at top level."); - return LinkerScriptReaderError::parse_error; - case Token::kw_entry: { - Entry *entry = parseEntry(); - if (!entry) - return LinkerScriptReaderError::parse_error; - _script._commands.push_back(entry); - break; - } - case Token::kw_phdrs: { - PHDRS *phdrs = parsePHDRS(); - if (!phdrs) - return LinkerScriptReaderError::parse_error; - _script._commands.push_back(phdrs); - break; - } - case Token::kw_search_dir: { - SearchDir *searchDir = parseSearchDir(); - if (!searchDir) - return LinkerScriptReaderError::parse_error; - _script._commands.push_back(searchDir); - break; - } - case Token::kw_sections: { - Sections *sections = parseSections(); - if (!sections) - return LinkerScriptReaderError::parse_error; - _script._commands.push_back(sections); - break; - } - case Token::identifier: - case Token::kw_hidden: - case Token::kw_provide: - case Token::kw_provide_hidden: { - const Command *cmd = parseSymbolAssignment(); - if (!cmd) - return LinkerScriptReaderError::parse_error; - _script._commands.push_back(cmd); - break; - } - case Token::kw_memory: { - const Command *cmd = parseMemory(); - if (!cmd) - return LinkerScriptReaderError::parse_error; - _script._commands.push_back(cmd); - break; - } - case Token::kw_extern: { - const Command *cmd = parseExtern(); - if (!cmd) - return LinkerScriptReaderError::parse_error; - _script._commands.push_back(cmd); - break; - } - default: - // Unexpected. - error(_tok, "expected linker script command"); - return LinkerScriptReaderError::parse_error; - } - } - return LinkerScriptReaderError::parse_error; -} - -const Expression *Parser::parseFunctionCall() { - assert((_tok._kind == Token::identifier || _tok._kind == Token::kw_align) && - "expected function call first tokens"); - SmallVector<const Expression *, 8> params; - StringRef name = _tok._range; - - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - - if (_tok._kind == Token::r_paren) { - consumeToken(); - return new (_alloc) FunctionCall(*this, _tok._range, params); - } - - if (const Expression *firstParam = parseExpression()) - params.push_back(firstParam); - else - return nullptr; - - while (_tok._kind == Token::comma) { - consumeToken(); - if (const Expression *param = parseExpression()) - params.push_back(param); - else - return nullptr; - } - - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - return new (_alloc) FunctionCall(*this, name, params); -} - -bool Parser::expectExprOperand() { - if (!(_tok._kind == Token::identifier || _tok._kind == Token::number || - _tok._kind == Token::kw_align || _tok._kind == Token::l_paren || - _tok._kind == Token::minus || _tok._kind == Token::tilde)) { - error(_tok, "expected symbol, number, minus, tilde or left parenthesis."); - return false; - } - return true; -} - -const Expression *Parser::parseExprOperand() { - if (!expectExprOperand()) - return nullptr; - - switch (_tok._kind) { - case Token::identifier: { - if (peek()._kind== Token::l_paren) - return parseFunctionCall(); - auto *sym = new (_alloc) Symbol(*this, _tok._range); - consumeToken(); - return sym; - } - case Token::kw_align: - return parseFunctionCall(); - case Token::minus: - consumeToken(); - return new (_alloc) Unary(*this, Unary::Minus, parseExprOperand()); - case Token::tilde: - consumeToken(); - return new (_alloc) Unary(*this, Unary::Not, parseExprOperand()); - case Token::number: { - auto val = parseNum(_tok._range); - if (val.getError()) { - error(_tok, "Unrecognized number constant"); - return nullptr; - } - auto *c = new (_alloc) Constant(*this, *val); - consumeToken(); - return c; - } - case Token::l_paren: { - consumeToken(); - const Expression *expr = parseExpression(); - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - return expr; - } - default: - llvm_unreachable("Unknown token"); - } -} - -static bool TokenToBinOp(const Token &tok, BinOp::Operation &op, - unsigned &precedence) { - switch (tok._kind) { - case Token::star: - op = BinOp::Mul; - precedence = 3; - return true; - case Token::slash: - op = BinOp::Div; - precedence = 3; - return true; - case Token::plus: - op = BinOp::Sum; - precedence = 4; - return true; - case Token::minus: - op = BinOp::Sub; - precedence = 4; - return true; - case Token::lessless: - op = BinOp::Shl; - precedence = 5; - return true; - case Token::greatergreater: - op = BinOp::Shr; - precedence = 5; - return true; - case Token::less: - op = BinOp::CompareLess; - precedence = 6; - return true; - case Token::greater: - op = BinOp::CompareGreater; - precedence = 6; - return true; - case Token::lessequal: - op = BinOp::CompareLessEqual; - precedence = 6; - return true; - case Token::greaterequal: - op = BinOp::CompareGreaterEqual; - precedence = 6; - return true; - case Token::equalequal: - op = BinOp::CompareEqual; - precedence = 7; - return true; - case Token::exclaimequal: - op = BinOp::CompareDifferent; - precedence = 7; - return true; - case Token::amp: - op = BinOp::And; - precedence = 8; - return true; - case Token::pipe: - op = BinOp::Or; - precedence = 10; - return true; - default: - break; - } - return false; -} - -static bool isExpressionOperator(Token tok) { - switch (tok._kind) { - case Token::star: - case Token::slash: - case Token::plus: - case Token::minus: - case Token::lessless: - case Token::greatergreater: - case Token::less: - case Token::greater: - case Token::lessequal: - case Token::greaterequal: - case Token::equalequal: - case Token::exclaimequal: - case Token::amp: - case Token::pipe: - case Token::question: - return true; - default: - return false; - } -} - -const Expression *Parser::parseExpression(unsigned precedence) { - assert(precedence <= 13 && "Invalid precedence value"); - if (!expectExprOperand()) - return nullptr; - - const Expression *expr = parseExprOperand(); - if (!expr) - return nullptr; - - BinOp::Operation op; - unsigned binOpPrecedence = 0; - if (TokenToBinOp(_tok, op, binOpPrecedence)) { - if (precedence >= binOpPrecedence) - return parseOperatorOperandLoop(expr, precedence); - return expr; - } - - // Non-binary operators - if (_tok._kind == Token::question && precedence >= 13) - return parseOperatorOperandLoop(expr, precedence); - return expr; -} - -const Expression *Parser::parseOperatorOperandLoop(const Expression *lhs, - unsigned highestPrecedence) { - assert(highestPrecedence <= 13 && "Invalid precedence value"); - unsigned precedence = 0; - const Expression *binOp = nullptr; - - while (1) { - BinOp::Operation op; - if (!TokenToBinOp(_tok, op, precedence)) { - if (_tok._kind == Token::question && highestPrecedence >= 13) - return parseTernaryCondOp(lhs); - return binOp; - } - - if (precedence > highestPrecedence) - return binOp; - - consumeToken(); - const Expression *rhs = parseExpression(precedence - 1); - if (!rhs) - return nullptr; - binOp = new (_alloc) BinOp(*this, lhs, op, rhs); - lhs = binOp; - } -} - -const Expression *Parser::parseTernaryCondOp(const Expression *lhs) { - assert(_tok._kind == Token::question && "Expected question mark"); - - consumeToken(); - - // The ternary conditional operator has right-to-left associativity. - // To implement this, we allow our children to contain ternary conditional - // operators themselves (precedence 13). - const Expression *trueExpr = parseExpression(13); - if (!trueExpr) - return nullptr; - - if (!expectAndConsume(Token::colon, "expected :")) - return nullptr; - - const Expression *falseExpr = parseExpression(13); - if (!falseExpr) - return nullptr; - - return new (_alloc) TernaryConditional(*this, lhs, trueExpr, falseExpr); -} - -// Parse OUTPUT(ident) -Output *Parser::parseOutput() { - assert(_tok._kind == Token::kw_output && "Expected OUTPUT"); - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - - if (_tok._kind != Token::identifier) { - error(_tok, "Expected identifier in OUTPUT."); - return nullptr; - } - - auto ret = new (_alloc) Output(*this, _tok._range); - consumeToken(); - - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - - return ret; -} - -// Parse OUTPUT_FORMAT(ident) -OutputFormat *Parser::parseOutputFormat() { - assert(_tok._kind == Token::kw_output_format && "Expected OUTPUT_FORMAT!"); - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - - if (_tok._kind != Token::identifier) { - error(_tok, "Expected identifier in OUTPUT_FORMAT."); - return nullptr; - } - - SmallVector<StringRef, 8> formats; - formats.push_back(_tok._range); - - consumeToken(); - - do { - if (isNextToken(Token::comma)) - consumeToken(); - else - break; - if (_tok._kind != Token::identifier) { - error(_tok, "Expected identifier in OUTPUT_FORMAT."); - return nullptr; - } - formats.push_back(_tok._range); - consumeToken(); - } while (isNextToken(Token::comma)); - - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - - return new (_alloc) OutputFormat(*this, formats); -} - -// Parse OUTPUT_ARCH(ident) -OutputArch *Parser::parseOutputArch() { - assert(_tok._kind == Token::kw_output_arch && "Expected OUTPUT_ARCH!"); - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - - if (_tok._kind != Token::identifier) { - error(_tok, "Expected identifier in OUTPUT_ARCH."); - return nullptr; - } - - auto ret = new (_alloc) OutputArch(*this, _tok._range); - consumeToken(); - - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - - return ret; -} - -// Parse file list for INPUT or GROUP -template<class T> T *Parser::parsePathList() { - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - - SmallVector<Path, 8> paths; - while (_tok._kind == Token::identifier || _tok._kind == Token::libname || - _tok._kind == Token::kw_as_needed) { - switch (_tok._kind) { - case Token::identifier: - paths.push_back(Path(_tok._range)); - consumeToken(); - break; - case Token::libname: - paths.push_back(Path(_tok._range, false, true)); - consumeToken(); - break; - case Token::kw_as_needed: - if (!parseAsNeeded(paths)) - return nullptr; - break; - default: - llvm_unreachable("Invalid token."); - } - } - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - return new (_alloc) T(*this, paths); -} - -// Parse AS_NEEDED(file ...) -bool Parser::parseAsNeeded(SmallVectorImpl<Path> &paths) { - assert(_tok._kind == Token::kw_as_needed && "Expected AS_NEEDED!"); - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return false; - - while (_tok._kind == Token::identifier || _tok._kind == Token::libname) { - switch (_tok._kind) { - case Token::identifier: - paths.push_back(Path(_tok._range, true, false)); - consumeToken(); - break; - case Token::libname: - paths.push_back(Path(_tok._range, true, true)); - consumeToken(); - break; - default: - llvm_unreachable("Invalid token."); - } - } - - if (!expectAndConsume(Token::r_paren, "expected )")) - return false; - return true; -} - -// Parse ENTRY(ident) -Entry *Parser::parseEntry() { - assert(_tok._kind == Token::kw_entry && "Expected ENTRY!"); - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - if (_tok._kind != Token::identifier) { - error(_tok, "expected identifier in ENTRY"); - return nullptr; - } - StringRef entryName(_tok._range); - consumeToken(); - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - return new (_alloc) Entry(*this, entryName); -} - -// Parse SEARCH_DIR(ident) -SearchDir *Parser::parseSearchDir() { - assert(_tok._kind == Token::kw_search_dir && "Expected SEARCH_DIR!"); - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - if (_tok._kind != Token::identifier) { - error(_tok, "expected identifier in SEARCH_DIR"); - return nullptr; - } - StringRef searchPath(_tok._range); - consumeToken(); - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - return new (_alloc) SearchDir(*this, searchPath); -} - -const SymbolAssignment *Parser::parseSymbolAssignment() { - assert((_tok._kind == Token::identifier || _tok._kind == Token::kw_hidden || - _tok._kind == Token::kw_provide || - _tok._kind == Token::kw_provide_hidden) && - "Expected identifier!"); - SymbolAssignment::AssignmentVisibility visibility = SymbolAssignment::Default; - SymbolAssignment::AssignmentKind kind; - int numParen = 0; - - switch (_tok._kind) { - case Token::kw_hidden: - visibility = SymbolAssignment::Hidden; - ++numParen; - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - break; - case Token::kw_provide: - visibility = SymbolAssignment::Provide; - ++numParen; - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - break; - case Token::kw_provide_hidden: - visibility = SymbolAssignment::ProvideHidden; - ++numParen; - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - break; - default: - break; - } - - StringRef name = _tok._range; - consumeToken(); - - // Parse assignment operator (=, +=, -= etc.) - switch (_tok._kind) { - case Token::equal: - kind = SymbolAssignment::Simple; - break; - case Token::plusequal: - kind = SymbolAssignment::Sum; - break; - case Token::minusequal: - kind = SymbolAssignment::Sub; - break; - case Token::starequal: - kind = SymbolAssignment::Mul; - break; - case Token::slashequal: - kind = SymbolAssignment::Div; - break; - case Token::ampequal: - kind = SymbolAssignment::And; - break; - case Token::pipeequal: - kind = SymbolAssignment::Or; - break; - case Token::lesslessequal: - kind = SymbolAssignment::Shl; - break; - case Token::greatergreaterequal: - kind = SymbolAssignment::Shr; - break; - default: - error(_tok, "unexpected token"); - return nullptr; - } - - consumeToken(); - - const Expression *expr = nullptr; - switch (_tok._kind) { - case Token::number: - case Token::kw_align: - case Token::identifier: - case Token::l_paren: - expr = parseExpression(); - if (!expr) - return nullptr; - break; - default: - error(_tok, "unexpected token while parsing assignment value."); - return nullptr; - } - - for (int i = 0; i < numParen; ++i) - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - - return new (_alloc) SymbolAssignment(*this, name, expr, kind, visibility); -} - -llvm::ErrorOr<InputSectionsCmd::VectorTy> Parser::parseExcludeFile() { - assert(_tok._kind == Token::kw_exclude_file && "Expected EXCLUDE_FILE!"); - InputSectionsCmd::VectorTy res; - consumeToken(); - - if (!expectAndConsume(Token::l_paren, "expected (")) - return llvm::ErrorOr<InputSectionsCmd::VectorTy>( - make_error_code(llvm::errc::io_error)); - - while (_tok._kind == Token::identifier) { - res.push_back(new (_alloc) InputSectionName(*this, _tok._range, true)); - consumeToken(); - } - - if (!expectAndConsume(Token::r_paren, "expected )")) - return llvm::ErrorOr<InputSectionsCmd::VectorTy>( - make_error_code(llvm::errc::io_error)); - return llvm::ErrorOr<InputSectionsCmd::VectorTy>(std::move(res)); -} - -int Parser::parseSortDirectives(WildcardSortMode &sortMode) { - int numParsedDirectives = 0; - sortMode = WildcardSortMode::NA; - - if (_tok._kind == Token::kw_sort_by_name) { - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return -1; - ++numParsedDirectives; - sortMode = WildcardSortMode::ByName; - } - - if (_tok._kind == Token::kw_sort_by_init_priority) { - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return -1; - ++numParsedDirectives; - sortMode = WildcardSortMode::ByInitPriority; - } - - if (_tok._kind == Token::kw_sort_by_alignment) { - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return -1; - ++numParsedDirectives; - if (sortMode != WildcardSortMode::ByName) - sortMode = WildcardSortMode::ByAlignment; - else - sortMode = WildcardSortMode::ByNameAndAlignment; - } - - if (numParsedDirectives < 2 && _tok._kind == Token::kw_sort_by_name) { - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return -1; - ++numParsedDirectives; - if (sortMode == WildcardSortMode::ByAlignment) - sortMode = WildcardSortMode::ByAlignmentAndName; - } - - if (numParsedDirectives < 2 && _tok._kind == Token::kw_sort_by_alignment) { - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return -1; - ++numParsedDirectives; - } - - if (numParsedDirectives == 0 && _tok._kind == Token::kw_sort_none) { - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return -1; - ++numParsedDirectives; - sortMode = WildcardSortMode::None; - } - - return numParsedDirectives; -} - -const InputSection *Parser::parseSortedInputSections() { - assert((_tok._kind == Token::kw_sort_by_name || - _tok._kind == Token::kw_sort_by_alignment || - _tok._kind == Token::kw_sort_by_init_priority || - _tok._kind == Token::kw_sort_none) && - "Expected SORT directives!"); - - WildcardSortMode sortMode = WildcardSortMode::NA; - int numParen = parseSortDirectives(sortMode); - if (numParen == -1) - return nullptr; - - SmallVector<const InputSection *, 8> inputSections; - - while (_tok._kind == Token::identifier) { - inputSections.push_back(new (_alloc) - InputSectionName(*this, _tok._range, false)); - consumeToken(); - } - - // Eat "numParen" rparens - for (int i = 0, e = numParen; i != e; ++i) - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - - return new (_alloc) InputSectionSortedGroup(*this, sortMode, inputSections); -} - -const InputSectionsCmd *Parser::parseInputSectionsCmd() { - assert((_tok._kind == Token::identifier || _tok._kind == Token::colon || - _tok._kind == Token::star || _tok._kind == Token::kw_keep || - _tok._kind == Token::kw_sort_by_name || - _tok._kind == Token::kw_sort_by_alignment || - _tok._kind == Token::kw_sort_by_init_priority || - _tok._kind == Token::kw_sort_none) && - "Expected input section first tokens!"); - int numParen = 1; - bool keep = false; - WildcardSortMode fileSortMode = WildcardSortMode::NA; - WildcardSortMode archiveSortMode = WildcardSortMode::NA; - StringRef memberName; - StringRef archiveName; - - if (_tok._kind == Token::kw_keep) { - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - ++numParen; - keep = true; - } - - // Input name - if (_tok._kind != Token::colon) { - int numParen = parseSortDirectives(fileSortMode); - if (numParen == -1) - return nullptr; - memberName = _tok._range; - consumeToken(); - if (numParen) { - while (numParen--) - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - } - } - if (_tok._kind == Token::colon) { - consumeToken(); - if (_tok._kind == Token::identifier || - _tok._kind == Token::kw_sort_by_name || - _tok._kind == Token::kw_sort_by_alignment || - _tok._kind == Token::kw_sort_by_init_priority || - _tok._kind == Token::kw_sort_none) { - int numParen = parseSortDirectives(archiveSortMode); - if (numParen == -1) - return nullptr; - archiveName = _tok._range; - consumeToken(); - for (int i = 0; i != numParen; ++i) - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - } - } - - SmallVector<const InputSection *, 8> inputSections; - - if (_tok._kind != Token::l_paren) - return new (_alloc) - InputSectionsCmd(*this, memberName, archiveName, keep, fileSortMode, - archiveSortMode, inputSections); - consumeToken(); - - while (_tok._kind == Token::identifier || - _tok._kind == Token::kw_exclude_file || - _tok._kind == Token::kw_sort_by_name || - _tok._kind == Token::kw_sort_by_alignment || - _tok._kind == Token::kw_sort_by_init_priority || - _tok._kind == Token::kw_sort_none) { - switch (_tok._kind) { - case Token::kw_exclude_file: { - auto vec = parseExcludeFile(); - if (vec.getError()) - return nullptr; - inputSections.insert(inputSections.end(), vec->begin(), vec->end()); - break; - } - case Token::star: - case Token::identifier: { - inputSections.push_back(new (_alloc) - InputSectionName(*this, _tok._range, false)); - consumeToken(); - break; - } - case Token::kw_sort_by_name: - case Token::kw_sort_by_alignment: - case Token::kw_sort_by_init_priority: - case Token::kw_sort_none: { - const InputSection *group = parseSortedInputSections(); - if (!group) - return nullptr; - inputSections.push_back(group); - break; - } - default: - llvm_unreachable("Unknown token"); - } - } - - for (int i = 0; i < numParen; ++i) - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - return new (_alloc) - InputSectionsCmd(*this, memberName, archiveName, keep, fileSortMode, - archiveSortMode, inputSections); -} - -const FillCmd *Parser::parseFillCmd() { - assert(_tok._kind == Token::kw_fill && "Expected FILL!"); - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - - SmallVector<uint8_t, 8> storage; - - // If the expression is just a number, it's arbitrary length. - if (_tok._kind == Token::number && peek()._kind == Token::r_paren) { - if (_tok._range.size() > 2 && _tok._range.startswith("0x")) { - StringRef num = _tok._range.substr(2); - for (char c : num) { - unsigned nibble = llvm::hexDigitValue(c); - if (nibble == -1u) - goto not_simple_hex; - storage.push_back(nibble); - } - - if (storage.size() % 2 != 0) - storage.insert(storage.begin(), 0); - - // Collapse nibbles. - for (std::size_t i = 0, e = storage.size() / 2; i != e; ++i) - storage[i] = (storage[i * 2] << 4) + storage[(i * 2) + 1]; - - storage.resize(storage.size() / 2); - } - } -not_simple_hex: - - const Expression *expr = parseExpression(); - if (!expr) - return nullptr; - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - - return new(getAllocator()) FillCmd(*this, storage); -} - -const OutputSectionDescription *Parser::parseOutputSectionDescription() { - assert((_tok._kind == Token::kw_discard || _tok._kind == Token::identifier) && - "Expected /DISCARD/ or identifier!"); - StringRef sectionName; - const Expression *address = nullptr; - const Expression *align = nullptr; - const Expression *subAlign = nullptr; - const Expression *at = nullptr; - const Expression *fillExpr = nullptr; - StringRef fillStream; - bool alignWithInput = false; - bool discard = false; - OutputSectionDescription::Constraint constraint = - OutputSectionDescription::C_None; - SmallVector<const Command *, 8> outputSectionCommands; - - if (_tok._kind == Token::kw_discard) - discard = true; - else - sectionName = _tok._range; - consumeToken(); - - if (_tok._kind == Token::number || _tok._kind == Token::identifier || - _tok._kind == Token::kw_align || _tok._kind == Token::l_paren) { - address = parseExpression(); - if (!address) - return nullptr; - } - - if (!expectAndConsume(Token::colon, "expected :")) - return nullptr; - - if (_tok._kind == Token::kw_at) { - consumeToken(); - at = parseExpression(); - if (!at) - return nullptr; - } - - if (_tok._kind == Token::kw_align) { - consumeToken(); - align = parseExpression(); - if (!align) - return nullptr; - } - - if (_tok._kind == Token::kw_align_with_input) { - consumeToken(); - alignWithInput = true; - } - - if (_tok._kind == Token::kw_subalign) { - consumeToken(); - subAlign = parseExpression(); - if (!subAlign) - return nullptr; - } - - if (_tok._kind == Token::kw_only_if_ro) { - consumeToken(); - constraint = OutputSectionDescription::C_OnlyIfRO; - } else if (_tok._kind == Token::kw_only_if_rw) { - consumeToken(); - constraint = OutputSectionDescription::C_OnlyIfRW; - } - - if (!expectAndConsume(Token::l_brace, "expected {")) - return nullptr; - - // Parse zero or more output-section-commands - while (_tok._kind != Token::r_brace) { - switch (_tok._kind) { - case Token::semicolon: - consumeToken(); - break; - case Token::identifier: - switch (peek()._kind) { - case Token::equal: - case Token::plusequal: - case Token::minusequal: - case Token::starequal: - case Token::slashequal: - case Token::ampequal: - case Token::pipeequal: - case Token::lesslessequal: - case Token::greatergreaterequal: - if (const Command *cmd = parseSymbolAssignment()) - outputSectionCommands.push_back(cmd); - else - return nullptr; - break; - default: - if (const Command *cmd = parseInputSectionsCmd()) - outputSectionCommands.push_back(cmd); - else - return nullptr; - break; - } - break; - case Token::kw_fill: - if (const Command *cmd = parseFillCmd()) - outputSectionCommands.push_back(cmd); - else - return nullptr; - break; - case Token::kw_keep: - case Token::star: - case Token::colon: - case Token::kw_sort_by_name: - case Token::kw_sort_by_alignment: - case Token::kw_sort_by_init_priority: - case Token::kw_sort_none: - if (const Command *cmd = parseInputSectionsCmd()) - outputSectionCommands.push_back(cmd); - else - return nullptr; - break; - case Token::kw_hidden: - case Token::kw_provide: - case Token::kw_provide_hidden: - if (const Command *cmd = parseSymbolAssignment()) - outputSectionCommands.push_back(cmd); - else - return nullptr; - break; - default: - error(_tok, "expected symbol assignment or input file name."); - return nullptr; - } - } - - if (!expectAndConsume(Token::r_brace, "expected }")) - return nullptr; - - SmallVector<StringRef, 2> phdrs; - while (_tok._kind == Token::colon) { - consumeToken(); - if (_tok._kind != Token::identifier) { - error(_tok, "expected program header name"); - return nullptr; - } - phdrs.push_back(_tok._range); - consumeToken(); - } - - if (_tok._kind == Token::equal) { - consumeToken(); - if (_tok._kind != Token::number || !_tok._range.startswith_lower("0x")) { - fillExpr = parseExpression(); - if (!fillExpr) - return nullptr; - } else { - std::string strBuf; - if (isExpressionOperator(peek()) || - !parseHexToByteStream(_tok._range.drop_front(2), strBuf)) { - fillExpr = parseExpression(); - if(!fillExpr) - return nullptr; - } else { - char *rawBuf = (char *) _alloc.Allocate(strBuf.size(), 1); - memcpy(rawBuf, strBuf.c_str(), strBuf.size()); - fillStream = StringRef(rawBuf, strBuf.size()); - consumeToken(); - } - } - } - - return new (_alloc) OutputSectionDescription( - *this, sectionName, address, align, subAlign, at, fillExpr, fillStream, - alignWithInput, discard, constraint, outputSectionCommands, phdrs); -} - -const Overlay *Parser::parseOverlay() { - assert(_tok._kind == Token::kw_overlay && "Expected OVERLAY!"); - error(_tok, "Overlay description is not yet supported."); - return nullptr; -} - -const PHDR *Parser::parsePHDR() { - assert(_tok._kind == Token::identifier && "Expected identifier!"); - - StringRef name = _tok._range; - consumeToken(); - - uint64_t type; - - switch (_tok._kind) { - case Token::identifier: - case Token::number: - case Token::l_paren: { - const Expression *expr = parseExpression(); - if (!expr) - return nullptr; - Expression::SymbolTableTy PHDRTypes; -#define PHDR_INSERT(x) PHDRTypes.insert(std::make_pair(#x, llvm::ELF::x)) - PHDR_INSERT(PT_NULL); - PHDR_INSERT(PT_LOAD); - PHDR_INSERT(PT_DYNAMIC); - PHDR_INSERT(PT_INTERP); - PHDR_INSERT(PT_NOTE); - PHDR_INSERT(PT_SHLIB); - PHDR_INSERT(PT_PHDR); - PHDR_INSERT(PT_TLS); - PHDR_INSERT(PT_LOOS); - PHDR_INSERT(PT_GNU_EH_FRAME); - PHDR_INSERT(PT_GNU_STACK); - PHDR_INSERT(PT_GNU_RELRO); - PHDR_INSERT(PT_SUNW_EH_FRAME); - PHDR_INSERT(PT_SUNW_UNWIND); - PHDR_INSERT(PT_HIOS); - PHDR_INSERT(PT_LOPROC); - PHDR_INSERT(PT_ARM_ARCHEXT); - PHDR_INSERT(PT_ARM_EXIDX); - PHDR_INSERT(PT_ARM_UNWIND); - PHDR_INSERT(PT_MIPS_REGINFO); - PHDR_INSERT(PT_MIPS_RTPROC); - PHDR_INSERT(PT_MIPS_OPTIONS); - PHDR_INSERT(PT_MIPS_ABIFLAGS); - PHDR_INSERT(PT_HIPROC); -#undef PHDR_INSERT - auto t = expr->evalExpr(PHDRTypes); - if (t == LinkerScriptReaderError::unknown_symbol_in_expr) { - error(_tok, "Unknown type"); - return nullptr; - } - if (!t) - return nullptr; - type = *t; - break; - } - default: - error(_tok, "expected identifier or expression"); - return nullptr; - } - - uint64_t flags = 0; - const Expression *flagsExpr = nullptr; - bool includeFileHdr = false; - bool includePHDRs = false; - - while (_tok._kind != Token::semicolon) { - switch (_tok._kind) { - case Token::kw_filehdr: - if (includeFileHdr) { - error(_tok, "Duplicate FILEHDR attribute"); - return nullptr; - } - includeFileHdr = true; - consumeToken(); - break; - case Token::kw_phdrs: - if (includePHDRs) { - error(_tok, "Duplicate PHDRS attribute"); - return nullptr; - } - includePHDRs = true; - consumeToken(); - break; - case Token::kw_flags: { - if (flagsExpr) { - error(_tok, "Duplicate FLAGS attribute"); - return nullptr; - } - consumeToken(); - if (!expectAndConsume(Token::l_paren, "Expected (")) - return nullptr; - flagsExpr = parseExpression(); - if (!flagsExpr) - return nullptr; - auto f = flagsExpr->evalExpr(); - if (!f) - return nullptr; - flags = *f; - if (!expectAndConsume(Token::r_paren, "Expected )")) - return nullptr; - } break; - default: - error(_tok, "Unexpected token"); - return nullptr; - } - } - - if (!expectAndConsume(Token::semicolon, "Expected ;")) - return nullptr; - - return new (getAllocator()) - PHDR(name, type, includeFileHdr, includePHDRs, nullptr, flags); -} - -PHDRS *Parser::parsePHDRS() { - assert(_tok._kind == Token::kw_phdrs && "Expected PHDRS!"); - consumeToken(); - if (!expectAndConsume(Token::l_brace, "expected {")) - return nullptr; - - SmallVector<const PHDR *, 8> phdrs; - - while (true) { - if (_tok._kind == Token::identifier) { - const PHDR *phdr = parsePHDR(); - if (!phdr) - return nullptr; - phdrs.push_back(phdr); - } else - break; - } - - if (!expectAndConsume(Token::r_brace, "expected }")) - return nullptr; - - return new (getAllocator()) PHDRS(*this, phdrs); -} - -Sections *Parser::parseSections() { - assert(_tok._kind == Token::kw_sections && "Expected SECTIONS!"); - consumeToken(); - if (!expectAndConsume(Token::l_brace, "expected {")) - return nullptr; - SmallVector<const Command *, 8> sectionsCommands; - - bool unrecognizedToken = false; - // Parse zero or more sections-commands - while (!unrecognizedToken) { - switch (_tok._kind) { - case Token::semicolon: - consumeToken(); - break; - - case Token::identifier: - switch (peek()._kind) { - case Token::equal: - case Token::plusequal: - case Token::minusequal: - case Token::starequal: - case Token::slashequal: - case Token::ampequal: - case Token::pipeequal: - case Token::lesslessequal: - case Token::greatergreaterequal: - if (const Command *cmd = parseSymbolAssignment()) - sectionsCommands.push_back(cmd); - else - return nullptr; - break; - default: - if (const Command *cmd = parseOutputSectionDescription()) - sectionsCommands.push_back(cmd); - else - return nullptr; - break; - } - break; - - case Token::kw_discard: - case Token::star: - if (const Command *cmd = parseOutputSectionDescription()) - sectionsCommands.push_back(cmd); - else - return nullptr; - break; - - case Token::kw_entry: - if (const Command *cmd = parseEntry()) - sectionsCommands.push_back(cmd); - else - return nullptr; - break; - - case Token::kw_hidden: - case Token::kw_provide: - case Token::kw_provide_hidden: - if (const Command *cmd = parseSymbolAssignment()) - sectionsCommands.push_back(cmd); - else - return nullptr; - break; - - case Token::kw_overlay: - if (const Command *cmd = parseOverlay()) - sectionsCommands.push_back(cmd); - else - return nullptr; - break; - - default: - unrecognizedToken = true; - break; - } - } - - if (!expectAndConsume( - Token::r_brace, - "expected symbol assignment, entry, overlay or output section name.")) - return nullptr; - - return new (_alloc) Sections(*this, sectionsCommands); -} - -Memory *Parser::parseMemory() { - assert(_tok._kind == Token::kw_memory && "Expected MEMORY!"); - consumeToken(); - if (!expectAndConsume(Token::l_brace, "expected {")) - return nullptr; - SmallVector<const MemoryBlock *, 8> blocks; - - bool unrecognizedToken = false; - // Parse zero or more memory block descriptors. - while (!unrecognizedToken) { - if (_tok._kind == Token::identifier) { - StringRef name; - StringRef attrs; - const Expression *origin = nullptr; - const Expression *length = nullptr; - - name = _tok._range; - consumeToken(); - - // Parse optional memory region attributes. - if (_tok._kind == Token::l_paren) { - consumeToken(); - - if (_tok._kind != Token::identifier) { - error(_tok, "Expected memory attribute string."); - return nullptr; - } - attrs = _tok._range; - consumeToken(); - - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - } - - if (!expectAndConsume(Token::colon, "expected :")) - return nullptr; - - // Parse the ORIGIN (base address of memory block). - if (!expectAndConsume(Token::kw_origin, "expected ORIGIN")) - return nullptr; - - if (!expectAndConsume(Token::equal, "expected =")) - return nullptr; - - origin = parseExpression(); - if (!origin) - return nullptr; - - if (!expectAndConsume(Token::comma, "expected ,")) - return nullptr; - - // Parse the LENGTH (length of memory block). - if (!expectAndConsume(Token::kw_length, "expected LENGTH")) - return nullptr; - - if (!expectAndConsume(Token::equal, "expected =")) - return nullptr; - - length = parseExpression(); - if (!length) - return nullptr; - - auto *block = new (_alloc) MemoryBlock(name, attrs, origin, length); - blocks.push_back(block); - } else { - unrecognizedToken = true; - } - } - if (!expectAndConsume( - Token::r_brace, - "expected memory block definition.")) - return nullptr; - - return new (_alloc) Memory(*this, blocks); -} - -Extern *Parser::parseExtern() { - assert(_tok._kind == Token::kw_extern && "Expected EXTERN!"); - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - - // Parse one or more symbols. - SmallVector<StringRef, 8> symbols; - if (_tok._kind != Token::identifier) { - error(_tok, "expected one or more symbols in EXTERN."); - return nullptr; - } - symbols.push_back(_tok._range); - consumeToken(); - while (_tok._kind == Token::identifier) { - symbols.push_back(_tok._range); - consumeToken(); - } - - if (!expectAndConsume(Token::r_paren, "expected symbol in EXTERN.")) - return nullptr; - - return new (_alloc) Extern(*this, symbols); -} - -// Sema member functions -Sema::Sema() : _programPHDR(nullptr) {} - -std::error_code Sema::perform() { - llvm::StringMap<const PHDR *> phdrs; - - for (auto &parser : _scripts) { - for (const Command *c : parser->get()->_commands) { - if (const auto *sec = dyn_cast<Sections>(c)) { - linearizeAST(sec); - } else if (const auto *ph = dyn_cast<PHDRS>(c)) { - if (auto ec = collectPHDRs(ph, phdrs)) - return ec; - } - } - } - return buildSectionToPHDR(phdrs); -} - -bool Sema::less(const SectionKey &lhs, const SectionKey &rhs) const { - int a = getLayoutOrder(lhs, true); - int b = getLayoutOrder(rhs, true); - - if (a != b) { - if (a < 0) - return false; - if (b < 0) - return true; - return a < b; - } - - // If both sections are not mapped anywhere, they have the same order - if (a < 0) - return false; - - // If both sections fall into the same layout order, we need to find their - // relative position as written in the (InputSectionsCmd). - return localCompare(a, lhs, rhs); -} - -StringRef Sema::getOutputSection(const SectionKey &key) const { - int layoutOrder = getLayoutOrder(key, true); - if (layoutOrder < 0) - return StringRef(); - - for (int i = layoutOrder - 1; i >= 0; --i) { - if (!isa<OutputSectionDescription>(_layoutCommands[i])) - continue; - - const OutputSectionDescription *out = - dyn_cast<OutputSectionDescription>(_layoutCommands[i]); - return out->name(); - } - - return StringRef(); -} - -std::vector<const SymbolAssignment *> -Sema::getExprs(const SectionKey &key) { - int layoutOrder = getLayoutOrder(key, false); - auto ans = std::vector<const SymbolAssignment *>(); - - if (layoutOrder < 0 || _deliveredExprs.count(layoutOrder) > 0) - return ans; - - for (int i = layoutOrder - 1; i >= 0; --i) { - if (isa<InputSection>(_layoutCommands[i])) - break; - if (auto assgn = dyn_cast<SymbolAssignment>(_layoutCommands[i])) - ans.push_back(assgn); - } - - // Reverse this order so we evaluate the expressions in the original order - // of the linker script - std::reverse(ans.begin(), ans.end()); - - // Mark this layout number as delivered - _deliveredExprs.insert(layoutOrder); - return ans; -} - -std::error_code Sema::evalExpr(const SymbolAssignment *assgn, - uint64_t &curPos) { - _symbolTable[StringRef(".")] = curPos; - - auto ans = assgn->expr()->evalExpr(_symbolTable); - if (ans.getError()) - return ans.getError(); - uint64_t result = *ans; - - if (assgn->symbol() == ".") { - curPos = result; - return std::error_code(); - } - - _symbolTable[assgn->symbol()] = result; - return std::error_code(); -} - -const llvm::StringSet<> &Sema::getScriptDefinedSymbols() const { - // Do we have cached results? - if (!_definedSymbols.empty()) - return _definedSymbols; - - // Populate our defined set and return it - for (auto cmd : _layoutCommands) - if (auto sa = dyn_cast<SymbolAssignment>(cmd)) { - StringRef symbol = sa->symbol(); - if (!symbol.empty() && symbol != ".") - _definedSymbols.insert(symbol); - } - - return _definedSymbols; -} - -uint64_t Sema::getLinkerScriptExprValue(StringRef name) const { - auto it = _symbolTable.find(name); - assert (it != _symbolTable.end() && "Invalid symbol name!"); - return it->second; -} - -bool Sema::hasPHDRs() const { return !_sectionToPHDR.empty(); } - -std::vector<const PHDR *> Sema::getPHDRsForOutputSection(StringRef name) const { - auto vec = _sectionToPHDR.lookup(name); - return std::vector<const PHDR *>(std::begin(vec), std::end(vec)); -} - -const PHDR *Sema::getProgramPHDR() const { return _programPHDR; } - -void Sema::dump() const { - raw_ostream &os = llvm::outs(); - os << "Linker script semantics dump\n"; - int num = 0; - for (auto &parser : _scripts) { - os << "Dumping script #" << ++num << ":\n"; - parser->get()->dump(os); - os << "\n"; - } - os << "Dumping rule ids:\n"; - for (unsigned i = 0; i < _layoutCommands.size(); ++i) { - os << "LayoutOrder " << i << ":\n"; - _layoutCommands[i]->dump(os); - os << "\n\n"; - } -} - -/// Given a string "pattern" with wildcard characters, return true if it -/// matches "name". This function is useful when checking if a given name -/// pattern written in the linker script, i.e. ".text*", should match -/// ".text.anytext". -static bool wildcardMatch(StringRef pattern, StringRef name) { - auto i = name.begin(); - - // Check if each char in pattern also appears in our input name, handling - // special wildcard characters. - for (auto j = pattern.begin(), e = pattern.end(); j != e; ++j) { - if (i == name.end()) - return false; - - switch (*j) { - case '*': - while (!wildcardMatch(pattern.drop_front(j - pattern.begin() + 1), - name.drop_front(i - name.begin()))) { - if (i == name.end()) - return false; - ++i; - } - break; - case '?': - // Matches any character - ++i; - break; - case '[': { - // Matches a range of characters specified between brackets - size_t end = pattern.find(']', j - pattern.begin()); - if (end == pattern.size()) - return false; - - StringRef chars = pattern.slice(j - pattern.begin(), end); - if (chars.find(i) == StringRef::npos) - return false; - - j = pattern.begin() + end; - ++i; - break; - } - case '\\': - ++j; - if (*j != *i) - return false; - ++i; - break; - default: - // No wildcard character means we must match exactly the same char - if (*j != *i) - return false; - ++i; - break; - } - } - - // If our pattern has't consumed the entire string, it is not a match - return i == name.end(); -} - -int Sema::matchSectionName(int id, const SectionKey &key) const { - const InputSectionsCmd *cmd = dyn_cast<InputSectionsCmd>(_layoutCommands[id]); - - if (!cmd || !wildcardMatch(cmd->archiveName(), key.archivePath)) - return -1; - - while ((size_t)++id < _layoutCommands.size() && - (isa<InputSection>(_layoutCommands[id]))) { - if (isa<InputSectionSortedGroup>(_layoutCommands[id])) - continue; - - const InputSectionName *in = - dyn_cast<InputSectionName>(_layoutCommands[id]); - if (wildcardMatch(in->name(), key.sectionName)) - return id; - } - return -1; -} - -int Sema::getLayoutOrder(const SectionKey &key, bool coarse) const { - // First check if we already answered this layout question - if (coarse) { - auto entry = _cacheSectionOrder.find(key); - if (entry != _cacheSectionOrder.end()) - return entry->second; - } else { - auto entry = _cacheExpressionOrder.find(key); - if (entry != _cacheExpressionOrder.end()) - return entry->second; - } - - // Try to match exact file name - auto range = _memberToLayoutOrder.equal_range(key.memberPath); - for (auto I = range.first, E = range.second; I != E; ++I) { - int order = I->second; - int exprOrder = -1; - - if ((exprOrder = matchSectionName(order, key)) >= 0) { - if (coarse) { - _cacheSectionOrder.insert(std::make_pair(key, order)); - return order; - } - _cacheExpressionOrder.insert(std::make_pair(key, exprOrder)); - return exprOrder; - } - } - - // If we still couldn't find a rule for this input section, try to match - // wildcards - for (const auto &I : _memberNameWildcards) { - if (!wildcardMatch(I.first, key.memberPath)) - continue; - int order = I.second; - int exprOrder = -1; - - if ((exprOrder = matchSectionName(order, key)) >= 0) { - if (coarse) { - _cacheSectionOrder.insert(std::make_pair(key, order)); - return order; - } - _cacheExpressionOrder.insert(std::make_pair(key, exprOrder)); - return exprOrder; - } - } - - _cacheSectionOrder.insert(std::make_pair(key, -1)); - _cacheExpressionOrder.insert(std::make_pair(key, -1)); - return -1; -} - -static bool compareSortedNames(WildcardSortMode sortMode, StringRef lhs, - StringRef rhs) { - switch (sortMode) { - case WildcardSortMode::None: - case WildcardSortMode::NA: - return false; - case WildcardSortMode::ByAlignment: - case WildcardSortMode::ByInitPriority: - case WildcardSortMode::ByAlignmentAndName: - assert(false && "Unimplemented sort order"); - break; - case WildcardSortMode::ByName: - return lhs.compare(rhs) < 0; - case WildcardSortMode::ByNameAndAlignment: - int compare = lhs.compare(rhs); - if (compare != 0) - return compare < 0; - return compareSortedNames(WildcardSortMode::ByAlignment, lhs, rhs); - } - return false; -} - -static bool sortedGroupContains(const InputSectionSortedGroup *cmd, - const Sema::SectionKey &key) { - for (const InputSection *child : *cmd) { - if (auto i = dyn_cast<InputSectionName>(child)) { - if (wildcardMatch(i->name(), key.sectionName)) - return true; - continue; - } - - auto *sortedGroup = dyn_cast<InputSectionSortedGroup>(child); - assert(sortedGroup && "Expected InputSectionSortedGroup object"); - - if (sortedGroupContains(sortedGroup, key)) - return true; - } - - return false; -} - -bool Sema::localCompare(int order, const SectionKey &lhs, - const SectionKey &rhs) const { - const InputSectionsCmd *cmd = - dyn_cast<InputSectionsCmd>(_layoutCommands[order]); - - assert(cmd && "Invalid InputSectionsCmd index"); - - if (lhs.archivePath != rhs.archivePath) - return compareSortedNames(cmd->archiveSortMode(), lhs.archivePath, - rhs.archivePath); - - if (lhs.memberPath != rhs.memberPath) - return compareSortedNames(cmd->fileSortMode(), lhs.memberPath, - rhs.memberPath); - - // Both sections come from the same exact same file and rule. Start walking - // through input section names as written in the linker script and the - // first one to match will have higher priority. - for (const InputSection *inputSection : *cmd) { - if (auto i = dyn_cast<InputSectionName>(inputSection)) { - // If both match, return false (both have equal priority) - // If rhs match, return false (rhs has higher priority) - if (wildcardMatch(i->name(), rhs.sectionName)) - return false; - // If lhs matches first, it has priority over rhs - if (wildcardMatch(i->name(), lhs.sectionName)) - return true; - continue; - } - - // Handle sorted subgroups specially - auto *sortedGroup = dyn_cast<InputSectionSortedGroup>(inputSection); - assert(sortedGroup && "Expected InputSectionSortedGroup object"); - - bool a = sortedGroupContains(sortedGroup, lhs); - bool b = sortedGroupContains(sortedGroup, rhs); - if (a && !b) - return false; - if (b && !a) - return true; - if (!a && !a) - continue; - - return compareSortedNames(sortedGroup->sortMode(), lhs.sectionName, - rhs.sectionName); - } - - llvm_unreachable(""); - return false; -} - -std::error_code Sema::collectPHDRs(const PHDRS *ph, - llvm::StringMap<const PHDR *> &phdrs) { - bool loadFound = false; - for (auto *p : *ph) { - phdrs[p->name()] = p; - - switch (p->type()) { - case llvm::ELF::PT_PHDR: - if (_programPHDR != nullptr) - return LinkerScriptReaderError::extra_program_phdr; - if (loadFound) - return LinkerScriptReaderError::misplaced_program_phdr; - if (!p->hasPHDRs()) - return LinkerScriptReaderError::program_phdr_wrong_phdrs; - _programPHDR = p; - break; - case llvm::ELF::PT_LOAD: - // Program header, if available, should have program header table - // mapped in the first loadable segment. - if (!loadFound && _programPHDR && !p->hasPHDRs()) - return LinkerScriptReaderError::program_phdr_wrong_phdrs; - loadFound = true; - break; - } - } - return std::error_code(); -} - -std::error_code Sema::buildSectionToPHDR(llvm::StringMap<const PHDR *> &phdrs) { - const bool noPhdrs = phdrs.empty(); - - // Add NONE header to the map provided there's no user-defined - // header with the same name. - if (!phdrs.count(PHDR_NONE.name())) - phdrs[PHDR_NONE.name()] = &PHDR_NONE; - - // Match output sections to available headers. - llvm::SmallVector<const PHDR *, 2> phdrsCur, phdrsLast { &PHDR_NONE }; - for (const Command *cmd : _layoutCommands) { - auto osd = dyn_cast<OutputSectionDescription>(cmd); - if (!osd || osd->isDiscarded()) - continue; - - phdrsCur.clear(); - for (StringRef name : osd->PHDRs()) { - auto it = phdrs.find(name); - if (it == phdrs.end()) { - return LinkerScriptReaderError::unknown_phdr_ids; - } - phdrsCur.push_back(it->second); - } - - // If no headers and no errors - insert empty headers set. - // If the current set of headers is empty, then use the last non-empty - // set. Otherwise mark the current set to be the last non-empty set for - // successors. - if (noPhdrs) - phdrsCur.clear(); - else if (phdrsCur.empty()) - phdrsCur = phdrsLast; - else - phdrsLast = phdrsCur; - - _sectionToPHDR[osd->name()] = phdrsCur; - } - return std::error_code(); -} - -static bool hasWildcard(StringRef name) { - for (auto ch : name) - if (ch == '*' || ch == '?' || ch == '[' || ch == '\\') - return true; - return false; -} - -void Sema::linearizeAST(const InputSection *inputSection) { - if (isa<InputSectionName>(inputSection)) { - _layoutCommands.push_back(inputSection); - return; - } - - auto *sortedGroup = dyn_cast<InputSectionSortedGroup>(inputSection); - assert(sortedGroup && "Expected InputSectionSortedGroup object"); - - for (const InputSection *child : *sortedGroup) { - linearizeAST(child); - } -} - -void Sema::linearizeAST(const InputSectionsCmd *inputSections) { - StringRef memberName = inputSections->memberName(); - // Populate our maps for fast lookup of InputSectionsCmd - if (hasWildcard(memberName)) - _memberNameWildcards.push_back( - std::make_pair(memberName, (int)_layoutCommands.size())); - else if (!memberName.empty()) - _memberToLayoutOrder.insert( - std::make_pair(memberName.str(), (int)_layoutCommands.size())); - - _layoutCommands.push_back(inputSections); - for (const InputSection *inputSection : *inputSections) - linearizeAST(inputSection); -} - -void Sema::linearizeAST(const Sections *sections) { - for (const Command *sectionCommand : *sections) { - if (isa<SymbolAssignment>(sectionCommand)) { - _layoutCommands.push_back(sectionCommand); - continue; - } - - if (!isa<OutputSectionDescription>(sectionCommand)) - continue; - - _layoutCommands.push_back(sectionCommand); - auto *outSection = dyn_cast<OutputSectionDescription>(sectionCommand); - - for (const Command *outSecCommand : *outSection) { - if (isa<SymbolAssignment>(outSecCommand)) { - _layoutCommands.push_back(outSecCommand); - continue; - } - - if (!isa<InputSectionsCmd>(outSecCommand)) - continue; - - linearizeAST(dyn_cast<InputSectionsCmd>(outSecCommand)); - } - } -} - -} // end namespace script -} // end namespace lld diff --git a/lib/ReaderWriter/MachO/ArchHandler.h b/lib/ReaderWriter/MachO/ArchHandler.h index 120f5dfd4cd2..70a63bd1004b 100644 --- a/lib/ReaderWriter/MachO/ArchHandler.h +++ b/lib/ReaderWriter/MachO/ArchHandler.h @@ -7,18 +7,19 @@ // //===----------------------------------------------------------------------===// +#ifndef LLD_READER_WRITER_MACHO_ARCH_HANDLER_H +#define LLD_READER_WRITER_MACHO_ARCH_HANDLER_H + #include "Atoms.h" #include "File.h" #include "MachONormalizedFile.h" #include "lld/Core/LLVM.h" +#include "lld/Core/Error.h" #include "lld/Core/Reference.h" #include "lld/Core/Simple.h" #include "lld/ReaderWriter/MachOLinkingContext.h" #include "llvm/ADT/Triple.h" -#ifndef LLD_READER_WRITER_MACHO_ARCH_HANDLER_H -#define LLD_READER_WRITER_MACHO_ARCH_HANDLER_H - namespace lld { namespace mach_o { @@ -78,6 +79,11 @@ public: /// actually be used. virtual uint32_t dwarfCompactUnwindType() = 0; + /// Reference from an __eh_frame CIE atom to its personality function it's + /// describing. Usually pointer-sized and PC-relative, but differs in whether + /// it needs to be in relocatable objects. + virtual Reference::KindValue unwindRefToPersonalityFunctionKind() = 0; + /// Reference from an __eh_frame FDE to the CIE it's based on. virtual Reference::KindValue unwindRefToCIEKind() = 0; @@ -92,6 +98,10 @@ public: /// __eh_frame. virtual Reference::KindValue unwindRefToEhFrameKind() = 0; + /// Returns a pointer sized reference kind. On 64-bit targets this will + /// likely be something like pointer64, and pointer32 on 32-bit targets. + virtual Reference::KindValue pointerKind() = 0; + virtual const Atom *fdeTargetFunction(const DefinedAtom *fde); /// Used by normalizedFromAtoms() to know where to generated rebasing and @@ -107,20 +117,20 @@ public: /// Prototype for a helper function. Given a sectionIndex and address, /// finds the atom and offset with that atom of that address. - typedef std::function<std::error_code (uint32_t sectionIndex, uint64_t addr, + typedef std::function<llvm::Error (uint32_t sectionIndex, uint64_t addr, const lld::Atom **, Reference::Addend *)> FindAtomBySectionAndAddress; /// Prototype for a helper function. Given a symbolIndex, finds the atom /// representing that symbol. - typedef std::function<std::error_code (uint32_t symbolIndex, + typedef std::function<llvm::Error (uint32_t symbolIndex, const lld::Atom **)> FindAtomBySymbolIndex; /// Analyzes a relocation from a .o file and returns the info /// (kind, target, addend) needed to instantiate a Reference. /// Two helper functions are passed as parameters to find the target atom /// given a symbol index or address. - virtual std::error_code + virtual llvm::Error getReferenceInfo(const normalized::Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom, @@ -135,7 +145,7 @@ public: /// (kind, target, addend) needed to instantiate a Reference. /// Two helper functions are passed as parameters to find the target atom /// given a symbol index or address. - virtual std::error_code + virtual llvm::Error getPairReferenceInfo(const normalized::Relocation &reloc1, const normalized::Relocation &reloc2, const DefinedAtom *inAtom, @@ -169,7 +179,7 @@ public: FindAddressForAtom findAddress, FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress, - uint8_t *atomContentBuffer) = 0; + llvm::MutableArrayRef<uint8_t> atomContentBuffer) = 0; /// Used in -r mode to convert a Reference to a mach-o relocation. virtual void appendSectionRelocations(const DefinedAtom &atom, @@ -251,7 +261,10 @@ public: ReferenceInfo stubHelperReferenceToImm; ReferenceInfo stubHelperReferenceToHelperCommon; + DefinedAtom::ContentType stubHelperImageCacheContentType; + uint32_t stubHelperCommonSize; + uint8_t stubHelperCommonAlignment; uint8_t stubHelperCommonBytes[36]; ReferenceInfo stubHelperCommonReferenceToCache; OptionalRefInfo optStubHelperCommonReferenceToCache; diff --git a/lib/ReaderWriter/MachO/ArchHandler_arm.cpp b/lib/ReaderWriter/MachO/ArchHandler_arm.cpp index 4e15a2d434c6..3286fe064535 100644 --- a/lib/ReaderWriter/MachO/ArchHandler_arm.cpp +++ b/lib/ReaderWriter/MachO/ArchHandler_arm.cpp @@ -51,6 +51,10 @@ public: return invalid; } + Reference::KindValue unwindRefToPersonalityFunctionKind() override { + return invalid; + } + Reference::KindValue unwindRefToCIEKind() override { return invalid; } @@ -63,21 +67,25 @@ public: return invalid; } + Reference::KindValue pointerKind() override { + return invalid; + } + uint32_t dwarfCompactUnwindType() override { // FIXME return -1; } - std::error_code getReferenceInfo(const normalized::Relocation &reloc, - const DefinedAtom *inAtom, - uint32_t offsetInAtom, - uint64_t fixupAddress, bool swap, - FindAtomBySectionAndAddress atomFromAddress, - FindAtomBySymbolIndex atomFromSymbolIndex, - Reference::KindValue *kind, - const lld::Atom **target, - Reference::Addend *addend) override; - std::error_code + llvm::Error getReferenceInfo(const normalized::Relocation &reloc, + const DefinedAtom *inAtom, + uint32_t offsetInAtom, + uint64_t fixupAddress, bool swap, + FindAtomBySectionAndAddress atomFromAddress, + FindAtomBySymbolIndex atomFromSymbolIndex, + Reference::KindValue *kind, + const lld::Atom **target, + Reference::Addend *addend) override; + llvm::Error getPairReferenceInfo(const normalized::Relocation &reloc1, const normalized::Relocation &reloc2, const DefinedAtom *inAtom, @@ -93,7 +101,7 @@ public: FindAddressForAtom findAddress, FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress, - uint8_t *atomContentBuffer) override; + llvm::MutableArrayRef<uint8_t> atomContentBuffer) override; void appendSectionRelocations(const DefinedAtom &atom, uint64_t atomSectionOffset, @@ -256,8 +264,13 @@ const ArchHandler::StubInfo ArchHandler_arm::_sStubInfoArmPIC = { { Reference::KindArch::ARM, lazyImmediateLocation, 8, 0 }, { Reference::KindArch::ARM, arm_b24, 4, 0 }, + // Stub helper image cache content type + DefinedAtom::typeGOT, + // Stub Helper-Common size and code 36, + // Stub helper alignment + 2, { // push lazy-info-offset 0x04, 0xC0, 0x2D, 0xE5, // str ip, [sp, #-4]! // push address of dyld_mageLoaderCache @@ -505,13 +518,12 @@ uint32_t ArchHandler_arm::clearThumbBit(uint32_t value, const Atom *target) { return value; } -std::error_code ArchHandler_arm::getReferenceInfo( +llvm::Error ArchHandler_arm::getReferenceInfo( const Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom, uint64_t fixupAddress, bool isBig, FindAtomBySectionAndAddress atomFromAddress, FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind, const lld::Atom **target, Reference::Addend *addend) { - typedef std::error_code E; const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; uint64_t targetAddress; uint32_t instruction = *(const ulittle32_t *)fixupContent; @@ -523,12 +535,12 @@ std::error_code ArchHandler_arm::getReferenceInfo( *kind = thumb_b22; else *kind = thumb_bl22; - if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; // Instruction contains branch to addend. displacement = getDisplacementFromThumbBranch(instruction, fixupAddress); *addend = fixupAddress + 4 + displacement; - return std::error_code(); + return llvm::Error(); case ARM_THUMB_RELOC_BR22 | rPcRel | rLength4: // ex: bl _foo (and _foo is defined) if ((instruction & 0xD000F800) == 0x9000F000) @@ -546,12 +558,12 @@ std::error_code ArchHandler_arm::getReferenceInfo( *kind = thumb_bl22; displacement = getDisplacementFromThumbBranch(instruction, fixupAddress); targetAddress = fixupAddress + 4 + displacement; - if (E ec = atomFromAddress(0, reloc.value, target, addend)) + if (auto ec = atomFromAddress(0, reloc.value, target, addend)) return ec; // reloc.value is target atom's address. Instruction contains branch // to atom+addend. *addend += (targetAddress - reloc.value); - return std::error_code(); + return llvm::Error(); case ARM_RELOC_BR24 | rPcRel | rExtern | rLength4: // ex: bl _foo (and _foo is undefined) if (((instruction & 0x0F000000) == 0x0A000000) @@ -559,12 +571,12 @@ std::error_code ArchHandler_arm::getReferenceInfo( *kind = arm_b24; else *kind = arm_bl24; - if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; // Instruction contains branch to addend. displacement = getDisplacementFromArmBranch(instruction); *addend = fixupAddress + 8 + displacement; - return std::error_code(); + return llvm::Error(); case ARM_RELOC_BR24 | rPcRel | rLength4: // ex: bl _foo (and _foo is defined) if (((instruction & 0x0F000000) == 0x0A000000) @@ -584,40 +596,40 @@ std::error_code ArchHandler_arm::getReferenceInfo( *kind = arm_bl24; displacement = getDisplacementFromArmBranch(instruction); targetAddress = fixupAddress + 8 + displacement; - if (E ec = atomFromAddress(0, reloc.value, target, addend)) + if (auto ec = atomFromAddress(0, reloc.value, target, addend)) return ec; // reloc.value is target atom's address. Instruction contains branch // to atom+addend. *addend += (targetAddress - reloc.value); - return std::error_code(); + return llvm::Error(); case ARM_RELOC_VANILLA | rExtern | rLength4: // ex: .long _foo (and _foo is undefined) *kind = pointer32; - if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = instruction; - return std::error_code(); + return llvm::Error(); case ARM_RELOC_VANILLA | rLength4: // ex: .long _foo (and _foo is defined) *kind = pointer32; - if (E ec = atomFromAddress(reloc.symbol, instruction, target, addend)) + if (auto ec = atomFromAddress(reloc.symbol, instruction, target, addend)) return ec; *addend = clearThumbBit((uint32_t) * addend, *target); - return std::error_code(); + return llvm::Error(); case ARM_RELOC_VANILLA | rScattered | rLength4: // ex: .long _foo+a (and _foo is defined) *kind = pointer32; - if (E ec = atomFromAddress(0, reloc.value, target, addend)) + if (auto ec = atomFromAddress(0, reloc.value, target, addend)) return ec; *addend += (clearThumbBit(instruction, *target) - reloc.value); - return std::error_code(); + return llvm::Error(); default: - return make_dynamic_error_code("unsupported arm relocation type"); + return llvm::make_error<GenericError>("unsupported arm relocation type"); } - return std::error_code(); + return llvm::Error(); } -std::error_code +llvm::Error ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1, const normalized::Relocation &reloc2, const DefinedAtom *inAtom, @@ -770,10 +782,9 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1, pointerDiff = true; break; default: - return make_dynamic_error_code("unsupported arm relocation pair"); + return llvm::make_error<GenericError>("unsupported arm relocation pair"); } const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; - std::error_code ec; uint32_t instruction = *(const ulittle32_t *)fixupContent; uint32_t value; uint32_t fromAddress; @@ -786,14 +797,12 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1, if (pointerDiff) { toAddress = reloc1.value; fromAddress = reloc2.value; - ec = atomFromAddr(0, toAddress, target, &offsetInTo); - if (ec) + if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo)) return ec; - ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom); - if (ec) + if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom)) return ec; if (scatterable && (fromTarget != inAtom)) - return make_dynamic_error_code( + return llvm::make_error<GenericError>( "SECTDIFF relocation where subtrahend label is not in atom"); *kind = delta32; value = clearThumbBit(instruction, *target); @@ -801,35 +810,33 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1, } else if (funcRel) { toAddress = reloc1.value; fromAddress = reloc2.value; - ec = atomFromAddr(0, toAddress, target, &offsetInTo); - if (ec) + if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo)) return ec; - ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom); - if (ec) + if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom)) return ec; if (fromTarget != inAtom) - return make_dynamic_error_code("ARM_RELOC_HALF_SECTDIFF relocation " - "where subtrahend label is not in atom"); + return llvm::make_error<GenericError>("ARM_RELOC_HALF_SECTDIFF relocation" + " where subtrahend label is not in atom"); other16 = (reloc2.offset & 0xFFFF); if (thumbReloc) { if (top) { if (!isThumbMovt(instruction)) - return make_dynamic_error_code("expected movt instruction"); + return llvm::make_error<GenericError>("expected movt instruction"); } else { if (!isThumbMovw(instruction)) - return make_dynamic_error_code("expected movw instruction"); + return llvm::make_error<GenericError>("expected movw instruction"); } instruction16 = getWordFromThumbMov(instruction); } else { if (top) { if (!isArmMovt(instruction)) - return make_dynamic_error_code("expected movt instruction"); + return llvm::make_error<GenericError>("expected movt instruction"); } else { if (!isArmMovw(instruction)) - return make_dynamic_error_code("expected movw instruction"); + return llvm::make_error<GenericError>("expected movw instruction"); } instruction16 = getWordFromArmMov(instruction); } @@ -840,28 +847,28 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1, value = clearThumbBit(value, *target); int64_t ta = (int64_t) value - (toAddress - fromAddress); *addend = ta - offsetInFrom; - return std::error_code(); + return llvm::Error(); } else { uint32_t sectIndex; if (thumbReloc) { if (top) { if (!isThumbMovt(instruction)) - return make_dynamic_error_code("expected movt instruction"); + return llvm::make_error<GenericError>("expected movt instruction"); } else { if (!isThumbMovw(instruction)) - return make_dynamic_error_code("expected movw instruction"); + return llvm::make_error<GenericError>("expected movw instruction"); } instruction16 = getWordFromThumbMov(instruction); } else { if (top) { if (!isArmMovt(instruction)) - return make_dynamic_error_code("expected movt instruction"); + return llvm::make_error<GenericError>("expected movt instruction"); } else { if (!isArmMovw(instruction)) - return make_dynamic_error_code("expected movw instruction"); + return llvm::make_error<GenericError>("expected movw instruction"); } instruction16 = getWordFromArmMov(instruction); } @@ -871,8 +878,7 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1, else value = (other16 << 16) | instruction16; if (reloc1.isExtern) { - ec = atomFromSymbolIndex(reloc1.symbol, target); - if (ec) + if (auto ec = atomFromSymbolIndex(reloc1.symbol, target)) return ec; *addend = value; } else { @@ -883,14 +889,13 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1, toAddress = value; sectIndex = reloc1.symbol; } - ec = atomFromAddr(sectIndex, toAddress, target, &offsetInTo); - if (ec) + if (auto ec = atomFromAddr(sectIndex, toAddress, target, &offsetInTo)) return ec; *addend = value - toAddress; } } - return std::error_code(); + return llvm::Error(); } void ArchHandler_arm::applyFixupFinal(const Reference &ref, uint8_t *loc, @@ -1006,9 +1011,10 @@ void ArchHandler_arm::generateAtomContent(const DefinedAtom &atom, FindAddressForAtom findAddress, FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress, - uint8_t *atomContentBuffer) { + llvm::MutableArrayRef<uint8_t> atomContentBuffer) { // Copy raw bytes. - memcpy(atomContentBuffer, atom.rawContent().data(), atom.size()); + std::copy(atom.rawContent().begin(), atom.rawContent().end(), + atomContentBuffer.begin()); // Apply fix-ups. bool thumbMode = false; for (const Reference *ref : atom) { @@ -1384,7 +1390,8 @@ void ArchHandler_arm::appendSectionRelocations( void ArchHandler_arm::addAdditionalReferences(MachODefinedAtom &atom) { if (atom.isThumb()) { - atom.addReference(0, modeThumbCode, &atom, 0, Reference::KindArch::ARM); + atom.addReference(Reference::KindNamespace::mach_o, + Reference::KindArch::ARM, modeThumbCode, 0, &atom, 0); } } @@ -1415,6 +1422,8 @@ public: _name = tmp.copy(file.allocator()); } + ~Thumb2ToArmShimAtom() override = default; + StringRef name() const override { return _name; } @@ -1458,6 +1467,8 @@ public: _name = tmp.copy(file.allocator()); } + ~ArmToThumbShimAtom() override = default; + StringRef name() const override { return _name; } diff --git a/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp b/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp index 778f6f4add74..a61f6aac05e1 100644 --- a/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp +++ b/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp @@ -53,6 +53,9 @@ public: case delta32ToGOT: canBypassGOT = false; return true; + case unwindCIEToPersonalityFunction: + canBypassGOT = false; + return true; case imageOffsetGot: canBypassGOT = false; return true; @@ -108,6 +111,10 @@ public: return imageOffsetGot; } + Reference::KindValue unwindRefToPersonalityFunctionKind() override { + return unwindCIEToPersonalityFunction; + } + Reference::KindValue unwindRefToCIEKind() override { return negDelta32; } @@ -120,20 +127,24 @@ public: return unwindInfoToEhFrame; } + Reference::KindValue pointerKind() override { + return pointer64; + } + uint32_t dwarfCompactUnwindType() override { return 0x03000000; } - std::error_code getReferenceInfo(const normalized::Relocation &reloc, - const DefinedAtom *inAtom, - uint32_t offsetInAtom, - uint64_t fixupAddress, bool isBig, - FindAtomBySectionAndAddress atomFromAddress, - FindAtomBySymbolIndex atomFromSymbolIndex, - Reference::KindValue *kind, - const lld::Atom **target, - Reference::Addend *addend) override; - std::error_code + llvm::Error getReferenceInfo(const normalized::Relocation &reloc, + const DefinedAtom *inAtom, + uint32_t offsetInAtom, + uint64_t fixupAddress, bool isBig, + FindAtomBySectionAndAddress atomFromAddress, + FindAtomBySymbolIndex atomFromSymbolIndex, + Reference::KindValue *kind, + const lld::Atom **target, + Reference::Addend *addend) override; + llvm::Error getPairReferenceInfo(const normalized::Relocation &reloc1, const normalized::Relocation &reloc2, const DefinedAtom *inAtom, @@ -153,7 +164,7 @@ public: FindAddressForAtom findAddress, FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress, - uint8_t *atomContentBuffer) override; + llvm::MutableArrayRef<uint8_t> atomContentBuffer) override; void appendSectionRelocations(const DefinedAtom &atom, uint64_t atomSectionOffset, @@ -197,6 +208,9 @@ private: imageOffset, /// Location contains offset of atom in final image imageOffsetGot, /// Location contains offset of GOT entry for atom in /// final image (typically personality function). + unwindCIEToPersonalityFunction, /// Nearly delta32ToGOT, but cannot be + /// rematerialized in relocatable object + /// (yay for implicit contracts!). unwindFDEToFunction, /// Nearly delta64, but cannot be rematerialized in /// relocatable object (yay for implicit contracts!). unwindInfoToEhFrame, /// Fix low 24 bits of compact unwind encoding to @@ -244,6 +258,7 @@ const Registry::KindStrings ArchHandler_arm64::_sKindStrings[] = { LLD_KIND_STRING_ENTRY(lazyImmediateLocation), LLD_KIND_STRING_ENTRY(imageOffset), LLD_KIND_STRING_ENTRY(imageOffsetGot), + LLD_KIND_STRING_ENTRY(unwindCIEToPersonalityFunction), LLD_KIND_STRING_ENTRY(unwindFDEToFunction), LLD_KIND_STRING_ENTRY(unwindInfoToEhFrame), @@ -279,8 +294,13 @@ const ArchHandler::StubInfo ArchHandler_arm64::_sStubInfo = { { Reference::KindArch::AArch64, lazyImmediateLocation, 8, 0 }, { Reference::KindArch::AArch64, branch26, 4, 0 }, + // Stub helper image cache content type + DefinedAtom::typeGOT, + // Stub Helper-Common size and code 24, + // Stub helper alignment + 2, { 0x11, 0x00, 0x00, 0x90, // ADRP X17, dyld_ImageLoaderCache@page 0x31, 0x02, 0x00, 0x91, // ADD X17, X17, dyld_ImageLoaderCache@pageoff 0xF0, 0x47, 0xBF, 0xA9, // STP X16/X17, [SP, #-16]! @@ -355,7 +375,7 @@ uint32_t ArchHandler_arm64::setImm12(uint32_t instruction, uint32_t offset) { return (instruction & 0xFFC003FF) | imm12; } -std::error_code ArchHandler_arm64::getReferenceInfo( +llvm::Error ArchHandler_arm64::getReferenceInfo( const Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom, uint64_t fixupAddress, bool isBig, FindAtomBySectionAndAddress atomFromAddress, @@ -369,56 +389,56 @@ std::error_code ArchHandler_arm64::getReferenceInfo( if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = 0; - return std::error_code(); + return llvm::Error(); case ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4: // ex: adrp x1, _foo@PAGE *kind = page21; if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = 0; - return std::error_code(); + return llvm::Error(); case ARM64_RELOC_PAGEOFF12 | rExtern | rLength4: // ex: ldr x0, [x1, _foo@PAGEOFF] *kind = offset12KindFromInstruction(*(const little32_t *)fixupContent); if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = 0; - return std::error_code(); + return llvm::Error(); case ARM64_RELOC_GOT_LOAD_PAGE21 | rPcRel | rExtern | rLength4: // ex: adrp x1, _foo@GOTPAGE *kind = gotPage21; if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = 0; - return std::error_code(); + return llvm::Error(); case ARM64_RELOC_GOT_LOAD_PAGEOFF12 | rExtern | rLength4: // ex: ldr x0, [x1, _foo@GOTPAGEOFF] *kind = gotOffset12; if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = 0; - return std::error_code(); + return llvm::Error(); case ARM64_RELOC_TLVP_LOAD_PAGE21 | rPcRel | rExtern | rLength4: // ex: adrp x1, _foo@TLVPAGE *kind = tlvPage21; if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = 0; - return std::error_code(); + return llvm::Error(); case ARM64_RELOC_TLVP_LOAD_PAGEOFF12 | rExtern | rLength4: // ex: ldr x0, [x1, _foo@TLVPAGEOFF] *kind = tlvOffset12; if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = 0; - return std::error_code(); + return llvm::Error(); case ARM64_RELOC_UNSIGNED | rExtern | rLength8: // ex: .quad _foo + N *kind = pointer64; if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = *(const little64_t *)fixupContent; - return std::error_code(); + return llvm::Error(); case ARM64_RELOC_UNSIGNED | rLength8: // ex: .quad Lfoo + N *kind = pointer64; @@ -430,27 +450,33 @@ std::error_code ArchHandler_arm64::getReferenceInfo( if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = 0; - return std::error_code(); + return llvm::Error(); case ARM64_RELOC_POINTER_TO_GOT | rPcRel | rExtern | rLength4: // ex: .long _foo@GOT - . - *kind = delta32ToGOT; + + // If we are in an .eh_frame section, then the kind of the relocation should + // not be delta32ToGOT. It may instead be unwindCIEToPersonalityFunction. + if (inAtom->contentType() == DefinedAtom::typeCFI) + *kind = unwindCIEToPersonalityFunction; + else + *kind = delta32ToGOT; + if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = 0; - return std::error_code(); + return llvm::Error(); default: - return make_dynamic_error_code("unsupported arm64 relocation type"); + return llvm::make_error<GenericError>("unsupported arm64 relocation type"); } } -std::error_code ArchHandler_arm64::getPairReferenceInfo( +llvm::Error ArchHandler_arm64::getPairReferenceInfo( const normalized::Relocation &reloc1, const normalized::Relocation &reloc2, const DefinedAtom *inAtom, uint32_t offsetInAtom, uint64_t fixupAddress, bool swap, bool scatterable, FindAtomBySectionAndAddress atomFromAddress, FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind, const lld::Atom **target, Reference::Addend *addend) { const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; - const uint32_t *cont32 = reinterpret_cast<const uint32_t *>(fixupContent); switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) { case ((ARM64_RELOC_ADDEND | rLength4) << 16 | ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4): @@ -459,7 +485,7 @@ std::error_code ArchHandler_arm64::getPairReferenceInfo( if (auto ec = atomFromSymbolIndex(reloc2.symbol, target)) return ec; *addend = reloc1.symbol; - return std::error_code(); + return llvm::Error(); case ((ARM64_RELOC_ADDEND | rLength4) << 16 | ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4): // ex: adrp x1, _foo@PAGE @@ -467,26 +493,36 @@ std::error_code ArchHandler_arm64::getPairReferenceInfo( if (auto ec = atomFromSymbolIndex(reloc2.symbol, target)) return ec; *addend = reloc1.symbol; - return std::error_code(); + return llvm::Error(); case ((ARM64_RELOC_ADDEND | rLength4) << 16 | - ARM64_RELOC_PAGEOFF12 | rExtern | rLength4): + ARM64_RELOC_PAGEOFF12 | rExtern | rLength4): { // ex: ldr w0, [x1, _foo@PAGEOFF] - *kind = offset12KindFromInstruction(*cont32); + uint32_t cont32 = (int32_t)*(const little32_t *)fixupContent; + *kind = offset12KindFromInstruction(cont32); if (auto ec = atomFromSymbolIndex(reloc2.symbol, target)) return ec; *addend = reloc1.symbol; - return std::error_code(); + return llvm::Error(); + } case ((ARM64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 | ARM64_RELOC_UNSIGNED | rExtern | rLength8): // ex: .quad _foo - . - *kind = delta64; if (auto ec = atomFromSymbolIndex(reloc2.symbol, target)) return ec; + + // If we are in an .eh_frame section, then the kind of the relocation should + // not be delta64. It may instead be unwindFDEToFunction. + if (inAtom->contentType() == DefinedAtom::typeCFI) + *kind = unwindFDEToFunction; + else + *kind = delta64; + // The offsets of the 2 relocations must match if (reloc1.offset != reloc2.offset) - return make_dynamic_error_code("paired relocs must have the same offset"); + return llvm::make_error<GenericError>( + "paired relocs must have the same offset"); *addend = (int64_t)*(const little64_t *)fixupContent + offsetInAtom; - return std::error_code(); + return llvm::Error(); case ((ARM64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 | ARM64_RELOC_UNSIGNED | rExtern | rLength4): // ex: .quad _foo - . @@ -494,18 +530,19 @@ std::error_code ArchHandler_arm64::getPairReferenceInfo( if (auto ec = atomFromSymbolIndex(reloc2.symbol, target)) return ec; *addend = (int32_t)*(const little32_t *)fixupContent + offsetInAtom; - return std::error_code(); + return llvm::Error(); default: - return make_dynamic_error_code("unsupported arm64 relocation pair"); + return llvm::make_error<GenericError>("unsupported arm64 relocation pair"); } } void ArchHandler_arm64::generateAtomContent( const DefinedAtom &atom, bool relocatable, FindAddressForAtom findAddress, FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress, - uint8_t *atomContentBuffer) { + llvm::MutableArrayRef<uint8_t> atomContentBuffer) { // Copy raw bytes. - memcpy(atomContentBuffer, atom.rawContent().data(), atom.size()); + std::copy(atom.rawContent().begin(), atom.rawContent().end(), + atomContentBuffer.begin()); // Apply fix-ups. #ifndef NDEBUG if (atom.begin() != atom.end()) { @@ -620,6 +657,7 @@ void ArchHandler_arm64::applyFixupFinal(const Reference &ref, uint8_t *loc, return; case delta32: case delta32ToGOT: + case unwindCIEToPersonalityFunction: *loc32 = (targetAddress - fixupAddress) + ref.addend(); return; case negDelta32: @@ -710,6 +748,13 @@ void ArchHandler_arm64::applyFixupRelocatable(const Reference &ref, case delta32ToGOT: *loc32 = inAtomAddress - fixupAddress; return; + case unwindCIEToPersonalityFunction: + // We don't emit unwindCIEToPersonalityFunction in -r mode as they are + // implicitly generated from the data in the __eh_frame section. So here we + // need to use the targetAddress so that we can generate the full relocation + // when we parse again later. + *loc32 = targetAddress - fixupAddress; + return; case addOffset12: llvm_unreachable("lazy reference kind implies GOT pass was run"); case lazyPointer: @@ -832,6 +877,7 @@ void ArchHandler_arm64::appendSectionRelocations( case imageOffset: case imageOffsetGot: llvm_unreachable("deltas from mach_header can only be in final images"); + case unwindCIEToPersonalityFunction: case unwindFDEToFunction: case unwindInfoToEhFrame: case negDelta32: diff --git a/lib/ReaderWriter/MachO/ArchHandler_x86.cpp b/lib/ReaderWriter/MachO/ArchHandler_x86.cpp index 7aac2584d078..15f1f793b5d7 100644 --- a/lib/ReaderWriter/MachO/ArchHandler_x86.cpp +++ b/lib/ReaderWriter/MachO/ArchHandler_x86.cpp @@ -58,6 +58,10 @@ public: return invalid; } + Reference::KindValue unwindRefToPersonalityFunctionKind() override { + return invalid; + } + Reference::KindValue unwindRefToCIEKind() override { return negDelta32; } @@ -70,20 +74,24 @@ public: return invalid; } + Reference::KindValue pointerKind() override { + return invalid; + } + uint32_t dwarfCompactUnwindType() override { return 0x04000000U; } - std::error_code getReferenceInfo(const normalized::Relocation &reloc, - const DefinedAtom *inAtom, - uint32_t offsetInAtom, - uint64_t fixupAddress, bool swap, - FindAtomBySectionAndAddress atomFromAddress, - FindAtomBySymbolIndex atomFromSymbolIndex, - Reference::KindValue *kind, - const lld::Atom **target, - Reference::Addend *addend) override; - std::error_code + llvm::Error getReferenceInfo(const normalized::Relocation &reloc, + const DefinedAtom *inAtom, + uint32_t offsetInAtom, + uint64_t fixupAddress, bool swap, + FindAtomBySectionAndAddress atomFromAddress, + FindAtomBySymbolIndex atomFromSymbolIndex, + Reference::KindValue *kind, + const lld::Atom **target, + Reference::Addend *addend) override; + llvm::Error getPairReferenceInfo(const normalized::Relocation &reloc1, const normalized::Relocation &reloc2, const DefinedAtom *inAtom, @@ -99,7 +107,7 @@ public: FindAddressForAtom findAddress, FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress, - uint8_t *atomContentBuffer) override; + llvm::MutableArrayRef<uint8_t> atomContentBuffer) override; void appendSectionRelocations(const DefinedAtom &atom, uint64_t atomSectionOffset, @@ -212,8 +220,13 @@ const ArchHandler::StubInfo ArchHandler_x86::_sStubInfo = { { Reference::KindArch::x86, lazyImmediateLocation, 1, 0 }, { Reference::KindArch::x86, branch32, 6, 0 }, + // Stub helper image cache content type + DefinedAtom::typeNonLazyPointer, + // Stub Helper-Common size and code 12, + // Stub helper alignment + 2, { 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $dyld_ImageLoaderCache 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *_fast_lazy_bind 0x90 }, // nop @@ -238,7 +251,7 @@ bool ArchHandler_x86::isPairedReloc(const Relocation &reloc) { (reloc.type == GENERIC_RELOC_SECTDIFF); } -std::error_code +llvm::Error ArchHandler_x86::getReferenceInfo(const Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom, @@ -248,7 +261,6 @@ ArchHandler_x86::getReferenceInfo(const Relocation &reloc, Reference::KindValue *kind, const lld::Atom **target, Reference::Addend *addend) { - typedef std::error_code E; DefinedAtom::ContentPermissions perms; const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; uint64_t targetAddress; @@ -256,7 +268,7 @@ ArchHandler_x86::getReferenceInfo(const Relocation &reloc, case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength4: // ex: call _foo (and _foo undefined) *kind = branch32; - if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = fixupAddress + 4 + (int32_t)*(const little32_t *)fixupContent; break; @@ -272,14 +284,14 @@ ArchHandler_x86::getReferenceInfo(const Relocation &reloc, *kind = branch32; targetAddress = fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent; - if (E ec = atomFromAddress(0, reloc.value, target, addend)) + if (auto ec = atomFromAddress(0, reloc.value, target, addend)) return ec; *addend = targetAddress - reloc.value; break; case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2: // ex: callw _foo (and _foo undefined) *kind = branch16; - if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = fixupAddress + 2 + (int16_t)*(const little16_t *)fixupContent; break; @@ -295,7 +307,7 @@ ArchHandler_x86::getReferenceInfo(const Relocation &reloc, *kind = branch16; targetAddress = fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent; - if (E ec = atomFromAddress(0, reloc.value, target, addend)) + if (auto ec = atomFromAddress(0, reloc.value, target, addend)) return ec; *addend = targetAddress - reloc.value; break; @@ -306,7 +318,7 @@ ArchHandler_x86::getReferenceInfo(const Relocation &reloc, *kind = ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32 : pointer32; - if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = *(const ulittle32_t *)fixupContent; break; @@ -326,17 +338,17 @@ ArchHandler_x86::getReferenceInfo(const Relocation &reloc, *kind = ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32 : pointer32; - if (E ec = atomFromAddress(0, reloc.value, target, addend)) + if (auto ec = atomFromAddress(0, reloc.value, target, addend)) return ec; *addend = *(const ulittle32_t *)fixupContent - reloc.value; break; default: - return make_dynamic_error_code("unsupported i386 relocation type"); + return llvm::make_error<GenericError>("unsupported i386 relocation type"); } - return std::error_code(); + return llvm::Error(); } -std::error_code +llvm::Error ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1, const normalized::Relocation &reloc2, const DefinedAtom *inAtom, @@ -349,7 +361,6 @@ ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1, const lld::Atom **target, Reference::Addend *addend) { const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; - std::error_code ec; DefinedAtom::ContentPermissions perms = inAtom->permissions(); uint32_t fromAddress; uint32_t toAddress; @@ -365,15 +376,13 @@ ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1, toAddress = reloc1.value; fromAddress = reloc2.value; value = *(const little32_t *)fixupContent; - ec = atomFromAddr(0, toAddress, target, &offsetInTo); - if (ec) + if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo)) return ec; - ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom); - if (ec) + if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom)) return ec; if (fromTarget != inAtom) { if (*target != inAtom) - return make_dynamic_error_code( + return llvm::make_error<GenericError>( "SECTDIFF relocation where neither target is in atom"); *kind = negDelta32; *addend = toAddress - value - fromAddress; @@ -394,10 +403,10 @@ ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1, *addend = fromAddress + value - toAddress; } } - return std::error_code(); + return llvm::Error(); break; default: - return make_dynamic_error_code("unsupported i386 relocation type"); + return llvm::make_error<GenericError>("unsupported i386 relocation type"); } } @@ -406,9 +415,10 @@ void ArchHandler_x86::generateAtomContent(const DefinedAtom &atom, FindAddressForAtom findAddress, FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress, - uint8_t *atomContentBuffer) { + llvm::MutableArrayRef<uint8_t> atomContentBuffer) { // Copy raw bytes. - memcpy(atomContentBuffer, atom.rawContent().data(), atom.size()); + std::copy(atom.rawContent().begin(), atom.rawContent().end(), + atomContentBuffer.begin()); // Apply fix-ups. for (const Reference *ref : atom) { uint32_t offset = ref->offsetInAtom(); diff --git a/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp index 8b4d1cf38cba..c36982a77b13 100644 --- a/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp +++ b/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp @@ -104,6 +104,10 @@ public: return imageOffsetGot; } + Reference::KindValue unwindRefToPersonalityFunctionKind() override { + return ripRel32Got; + } + Reference::KindValue unwindRefToCIEKind() override { return negDelta32; } @@ -116,6 +120,10 @@ public: return unwindInfoToEhFrame; } + Reference::KindValue pointerKind() override { + return pointer64; + } + uint32_t dwarfCompactUnwindType() override { return 0x04000000U; } @@ -130,16 +138,16 @@ public: bool isPointer(const Reference &) override; bool isPairedReloc(const normalized::Relocation &) override; - std::error_code getReferenceInfo(const normalized::Relocation &reloc, - const DefinedAtom *inAtom, - uint32_t offsetInAtom, - uint64_t fixupAddress, bool swap, - FindAtomBySectionAndAddress atomFromAddress, - FindAtomBySymbolIndex atomFromSymbolIndex, - Reference::KindValue *kind, - const lld::Atom **target, - Reference::Addend *addend) override; - std::error_code + llvm::Error getReferenceInfo(const normalized::Relocation &reloc, + const DefinedAtom *inAtom, + uint32_t offsetInAtom, + uint64_t fixupAddress, bool swap, + FindAtomBySectionAndAddress atomFromAddress, + FindAtomBySymbolIndex atomFromSymbolIndex, + Reference::KindValue *kind, + const lld::Atom **target, + Reference::Addend *addend) override; + llvm::Error getPairReferenceInfo(const normalized::Relocation &reloc1, const normalized::Relocation &reloc2, const DefinedAtom *inAtom, @@ -159,7 +167,7 @@ public: FindAddressForAtom findAddress, FindAddressForAtom findSectionAddress, uint64_t imageBase, - uint8_t *atomContentBuffer) override; + llvm::MutableArrayRef<uint8_t> atomContentBuffer) override; void appendSectionRelocations(const DefinedAtom &atom, uint64_t atomSectionOffset, @@ -195,6 +203,7 @@ private: delta32, /// ex: .long _foo - . delta64Anon, /// ex: .quad L1 - . delta32Anon, /// ex: .long L1 - . + negDelta64, /// ex: .quad . - _foo negDelta32, /// ex: .long . - _foo // Kinds introduced by Passes: @@ -216,8 +225,6 @@ private: }; Reference::KindValue kindFromReloc(const normalized::Relocation &reloc); - Reference::KindValue kindFromRelocPair(const normalized::Relocation &reloc1, - const normalized::Relocation &reloc2); void applyFixupFinal(const Reference &ref, uint8_t *location, uint64_t fixupAddress, uint64_t targetAddress, @@ -246,6 +253,7 @@ const Registry::KindStrings ArchHandler_x86_64::_sKindStrings[] = { LLD_KIND_STRING_ENTRY(pointer64), LLD_KIND_STRING_ENTRY(pointer64Anon), LLD_KIND_STRING_ENTRY(delta32), LLD_KIND_STRING_ENTRY(delta64), LLD_KIND_STRING_ENTRY(delta32Anon), LLD_KIND_STRING_ENTRY(delta64Anon), + LLD_KIND_STRING_ENTRY(negDelta64), LLD_KIND_STRING_ENTRY(negDelta32), LLD_KIND_STRING_ENTRY(imageOffset), LLD_KIND_STRING_ENTRY(imageOffsetGot), LLD_KIND_STRING_ENTRY(unwindFDEToFunction), @@ -280,8 +288,13 @@ const ArchHandler::StubInfo ArchHandler_x86_64::_sStubInfo = { { Reference::KindArch::x86_64, lazyImmediateLocation, 1, 0 }, { Reference::KindArch::x86_64, branch32, 6, 0 }, + // Stub helper image cache content type + DefinedAtom::typeNonLazyPointer, + // Stub Helper-Common size and code 16, + // Stub helper alignment + 2, { 0x4C, 0x8D, 0x1D, 0x00, 0x00, 0x00, 0x00, // leaq cache(%rip),%r11 0x41, 0x53, // push %r11 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *binder(%rip) @@ -348,7 +361,7 @@ ArchHandler_x86_64::kindFromReloc(const Relocation &reloc) { } } -std::error_code +llvm::Error ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom, @@ -358,34 +371,33 @@ ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc, Reference::KindValue *kind, const lld::Atom **target, Reference::Addend *addend) { - typedef std::error_code E; *kind = kindFromReloc(reloc); if (*kind == invalid) - return make_dynamic_error_code("unknown type"); + return llvm::make_error<GenericError>("unknown type"); const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; uint64_t targetAddress; switch (*kind) { case branch32: case ripRel32: - if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = *(const little32_t *)fixupContent; - return std::error_code(); + return llvm::Error(); case ripRel32Minus1: - if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = (int32_t)*(const little32_t *)fixupContent + 1; - return std::error_code(); + return llvm::Error(); case ripRel32Minus2: - if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = (int32_t)*(const little32_t *)fixupContent + 2; - return std::error_code(); + return llvm::Error(); case ripRel32Minus4: - if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = (int32_t)*(const little32_t *)fixupContent + 4; - return std::error_code(); + return llvm::Error(); case ripRel32Anon: targetAddress = fixupAddress + 4 + *(const little32_t *)fixupContent; return atomFromAddress(reloc.symbol, targetAddress, target, addend); @@ -401,13 +413,13 @@ ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc, case ripRel32GotLoad: case ripRel32Got: case ripRel32Tlv: - if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = *(const little32_t *)fixupContent; - return std::error_code(); + return llvm::Error(); case tlvInitSectionOffset: case pointer64: - if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; // If this is the 3rd pointer of a tlv-thunk (i.e. the pointer to the TLV's // initial value) we need to handle it specially. @@ -417,7 +429,7 @@ ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc, assert(*addend == 0 && "TLV-init has non-zero addend?"); } else *addend = *(const little64_t *)fixupContent; - return std::error_code(); + return llvm::Error(); case pointer64Anon: targetAddress = *(const little64_t *)fixupContent; return atomFromAddress(reloc.symbol, targetAddress, target, addend); @@ -426,28 +438,7 @@ ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc, } } -Reference::KindValue -ArchHandler_x86_64::kindFromRelocPair(const normalized::Relocation &reloc1, - const normalized::Relocation &reloc2) { - switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) { - case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 | - X86_64_RELOC_UNSIGNED | rExtern | rLength8): - return delta64; - case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 | - X86_64_RELOC_UNSIGNED | rExtern | rLength4): - return delta32; - case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 | - X86_64_RELOC_UNSIGNED | rLength8): - return delta64Anon; - case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 | - X86_64_RELOC_UNSIGNED | rLength4): - return delta32Anon; - default: - llvm_unreachable("bad reloc pairs"); - } -} - -std::error_code +llvm::Error ArchHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1, const normalized::Relocation &reloc2, const DefinedAtom *inAtom, @@ -459,45 +450,71 @@ ArchHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1, Reference::KindValue *kind, const lld::Atom **target, Reference::Addend *addend) { - *kind = kindFromRelocPair(reloc1, reloc2); - if (*kind == invalid) - return make_dynamic_error_code("unknown pair"); const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; - typedef std::error_code E; uint64_t targetAddress; const lld::Atom *fromTarget; - if (E ec = atomFromSymbolIndex(reloc1.symbol, &fromTarget)) + if (auto ec = atomFromSymbolIndex(reloc1.symbol, &fromTarget)) return ec; - if (fromTarget != inAtom) - return make_dynamic_error_code("pointer diff not in base atom"); - switch (*kind) { - case delta64: - if (E ec = atomFromSymbolIndex(reloc2.symbol, target)) + + switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) { + case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 | + X86_64_RELOC_UNSIGNED | rExtern | rLength8): { + if (auto ec = atomFromSymbolIndex(reloc2.symbol, target)) return ec; - *addend = (int64_t)*(const little64_t *)fixupContent + offsetInAtom; - return std::error_code(); - case delta32: - if (E ec = atomFromSymbolIndex(reloc2.symbol, target)) + uint64_t encodedAddend = (int64_t)*(const little64_t *)fixupContent; + if (inAtom == fromTarget) { + *kind = delta64; + *addend = encodedAddend + offsetInAtom; + } else if (inAtom == *target) { + *kind = negDelta64; + *addend = encodedAddend - offsetInAtom; + *target = fromTarget; + } else + return llvm::make_error<GenericError>("Invalid pointer diff"); + return llvm::Error(); + } + case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 | + X86_64_RELOC_UNSIGNED | rExtern | rLength4): { + if (auto ec = atomFromSymbolIndex(reloc2.symbol, target)) return ec; - *addend = (int32_t)*(const little32_t *)fixupContent + offsetInAtom; - return std::error_code(); - case delta64Anon: + uint32_t encodedAddend = (int32_t)*(const little32_t *)fixupContent; + if (inAtom == fromTarget) { + *kind = delta32; + *addend = encodedAddend + offsetInAtom; + } else if (inAtom == *target) { + *kind = negDelta32; + *addend = encodedAddend - offsetInAtom; + *target = fromTarget; + } else + return llvm::make_error<GenericError>("Invalid pointer diff"); + return llvm::Error(); + } + case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 | + X86_64_RELOC_UNSIGNED | rLength8): + if (fromTarget != inAtom) + return llvm::make_error<GenericError>("pointer diff not in base atom"); + *kind = delta64Anon; targetAddress = offsetInAtom + (int64_t)*(const little64_t *)fixupContent; return atomFromAddress(reloc2.symbol, targetAddress, target, addend); - case delta32Anon: + case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 | + X86_64_RELOC_UNSIGNED | rLength4): + if (fromTarget != inAtom) + return llvm::make_error<GenericError>("pointer diff not in base atom"); + *kind = delta32Anon; targetAddress = offsetInAtom + (int32_t)*(const little32_t *)fixupContent; return atomFromAddress(reloc2.symbol, targetAddress, target, addend); default: - llvm_unreachable("bad reloc pair kind"); + return llvm::make_error<GenericError>("unknown pair"); } } void ArchHandler_x86_64::generateAtomContent( const DefinedAtom &atom, bool relocatable, FindAddressForAtom findAddress, FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress, - uint8_t *atomContentBuffer) { + llvm::MutableArrayRef<uint8_t> atomContentBuffer) { // Copy raw bytes. - memcpy(atomContentBuffer, atom.rawContent().data(), atom.size()); + std::copy(atom.rawContent().begin(), atom.rawContent().end(), + atomContentBuffer.begin()); // Apply fix-ups. for (const Reference *ref : atom) { uint32_t offset = ref->offsetInAtom(); @@ -571,6 +588,9 @@ void ArchHandler_x86_64::applyFixupFinal( loc[-2] = 0x8D; *loc32 = targetAddress - (fixupAddress + 4) + ref.addend(); return; + case negDelta64: + *loc64 = fixupAddress - targetAddress + ref.addend(); + return; case negDelta32: *loc32 = fixupAddress - targetAddress + ref.addend(); return; @@ -675,8 +695,11 @@ void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref, // Then we want to encode the value (Ltarget + addend) - (LFixup - _base) *loc64 = (targetAddress + ref.addend()) - (fixupAddress - inAtomAddress); return; + case negDelta64: + *loc64 = ref.addend() + fixupAddress - inAtomAddress; + return; case negDelta32: - *loc32 = fixupAddress - targetAddress + ref.addend(); + *loc32 = ref.addend() + fixupAddress - inAtomAddress; return; case ripRel32GotLoadNowLea: llvm_unreachable("ripRel32GotLoadNowLea implies GOT pass was run"); @@ -796,7 +819,18 @@ void ArchHandler_x86_64::appendSectionRelocations( return; case unwindFDEToFunction: case unwindInfoToEhFrame: + return; case negDelta32: + appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, + X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 ); + appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0, + X86_64_RELOC_UNSIGNED | rExtern | rLength4 ); + return; + case negDelta64: + appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, + X86_64_RELOC_SUBTRACTOR | rExtern | rLength8 ); + appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0, + X86_64_RELOC_UNSIGNED | rExtern | rLength8 ); return; case ripRel32GotLoadNowLea: llvm_unreachable("ripRel32GotLoadNowLea implies GOT pass was run"); diff --git a/lib/ReaderWriter/MachO/Atoms.h b/lib/ReaderWriter/MachO/Atoms.h index 9f2e5acad99a..573efca9f6f9 100644 --- a/lib/ReaderWriter/MachO/Atoms.h +++ b/lib/ReaderWriter/MachO/Atoms.h @@ -1,4 +1,4 @@ -//===- lib/ReaderWriter/MachO/Atoms.h -------------------------------------===// +//===- lib/ReaderWriter/MachO/Atoms.h ---------------------------*- C++ -*-===// // // The LLVM Linker // @@ -10,10 +10,21 @@ #ifndef LLD_READER_WRITER_MACHO_ATOMS_H #define LLD_READER_WRITER_MACHO_ATOMS_H +#include "lld/Core/Atom.h" +#include "lld/Core/DefinedAtom.h" +#include "lld/Core/SharedLibraryAtom.h" #include "lld/Core/Simple.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include <cstdint> +#include <string> namespace lld { + +class File; + namespace mach_o { + class MachODefinedAtom : public SimpleDefinedAtom { public: MachODefinedAtom(const File &f, const StringRef name, Scope scope, @@ -32,6 +43,8 @@ public: _contentType(type), _scope(scope), _merge(mergeNo), _thumb(false), _noDeadStrip(noDeadStrip) {} + ~MachODefinedAtom() override = default; + uint64_t size() const override { return _content.size(); } ContentType contentType() const override { return _contentType; } @@ -61,15 +74,6 @@ public: bool isThumb() const { return _thumb; } - void addReference(uint32_t offsetInAtom, uint16_t relocType, - const Atom *target, Reference::Addend addend, - Reference::KindArch arch = Reference::KindArch::x86_64, - Reference::KindNamespace ns - = Reference::KindNamespace::mach_o) { - SimpleDefinedAtom::addReference(ns, arch, relocType, offsetInAtom, target, - addend); - } - private: const StringRef _name; const ArrayRef<uint8_t> _content; @@ -92,6 +96,8 @@ public: content, align), _sectionName(sectionName) {} + ~MachODefinedCustomSectionAtom() override = default; + SectionChoice sectionChoice() const override { return DefinedAtom::sectionCustomRequired; } @@ -110,6 +116,8 @@ public: : SimpleDefinedAtom(f), _name(name), _scope(scope), _size(size), _align(align) {} + ~MachOTentativeDefAtom() override = default; + uint64_t size() const override { return _size; } Merge merge() const override { return DefinedAtom::mergeAsTentative; } @@ -167,7 +175,7 @@ private: StringRef _dylibInstallName; }; -} // namespace mach_o -} // namespace lld +} // end namespace mach_o +} // end namespace lld #endif // LLD_READER_WRITER_MACHO_ATOMS_H diff --git a/lib/ReaderWriter/MachO/CMakeLists.txt b/lib/ReaderWriter/MachO/CMakeLists.txt index a389ca51ddfd..70f451c997b3 100644 --- a/lib/ReaderWriter/MachO/CMakeLists.txt +++ b/lib/ReaderWriter/MachO/CMakeLists.txt @@ -13,6 +13,7 @@ add_lld_library(lldMachO MachONormalizedFileFromAtoms.cpp MachONormalizedFileToAtoms.cpp MachONormalizedFileYAML.cpp + ObjCPass.cpp ShimPass.cpp StubsPass.cpp TLVPass.cpp @@ -22,6 +23,7 @@ add_lld_library(lldMachO lldYAML LLVMObject LLVMSupport + ${PTHREAD_LIB} ) include_directories(.) diff --git a/lib/ReaderWriter/MachO/CompactUnwindPass.cpp b/lib/ReaderWriter/MachO/CompactUnwindPass.cpp index 4b8644a67e70..6f5ab83dbda6 100644 --- a/lib/ReaderWriter/MachO/CompactUnwindPass.cpp +++ b/lib/ReaderWriter/MachO/CompactUnwindPass.cpp @@ -59,7 +59,7 @@ struct CompactUnwindEntry { }; struct UnwindInfoPage { - std::vector<CompactUnwindEntry> entries; + ArrayRef<CompactUnwindEntry> entries; }; } @@ -88,6 +88,8 @@ public: addSecondLevelPages(pages); } + ~UnwindInfoAtom() override = default; + ContentType contentType() const override { return DefinedAtom::typeProcessedUnwindInfo; } @@ -179,7 +181,7 @@ public: } // Finally, write out the final sentinel index - CompactUnwindEntry &finalEntry = pages[pages.size() - 1].entries.back(); + auto &finalEntry = pages[pages.size() - 1].entries.back(); addImageReference(_topLevelIndexOffset + 3 * pages.size() * sizeof(uint32_t), finalEntry.rangeStart, finalEntry.rangeLength); @@ -273,11 +275,13 @@ class CompactUnwindPass : public Pass { public: CompactUnwindPass(const MachOLinkingContext &context) : _ctx(context), _archHandler(_ctx.archHandler()), - _file("<mach-o Compact Unwind Pass>"), - _isBig(MachOLinkingContext::isBigEndian(_ctx.arch())) {} + _file(*_ctx.make_file<MachOFile>("<mach-o Compact Unwind Pass>")), + _isBig(MachOLinkingContext::isBigEndian(_ctx.arch())) { + _file.setOrdinal(_ctx.getNextOrdinalAndIncrement()); + } private: - std::error_code perform(SimpleFile &mergedFile) override { + llvm::Error perform(SimpleFile &mergedFile) override { DEBUG(llvm::dbgs() << "MachO Compact Unwind pass\n"); std::map<const Atom *, CompactUnwindEntry> unwindLocs; @@ -294,7 +298,7 @@ private: // Skip rest of pass if no unwind info. if (unwindLocs.empty() && dwarfFrames.empty()) - return std::error_code(); + return llvm::Error(); // FIXME: if there are more than 4 personality functions then we need to // defer to DWARF info for the ones we don't put in the list. They should @@ -321,26 +325,23 @@ private: // boundaries. That might be worth doing, or perhaps we could perform some // minor balancing for expected number of lookups. std::vector<UnwindInfoPage> pages; - unsigned pageStart = 0; + auto remainingInfos = llvm::makeArrayRef(unwindInfos); do { pages.push_back(UnwindInfoPage()); // FIXME: we only create regular pages at the moment. These can hold up to // 1021 entries according to the documentation. - unsigned entriesInPage = - std::min(1021U, (unsigned)unwindInfos.size() - pageStart); + unsigned entriesInPage = std::min(1021U, (unsigned)remainingInfos.size()); - std::copy(unwindInfos.begin() + pageStart, - unwindInfos.begin() + pageStart + entriesInPage, - std::back_inserter(pages.back().entries)); - pageStart += entriesInPage; + pages.back().entries = remainingInfos.slice(0, entriesInPage); + remainingInfos = remainingInfos.slice(entriesInPage); DEBUG(llvm::dbgs() << " Page from " << pages.back().entries[0].rangeStart->name() << " to " << pages.back().entries.back().rangeStart->name() << " + " << llvm::format("0x%x", pages.back().entries.back().rangeLength) << " has " << entriesInPage << " entries\n"); - } while (pageStart < unwindInfos.size()); + } while (!remainingInfos.empty()); auto *unwind = new (_file.allocator()) UnwindInfoAtom(_archHandler, _file, _isBig, personalities, @@ -352,7 +353,7 @@ private: return atom->contentType() == DefinedAtom::typeCompactUnwindInfo; }); - return std::error_code(); + return llvm::Error(); } void collectCompactUnwindEntries( @@ -568,7 +569,7 @@ private: const MachOLinkingContext &_ctx; mach_o::ArchHandler &_archHandler; - MachOFile _file; + MachOFile &_file; bool _isBig; }; diff --git a/lib/ReaderWriter/MachO/ExecutableAtoms.h b/lib/ReaderWriter/MachO/ExecutableAtoms.h index 2e99af903dbd..acced33b7e74 100644 --- a/lib/ReaderWriter/MachO/ExecutableAtoms.h +++ b/lib/ReaderWriter/MachO/ExecutableAtoms.h @@ -11,10 +11,10 @@ #define LLD_READER_WRITER_MACHO_EXECUTABLE_ATOMS_H #include "Atoms.h" +#include "File.h" #include "llvm/Support/MachO.h" -#include "lld/Core/ArchiveLibraryFile.h" #include "lld/Core/DefinedAtom.h" #include "lld/Core/File.h" #include "lld/Core/LinkingContext.h" @@ -34,7 +34,7 @@ namespace mach_o { class CEntryFile : public SimpleFile { public: CEntryFile(const MachOLinkingContext &context) - : SimpleFile("C entry"), + : SimpleFile("C entry", kindCEntryObject), _undefMain(*this, context.entrySymbolName()) { this->addAtom(_undefMain); } @@ -51,7 +51,7 @@ private: class StubHelperFile : public SimpleFile { public: StubHelperFile(const MachOLinkingContext &context) - : SimpleFile("stub runtime"), + : SimpleFile("stub runtime", kindStubHelperObject), _undefBinder(*this, context.binderSymbolName()) { this->addAtom(_undefBinder); } @@ -65,66 +65,88 @@ private: // MachHeaderAliasFile lazily instantiates the magic symbols that mark the start // of the mach_header for final linked images. // -class MachHeaderAliasFile : public ArchiveLibraryFile { +class MachHeaderAliasFile : public SimpleFile { public: MachHeaderAliasFile(const MachOLinkingContext &context) - : ArchiveLibraryFile("mach_header symbols") { - switch (context.outputMachOType()) { - case llvm::MachO::MH_EXECUTE: - _machHeaderSymbolName = "__mh_execute_header"; - break; - case llvm::MachO::MH_DYLIB: - _machHeaderSymbolName = "__mh_dylib_header"; - break; - case llvm::MachO::MH_BUNDLE: - _machHeaderSymbolName = "__mh_bundle_header"; - break; - case llvm::MachO::MH_DYLINKER: - _machHeaderSymbolName = "__mh_dylinker_header"; - break; - case llvm::MachO::MH_PRELOAD: - _machHeaderSymbolName = "__mh_preload_header"; - break; - default: - llvm_unreachable("no mach_header symbol for file type"); - } - } - - std::error_code - parseAllMembers(std::vector<std::unique_ptr<File>> &result) override { - return std::error_code(); - } - - File *find(StringRef sym, bool dataSymbolOnly) override { - if (sym.equals("___dso_handle") || sym.equals(_machHeaderSymbolName)) { + : SimpleFile("mach_header symbols", kindHeaderObject) { + StringRef machHeaderSymbolName; + DefinedAtom::Scope symbolScope = DefinedAtom::scopeLinkageUnit; + StringRef dsoHandleName; + switch (context.outputMachOType()) { + case llvm::MachO::MH_OBJECT: + machHeaderSymbolName = "__mh_object_header"; + break; + case llvm::MachO::MH_EXECUTE: + machHeaderSymbolName = "__mh_execute_header"; + symbolScope = DefinedAtom::scopeGlobal; + dsoHandleName = "___dso_handle"; + break; + case llvm::MachO::MH_FVMLIB: + llvm_unreachable("no mach_header symbol for file type"); + case llvm::MachO::MH_CORE: + llvm_unreachable("no mach_header symbol for file type"); + case llvm::MachO::MH_PRELOAD: + llvm_unreachable("no mach_header symbol for file type"); + case llvm::MachO::MH_DYLIB: + machHeaderSymbolName = "__mh_dylib_header"; + dsoHandleName = "___dso_handle"; + break; + case llvm::MachO::MH_DYLINKER: + machHeaderSymbolName = "__mh_dylinker_header"; + dsoHandleName = "___dso_handle"; + break; + case llvm::MachO::MH_BUNDLE: + machHeaderSymbolName = "__mh_bundle_header"; + dsoHandleName = "___dso_handle"; + break; + case llvm::MachO::MH_DYLIB_STUB: + llvm_unreachable("no mach_header symbol for file type"); + case llvm::MachO::MH_DSYM: + llvm_unreachable("no mach_header symbol for file type"); + case llvm::MachO::MH_KEXT_BUNDLE: + dsoHandleName = "___dso_handle"; + break; + } + if (!machHeaderSymbolName.empty()) _definedAtoms.push_back(new (allocator()) MachODefinedAtom( - *this, sym, DefinedAtom::scopeLinkageUnit, - DefinedAtom::typeMachHeader, DefinedAtom::mergeNo, false, false, + *this, machHeaderSymbolName, symbolScope, + DefinedAtom::typeMachHeader, DefinedAtom::mergeNo, false, + true /* noDeadStrip */, ArrayRef<uint8_t>(), DefinedAtom::Alignment(4096))); - return this; - } - return nullptr; + + if (!dsoHandleName.empty()) + _definedAtoms.push_back(new (allocator()) MachODefinedAtom( + *this, dsoHandleName, DefinedAtom::scopeLinkageUnit, + DefinedAtom::typeDSOHandle, DefinedAtom::mergeNo, false, + true /* noDeadStrip */, + ArrayRef<uint8_t>(), DefinedAtom::Alignment(1))); } - const AtomVector<DefinedAtom> &defined() const override { + const AtomRange<DefinedAtom> defined() const override { return _definedAtoms; } - const AtomVector<UndefinedAtom> &undefined() const override { + const AtomRange<UndefinedAtom> undefined() const override { return _noUndefinedAtoms; } - const AtomVector<SharedLibraryAtom> &sharedLibrary() const override { + const AtomRange<SharedLibraryAtom> sharedLibrary() const override { return _noSharedLibraryAtoms; } - const AtomVector<AbsoluteAtom> &absolute() const override { + const AtomRange<AbsoluteAtom> absolute() const override { return _noAbsoluteAtoms; } + void clearAtoms() override { + _definedAtoms.clear(); + _noUndefinedAtoms.clear(); + _noSharedLibraryAtoms.clear(); + _noAbsoluteAtoms.clear(); + } + private: mutable AtomVector<DefinedAtom> _definedAtoms; - StringRef _machHeaderSymbolName; }; } // namespace mach_o diff --git a/lib/ReaderWriter/MachO/File.h b/lib/ReaderWriter/MachO/File.h index c97dfa142b8d..64a0fcf82844 100644 --- a/lib/ReaderWriter/MachO/File.h +++ b/lib/ReaderWriter/MachO/File.h @@ -14,6 +14,7 @@ #include "MachONormalizedFile.h" #include "lld/Core/SharedLibraryFile.h" #include "lld/Core/Simple.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" #include <unordered_map> @@ -25,9 +26,10 @@ using lld::mach_o::normalized::Section; class MachOFile : public SimpleFile { public: MachOFile(std::unique_ptr<MemoryBuffer> mb, MachOLinkingContext *ctx) - : SimpleFile(mb->getBufferIdentifier()), _mb(std::move(mb)), _ctx(ctx) {} + : SimpleFile(mb->getBufferIdentifier(), File::kindMachObject), + _mb(std::move(mb)), _ctx(ctx) {} - MachOFile(StringRef path) : SimpleFile(path) {} + MachOFile(StringRef path) : SimpleFile(path, File::kindMachObject) {} void addDefinedAtom(StringRef name, Atom::Scope scope, DefinedAtom::ContentType type, DefinedAtom::Merge merge, @@ -187,16 +189,51 @@ public: visitor(offAndAtom.atom, offAndAtom.offset); } + MachOLinkingContext::Arch arch() const { return _arch; } + void setArch(MachOLinkingContext::Arch arch) { _arch = arch; } + + MachOLinkingContext::OS OS() const { return _os; } + void setOS(MachOLinkingContext::OS os) { _os = os; } + + MachOLinkingContext::ObjCConstraint objcConstraint() const { + return _objcConstraint; + } + void setObjcConstraint(MachOLinkingContext::ObjCConstraint v) { + _objcConstraint = v; + } + + uint32_t minVersion() const { return _minVersion; } + void setMinVersion(uint32_t v) { _minVersion = v; } + + LoadCommandType minVersionLoadCommandKind() const { + return _minVersionLoadCommandKind; + } + void setMinVersionLoadCommandKind(LoadCommandType v) { + _minVersionLoadCommandKind = v; + } + + uint32_t swiftVersion() const { return _swiftVersion; } + void setSwiftVersion(uint32_t v) { _swiftVersion = v; } + + bool subsectionsViaSymbols() const { + return _flags & llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS; + } + void setFlags(normalized::FileFlags v) { _flags = v; } + + /// Methods for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const File *F) { + return F->kind() == File::kindMachObject; + } + protected: std::error_code doParse() override { // Convert binary file to normalized mach-o. auto normFile = normalized::readBinary(_mb, _ctx->arch()); - if (std::error_code ec = normFile.getError()) - return ec; + if (auto ec = normFile.takeError()) + return llvm::errorToErrorCode(std::move(ec)); // Convert normalized mach-o to atoms. - if (std::error_code ec = normalized::normalizedObjectToAtoms( - this, **normFile, false)) - return ec; + if (auto ec = normalized::normalizedObjectToAtoms(this, **normFile, false)) + return llvm::errorToErrorCode(std::move(ec)); return std::error_code(); } @@ -220,6 +257,14 @@ private: MachOLinkingContext *_ctx; SectionToAtoms _sectionAtoms; NameToAtom _undefAtoms; + MachOLinkingContext::Arch _arch = MachOLinkingContext::arch_unknown; + MachOLinkingContext::OS _os = MachOLinkingContext::OS::unknown; + uint32_t _minVersion = 0; + LoadCommandType _minVersionLoadCommandKind = (LoadCommandType)0; + MachOLinkingContext::ObjCConstraint _objcConstraint = + MachOLinkingContext::objc_unknown; + uint32_t _swiftVersion = 0; + normalized::FileFlags _flags = llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS; }; class MachODylibFile : public SharedLibraryFile { @@ -230,7 +275,7 @@ public: MachODylibFile(StringRef path) : SharedLibraryFile(path) {} - const SharedLibraryAtom *exports(StringRef name, bool isData) const override { + OwningAtomPtr<SharedLibraryAtom> exports(StringRef name) const override { // Pass down _installName so that if this requested symbol // is re-exported through this dylib, the SharedLibraryAtom's loadName() // is this dylib installName and not the implementation dylib's. @@ -273,35 +318,39 @@ public: std::error_code doParse() override { // Convert binary file to normalized mach-o. auto normFile = normalized::readBinary(_mb, _ctx->arch()); - if (std::error_code ec = normFile.getError()) - return ec; + if (auto ec = normFile.takeError()) + return llvm::errorToErrorCode(std::move(ec)); // Convert normalized mach-o to atoms. - if (std::error_code ec = normalized::normalizedDylibToAtoms( - this, **normFile, false)) - return ec; + if (auto ec = normalized::normalizedDylibToAtoms(this, **normFile, false)) + return llvm::errorToErrorCode(std::move(ec)); return std::error_code(); } private: - const SharedLibraryAtom *exports(StringRef name, + OwningAtomPtr<SharedLibraryAtom> exports(StringRef name, StringRef installName) const { // First, check if requested symbol is directly implemented by this dylib. auto entry = _nameToAtom.find(name); if (entry != _nameToAtom.end()) { - if (!entry->second.atom) { - // Lazily create SharedLibraryAtom. - entry->second.atom = - new (allocator()) MachOSharedLibraryAtom(*this, name, installName, - entry->second.weakDef); - } - return entry->second.atom; + // FIXME: Make this map a set and only used in assert builds. + // Note, its safe to assert here as the resolver is the only client of + // this API and it only requests exports for undefined symbols. + // If we return from here we are no longer undefined so we should never + // get here again. + assert(!entry->second.atom && "Duplicate shared library export"); + bool weakDef = entry->second.weakDef; + auto *atom = new (allocator()) MachOSharedLibraryAtom(*this, name, + installName, + weakDef); + entry->second.atom = atom; + return atom; } // Next, check if symbol is implemented in some re-exported dylib. for (const ReExportedDylib &dylib : _reExportedDylibs) { assert(dylib.file); auto atom = dylib.file->exports(name, installName); - if (atom) + if (atom.get()) return atom; } diff --git a/lib/ReaderWriter/MachO/FlatNamespaceFile.h b/lib/ReaderWriter/MachO/FlatNamespaceFile.h index 6c6a9262ba2e..76d295841c9d 100644 --- a/lib/ReaderWriter/MachO/FlatNamespaceFile.h +++ b/lib/ReaderWriter/MachO/FlatNamespaceFile.h @@ -25,34 +25,34 @@ public: FlatNamespaceFile(const MachOLinkingContext &context) : SharedLibraryFile("flat namespace") { } - const SharedLibraryAtom *exports(StringRef name, - bool dataSymbolOnly) const override { - _sharedLibraryAtoms.push_back( - new (allocator()) MachOSharedLibraryAtom(*this, name, getDSOName(), - false)); - - return _sharedLibraryAtoms.back(); + OwningAtomPtr<SharedLibraryAtom> exports(StringRef name) const override { + return new (allocator()) MachOSharedLibraryAtom(*this, name, getDSOName(), + false); } StringRef getDSOName() const override { return "flat-namespace"; } - const AtomVector<DefinedAtom> &defined() const override { + const AtomRange<DefinedAtom> defined() const override { return _noDefinedAtoms; } - const AtomVector<UndefinedAtom> &undefined() const override { + const AtomRange<UndefinedAtom> undefined() const override { return _noUndefinedAtoms; } - const AtomVector<SharedLibraryAtom> &sharedLibrary() const override { - return _sharedLibraryAtoms; + const AtomRange<SharedLibraryAtom> sharedLibrary() const override { + return _noSharedLibraryAtoms; } - const AtomVector<AbsoluteAtom> &absolute() const override { + const AtomRange<AbsoluteAtom> absolute() const override { return _noAbsoluteAtoms; } -private: - mutable AtomVector<SharedLibraryAtom> _sharedLibraryAtoms; + void clearAtoms() override { + _noDefinedAtoms.clear(); + _noUndefinedAtoms.clear(); + _noSharedLibraryAtoms.clear(); + _noAbsoluteAtoms.clear(); + } }; } // namespace mach_o diff --git a/lib/ReaderWriter/MachO/GOTPass.cpp b/lib/ReaderWriter/MachO/GOTPass.cpp index a5816277dd71..6cdca0a9e055 100644 --- a/lib/ReaderWriter/MachO/GOTPass.cpp +++ b/lib/ReaderWriter/MachO/GOTPass.cpp @@ -54,6 +54,8 @@ public: GOTEntryAtom(const File &file, bool is64, StringRef name) : SimpleDefinedAtom(file), _is64(is64), _name(name) { } + ~GOTEntryAtom() override = default; + ContentType contentType() const override { return DefinedAtom::typeGOT; } @@ -91,10 +93,12 @@ class GOTPass : public Pass { public: GOTPass(const MachOLinkingContext &context) : _ctx(context), _archHandler(_ctx.archHandler()), - _file("<mach-o GOT Pass>") {} + _file(*_ctx.make_file<MachOFile>("<mach-o GOT Pass>")) { + _file.setOrdinal(_ctx.getNextOrdinalAndIncrement()); + } private: - std::error_code perform(SimpleFile &mergedFile) override { + llvm::Error perform(SimpleFile &mergedFile) override { // Scan all references in all atoms. for (const DefinedAtom *atom : mergedFile.defined()) { for (const Reference *ref : *atom) { @@ -130,7 +134,7 @@ private: for (const GOTEntryAtom *slot : entries) mergedFile.addAtom(*slot); - return std::error_code(); + return llvm::Error(); } bool shouldReplaceTargetWithGOTAtom(const Atom *target, bool canBypassGOT) { @@ -167,7 +171,7 @@ private: const MachOLinkingContext &_ctx; mach_o::ArchHandler &_archHandler; - MachOFile _file; + MachOFile &_file; llvm::DenseMap<const Atom*, const GOTEntryAtom*> _targetToGOT; }; diff --git a/lib/ReaderWriter/MachO/LayoutPass.cpp b/lib/ReaderWriter/MachO/LayoutPass.cpp index 0c14ee9d39ab..dd2ee8567ec9 100644 --- a/lib/ReaderWriter/MachO/LayoutPass.cpp +++ b/lib/ReaderWriter/MachO/LayoutPass.cpp @@ -17,6 +17,7 @@ #include "llvm/Support/Debug.h" #include <algorithm> #include <set> +#include <utility> using namespace lld; @@ -133,7 +134,7 @@ static void checkReachabilityFromRoot(AtomToAtomT &followOnRoots, } } -static void printDefinedAtoms(const SimpleFile::DefinedAtomRange &atomRange) { +static void printDefinedAtoms(const File::AtomRange<DefinedAtom> &atomRange) { for (const DefinedAtom *atom : atomRange) { llvm::dbgs() << " file=" << atom->file().path() << ", name=" << atom->name() @@ -146,7 +147,7 @@ static void printDefinedAtoms(const SimpleFile::DefinedAtomRange &atomRange) { /// Verify that the followon chain is sane. Should not be called in /// release binary. -void LayoutPass::checkFollowonChain(SimpleFile::DefinedAtomRange &range) { +void LayoutPass::checkFollowonChain(const File::AtomRange<DefinedAtom> &range) { ScopedTask task(getDefaultDomain(), "LayoutPass::checkFollowonChain"); // Verify that there's no cycle in follow-on chain. @@ -176,8 +177,8 @@ static bool compareAtomsSub(const LayoutPass::SortKey &lc, const LayoutPass::SortKey &rc, LayoutPass::SortOverride customSorter, std::string &reason) { - const DefinedAtom *left = lc._atom; - const DefinedAtom *right = rc._atom; + const DefinedAtom *left = lc._atom.get(); + const DefinedAtom *right = rc._atom.get(); if (left == right) { reason = "same"; return false; @@ -252,14 +253,15 @@ static bool compareAtoms(const LayoutPass::SortKey &lc, bool result = compareAtomsSub(lc, rc, customSorter, reason); DEBUG({ StringRef comp = result ? "<" : ">="; - llvm::dbgs() << "Layout: '" << lc._atom->name() << "' " << comp << " '" - << rc._atom->name() << "' (" << reason << ")\n"; + llvm::dbgs() << "Layout: '" << lc._atom.get()->name() + << "' " << comp << " '" + << rc._atom.get()->name() << "' (" << reason << ")\n"; }); return result; } LayoutPass::LayoutPass(const Registry ®istry, SortOverride sorter) - : _registry(registry), _customSorter(sorter) {} + : _registry(registry), _customSorter(std::move(sorter)) {} // Returns the atom immediately followed by the given atom in the followon // chain. @@ -329,12 +331,12 @@ void LayoutPass::setChainRoot(const DefinedAtom *targetAtom, /// d) If the targetAtom is part of a different chain and the root of the /// targetAtom until the targetAtom has all atoms of size 0, then chain the /// targetAtoms and its tree to the current chain -void LayoutPass::buildFollowOnTable(SimpleFile::DefinedAtomRange &range) { +void LayoutPass::buildFollowOnTable(const File::AtomRange<DefinedAtom> &range) { ScopedTask task(getDefaultDomain(), "LayoutPass::buildFollowOnTable"); // Set the initial size of the followon and the followonNext hash to the // number of atoms that we have. - _followOnRoots.resize(range.size()); - _followOnNexts.resize(range.size()); + _followOnRoots.reserve(range.size()); + _followOnNexts.reserve(range.size()); for (const DefinedAtom *ai : range) { for (const Reference *r : *ai) { if (r->kindNamespace() != lld::Reference::KindNamespace::all || @@ -397,7 +399,8 @@ void LayoutPass::buildFollowOnTable(SimpleFile::DefinedAtomRange &range) { /// assigning ordinals to each atom, if the atoms have their ordinals /// already assigned skip the atom and move to the next. This is the /// main map thats used to sort the atoms while comparing two atoms together -void LayoutPass::buildOrdinalOverrideMap(SimpleFile::DefinedAtomRange &range) { +void +LayoutPass::buildOrdinalOverrideMap(const File::AtomRange<DefinedAtom> &range) { ScopedTask task(getDefaultDomain(), "LayoutPass::buildOrdinalOverrideMap"); uint64_t index = 0; for (const DefinedAtom *ai : range) { @@ -417,31 +420,31 @@ void LayoutPass::buildOrdinalOverrideMap(SimpleFile::DefinedAtomRange &range) { } std::vector<LayoutPass::SortKey> -LayoutPass::decorate(SimpleFile::DefinedAtomRange &atomRange) const { +LayoutPass::decorate(File::AtomRange<DefinedAtom> &atomRange) const { std::vector<SortKey> ret; - for (const DefinedAtom *atom : atomRange) { - auto ri = _followOnRoots.find(atom); - auto oi = _ordinalOverrideMap.find(atom); - const DefinedAtom *root = (ri == _followOnRoots.end()) ? atom : ri->second; + for (OwningAtomPtr<DefinedAtom> &atom : atomRange.owning_ptrs()) { + auto ri = _followOnRoots.find(atom.get()); + auto oi = _ordinalOverrideMap.find(atom.get()); + const auto *root = (ri == _followOnRoots.end()) ? atom.get() : ri->second; uint64_t override = (oi == _ordinalOverrideMap.end()) ? 0 : oi->second; - ret.push_back(SortKey(atom, root, override)); + ret.push_back(SortKey(std::move(atom), root, override)); } return ret; } -void LayoutPass::undecorate(SimpleFile::DefinedAtomRange &atomRange, +void LayoutPass::undecorate(File::AtomRange<DefinedAtom> &atomRange, std::vector<SortKey> &keys) const { size_t i = 0; for (SortKey &k : keys) - atomRange[i++] = k._atom; + atomRange[i++] = std::move(k._atom); } /// Perform the actual pass -std::error_code LayoutPass::perform(SimpleFile &mergedFile) { +llvm::Error LayoutPass::perform(SimpleFile &mergedFile) { DEBUG(llvm::dbgs() << "******** Laying out atoms:\n"); // sort the atoms ScopedTask task(getDefaultDomain(), "LayoutPass"); - SimpleFile::DefinedAtomRange atomRange = mergedFile.definedAtoms(); + File::AtomRange<DefinedAtom> atomRange = mergedFile.defined(); // Build follow on tables buildFollowOnTable(atomRange); @@ -471,7 +474,7 @@ std::error_code LayoutPass::perform(SimpleFile &mergedFile) { }); DEBUG(llvm::dbgs() << "******** Finished laying out atoms\n"); - return std::error_code(); + return llvm::Error(); } void addLayoutPass(PassManager &pm, const MachOLinkingContext &ctx) { diff --git a/lib/ReaderWriter/MachO/LayoutPass.h b/lib/ReaderWriter/MachO/LayoutPass.h index d6072b0ca4fb..c18777eded0a 100644 --- a/lib/ReaderWriter/MachO/LayoutPass.h +++ b/lib/ReaderWriter/MachO/LayoutPass.h @@ -33,11 +33,31 @@ namespace mach_o { class LayoutPass : public Pass { public: struct SortKey { - SortKey(const DefinedAtom *atom, const DefinedAtom *root, uint64_t override) - : _atom(atom), _root(root), _override(override) {} - const DefinedAtom *_atom; + SortKey(OwningAtomPtr<DefinedAtom> &&atom, + const DefinedAtom *root, uint64_t override) + : _atom(std::move(atom)), _root(root), _override(override) {} + OwningAtomPtr<DefinedAtom> _atom; const DefinedAtom *_root; uint64_t _override; + + // Note, these are only here to appease MSVC bots which didn't like + // the same methods being implemented/deleted in OwningAtomPtr. + SortKey(SortKey &&key) : _atom(std::move(key._atom)), _root(key._root), + _override(key._override) { + key._root = nullptr; + } + + SortKey &operator=(SortKey &&key) { + _atom = std::move(key._atom); + _root = key._root; + key._root = nullptr; + _override = key._override; + return *this; + } + + private: + SortKey(const SortKey &) = delete; + void operator=(const SortKey&) = delete; }; typedef std::function<bool (const DefinedAtom *left, const DefinedAtom *right, @@ -46,17 +66,17 @@ public: LayoutPass(const Registry ®istry, SortOverride sorter); /// Sorts atoms in mergedFile by content type then by command line order. - std::error_code perform(SimpleFile &mergedFile) override; + llvm::Error perform(SimpleFile &mergedFile) override; ~LayoutPass() override = default; private: // Build the followOn atoms chain as specified by the kindLayoutAfter // reference type - void buildFollowOnTable(SimpleFile::DefinedAtomRange &range); + void buildFollowOnTable(const File::AtomRange<DefinedAtom> &range); // Build a map of Atoms to ordinals for sorting the atoms - void buildOrdinalOverrideMap(SimpleFile::DefinedAtomRange &range); + void buildOrdinalOverrideMap(const File::AtomRange<DefinedAtom> &range); const Registry &_registry; SortOverride _customSorter; @@ -84,12 +104,13 @@ private: void setChainRoot(const DefinedAtom *targetAtom, const DefinedAtom *root); - std::vector<SortKey> decorate(SimpleFile::DefinedAtomRange &atomRange) const; - void undecorate(SimpleFile::DefinedAtomRange &atomRange, + std::vector<SortKey> decorate(File::AtomRange<DefinedAtom> &atomRange) const; + + void undecorate(File::AtomRange<DefinedAtom> &atomRange, std::vector<SortKey> &keys) const; // Check if the follow-on graph is a correct structure. For debugging only. - void checkFollowonChain(SimpleFile::DefinedAtomRange &range); + void checkFollowonChain(const File::AtomRange<DefinedAtom> &range); }; } // namespace mach_o diff --git a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp index 1c97c5a39d3f..05375f145d34 100644 --- a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp +++ b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp @@ -35,6 +35,7 @@ #endif using lld::mach_o::ArchHandler; +using lld::mach_o::MachOFile; using lld::mach_o::MachODylibFile; using namespace llvm::MachO; @@ -75,6 +76,35 @@ bool MachOLinkingContext::parsePackedVersion(StringRef str, uint32_t &result) { return false; } +bool MachOLinkingContext::parsePackedVersion(StringRef str, uint64_t &result) { + result = 0; + + if (str.empty()) + return false; + + SmallVector<StringRef, 5> parts; + llvm::SplitString(str, parts, "."); + + unsigned long long num; + if (llvm::getAsUnsignedInteger(parts[0], 10, num)) + return true; + if (num > 0xFFFFFF) + return true; + result = num << 40; + + unsigned Shift = 30; + for (StringRef str : llvm::makeArrayRef(parts).slice(1)) { + if (llvm::getAsUnsignedInteger(str, 10, num)) + return true; + if (num > 0x3FF) + return true; + result |= (num << Shift); + Shift -= 10; + } + + return false; +} + MachOLinkingContext::ArchInfo MachOLinkingContext::_s_archInfos[] = { { "x86_64", arch_x86_64, true, CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL }, { "i386", arch_x86, true, CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL }, @@ -139,44 +169,52 @@ bool MachOLinkingContext::sliceFromFatFile(MemoryBufferRef mb, uint32_t &offset, return mach_o::normalized::sliceFromFatFile(mb, _arch, offset, size); } -MachOLinkingContext::MachOLinkingContext() - : _outputMachOType(MH_EXECUTE), _outputMachOTypeStatic(false), - _doNothing(false), _pie(false), _arch(arch_unknown), _os(OS::macOSX), - _osMinVersion(0), _pageZeroSize(0), _pageSize(4096), _baseAddress(0), - _stackSize(0), _compatibilityVersion(0), _currentVersion(0), - _flatNamespace(false), _undefinedMode(UndefinedMode::error), - _deadStrippableDylib(false), _printAtoms(false), _testingFileUsage(false), - _keepPrivateExterns(false), _demangle(false), _archHandler(nullptr), - _exportMode(ExportMode::globals), - _debugInfoMode(DebugInfoMode::addDebugMap), _orderFileEntries(0), - _flatNamespaceFile(nullptr) {} - -MachOLinkingContext::~MachOLinkingContext() {} +MachOLinkingContext::MachOLinkingContext() {} + +MachOLinkingContext::~MachOLinkingContext() { + // Atoms are allocated on BumpPtrAllocator's on File's. + // As we transfer atoms from one file to another, we need to clear all of the + // atoms before we remove any of the BumpPtrAllocator's. + auto &nodes = getNodes(); + for (unsigned i = 0, e = nodes.size(); i != e; ++i) { + FileNode *node = dyn_cast<FileNode>(nodes[i].get()); + if (!node) + continue; + File *file = node->getFile(); + file->clearAtoms(); + } +} void MachOLinkingContext::configure(HeaderFileType type, Arch arch, OS os, - uint32_t minOSVersion) { + uint32_t minOSVersion, + bool exportDynamicSymbols) { _outputMachOType = type; _arch = arch; _os = os; _osMinVersion = minOSVersion; // If min OS not specified on command line, use reasonable defaults. - if (minOSVersion == 0) { - switch (_arch) { - case arch_x86_64: - case arch_x86: - parsePackedVersion("10.8", _osMinVersion); - _os = MachOLinkingContext::OS::macOSX; - break; - case arch_armv6: - case arch_armv7: - case arch_armv7s: - case arch_arm64: - parsePackedVersion("7.0", _osMinVersion); - _os = MachOLinkingContext::OS::iOS; - break; - default: - break; + // Note that we only do sensible defaults when emitting something other than + // object and preload. + if (_outputMachOType != llvm::MachO::MH_OBJECT && + _outputMachOType != llvm::MachO::MH_PRELOAD) { + if (minOSVersion == 0) { + switch (_arch) { + case arch_x86_64: + case arch_x86: + parsePackedVersion("10.8", _osMinVersion); + _os = MachOLinkingContext::OS::macOSX; + break; + case arch_armv6: + case arch_armv7: + case arch_armv7s: + case arch_arm64: + parsePackedVersion("7.0", _osMinVersion); + _os = MachOLinkingContext::OS::iOS; + break; + default: + break; + } } } @@ -217,9 +255,10 @@ void MachOLinkingContext::configure(HeaderFileType type, Arch arch, OS os, case OS::unknown: break; } + setGlobalsAreDeadStripRoots(exportDynamicSymbols); break; case llvm::MachO::MH_DYLIB: - setGlobalsAreDeadStripRoots(true); + setGlobalsAreDeadStripRoots(exportDynamicSymbols); break; case llvm::MachO::MH_BUNDLE: break; @@ -325,6 +364,11 @@ bool MachOLinkingContext::needsCompactUnwindPass() const { } } +bool MachOLinkingContext::needsObjCPass() const { + // ObjC pass is only needed if any of the inputs were ObjC. + return _objcConstraint != objc_unknown; +} + bool MachOLinkingContext::needsShimPass() const { // Shim pass only used in final executables. if (_outputMachOType == MH_OBJECT) @@ -368,9 +412,11 @@ bool MachOLinkingContext::minOS(StringRef mac, StringRef iOS) const { return false; return _osMinVersion >= parsedVersion; case OS::unknown: - break; + // If we don't know the target, then assume that we don't meet the min OS. + // This matches the ld64 behaviour + return false; } - llvm_unreachable("target not configured for iOS or MacOSX"); + llvm_unreachable("invalid OS enum"); } bool MachOLinkingContext::addEntryPointLoadCommand() const { @@ -484,7 +530,7 @@ void MachOLinkingContext::addFrameworkSearchDir(StringRef fwPath, _frameworkDirs.push_back(fwPath); } -ErrorOr<StringRef> +llvm::Optional<StringRef> MachOLinkingContext::searchDirForLibrary(StringRef path, StringRef libName) const { SmallString<256> fullPath; @@ -494,7 +540,7 @@ MachOLinkingContext::searchDirForLibrary(StringRef path, llvm::sys::path::append(fullPath, libName); if (fileExists(fullPath)) return fullPath.str().copy(_allocator); - return make_error_code(llvm::errc::no_such_file_or_directory); + return llvm::None; } // Search for dynamic library @@ -509,21 +555,23 @@ MachOLinkingContext::searchDirForLibrary(StringRef path, if (fileExists(fullPath)) return fullPath.str().copy(_allocator); - return make_error_code(llvm::errc::no_such_file_or_directory); + return llvm::None; } -ErrorOr<StringRef> MachOLinkingContext::searchLibrary(StringRef libName) const { +llvm::Optional<StringRef> +MachOLinkingContext::searchLibrary(StringRef libName) const { SmallString<256> path; for (StringRef dir : searchDirs()) { - ErrorOr<StringRef> ec = searchDirForLibrary(dir, libName); - if (ec) - return ec; + llvm::Optional<StringRef> searchDir = searchDirForLibrary(dir, libName); + if (searchDir) + return searchDir; } - return make_error_code(llvm::errc::no_such_file_or_directory); + return llvm::None; } -ErrorOr<StringRef> MachOLinkingContext::findPathForFramework(StringRef fwName) const{ +llvm::Optional<StringRef> +MachOLinkingContext::findPathForFramework(StringRef fwName) const{ SmallString<256> fullPath; for (StringRef dir : frameworkDirs()) { fullPath.assign(dir); @@ -532,7 +580,7 @@ ErrorOr<StringRef> MachOLinkingContext::findPathForFramework(StringRef fwName) c return fullPath.str().copy(_allocator); } - return make_error_code(llvm::errc::no_such_file_or_directory); + return llvm::None; } bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) { @@ -589,6 +637,10 @@ bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) { } void MachOLinkingContext::addPasses(PassManager &pm) { + // objc pass should be before layout pass. Otherwise test cases may contain + // no atoms which confuses the layout pass. + if (needsObjCPass()) + mach_o::addObjCPass(pm, *this); mach_o::addLayoutPass(pm, *this); if (needsStubsPass()) mach_o::addStubsPass(pm, *this); @@ -656,9 +708,8 @@ MachODylibFile* MachOLinkingContext::findIndirectDylib(StringRef path) { if (leafName.startswith("lib") && leafName.endswith(".dylib")) { // FIXME: Need to enhance searchLibrary() to only look for .dylib auto libPath = searchLibrary(leafName); - if (!libPath.getError()) { - return loadIndirectDylib(libPath.get()); - } + if (libPath) + return loadIndirectDylib(libPath.getValue()); } // Try full path with sysroot. @@ -990,4 +1041,77 @@ void MachOLinkingContext::finalizeInputFiles() { elements.push_back(llvm::make_unique<GroupEnd>(numLibs)); } +llvm::Error MachOLinkingContext::handleLoadedFile(File &file) { + auto *machoFile = dyn_cast<MachOFile>(&file); + if (!machoFile) + return llvm::Error(); + + // Check that the arch of the context matches that of the file. + // Also set the arch of the context if it didn't have one. + if (_arch == arch_unknown) { + _arch = machoFile->arch(); + } else if (machoFile->arch() != arch_unknown && machoFile->arch() != _arch) { + // Archs are different. + return llvm::make_error<GenericError>(file.path() + + Twine(" cannot be linked due to incompatible architecture")); + } + + // Check that the OS of the context matches that of the file. + // Also set the OS of the context if it didn't have one. + if (_os == OS::unknown) { + _os = machoFile->OS(); + } else if (machoFile->OS() != OS::unknown && machoFile->OS() != _os) { + // OSes are different. + return llvm::make_error<GenericError>(file.path() + + Twine(" cannot be linked due to incompatible operating systems")); + } + + // Check that if the objc info exists, that it is compatible with the target + // OS. + switch (machoFile->objcConstraint()) { + case objc_unknown: + // The file is not compiled with objc, so skip the checks. + break; + case objc_gc_only: + case objc_supports_gc: + llvm_unreachable("GC support should already have thrown an error"); + case objc_retainReleaseForSimulator: + // The file is built with simulator objc, so make sure that the context + // is also building with simulator support. + if (_os != OS::iOS_simulator) + return llvm::make_error<GenericError>(file.path() + + Twine(" cannot be linked. It contains ObjC built for the simulator" + " while we are linking a non-simulator target")); + assert((_objcConstraint == objc_unknown || + _objcConstraint == objc_retainReleaseForSimulator) && + "Must be linking with retain/release for the simulator"); + _objcConstraint = objc_retainReleaseForSimulator; + break; + case objc_retainRelease: + // The file is built without simulator objc, so make sure that the + // context is also building without simulator support. + if (_os == OS::iOS_simulator) + return llvm::make_error<GenericError>(file.path() + + Twine(" cannot be linked. It contains ObjC built for a non-simulator" + " target while we are linking a simulator target")); + assert((_objcConstraint == objc_unknown || + _objcConstraint == objc_retainRelease) && + "Must be linking with retain/release for a non-simulator target"); + _objcConstraint = objc_retainRelease; + break; + } + + // Check that the swift version of the context matches that of the file. + // Also set the swift version of the context if it didn't have one. + if (!_swiftVersion) { + _swiftVersion = machoFile->swiftVersion(); + } else if (machoFile->swiftVersion() && + machoFile->swiftVersion() != _swiftVersion) { + // Swift versions are different. + return llvm::make_error<GenericError>("different swift versions"); + } + + return llvm::Error(); +} + } // end namespace lld diff --git a/lib/ReaderWriter/MachO/MachONormalizedFile.h b/lib/ReaderWriter/MachO/MachONormalizedFile.h index cccf180f1043..92a21f7ef83d 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFile.h +++ b/lib/ReaderWriter/MachO/MachONormalizedFile.h @@ -39,6 +39,9 @@ /// +-------+ /// +#ifndef LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H +#define LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H + #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" #include "lld/ReaderWriter/MachOLinkingContext.h" @@ -50,9 +53,6 @@ #include "llvm/Support/MachO.h" #include "llvm/Support/YAMLTraits.h" -#ifndef LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H -#define LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H - using llvm::BumpPtrAllocator; using llvm::yaml::Hex64; using llvm::yaml::Hex32; @@ -105,6 +105,9 @@ typedef std::vector<uint32_t> IndirectSymbols; /// A typedef so that YAML I/O can encode/decode section attributes. LLVM_YAML_STRONG_TYPEDEF(uint32_t, SectionAttr) +/// A typedef so that YAML I/O can encode/decode section alignment. +LLVM_YAML_STRONG_TYPEDEF(uint16_t, SectionAlignment) + /// Mach-O has a 32-bit and 64-bit section record. This normalized form /// can support either kind. struct Section { @@ -115,7 +118,7 @@ struct Section { StringRef sectionName; SectionType type; SectionAttr attributes; - uint16_t alignment; + SectionAlignment alignment; Hex64 address; ArrayRef<uint8_t> content; Relocations relocations; @@ -172,7 +175,8 @@ struct Segment { StringRef name; Hex64 address; Hex64 size; - VMProtect access; + VMProtect init_access; + VMProtect max_access; }; /// Only used in normalized final linked images to specify on which dylibs @@ -245,6 +249,8 @@ struct NormalizedFile { PackedVersion compatVersion = 0; // dylibs only PackedVersion currentVersion = 0; // dylibs only bool hasUUID = false; + bool hasMinVersionLoadCommand = false; + bool generateDataInCodeLoadCommand = false; std::vector<StringRef> rpaths; Hex64 entryAddress = 0; Hex64 stackSize = 0; @@ -252,6 +258,7 @@ struct NormalizedFile { Hex64 sourceVersion = 0; PackedVersion minOSverson = 0; PackedVersion sdkVersion = 0; + LoadCommandType minOSVersionKind = (LoadCommandType)0; // Maps to load commands with LINKEDIT content (final linked images only). Hex32 pageSize = 0; @@ -260,6 +267,7 @@ struct NormalizedFile { std::vector<BindLocation> weakBindingInfo; std::vector<BindLocation> lazyBindingInfo; std::vector<Export> exportInfo; + std::vector<uint8_t> functionStarts; std::vector<DataInCode> dataInCode; // TODO: @@ -281,40 +289,40 @@ bool sliceFromFatFile(MemoryBufferRef mb, MachOLinkingContext::Arch arch, uint32_t &offset, uint32_t &size); /// Reads a mach-o file and produces an in-memory normalized view. -ErrorOr<std::unique_ptr<NormalizedFile>> +llvm::Expected<std::unique_ptr<NormalizedFile>> readBinary(std::unique_ptr<MemoryBuffer> &mb, const MachOLinkingContext::Arch arch); /// Takes in-memory normalized view and writes a mach-o object file. -std::error_code writeBinary(const NormalizedFile &file, StringRef path); +llvm::Error writeBinary(const NormalizedFile &file, StringRef path); size_t headerAndLoadCommandsSize(const NormalizedFile &file); /// Parses a yaml encoded mach-o file to produce an in-memory normalized view. -ErrorOr<std::unique_ptr<NormalizedFile>> +llvm::Expected<std::unique_ptr<NormalizedFile>> readYaml(std::unique_ptr<MemoryBuffer> &mb); /// Writes a yaml encoded mach-o files given an in-memory normalized view. std::error_code writeYaml(const NormalizedFile &file, raw_ostream &out); -std::error_code +llvm::Error normalizedObjectToAtoms(MachOFile *file, const NormalizedFile &normalizedFile, bool copyRefs); -std::error_code +llvm::Error normalizedDylibToAtoms(MachODylibFile *file, const NormalizedFile &normalizedFile, bool copyRefs); /// Takes in-memory normalized dylib or object and parses it into lld::File -ErrorOr<std::unique_ptr<lld::File>> +llvm::Expected<std::unique_ptr<lld::File>> normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path, bool copyRefs); /// Takes atoms and generates a normalized macho-o view. -ErrorOr<std::unique_ptr<NormalizedFile>> +llvm::Expected<std::unique_ptr<NormalizedFile>> normalizedFromAtoms(const lld::File &atomFile, const MachOLinkingContext &ctxt); diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp index 1013d3ddaef3..a17de5be1742 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp +++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp @@ -53,7 +53,7 @@ namespace mach_o { namespace normalized { // Utility to call a lambda expression on each load command. -static std::error_code forEachLoadCommand( +static llvm::Error forEachLoadCommand( StringRef lcRange, unsigned lcCount, bool isBig, bool is64, std::function<bool(uint32_t cmd, uint32_t size, const char *lc)> func) { const char* p = lcRange.begin(); @@ -67,15 +67,15 @@ static std::error_code forEachLoadCommand( slc = &lcCopy; } if ( (p + slc->cmdsize) > lcRange.end() ) - return make_error_code(llvm::errc::executable_format_error); + return llvm::make_error<GenericError>("Load command exceeds range"); if (func(slc->cmd, slc->cmdsize, p)) - return std::error_code(); + return llvm::Error(); p += slc->cmdsize; } - return std::error_code(); + return llvm::Error(); } static std::error_code appendRelocations(Relocations &relocs, StringRef buffer, @@ -199,7 +199,7 @@ bool sliceFromFatFile(MemoryBufferRef mb, MachOLinkingContext::Arch arch, } /// Reads a mach-o file and produces an in-memory normalized view. -ErrorOr<std::unique_ptr<NormalizedFile>> +llvm::Expected<std::unique_ptr<NormalizedFile>> readBinary(std::unique_ptr<MemoryBuffer> &mb, const MachOLinkingContext::Arch arch) { // Make empty NormalizedFile. @@ -220,7 +220,7 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb, // Determine endianness and pointer size for mach-o file. bool is64, isBig; if (!isMachOHeader(mh, is64, isBig)) - return make_error_code(llvm::errc::executable_format_error); + return llvm::make_error<GenericError>("File is not a mach-o"); // Endian swap header, if needed. mach_header headerCopy; @@ -237,12 +237,13 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb, start + (is64 ? sizeof(mach_header_64) : sizeof(mach_header)); StringRef lcRange(lcStart, smh->sizeofcmds); if (lcRange.end() > (start + objSize)) - return make_error_code(llvm::errc::executable_format_error); + return llvm::make_error<GenericError>("Load commands exceed file size"); // Get architecture from mach_header. f->arch = MachOLinkingContext::archFromCpuType(smh->cputype, smh->cpusubtype); if (f->arch != arch) { - return make_dynamic_error_code(Twine("file is wrong architecture. Expected " + return llvm::make_error<GenericError>( + Twine("file is wrong architecture. Expected " "(" + MachOLinkingContext::nameFromArch(arch) + ") found (" + MachOLinkingContext::nameFromArch(f->arch) @@ -256,9 +257,9 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb, // Pre-scan load commands looking for indirect symbol table. uint32_t indirectSymbolTableOffset = 0; uint32_t indirectSymbolTableCount = 0; - std::error_code ec = forEachLoadCommand(lcRange, lcCount, isBig, is64, - [&](uint32_t cmd, uint32_t size, - const char *lc) -> bool { + auto ec = forEachLoadCommand(lcRange, lcCount, isBig, is64, + [&](uint32_t cmd, uint32_t size, + const char *lc) -> bool { if (cmd == LC_DYSYMTAB) { const dysymtab_command *d = reinterpret_cast<const dysymtab_command*>(lc); indirectSymbolTableOffset = read32(&d->indirectsymoff, isBig); @@ -268,7 +269,7 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb, return false; }); if (ec) - return ec; + return std::move(ec); // Walk load commands looking for segments/sections and the symbol table. const data_in_code_entry *dataInCode = nullptr; @@ -380,11 +381,11 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb, reinterpret_cast<const nlist_64 *>(start + symOffset); // Convert each nlist_64 to a lld::mach_o::normalized::Symbol. for(uint32_t i=0; i < symCount; ++i) { - const nlist_64 *sin = &symbols[i]; nlist_64 tempSym; - if (isBig != llvm::sys::IsBigEndianHost) { - tempSym = *sin; swapStruct(tempSym); sin = &tempSym; - } + memcpy(&tempSym, &symbols[i], sizeof(nlist_64)); + const nlist_64 *sin = &tempSym; + if (isBig != llvm::sys::IsBigEndianHost) + swapStruct(tempSym); Symbol sout; if (sin->n_strx > strSize) return true; @@ -471,11 +472,20 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb, case LC_DYLD_INFO_ONLY: dyldInfo = reinterpret_cast<const dyld_info_command*>(lc); break; + case LC_VERSION_MIN_MACOSX: + case LC_VERSION_MIN_IPHONEOS: + case LC_VERSION_MIN_WATCHOS: + case LC_VERSION_MIN_TVOS: + // If we are emitting an object file, then we may take the load command + // kind from these commands and pass it on to the output + // file. + f->minOSVersionKind = (LoadCommandType)cmd; + break; } return false; }); if (ec) - return ec; + return std::move(ec); if (dataInCode) { // Convert on-disk data_in_code_entry array to DataInCode vector. diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h index 1226860b021e..86823efa33c9 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h +++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h @@ -7,6 +7,8 @@ // //===----------------------------------------------------------------------===// +#ifndef LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H +#define LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H #include "MachONormalizedFile.h" #include "lld/Core/Error.h" @@ -16,16 +18,54 @@ #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Host.h" +#include "llvm/Support/LEB128.h" #include "llvm/Support/MachO.h" #include <system_error> -#ifndef LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H -#define LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H - namespace lld { namespace mach_o { namespace normalized { +class ByteBuffer { +public: + ByteBuffer() : _ostream(_bytes) { } + + void append_byte(uint8_t b) { + _ostream << b; + } + void append_uleb128(uint64_t value) { + llvm::encodeULEB128(value, _ostream); + } + void append_uleb128Fixed(uint64_t value, unsigned byteCount) { + unsigned min = llvm::getULEB128Size(value); + assert(min <= byteCount); + unsigned pad = byteCount - min; + llvm::encodeULEB128(value, _ostream, pad); + } + void append_sleb128(int64_t value) { + llvm::encodeSLEB128(value, _ostream); + } + void append_string(StringRef str) { + _ostream << str; + append_byte(0); + } + void align(unsigned alignment) { + while ( (_ostream.tell() % alignment) != 0 ) + append_byte(0); + } + size_t size() { + return _ostream.tell(); + } + const uint8_t *bytes() { + return reinterpret_cast<const uint8_t*>(_ostream.str().data()); + } + +private: + SmallVector<char, 128> _bytes; + // Stream ivar must be after SmallVector ivar to construct properly. + llvm::raw_svector_ostream _ostream; +}; + using namespace llvm::support::endian; using llvm::sys::getSwappedBytes; diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp index 4ecfece0629e..f3e159684e15 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp +++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp @@ -25,6 +25,8 @@ #include "MachONormalizedFileBinaryUtils.h" #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" +#include "llvm/ADT/ilist.h" +#include "llvm/ADT/ilist_node.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -35,7 +37,6 @@ #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/Format.h" #include "llvm/Support/Host.h" -#include "llvm/Support/LEB128.h" #include "llvm/Support/MachO.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" @@ -50,6 +51,72 @@ namespace lld { namespace mach_o { namespace normalized { +struct TrieNode; // Forward declaration. + +struct TrieEdge : public llvm::ilist_node<TrieEdge> { + TrieEdge(StringRef s, TrieNode *node) : _subString(s), _child(node) {} + + StringRef _subString; + struct TrieNode *_child; +}; + +} // namespace normalized +} // namespace mach_o +} // namespace lld + + +namespace llvm { + using lld::mach_o::normalized::TrieEdge; + template <> + struct ilist_traits<TrieEdge> + : public ilist_default_traits<TrieEdge> { + private: + mutable ilist_half_node<TrieEdge> Sentinel; + public: + TrieEdge *createSentinel() const { + return static_cast<TrieEdge*>(&Sentinel); + } + void destroySentinel(TrieEdge *) const {} + + TrieEdge *provideInitialHead() const { return createSentinel(); } + TrieEdge *ensureHead(TrieEdge*) const { return createSentinel(); } + static void noteHead(TrieEdge*, TrieEdge*) {} + void deleteNode(TrieEdge *N) {} + + private: + void createNode(const TrieEdge &); + }; +} // namespace llvm + + +namespace lld { +namespace mach_o { +namespace normalized { + +struct TrieNode { + typedef llvm::ilist<TrieEdge> TrieEdgeList; + + TrieNode(StringRef s) + : _cummulativeString(s), _address(0), _flags(0), _other(0), + _trieOffset(0), _hasExportInfo(false) {} + ~TrieNode() = default; + + void addSymbol(const Export &entry, BumpPtrAllocator &allocator, + std::vector<TrieNode *> &allNodes); + bool updateOffset(uint32_t &offset); + void appendToByteBuffer(ByteBuffer &out); + +private: + StringRef _cummulativeString; + TrieEdgeList _children; + uint64_t _address; + uint64_t _flags; + uint64_t _other; + StringRef _importedName; + uint32_t _trieOffset; + bool _hasExportInfo; +}; + /// Utility class for writing a mach-o binary file given an in-memory /// normalized file. class MachOFileLayout { @@ -66,13 +133,13 @@ public: /// Writes the normalized file as a binary mach-o file to the specified /// path. This does not have a stream interface because the generated /// file may need the 'x' bit set. - std::error_code writeBinary(StringRef path); + llvm::Error writeBinary(StringRef path); private: uint32_t loadCommandsSize(uint32_t &count); void buildFileOffsets(); void writeMachHeader(); - std::error_code writeLoadCommands(); + llvm::Error writeLoadCommands(); void writeSectionContent(); void writeRelocations(); void writeSymbolTable(); @@ -80,6 +147,7 @@ private: void writeBindingInfo(); void writeLazyBindingInfo(); void writeExportInfo(); + void writeFunctionStartsInfo(); void writeDataInCodeInfo(); void writeLinkEditContent(); void buildLinkEditInfo(); @@ -87,6 +155,7 @@ private: void buildBindInfo(); void buildLazyBindInfo(); void buildExportTrie(); + void computeFunctionStartsSize(); void computeDataInCodeSize(); void computeSymbolTableSizes(); void buildSectionRelocations(); @@ -110,83 +179,12 @@ private: }; template <typename T> - std::error_code writeSingleSegmentLoadCommand(uint8_t *&lc); - template <typename T> std::error_code writeSegmentLoadCommands(uint8_t *&lc); + llvm::Error writeSingleSegmentLoadCommand(uint8_t *&lc); + template <typename T> llvm::Error writeSegmentLoadCommands(uint8_t *&lc); uint32_t pointerAlign(uint32_t value); static StringRef dyldPath(); - class ByteBuffer { - public: - ByteBuffer() : _ostream(_bytes) { } - - void append_byte(uint8_t b) { - _ostream << b; - } - void append_uleb128(uint64_t value) { - llvm::encodeULEB128(value, _ostream); - } - void append_uleb128Fixed(uint64_t value, unsigned byteCount) { - unsigned min = llvm::getULEB128Size(value); - assert(min <= byteCount); - unsigned pad = byteCount - min; - llvm::encodeULEB128(value, _ostream, pad); - } - void append_sleb128(int64_t value) { - llvm::encodeSLEB128(value, _ostream); - } - void append_string(StringRef str) { - _ostream << str; - append_byte(0); - } - void align(unsigned alignment) { - while ( (_ostream.tell() % alignment) != 0 ) - append_byte(0); - } - size_t size() { - return _ostream.tell(); - } - const uint8_t *bytes() { - return reinterpret_cast<const uint8_t*>(_ostream.str().data()); - } - - private: - SmallVector<char, 128> _bytes; - // Stream ivar must be after SmallVector ivar to construct properly. - llvm::raw_svector_ostream _ostream; - }; - - struct TrieNode; // Forward declaration. - - struct TrieEdge { - TrieEdge(StringRef s, TrieNode *node) : _subString(s), _child(node) {} - - StringRef _subString; - struct TrieNode *_child; - }; - - struct TrieNode { - TrieNode(StringRef s) - : _cummulativeString(s), _address(0), _flags(0), _other(0), - _trieOffset(0), _hasExportInfo(false) {} - ~TrieNode() = default; - - void addSymbol(const Export &entry, BumpPtrAllocator &allocator, - std::vector<TrieNode *> &allNodes); - bool updateOffset(uint32_t &offset); - void appendToByteBuffer(ByteBuffer &out); - - private: - StringRef _cummulativeString; - std::list<TrieEdge> _children; - uint64_t _address; - uint64_t _flags; - uint64_t _other; - StringRef _importedName; - uint32_t _trieOffset; - bool _hasExportInfo; - }; - struct SegExtraInfo { uint32_t fileOffset; uint32_t fileSize; @@ -209,6 +207,7 @@ private: uint32_t _countOfLoadCommands; uint32_t _endOfLoadCommands; uint32_t _startOfRelocations; + uint32_t _startOfFunctionStarts; uint32_t _startOfDataInCode; uint32_t _startOfSymbols; uint32_t _startOfIndirectSymbols; @@ -219,6 +218,7 @@ private: uint32_t _symbolTableUndefinesStartIndex; uint32_t _symbolStringPoolSize; uint32_t _symbolTableSize; + uint32_t _functionStartsSize; uint32_t _dataInCodeSize; uint32_t _indirectSymbolTableCount; // Used in object file creation only @@ -255,7 +255,7 @@ StringRef MachOFileLayout::dyldPath() { } uint32_t MachOFileLayout::pointerAlign(uint32_t value) { - return llvm::RoundUpToAlignment(value, _is64 ? 8 : 4); + return llvm::alignTo(value, _is64 ? 8 : 4); } @@ -280,7 +280,15 @@ MachOFileLayout::MachOFileLayout(const NormalizedFile &file) + file.sections.size() * sectsSize + sizeof(symtab_command); _countOfLoadCommands = 2; - if (!_file.dataInCode.empty()) { + if (file.hasMinVersionLoadCommand) { + _endOfLoadCommands += sizeof(version_min_command); + _countOfLoadCommands++; + } + if (!_file.functionStarts.empty()) { + _endOfLoadCommands += sizeof(linkedit_data_command); + _countOfLoadCommands++; + } + if (_file.generateDataInCodeLoadCommand) { _endOfLoadCommands += sizeof(linkedit_data_command); _countOfLoadCommands++; } @@ -292,7 +300,7 @@ MachOFileLayout::MachOFileLayout(const NormalizedFile &file) if (isZeroFillSection(sect.type)) _sectInfo[§].fileOffset = 0; else { - offset = llvm::RoundUpToAlignment(offset, sect.alignment); + offset = llvm::alignTo(offset, sect.alignment); _sectInfo[§].fileOffset = offset; offset += sect.content.size(); } @@ -301,11 +309,13 @@ MachOFileLayout::MachOFileLayout(const NormalizedFile &file) _endOfSectionsContent = offset; computeSymbolTableSizes(); + computeFunctionStartsSize(); computeDataInCodeSize(); // Align start of relocations. _startOfRelocations = pointerAlign(_endOfSectionsContent); - _startOfDataInCode = _startOfRelocations + relocCount * 8; + _startOfFunctionStarts = _startOfRelocations + relocCount * 8; + _startOfDataInCode = _startOfFunctionStarts + _functionStartsSize; _startOfSymbols = _startOfDataInCode + _dataInCodeSize; // Add Indirect symbol table. _startOfIndirectSymbols = _startOfSymbols + _symbolTableSize; @@ -346,7 +356,8 @@ MachOFileLayout::MachOFileLayout(const NormalizedFile &file) _endOfLazyBindingInfo = _startOfLazyBindingInfo + _lazyBindingInfo.size(); _startOfExportTrie = _endOfLazyBindingInfo; _endOfExportTrie = _startOfExportTrie + _exportTrie.size(); - _startOfDataInCode = _endOfExportTrie; + _startOfFunctionStarts = _endOfExportTrie; + _startOfDataInCode = _startOfFunctionStarts + _functionStartsSize; _startOfSymbols = _startOfDataInCode + _dataInCodeSize; _startOfIndirectSymbols = _startOfSymbols + _symbolTableSize; _startOfSymbolStrings = _startOfIndirectSymbols @@ -368,6 +379,7 @@ MachOFileLayout::MachOFileLayout(const NormalizedFile &file) << " endOfLazyBindingInfo=" << _endOfLazyBindingInfo << "\n" << " startOfExportTrie=" << _startOfExportTrie << "\n" << " endOfExportTrie=" << _endOfExportTrie << "\n" + << " startOfFunctionStarts=" << _startOfFunctionStarts << "\n" << " startOfDataInCode=" << _startOfDataInCode << "\n" << " startOfSymbols=" << _startOfSymbols << "\n" << " startOfSymbolStrings=" << _startOfSymbolStrings << "\n" @@ -389,9 +401,6 @@ uint32_t MachOFileLayout::loadCommandsSize(uint32_t &count) { count += _file.segments.size(); // Add section record for each section. size += _file.sections.size() * sectionSize; - // Add one LC_SEGMENT for implicit __LINKEDIT segment - size += segCommandSize; - ++count; // If creating a dylib, add LC_ID_DYLIB. if (_file.fileType == llvm::MachO::MH_DYLIB) { @@ -413,10 +422,25 @@ uint32_t MachOFileLayout::loadCommandsSize(uint32_t &count) { ++count; } - // If main executable add LC_LOAD_DYLINKER and LC_MAIN + // If main executable add LC_LOAD_DYLINKER if (_file.fileType == llvm::MachO::MH_EXECUTE) { size += pointerAlign(sizeof(dylinker_command) + dyldPath().size()+1); ++count; + } + + // Add LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_WATCHOS, + // LC_VERSION_MIN_TVOS + if (_file.hasMinVersionLoadCommand) { + size += sizeof(version_min_command); + ++count; + } + + // Add LC_SOURCE_VERSION + size += sizeof(source_version_command); + ++count; + + // If main executable add LC_MAIN + if (_file.fileType == llvm::MachO::MH_EXECUTE) { size += sizeof(entry_point_command); ++count; } @@ -433,8 +457,15 @@ uint32_t MachOFileLayout::loadCommandsSize(uint32_t &count) { ++count; } - // Add LC_DATA_IN_CODE if needed - if (!_file.dataInCode.empty()) { + // Add LC_FUNCTION_STARTS if needed + if (!_file.functionStarts.empty()) { + size += sizeof(linkedit_data_command); + ++count; + } + + // Add LC_DATA_IN_CODE if requested. Note, we do encode zero length entries. + // FIXME: Zero length entries is only to match ld64. Should we change this? + if (_file.generateDataInCodeLoadCommand) { size += sizeof(linkedit_data_command); ++count; } @@ -517,7 +548,7 @@ void MachOFileLayout::buildFileOffsets() { llvm::dbgs() << "buildFileOffsets()\n"); for (const Segment &sg : _file.segments) { _segInfo[&sg].fileOffset = fileOffset; - if ((_seg1addr == INT64_MAX) && sg.access) + if ((_seg1addr == INT64_MAX) && sg.init_access) _seg1addr = sg.address; DEBUG_WITH_TYPE("MachOFileLayout", llvm::dbgs() << " segment=" << sg.name @@ -525,7 +556,7 @@ void MachOFileLayout::buildFileOffsets() { uint32_t segFileSize = 0; // A segment that is not zero-fill must use a least one page of disk space. - if (sg.access) + if (sg.init_access) segFileSize = _file.pageSize; for (const Section *s : _segInfo[&sg].sections) { uint32_t sectOffset = s->address - sg.address; @@ -539,10 +570,11 @@ void MachOFileLayout::buildFileOffsets() { << ", fileOffset=" << fileOffset << "\n"); } - _segInfo[&sg].fileSize = llvm::RoundUpToAlignment(segFileSize, - _file.pageSize); - fileOffset = llvm::RoundUpToAlignment(fileOffset + segFileSize, - _file.pageSize); + // round up all segments to page aligned, except __LINKEDIT + if (!sg.name.equals("__LINKEDIT")) { + _segInfo[&sg].fileSize = llvm::alignTo(segFileSize, _file.pageSize); + fileOffset = llvm::alignTo(fileOffset + segFileSize, _file.pageSize); + } _addressOfLinkEdit = sg.address + sg.size; } _startOfLinkEdit = fileOffset; @@ -553,10 +585,23 @@ size_t MachOFileLayout::size() const { } void MachOFileLayout::writeMachHeader() { + auto cpusubtype = MachOLinkingContext::cpuSubtypeFromArch(_file.arch); + // dynamic x86 executables on newer OS version should also set the + // CPU_SUBTYPE_LIB64 mask in the CPU subtype. + // FIXME: Check that this is a dynamic executable, not a static one. + if (_file.fileType == llvm::MachO::MH_EXECUTE && + cpusubtype == CPU_SUBTYPE_X86_64_ALL && + _file.os == MachOLinkingContext::OS::macOSX) { + uint32_t version; + bool failed = MachOLinkingContext::parsePackedVersion("10.5", version); + if (!failed && _file.minOSverson >= version) + cpusubtype |= CPU_SUBTYPE_LIB64; + } + mach_header *mh = reinterpret_cast<mach_header*>(_buffer); mh->magic = _is64 ? llvm::MachO::MH_MAGIC_64 : llvm::MachO::MH_MAGIC; mh->cputype = MachOLinkingContext::cpuTypeFromArch(_file.arch); - mh->cpusubtype = MachOLinkingContext::cpuSubtypeFromArch(_file.arch); + mh->cpusubtype = cpusubtype; mh->filetype = _file.fileType; mh->ncmds = _countOfLoadCommands; mh->sizeofcmds = _endOfLoadCommands - _startOfLoadCommands; @@ -583,7 +628,7 @@ uint32_t MachOFileLayout::indirectSymbolElementSize(const Section §) { } template <typename T> -std::error_code MachOFileLayout::writeSingleSegmentLoadCommand(uint8_t *&lc) { +llvm::Error MachOFileLayout::writeSingleSegmentLoadCommand(uint8_t *&lc) { typename T::command* seg = reinterpret_cast<typename T::command*>(lc); seg->cmd = T::LC; seg->cmdsize = sizeof(typename T::command) @@ -623,15 +668,37 @@ std::error_code MachOFileLayout::writeSingleSegmentLoadCommand(uint8_t *&lc) { ++sout; } lc = next; - return std::error_code(); + return llvm::Error(); } template <typename T> -std::error_code MachOFileLayout::writeSegmentLoadCommands(uint8_t *&lc) { +llvm::Error MachOFileLayout::writeSegmentLoadCommands(uint8_t *&lc) { uint32_t indirectSymRunningIndex = 0; for (const Segment &seg : _file.segments) { - // Write segment command with trailing sections. + // Link edit has no sections and a custom range of address, so handle it + // specially. SegExtraInfo &segInfo = _segInfo[&seg]; + if (seg.name.equals("__LINKEDIT")) { + size_t linkeditSize = _endOfLinkEdit - _startOfLinkEdit; + typename T::command* cmd = reinterpret_cast<typename T::command*>(lc); + cmd->cmd = T::LC; + cmd->cmdsize = sizeof(typename T::command); + uint8_t *next = lc + cmd->cmdsize; + setString16("__LINKEDIT", cmd->segname); + cmd->vmaddr = _addressOfLinkEdit; + cmd->vmsize = llvm::alignTo(linkeditSize, _file.pageSize); + cmd->fileoff = _startOfLinkEdit; + cmd->filesize = linkeditSize; + cmd->initprot = seg.init_access; + cmd->maxprot = seg.max_access; + cmd->nsects = 0; + cmd->flags = 0; + if (_swap) + swapStruct(*cmd); + lc = next; + continue; + } + // Write segment command with trailing sections. typename T::command* cmd = reinterpret_cast<typename T::command*>(lc); cmd->cmd = T::LC; cmd->cmdsize = sizeof(typename T::command) @@ -642,8 +709,8 @@ std::error_code MachOFileLayout::writeSegmentLoadCommands(uint8_t *&lc) { cmd->vmsize = seg.size; cmd->fileoff = segInfo.fileOffset; cmd->filesize = segInfo.fileSize; - cmd->maxprot = seg.access; - cmd->initprot = seg.access; + cmd->initprot = seg.init_access; + cmd->maxprot = seg.max_access; cmd->nsects = segInfo.sections.size(); cmd->flags = 0; if (_swap) @@ -671,36 +738,52 @@ std::error_code MachOFileLayout::writeSegmentLoadCommands(uint8_t *&lc) { } lc = reinterpret_cast<uint8_t*>(next); } - // Add implicit __LINKEDIT segment - size_t linkeditSize = _endOfLinkEdit - _startOfLinkEdit; - typename T::command* cmd = reinterpret_cast<typename T::command*>(lc); - cmd->cmd = T::LC; - cmd->cmdsize = sizeof(typename T::command); - uint8_t *next = lc + cmd->cmdsize; - setString16("__LINKEDIT", cmd->segname); - cmd->vmaddr = _addressOfLinkEdit; - cmd->vmsize = llvm::RoundUpToAlignment(linkeditSize, _file.pageSize); - cmd->fileoff = _startOfLinkEdit; - cmd->filesize = linkeditSize; - cmd->maxprot = VM_PROT_READ; - cmd->initprot = VM_PROT_READ; - cmd->nsects = 0; - cmd->flags = 0; + return llvm::Error(); +} + +static void writeVersionMinLoadCommand(const NormalizedFile &_file, + bool _swap, + uint8_t *&lc) { + if (!_file.hasMinVersionLoadCommand) + return; + version_min_command *vm = reinterpret_cast<version_min_command*>(lc); + switch (_file.os) { + case MachOLinkingContext::OS::unknown: + vm->cmd = _file.minOSVersionKind; + vm->cmdsize = sizeof(version_min_command); + vm->version = _file.minOSverson; + vm->sdk = 0; + break; + case MachOLinkingContext::OS::macOSX: + vm->cmd = LC_VERSION_MIN_MACOSX; + vm->cmdsize = sizeof(version_min_command); + vm->version = _file.minOSverson; + vm->sdk = _file.sdkVersion; + break; + case MachOLinkingContext::OS::iOS: + case MachOLinkingContext::OS::iOS_simulator: + vm->cmd = LC_VERSION_MIN_IPHONEOS; + vm->cmdsize = sizeof(version_min_command); + vm->version = _file.minOSverson; + vm->sdk = _file.sdkVersion; + break; + } if (_swap) - swapStruct(*cmd); - lc = next; - return std::error_code(); + swapStruct(*vm); + lc += sizeof(version_min_command); } -std::error_code MachOFileLayout::writeLoadCommands() { - std::error_code ec; +llvm::Error MachOFileLayout::writeLoadCommands() { uint8_t *lc = &_buffer[_startOfLoadCommands]; if (_file.fileType == llvm::MachO::MH_OBJECT) { // Object files have one unnamed segment which holds all sections. - if (_is64) - ec = writeSingleSegmentLoadCommand<MachO64Trait>(lc); - else - ec = writeSingleSegmentLoadCommand<MachO32Trait>(lc); + if (_is64) { + if (auto ec = writeSingleSegmentLoadCommand<MachO64Trait>(lc)) + return ec; + } else { + if (auto ec = writeSingleSegmentLoadCommand<MachO32Trait>(lc)) + return ec; + } // Add LC_SYMTAB with symbol table info symtab_command* st = reinterpret_cast<symtab_command*>(lc); st->cmd = LC_SYMTAB; @@ -713,8 +796,25 @@ std::error_code MachOFileLayout::writeLoadCommands() { if (_swap) swapStruct(*st); lc += sizeof(symtab_command); - // Add LC_DATA_IN_CODE if needed. - if (_dataInCodeSize != 0) { + + // Add LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, + // LC_VERSION_MIN_WATCHOS, LC_VERSION_MIN_TVOS + writeVersionMinLoadCommand(_file, _swap, lc); + + // Add LC_FUNCTION_STARTS if needed. + if (_functionStartsSize != 0) { + linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc); + dl->cmd = LC_FUNCTION_STARTS; + dl->cmdsize = sizeof(linkedit_data_command); + dl->dataoff = _startOfFunctionStarts; + dl->datasize = _functionStartsSize; + if (_swap) + swapStruct(*dl); + lc += sizeof(linkedit_data_command); + } + + // Add LC_DATA_IN_CODE if requested. + if (_file.generateDataInCodeLoadCommand) { linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc); dl->cmd = LC_DATA_IN_CODE; dl->cmdsize = sizeof(linkedit_data_command); @@ -726,10 +826,13 @@ std::error_code MachOFileLayout::writeLoadCommands() { } } else { // Final linked images have sections under segments. - if (_is64) - ec = writeSegmentLoadCommands<MachO64Trait>(lc); - else - ec = writeSegmentLoadCommands<MachO32Trait>(lc); + if (_is64) { + if (auto ec = writeSegmentLoadCommands<MachO64Trait>(lc)) + return ec; + } else { + if (auto ec = writeSegmentLoadCommands<MachO32Trait>(lc)) + return ec; + } // Add LC_ID_DYLIB command for dynamic libraries. if (_file.fileType == llvm::MachO::MH_DYLIB) { @@ -809,7 +912,7 @@ std::error_code MachOFileLayout::writeLoadCommands() { lc += sizeof(dysymtab_command); } - // If main executable, add LC_LOAD_DYLINKER and LC_MAIN. + // If main executable, add LC_LOAD_DYLINKER if (_file.fileType == llvm::MachO::MH_EXECUTE) { // Build LC_LOAD_DYLINKER load command. uint32_t size=pointerAlign(sizeof(dylinker_command)+dyldPath().size()+1); @@ -822,14 +925,39 @@ std::error_code MachOFileLayout::writeLoadCommands() { memcpy(lc+sizeof(dylinker_command), dyldPath().data(), dyldPath().size()); lc[sizeof(dylinker_command)+dyldPath().size()] = '\0'; lc += size; + } + + // Add LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_WATCHOS, + // LC_VERSION_MIN_TVOS + writeVersionMinLoadCommand(_file, _swap, lc); + + // Add LC_SOURCE_VERSION + { + // Note, using a temporary here to appease UB as we may not be aligned + // enough for a struct containing a uint64_t when emitting a 32-bit binary + source_version_command sv; + sv.cmd = LC_SOURCE_VERSION; + sv.cmdsize = sizeof(source_version_command); + sv.version = _file.sourceVersion; + if (_swap) + swapStruct(sv); + memcpy(lc, &sv, sizeof(source_version_command)); + lc += sizeof(source_version_command); + } + + // If main executable, add LC_MAIN. + if (_file.fileType == llvm::MachO::MH_EXECUTE) { // Build LC_MAIN load command. - entry_point_command* ep = reinterpret_cast<entry_point_command*>(lc); - ep->cmd = LC_MAIN; - ep->cmdsize = sizeof(entry_point_command); - ep->entryoff = _file.entryAddress - _seg1addr; - ep->stacksize = _file.stackSize; + // Note, using a temporary here to appease UB as we may not be aligned + // enough for a struct containing a uint64_t when emitting a 32-bit binary + entry_point_command ep; + ep.cmd = LC_MAIN; + ep.cmdsize = sizeof(entry_point_command); + ep.entryoff = _file.entryAddress - _seg1addr; + ep.stacksize = _file.stackSize; if (_swap) - swapStruct(*ep); + swapStruct(ep); + memcpy(lc, &ep, sizeof(entry_point_command)); lc += sizeof(entry_point_command); } @@ -865,8 +993,20 @@ std::error_code MachOFileLayout::writeLoadCommands() { lc += size; } - // Add LC_DATA_IN_CODE if needed. - if (_dataInCodeSize != 0) { + // Add LC_FUNCTION_STARTS if needed. + if (_functionStartsSize != 0) { + linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc); + dl->cmd = LC_FUNCTION_STARTS; + dl->cmdsize = sizeof(linkedit_data_command); + dl->dataoff = _startOfFunctionStarts; + dl->datasize = _functionStartsSize; + if (_swap) + swapStruct(*dl); + lc += sizeof(linkedit_data_command); + } + + // Add LC_DATA_IN_CODE if requested. + if (_file.generateDataInCodeLoadCommand) { linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc); dl->cmd = LC_DATA_IN_CODE; dl->cmdsize = sizeof(linkedit_data_command); @@ -877,7 +1017,7 @@ std::error_code MachOFileLayout::writeLoadCommands() { lc += sizeof(linkedit_data_command); } } - return ec; + return llvm::Error(); } void MachOFileLayout::writeSectionContent() { @@ -936,6 +1076,13 @@ void MachOFileLayout::appendSymbols(const std::vector<Symbol> &symbols, } } +void MachOFileLayout::writeFunctionStartsInfo() { + if (!_functionStartsSize) + return; + memcpy(&_buffer[_startOfFunctionStarts], _file.functionStarts.data(), + _functionStartsSize); +} + void MachOFileLayout::writeDataInCodeInfo() { uint32_t offset = _startOfDataInCode; for (const DataInCode &entry : _file.dataInCode) { @@ -1011,6 +1158,7 @@ void MachOFileLayout::buildLinkEditInfo() { buildLazyBindInfo(); buildExportTrie(); computeSymbolTableSizes(); + computeFunctionStartsSize(); computeDataInCodeSize(); } @@ -1079,9 +1227,9 @@ void MachOFileLayout::buildLazyBindInfo() { _lazyBindingInfo.align(_is64 ? 8 : 4); } -void MachOFileLayout::TrieNode::addSymbol(const Export& entry, - BumpPtrAllocator &allocator, - std::vector<TrieNode*> &allNodes) { +void TrieNode::addSymbol(const Export& entry, + BumpPtrAllocator &allocator, + std::vector<TrieNode*> &allNodes) { StringRef partialStr = entry.name.drop_front(_cummulativeString.size()); for (TrieEdge &edge : _children) { StringRef edgeStr = edge._subString; @@ -1110,7 +1258,7 @@ void MachOFileLayout::TrieNode::addSymbol(const Export& entry, abEdge._subString = abEdgeStr; abEdge._child = bNode; auto *bcEdge = new (allocator) TrieEdge(bcEdgeStr, cNode); - bNode->_children.push_back(std::move(*bcEdge)); + bNode->_children.insert(bNode->_children.end(), bcEdge); bNode->addSymbol(entry, allocator, allNodes); return; } @@ -1125,7 +1273,7 @@ void MachOFileLayout::TrieNode::addSymbol(const Export& entry, // No commonality with any existing child, make a new edge. auto *newNode = new (allocator) TrieNode(entry.name.copy(allocator)); auto *newEdge = new (allocator) TrieEdge(partialStr, newNode); - _children.push_back(std::move(*newEdge)); + _children.insert(_children.end(), newEdge); DEBUG_WITH_TYPE("trie-builder", llvm::dbgs() << "new TrieNode('" << entry.name << "') with edge '" << partialStr << "' from node='" @@ -1139,7 +1287,7 @@ void MachOFileLayout::TrieNode::addSymbol(const Export& entry, allNodes.push_back(newNode); } -bool MachOFileLayout::TrieNode::updateOffset(uint32_t& offset) { +bool TrieNode::updateOffset(uint32_t& offset) { uint32_t nodeSize = 1; // Length when no export info if (_hasExportInfo) { if (_flags & EXPORT_SYMBOL_FLAGS_REEXPORT) { @@ -1171,7 +1319,7 @@ bool MachOFileLayout::TrieNode::updateOffset(uint32_t& offset) { return result; } -void MachOFileLayout::TrieNode::appendToByteBuffer(ByteBuffer &out) { +void TrieNode::appendToByteBuffer(ByteBuffer &out) { if (_hasExportInfo) { if (_flags & EXPORT_SYMBOL_FLAGS_REEXPORT) { if (!_importedName.empty()) { @@ -1290,6 +1438,10 @@ void MachOFileLayout::computeSymbolTableSizes() { } } +void MachOFileLayout::computeFunctionStartsSize() { + _functionStartsSize = _file.functionStarts.size(); +} + void MachOFileLayout::computeDataInCodeSize() { _dataInCodeSize = _file.dataInCode.size() * sizeof(data_in_code_entry); } @@ -1297,6 +1449,7 @@ void MachOFileLayout::computeDataInCodeSize() { void MachOFileLayout::writeLinkEditContent() { if (_file.fileType == llvm::MachO::MH_OBJECT) { writeRelocations(); + writeFunctionStartsInfo(); writeDataInCodeInfo(); writeSymbolTable(); } else { @@ -1305,15 +1458,16 @@ void MachOFileLayout::writeLinkEditContent() { writeLazyBindingInfo(); // TODO: add weak binding info writeExportInfo(); + writeFunctionStartsInfo(); writeDataInCodeInfo(); writeSymbolTable(); } } -std::error_code MachOFileLayout::writeBinary(StringRef path) { +llvm::Error MachOFileLayout::writeBinary(StringRef path) { // Check for pending error from constructor. if (_ec) - return _ec; + return llvm::errorCodeToError(_ec); // Create FileOutputBuffer with calculated size. unsigned flags = 0; if (_file.fileType != llvm::MachO::MH_OBJECT) @@ -1321,23 +1475,22 @@ std::error_code MachOFileLayout::writeBinary(StringRef path) { ErrorOr<std::unique_ptr<llvm::FileOutputBuffer>> fobOrErr = llvm::FileOutputBuffer::create(path, size(), flags); if (std::error_code ec = fobOrErr.getError()) - return ec; + return llvm::errorCodeToError(ec); std::unique_ptr<llvm::FileOutputBuffer> &fob = *fobOrErr; // Write content. _buffer = fob->getBufferStart(); writeMachHeader(); - std::error_code ec = writeLoadCommands(); - if (ec) + if (auto ec = writeLoadCommands()) return ec; writeSectionContent(); writeLinkEditContent(); fob->commit(); - return std::error_code(); + return llvm::Error(); } /// Takes in-memory normalized view and writes a mach-o object file. -std::error_code writeBinary(const NormalizedFile &file, StringRef path) { +llvm::Error writeBinary(const NormalizedFile &file, StringRef path) { MachOFileLayout layout(file); return layout.writeBinary(path); } diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp index 575bc1a2b3a9..4775c75f7211 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp +++ b/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp @@ -92,23 +92,27 @@ struct SegmentInfo { StringRef name; uint64_t address; uint64_t size; - uint32_t access; + uint32_t init_access; + uint32_t max_access; std::vector<SectionInfo*> sections; uint32_t normalizedSegmentIndex; }; SegmentInfo::SegmentInfo(StringRef n) - : name(n), address(0), size(0), access(0), normalizedSegmentIndex(0) { + : name(n), address(0), size(0), init_access(0), max_access(0), + normalizedSegmentIndex(0) { } class Util { public: Util(const MachOLinkingContext &ctxt) : _ctx(ctxt), _archHandler(ctxt.archHandler()), _entryAtom(nullptr), - _hasTLVDescriptors(false) {} + _hasTLVDescriptors(false), _subsectionsViaSymbols(true) {} ~Util(); - void assignAtomsToSections(const lld::File &atomFile); + void processDefinedAtoms(const lld::File &atomFile); + void processAtomAttributes(const DefinedAtom *atom); + void assignAtomToSection(const DefinedAtom *atom); void organizeSections(); void assignAddressesToSections(const NormalizedFile &file); uint32_t fileFlags(); @@ -116,16 +120,29 @@ public: void copySectionInfo(NormalizedFile &file); void updateSectionInfo(NormalizedFile &file); void buildAtomToAddressMap(); - std::error_code addSymbols(const lld::File &atomFile, NormalizedFile &file); + llvm::Error addSymbols(const lld::File &atomFile, NormalizedFile &file); void addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file); void addRebaseAndBindingInfo(const lld::File &, NormalizedFile &file); void addExportInfo(const lld::File &, NormalizedFile &file); void addSectionRelocs(const lld::File &, NormalizedFile &file); + void addFunctionStarts(const lld::File &, NormalizedFile &file); void buildDataInCodeArray(const lld::File &, NormalizedFile &file); void addDependentDylibs(const lld::File &, NormalizedFile &file); void copyEntryPointAddress(NormalizedFile &file); void copySectionContent(NormalizedFile &file); + bool allSourceFilesHaveMinVersions() const { + return _allSourceFilesHaveMinVersions; + } + + uint32_t minVersion() const { + return _minVersion; + } + + LoadCommandType minVersionCommandType() const { + return _minVersionCommandType; + } + private: typedef std::map<DefinedAtom::ContentType, SectionInfo*> TypeToSection; typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress; @@ -147,9 +164,9 @@ private: uint8_t &segmentIndex, uint64_t &segmentStartAddr); const Atom *targetOfLazyPointer(const DefinedAtom *lpAtom); const Atom *targetOfStub(const DefinedAtom *stubAtom); - std::error_code getSymbolTableRegion(const DefinedAtom* atom, - bool &inGlobalsRegion, - SymbolScope &symbolScope); + llvm::Error getSymbolTableRegion(const DefinedAtom* atom, + bool &inGlobalsRegion, + SymbolScope &symbolScope); void appendSection(SectionInfo *si, NormalizedFile &file); uint32_t sectionIndexForAtom(const Atom *atom); @@ -180,6 +197,10 @@ private: AtomToIndex _atomToSymbolIndex; std::vector<const Atom *> _machHeaderAliasAtoms; bool _hasTLVDescriptors; + bool _subsectionsViaSymbols; + bool _allSourceFilesHaveMinVersions = true; + LoadCommandType _minVersionCommandType = (LoadCommandType)0; + uint32_t _minVersion = 0; }; Util::~Util() { @@ -239,6 +260,7 @@ struct MachOFinalSectionFromAtomType { const MachOFinalSectionFromAtomType sectsToAtomType[] = { ENTRY("__TEXT", "__text", S_REGULAR, typeCode), + ENTRY("__TEXT", "__text", S_REGULAR, typeMachHeader), ENTRY("__TEXT", "__cstring", S_CSTRING_LITERALS, typeCString), ENTRY("__TEXT", "__ustring", S_REGULAR, typeUTF16String), ENTRY("__TEXT", "__const", S_REGULAR, typeConstant), @@ -261,6 +283,8 @@ const MachOFinalSectionFromAtomType sectsToAtomType[] = { typeTerminatorPtr), ENTRY("__DATA", "__got", S_NON_LAZY_SYMBOL_POINTERS, typeGOT), + ENTRY("__DATA", "__nl_symbol_ptr", S_NON_LAZY_SYMBOL_POINTERS, + typeNonLazyPointer), ENTRY("__DATA", "__thread_vars", S_THREAD_LOCAL_VARIABLES, typeThunkTLV), ENTRY("__DATA", "__thread_data", S_THREAD_LOCAL_REGULAR, @@ -280,10 +304,11 @@ SectionInfo *Util::getFinalSection(DefinedAtom::ContentType atomType) { continue; SectionAttr sectionAttrs = 0; switch (atomType) { + case DefinedAtom::typeMachHeader: case DefinedAtom::typeCode: case DefinedAtom::typeStub: case DefinedAtom::typeStubHelper: - sectionAttrs = S_ATTR_PURE_INSTRUCTIONS; + sectionAttrs = S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS; break; case DefinedAtom::typeThunkTLV: _hasTLVDescriptors = true; @@ -366,27 +391,85 @@ void Util::appendAtom(SectionInfo *sect, const DefinedAtom *atom) { sect->size = offset + atom->size(); } -void Util::assignAtomsToSections(const lld::File &atomFile) { +void Util::processDefinedAtoms(const lld::File &atomFile) { for (const DefinedAtom *atom : atomFile.defined()) { - if (atom->contentType() == DefinedAtom::typeMachHeader) - _machHeaderAliasAtoms.push_back(atom); + processAtomAttributes(atom); + assignAtomToSection(atom); + } +} + +void Util::processAtomAttributes(const DefinedAtom *atom) { + if (auto *machoFile = dyn_cast<mach_o::MachOFile>(&atom->file())) { + // If the file doesn't use subsections via symbols, then make sure we don't + // add that flag to the final output file if we have a relocatable file. + if (!machoFile->subsectionsViaSymbols()) + _subsectionsViaSymbols = false; + + // All the source files must have min versions for us to output an object + // file with a min version. + if (auto v = machoFile->minVersion()) + _minVersion = std::max(_minVersion, v); else - appendAtom(sectionForAtom(atom), atom); + _allSourceFilesHaveMinVersions = false; + + // If we don't have a platform load command, but one of the source files + // does, then take the one from the file. + if (!_minVersionCommandType) + if (auto v = machoFile->minVersionLoadCommandKind()) + _minVersionCommandType = v; } } +void Util::assignAtomToSection(const DefinedAtom *atom) { + if (atom->contentType() == DefinedAtom::typeMachHeader) { + _machHeaderAliasAtoms.push_back(atom); + // Assign atom to this section with this offset. + AtomInfo ai = {atom, 0}; + sectionForAtom(atom)->atomsAndOffsets.push_back(ai); + } else if (atom->contentType() == DefinedAtom::typeDSOHandle) + _machHeaderAliasAtoms.push_back(atom); + else + appendAtom(sectionForAtom(atom), atom); +} + SegmentInfo *Util::segmentForName(StringRef segName) { for (SegmentInfo *si : _segmentInfos) { if ( si->name.equals(segName) ) return si; } auto *info = new (_allocator) SegmentInfo(segName); + + // Set the initial segment protection. if (segName.equals("__TEXT")) - info->access = VM_PROT_READ | VM_PROT_EXECUTE; - else if (segName.equals("__DATA")) - info->access = VM_PROT_READ | VM_PROT_WRITE; + info->init_access = VM_PROT_READ | VM_PROT_EXECUTE; else if (segName.equals("__PAGEZERO")) - info->access = 0; + info->init_access = 0; + else if (segName.equals("__LINKEDIT")) + info->init_access = VM_PROT_READ; + else { + // All others default to read-write + info->init_access = VM_PROT_READ | VM_PROT_WRITE; + } + + // Set max segment protection + // Note, its overkill to use a switch statement here, but makes it so much + // easier to use switch coverage to catch new cases. + switch (_ctx.os()) { + case lld::MachOLinkingContext::OS::unknown: + case lld::MachOLinkingContext::OS::macOSX: + case lld::MachOLinkingContext::OS::iOS_simulator: + if (segName.equals("__PAGEZERO")) { + info->max_access = 0; + break; + } + // All others default to all + info->max_access = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; + break; + case lld::MachOLinkingContext::OS::iOS: + // iPhoneOS always uses same protection for max and initial + info->max_access = info->init_access; + break; + } _segmentInfos.push_back(info); return info; } @@ -436,6 +519,8 @@ void Util::organizeSections() { default: break; } + segmentForName("__LINKEDIT"); + // Group sections into segments. for (SectionInfo *si : _sectionInfos) { SegmentInfo *seg = segmentForName(si->segmentName); @@ -465,10 +550,10 @@ void Util::organizeSections() { void Util::layoutSectionsInSegment(SegmentInfo *seg, uint64_t &addr) { seg->address = addr; for (SectionInfo *sect : seg->sections) { - sect->address = llvm::RoundUpToAlignment(addr, sect->alignment); + sect->address = llvm::alignTo(addr, sect->alignment); addr = sect->address + sect->size; } - seg->size = llvm::RoundUpToAlignment(addr - seg->address, _ctx.pageSize()); + seg->size = llvm::alignTo(addr - seg->address, _ctx.pageSize()); } // __TEXT segment lays out backwards so padding is at front after load commands. @@ -488,10 +573,10 @@ void Util::layoutSectionsInTextSegment(size_t hlcSize, SegmentInfo *seg, // Start assigning section address starting at padded offset. addr += (padding + hlcSize); for (SectionInfo *sect : seg->sections) { - sect->address = llvm::RoundUpToAlignment(addr, sect->alignment); + sect->address = llvm::alignTo(addr, sect->alignment); addr = sect->address + sect->size; } - seg->size = llvm::RoundUpToAlignment(addr - seg->address, _ctx.pageSize()); + seg->size = llvm::alignTo(addr - seg->address, _ctx.pageSize()); } void Util::assignAddressesToSections(const NormalizedFile &file) { @@ -511,7 +596,7 @@ void Util::assignAddressesToSections(const NormalizedFile &file) { } else layoutSectionsInSegment(seg, address); - address = llvm::RoundUpToAlignment(address, _ctx.pageSize()); + address = llvm::alignTo(address, _ctx.pageSize()); } DEBUG_WITH_TYPE("WriterMachO-norm", llvm::dbgs() << "assignAddressesToSections()\n"; @@ -536,7 +621,8 @@ void Util::copySegmentInfo(NormalizedFile &file) { seg.name = sgi->name; seg.address = sgi->address; seg.size = sgi->size; - seg.access = sgi->access; + seg.init_access = sgi->init_access; + seg.max_access = sgi->max_access; file.segments.push_back(seg); } } @@ -583,11 +669,20 @@ void Util::copySectionContent(NormalizedFile &file) { continue; } // Copy content from atoms to content buffer for section. - uint8_t *sectionContent = file.ownedAllocations.Allocate<uint8_t>(si->size); - normSect->content = llvm::makeArrayRef(sectionContent, si->size); + llvm::MutableArrayRef<uint8_t> sectionContent; + if (si->size) { + uint8_t *sectContent = file.ownedAllocations.Allocate<uint8_t>(si->size); + sectionContent = llvm::MutableArrayRef<uint8_t>(sectContent, si->size); + normSect->content = sectionContent; + } for (AtomInfo &ai : si->atomsAndOffsets) { - uint8_t *atomContent = reinterpret_cast<uint8_t*> - (§ionContent[ai.offsetInSection]); + if (!ai.atom->size()) { + assert(ai.atom->begin() == ai.atom->end() && + "Cannot have references without content"); + continue; + } + auto atomContent = sectionContent.slice(ai.offsetInSection, + ai.atom->size()); _archHandler.generateAtomContent(*ai.atom, r, addrForAtom, sectionAddrForAtom, _ctx.baseAddress(), atomContent); @@ -620,6 +715,11 @@ void Util::updateSectionInfo(NormalizedFile &file) { } void Util::copyEntryPointAddress(NormalizedFile &nFile) { + if (!_entryAtom) { + nFile.entryAddress = 0; + return; + } + if (_ctx.outputTypeHasEntry()) { if (_archHandler.isThumbFunction(*_entryAtom)) nFile.entryAddress = (_atomToAddress[_entryAtom] | 1); @@ -703,6 +803,8 @@ uint16_t Util::descBits(const DefinedAtom* atom) { } if (atom->contentType() == lld::DefinedAtom::typeResolver) desc |= N_SYMBOL_RESOLVER; + if (atom->contentType() == lld::DefinedAtom::typeMachHeader) + desc |= REFERENCED_DYNAMICALLY; if (_archHandler.isThumbFunction(*atom)) desc |= N_ARM_THUMB_DEF; if (atom->deadStrip() == DefinedAtom::deadStripNever) { @@ -718,56 +820,56 @@ bool Util::AtomSorter::operator()(const AtomAndIndex &left, return (left.atom->name().compare(right.atom->name()) < 0); } -std::error_code Util::getSymbolTableRegion(const DefinedAtom* atom, - bool &inGlobalsRegion, - SymbolScope &scope) { +llvm::Error Util::getSymbolTableRegion(const DefinedAtom* atom, + bool &inGlobalsRegion, + SymbolScope &scope) { bool rMode = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT); switch (atom->scope()) { case Atom::scopeTranslationUnit: scope = 0; inGlobalsRegion = false; - return std::error_code(); + return llvm::Error(); case Atom::scopeLinkageUnit: if ((_ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) && _ctx.exportSymbolNamed(atom->name())) { - return make_dynamic_error_code(Twine("cannot export hidden symbol ") - + atom->name()); + return llvm::make_error<GenericError>( + Twine("cannot export hidden symbol ") + atom->name()); } if (rMode) { if (_ctx.keepPrivateExterns()) { // -keep_private_externs means keep in globals region as N_PEXT. scope = N_PEXT | N_EXT; inGlobalsRegion = true; - return std::error_code(); + return llvm::Error(); } } // scopeLinkageUnit symbols are no longer global once linked. scope = N_PEXT; inGlobalsRegion = false; - return std::error_code(); + return llvm::Error(); case Atom::scopeGlobal: if (_ctx.exportRestrictMode()) { if (_ctx.exportSymbolNamed(atom->name())) { scope = N_EXT; inGlobalsRegion = true; - return std::error_code(); + return llvm::Error(); } else { scope = N_PEXT; inGlobalsRegion = false; - return std::error_code(); + return llvm::Error(); } } else { scope = N_EXT; inGlobalsRegion = true; - return std::error_code(); + return llvm::Error(); } break; } llvm_unreachable("atom->scope() unknown enum value"); } -std::error_code Util::addSymbols(const lld::File &atomFile, - NormalizedFile &file) { +llvm::Error Util::addSymbols(const lld::File &atomFile, + NormalizedFile &file) { bool rMode = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT); // Mach-O symbol table has three regions: locals, globals, undefs. @@ -863,7 +965,7 @@ std::error_code Util::addSymbols(const lld::File &atomFile, file.undefinedSymbols.push_back(sym); } - return std::error_code(); + return llvm::Error(); } const Atom *Util::targetOfLazyPointer(const DefinedAtom *lpAtom) { @@ -1055,7 +1157,53 @@ void Util::addSectionRelocs(const lld::File &, NormalizedFile &file) { } } +void Util::addFunctionStarts(const lld::File &, NormalizedFile &file) { + if (!_ctx.generateFunctionStartsLoadCommand()) + return; + file.functionStarts.reserve(8192); + // Delta compress function starts, starting with the mach header symbol. + const uint64_t badAddress = ~0ULL; + uint64_t addr = badAddress; + for (SectionInfo *si : _sectionInfos) { + for (const AtomInfo &info : si->atomsAndOffsets) { + auto type = info.atom->contentType(); + if (type == DefinedAtom::typeMachHeader) { + addr = _atomToAddress[info.atom]; + continue; + } + if (type != DefinedAtom::typeCode) + continue; + assert(addr != badAddress && "Missing mach header symbol"); + // Skip atoms which have 0 size. This is so that LC_FUNCTION_STARTS + // can't spill in to the next section. + if (!info.atom->size()) + continue; + uint64_t nextAddr = _atomToAddress[info.atom]; + if (_archHandler.isThumbFunction(*info.atom)) + nextAddr |= 1; + uint64_t delta = nextAddr - addr; + if (delta) { + ByteBuffer buffer; + buffer.append_uleb128(delta); + file.functionStarts.insert(file.functionStarts.end(), buffer.bytes(), + buffer.bytes() + buffer.size()); + } + addr = nextAddr; + } + } + + // Null terminate, and pad to pointer size for this arch. + file.functionStarts.push_back(0); + + auto size = file.functionStarts.size(); + for (unsigned i = size, e = llvm::alignTo(size, _ctx.is64Bit() ? 8 : 4); + i != e; ++i) + file.functionStarts.push_back(0); +} + void Util::buildDataInCodeArray(const lld::File &, NormalizedFile &file) { + if (!_ctx.generateDataInCodeLoadCommand()) + return; for (SectionInfo *si : _sectionInfos) { for (const AtomInfo &info : si->atomsAndOffsets) { // Atoms that contain data-in-code have "transition" references @@ -1183,7 +1331,7 @@ void Util::addExportInfo(const lld::File &atomFile, NormalizedFile &nFile) { uint32_t Util::fileFlags() { // FIXME: these need to determined at runtime. if (_ctx.outputMachOType() == MH_OBJECT) { - return MH_SUBSECTIONS_VIA_SYMBOLS; + return _subsectionsViaSymbols ? MH_SUBSECTIONS_VIA_SYMBOLS : 0; } else { uint32_t flags = MH_DYLDLINK; if (!_ctx.useFlatNamespace()) @@ -1203,12 +1351,12 @@ namespace mach_o { namespace normalized { /// Convert a set of Atoms into a normalized mach-o file. -ErrorOr<std::unique_ptr<NormalizedFile>> +llvm::Expected<std::unique_ptr<NormalizedFile>> normalizedFromAtoms(const lld::File &atomFile, const MachOLinkingContext &context) { // The util object buffers info until the normalized file can be made. Util util(context); - util.assignAtomsToSections(atomFile); + util.processDefinedAtoms(atomFile); util.organizeSections(); std::unique_ptr<NormalizedFile> f(new NormalizedFile()); @@ -1220,6 +1368,35 @@ normalizedFromAtoms(const lld::File &atomFile, normFile.installName = context.installName(); normFile.currentVersion = context.currentVersion(); normFile.compatVersion = context.compatibilityVersion(); + normFile.os = context.os(); + + // If we are emitting an object file, then the min version is the maximum + // of the min's of all the source files and the cmdline. + if (normFile.fileType == llvm::MachO::MH_OBJECT) + normFile.minOSverson = std::max(context.osMinVersion(), util.minVersion()); + else + normFile.minOSverson = context.osMinVersion(); + + normFile.minOSVersionKind = util.minVersionCommandType(); + + normFile.sdkVersion = context.sdkVersion(); + normFile.sourceVersion = context.sourceVersion(); + + if (context.generateVersionLoadCommand() && + context.os() != MachOLinkingContext::OS::unknown) + normFile.hasMinVersionLoadCommand = true; + else if (normFile.fileType == llvm::MachO::MH_OBJECT && + util.allSourceFilesHaveMinVersions() && + ((normFile.os != MachOLinkingContext::OS::unknown) || + util.minVersionCommandType())) { + // If we emit an object file, then it should contain a min version load + // command if all of the source files also contained min version commands. + // Also, we either need to have a platform, or found a platform from the + // source object files. + normFile.hasMinVersionLoadCommand = true; + } + normFile.generateDataInCodeLoadCommand = + context.generateDataInCodeLoadCommand(); normFile.pageSize = context.pageSize(); normFile.rpaths = context.rpaths(); util.addDependentDylibs(atomFile, normFile); @@ -1230,12 +1407,13 @@ normalizedFromAtoms(const lld::File &atomFile, util.updateSectionInfo(normFile); util.copySectionContent(normFile); if (auto ec = util.addSymbols(atomFile, normFile)) { - return ec; + return std::move(ec); } util.addIndirectSymbols(atomFile, normFile); util.addRebaseAndBindingInfo(atomFile, normFile); util.addExportInfo(atomFile, normFile); util.addSectionRelocs(atomFile, normFile); + util.addFunctionStarts(atomFile, normFile); util.buildDataInCodeArray(atomFile, normFile); util.copyEntryPointAddress(normFile); diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp index f9499b603214..fc760a3eddd0 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp +++ b/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp @@ -88,6 +88,8 @@ const MachORelocatableSectionToAtomType sectsToAtomType[] = { ENTRY("__DATA", "__thread_data", S_THREAD_LOCAL_REGULAR, typeTLVInitialData), ENTRY("__DATA", "__thread_bss", S_THREAD_LOCAL_ZEROFILL, typeTLVInitialZeroFill), + ENTRY("__DATA", "__objc_imageinfo", S_REGULAR, typeObjCImageInfo), + ENTRY("__DATA", "__objc_catlist", S_REGULAR, typeObjC2CategoryList), ENTRY("", "", S_INTERPOSING, typeInterposingTuples), ENTRY("__LD", "__compact_unwind", S_REGULAR, typeCompactUnwindInfo), @@ -180,6 +182,8 @@ void sectionParseInfo(DefinedAtom::ContentType atomType, atomizeCU), ENTRY(typeGOT, 4, scopeLinkageUnit, mergeByContent, atomizePointerSize), + ENTRY(typeObjC2CategoryList, 4, scopeTranslationUnit, mergeByContent, + atomizePointerSize), ENTRY(typeUnknown, 1, scopeGlobal, mergeNo, atomizeAtSymbols) }; @@ -265,11 +269,11 @@ void atomFromSymbol(DefinedAtom::ContentType atomType, const Section §ion, } } -std::error_code processSymboledSection(DefinedAtom::ContentType atomType, - const Section §ion, - const NormalizedFile &normalizedFile, - MachOFile &file, bool scatterable, - bool copyRefs) { +llvm::Error processSymboledSection(DefinedAtom::ContentType atomType, + const Section §ion, + const NormalizedFile &normalizedFile, + MachOFile &file, bool scatterable, + bool copyRefs) { // Find section's index. uint32_t sectIndex = 1; for (auto § : normalizedFile.sections) { @@ -316,7 +320,7 @@ std::error_code processSymboledSection(DefinedAtom::ContentType atomType, // If section has no symbols and no content, there are no atoms. if (symbols.empty() && section.content.empty()) - return std::error_code(); + return llvm::Error(); if (symbols.empty()) { // Section has no symbols, put all content in one anoymous atom. @@ -360,22 +364,22 @@ std::error_code processSymboledSection(DefinedAtom::ContentType atomType, file.eachAtomInSection(section, [&](MachODefinedAtom *atom, uint64_t offset)->void { if (prevAtom) - prevAtom->addReference(0, Reference::kindLayoutAfter, atom, 0, + prevAtom->addReference(Reference::KindNamespace::all, Reference::KindArch::all, - Reference::KindNamespace::all); + Reference::kindLayoutAfter, 0, atom, 0); prevAtom = atom; }); } - return std::error_code(); + return llvm::Error(); } -std::error_code processSection(DefinedAtom::ContentType atomType, - const Section §ion, - bool customSectionName, - const NormalizedFile &normalizedFile, - MachOFile &file, bool scatterable, - bool copyRefs) { +llvm::Error processSection(DefinedAtom::ContentType atomType, + const Section §ion, + bool customSectionName, + const NormalizedFile &normalizedFile, + MachOFile &file, bool scatterable, + bool copyRefs) { const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch); const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch); @@ -388,12 +392,13 @@ std::error_code processSection(DefinedAtom::ContentType atomType, // Validate section size. if ((section.content.size() % sizeMultiple) != 0) - return make_dynamic_error_code(Twine("Section ") + section.segmentName - + "/" + section.sectionName - + " has size (" - + Twine(section.content.size()) - + ") which is not a multiple of " - + Twine(sizeMultiple) ); + return llvm::make_error<GenericError>(Twine("Section ") + + section.segmentName + + "/" + section.sectionName + + " has size (" + + Twine(section.content.size()) + + ") which is not a multiple of " + + Twine(sizeMultiple)); if (atomizeModel == atomizeAtSymbols) { // Break section up into atoms each with a fixed size. @@ -435,13 +440,13 @@ std::error_code processSection(DefinedAtom::ContentType atomType, // Break section up into dwarf unwind CFIs (FDE or CIE). size = read32(§ion.content[offset], isBig) + 4; if (offset+size > section.content.size()) { - return make_dynamic_error_code(Twine(Twine("Section ") - + section.segmentName - + "/" + section.sectionName - + " is malformed. Size of CFI " - "starting at offset (" - + Twine(offset) - + ") is past end of section.")); + return llvm::make_error<GenericError>(Twine("Section ") + + section.segmentName + + "/" + section.sectionName + + " is malformed. Size of CFI " + "starting at offset (" + + Twine(offset) + + ") is past end of section."); } break; case atomizeCU: @@ -456,10 +461,11 @@ std::error_code processSection(DefinedAtom::ContentType atomType, break; } if (size == 0) { - return make_dynamic_error_code(Twine("Section ") + section.segmentName - + "/" + section.sectionName - + " is malformed. The last atom is " - "not zero terminated."); + return llvm::make_error<GenericError>(Twine("Section ") + + section.segmentName + + "/" + section.sectionName + + " is malformed. The last atom " + "is not zero terminated."); } if (customSectionName) { // Mach-O needs a segment and section name. Concatentate those two @@ -477,7 +483,7 @@ std::error_code processSection(DefinedAtom::ContentType atomType, offset += size; } } - return std::error_code(); + return llvm::Error(); } const Section* findSectionCoveringAddress(const NormalizedFile &normalizedFile, @@ -509,23 +515,23 @@ findAtomCoveringAddress(const NormalizedFile &normalizedFile, MachOFile &file, // Walks all relocations for a section in a normalized .o file and // creates corresponding lld::Reference objects. -std::error_code convertRelocs(const Section §ion, - const NormalizedFile &normalizedFile, - bool scatterable, - MachOFile &file, - ArchHandler &handler) { +llvm::Error convertRelocs(const Section §ion, + const NormalizedFile &normalizedFile, + bool scatterable, + MachOFile &file, + ArchHandler &handler) { // Utility function for ArchHandler to find atom by its address. auto atomByAddr = [&] (uint32_t sectIndex, uint64_t addr, const lld::Atom **atom, Reference::Addend *addend) - -> std::error_code { + -> llvm::Error { if (sectIndex > normalizedFile.sections.size()) - return make_dynamic_error_code(Twine("out of range section " + return llvm::make_error<GenericError>(Twine("out of range section " "index (") + Twine(sectIndex) + ")"); const Section *sect = nullptr; if (sectIndex == 0) { sect = findSectionCoveringAddress(normalizedFile, addr); if (!sect) - return make_dynamic_error_code(Twine("address (" + Twine(addr) + return llvm::make_error<GenericError>(Twine("address (" + Twine(addr) + ") is not in any section")); } else { sect = &normalizedFile.sections[sectIndex-1]; @@ -534,12 +540,12 @@ std::error_code convertRelocs(const Section §ion, uint64_t offsetInSect = addr - sect->address; *atom = file.findAtomCoveringAddress(*sect, offsetInSect, &offsetInTarget); *addend = offsetInTarget; - return std::error_code(); + return llvm::Error(); }; // Utility function for ArchHandler to find atom by its symbol index. auto atomBySymbol = [&] (uint32_t symbolIndex, const lld::Atom **result) - -> std::error_code { + -> llvm::Error { // Find symbol from index. const Symbol *sym = nullptr; uint32_t numLocal = normalizedFile.localSymbols.size(); @@ -552,13 +558,13 @@ std::error_code convertRelocs(const Section §ion, } else if (symbolIndex < numLocal+numGlobal+numUndef) { sym = &normalizedFile.undefinedSymbols[symbolIndex-numLocal-numGlobal]; } else { - return make_dynamic_error_code(Twine("symbol index (") + return llvm::make_error<GenericError>(Twine("symbol index (") + Twine(symbolIndex) + ") out of range"); } // Find atom from symbol. if ((sym->type & N_TYPE) == N_SECT) { if (sym->sect > normalizedFile.sections.size()) - return make_dynamic_error_code(Twine("symbol section index (") + return llvm::make_error<GenericError>(Twine("symbol section index (") + Twine(sym->sect) + ") out of range "); const Section &symSection = normalizedFile.sections[sym->sect-1]; uint64_t targetOffsetInSect = sym->value - symSection.address; @@ -566,19 +572,19 @@ std::error_code convertRelocs(const Section §ion, targetOffsetInSect); if (target) { *result = target; - return std::error_code(); + return llvm::Error(); } - return make_dynamic_error_code("no atom found for defined symbol"); + return llvm::make_error<GenericError>("no atom found for defined symbol"); } else if ((sym->type & N_TYPE) == N_UNDF) { const lld::Atom *target = file.findUndefAtom(sym->name); if (target) { *result = target; - return std::error_code(); + return llvm::Error(); } - return make_dynamic_error_code("no undefined atom found for sym"); + return llvm::make_error<GenericError>("no undefined atom found for sym"); } else { // Search undefs - return make_dynamic_error_code("no atom found for symbol"); + return llvm::make_error<GenericError>("no atom found for symbol"); } }; @@ -589,7 +595,8 @@ std::error_code convertRelocs(const Section §ion, const Relocation &reloc = *it; // Find atom this relocation is in. if (reloc.offset > section.content.size()) - return make_dynamic_error_code(Twine("r_address (") + Twine(reloc.offset) + return llvm::make_error<GenericError>( + Twine("r_address (") + Twine(reloc.offset) + ") is larger than section size (" + Twine(section.content.size()) + ")"); uint32_t offsetInAtom; @@ -602,68 +609,74 @@ std::error_code convertRelocs(const Section §ion, const lld::Atom *target = nullptr; Reference::Addend addend = 0; Reference::KindValue kind; - std::error_code relocErr; if (handler.isPairedReloc(reloc)) { // Handle paired relocations together. const Relocation &reloc2 = *++it; - relocErr = handler.getPairReferenceInfo( + auto relocErr = handler.getPairReferenceInfo( reloc, reloc2, inAtom, offsetInAtom, fixupAddress, isBig, scatterable, atomByAddr, atomBySymbol, &kind, &target, &addend); if (relocErr) { - return make_dynamic_error_code( - Twine("bad relocation (") + relocErr.message() - + ") in section " - + section.segmentName + "/" + section.sectionName - + " (r1_address=" + Twine::utohexstr(reloc.offset) - + ", r1_type=" + Twine(reloc.type) - + ", r1_extern=" + Twine(reloc.isExtern) - + ", r1_length=" + Twine((int)reloc.length) - + ", r1_pcrel=" + Twine(reloc.pcRel) - + (!reloc.scattered ? (Twine(", r1_symbolnum=") - + Twine(reloc.symbol)) - : (Twine(", r1_scattered=1, r1_value=") - + Twine(reloc.value))) - + ")" - + ", (r2_address=" + Twine::utohexstr(reloc2.offset) - + ", r2_type=" + Twine(reloc2.type) - + ", r2_extern=" + Twine(reloc2.isExtern) - + ", r2_length=" + Twine((int)reloc2.length) - + ", r2_pcrel=" + Twine(reloc2.pcRel) - + (!reloc2.scattered ? (Twine(", r2_symbolnum=") - + Twine(reloc2.symbol)) - : (Twine(", r2_scattered=1, r2_value=") - + Twine(reloc2.value))) - + ")" ); + return handleErrors(std::move(relocErr), + [&](std::unique_ptr<GenericError> GE) { + return llvm::make_error<GenericError>( + Twine("bad relocation (") + GE->getMessage() + + ") in section " + + section.segmentName + "/" + section.sectionName + + " (r1_address=" + Twine::utohexstr(reloc.offset) + + ", r1_type=" + Twine(reloc.type) + + ", r1_extern=" + Twine(reloc.isExtern) + + ", r1_length=" + Twine((int)reloc.length) + + ", r1_pcrel=" + Twine(reloc.pcRel) + + (!reloc.scattered ? (Twine(", r1_symbolnum=") + + Twine(reloc.symbol)) + : (Twine(", r1_scattered=1, r1_value=") + + Twine(reloc.value))) + + ")" + + ", (r2_address=" + Twine::utohexstr(reloc2.offset) + + ", r2_type=" + Twine(reloc2.type) + + ", r2_extern=" + Twine(reloc2.isExtern) + + ", r2_length=" + Twine((int)reloc2.length) + + ", r2_pcrel=" + Twine(reloc2.pcRel) + + (!reloc2.scattered ? (Twine(", r2_symbolnum=") + + Twine(reloc2.symbol)) + : (Twine(", r2_scattered=1, r2_value=") + + Twine(reloc2.value))) + + ")" ); + }); } } else { // Use ArchHandler to convert relocation record into information // needed to instantiate an lld::Reference object. - relocErr = handler.getReferenceInfo( + auto relocErr = handler.getReferenceInfo( reloc, inAtom, offsetInAtom, fixupAddress, isBig, atomByAddr, atomBySymbol, &kind, &target, &addend); if (relocErr) { - return make_dynamic_error_code( - Twine("bad relocation (") + relocErr.message() - + ") in section " - + section.segmentName + "/" + section.sectionName - + " (r_address=" + Twine::utohexstr(reloc.offset) - + ", r_type=" + Twine(reloc.type) - + ", r_extern=" + Twine(reloc.isExtern) - + ", r_length=" + Twine((int)reloc.length) - + ", r_pcrel=" + Twine(reloc.pcRel) - + (!reloc.scattered ? (Twine(", r_symbolnum=") + Twine(reloc.symbol)) - : (Twine(", r_scattered=1, r_value=") - + Twine(reloc.value))) - + ")" ); + return handleErrors(std::move(relocErr), + [&](std::unique_ptr<GenericError> GE) { + return llvm::make_error<GenericError>( + Twine("bad relocation (") + GE->getMessage() + + ") in section " + + section.segmentName + "/" + section.sectionName + + " (r_address=" + Twine::utohexstr(reloc.offset) + + ", r_type=" + Twine(reloc.type) + + ", r_extern=" + Twine(reloc.isExtern) + + ", r_length=" + Twine((int)reloc.length) + + ", r_pcrel=" + Twine(reloc.pcRel) + + (!reloc.scattered ? (Twine(", r_symbolnum=") + Twine(reloc.symbol)) + : (Twine(", r_scattered=1, r_value=") + + Twine(reloc.value))) + + ")" ); + }); } } // Instantiate an lld::Reference object and add to its atom. - inAtom->addReference(offsetInAtom, kind, target, addend, - handler.kindArch()); + inAtom->addReference(Reference::KindNamespace::mach_o, + handler.kindArch(), + kind, offsetInAtom, target, addend); } - return std::error_code(); + return llvm::Error(); } bool isDebugInfoSection(const Section §ion) { @@ -684,44 +697,81 @@ static int64_t readSPtr(bool is64, bool isBig, const uint8_t *addr) { struct CIEInfo { bool _augmentationDataPresent = false; - bool _mayHaveLSDA = false; + bool _mayHaveEH = false; + uint32_t _offsetOfLSDA = ~0U; + uint32_t _offsetOfPersonality = ~0U; + uint32_t _offsetOfFDEPointerEncoding = ~0U; + uint32_t _augmentationDataLength = ~0U; }; typedef llvm::DenseMap<const MachODefinedAtom*, CIEInfo> CIEInfoMap; -static std::error_code processAugmentationString(const uint8_t *augStr, - CIEInfo &cieInfo, - unsigned *len = nullptr) { +static llvm::Error processAugmentationString(const uint8_t *augStr, + CIEInfo &cieInfo, + unsigned &len) { if (augStr[0] == '\0') { - if (len) - *len = 1; - return std::error_code(); + len = 1; + return llvm::Error(); } if (augStr[0] != 'z') - return make_dynamic_error_code("expected 'z' at start of augmentation " - "string"); + return llvm::make_error<GenericError>("expected 'z' at start of " + "augmentation string"); cieInfo._augmentationDataPresent = true; uint64_t idx = 1; + uint32_t offsetInAugmentationData = 0; while (augStr[idx] != '\0') { if (augStr[idx] == 'L') { - cieInfo._mayHaveLSDA = true; + cieInfo._offsetOfLSDA = offsetInAugmentationData; + // This adds a single byte to the augmentation data. + ++offsetInAugmentationData; + ++idx; + continue; + } + if (augStr[idx] == 'P') { + cieInfo._offsetOfPersonality = offsetInAugmentationData; + // This adds a single byte to the augmentation data for the encoding, + // then a number of bytes for the pointer data. + // FIXME: We are assuming 4 is correct here for the pointer size as we + // always currently use delta32ToGOT. + offsetInAugmentationData += 5; ++idx; - } else + continue; + } + if (augStr[idx] == 'R') { + cieInfo._offsetOfFDEPointerEncoding = offsetInAugmentationData; + // This adds a single byte to the augmentation data. + ++offsetInAugmentationData; ++idx; + continue; + } + if (augStr[idx] == 'e') { + if (augStr[idx + 1] != 'h') + return llvm::make_error<GenericError>("expected 'eh' in " + "augmentation string"); + cieInfo._mayHaveEH = true; + idx += 2; + continue; + } + ++idx; } - if (len) - *len = idx + 1; - return std::error_code(); + cieInfo._augmentationDataLength = offsetInAugmentationData; + + len = idx + 1; + return llvm::Error(); } -static std::error_code processCIE(const NormalizedFile &normalizedFile, - MachODefinedAtom *atom, - CIEInfoMap &cieInfos) { +static llvm::Error processCIE(const NormalizedFile &normalizedFile, + MachOFile &file, + mach_o::ArchHandler &handler, + const Section *ehFrameSection, + MachODefinedAtom *atom, + uint64_t offset, + CIEInfoMap &cieInfos) { const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch); const uint8_t *frameData = atom->rawContent().data(); @@ -734,31 +784,170 @@ static std::error_code processCIE(const NormalizedFile &normalizedFile, uint64_t versionField = cieIDField + sizeof(uint32_t); uint64_t augmentationStringField = versionField + sizeof(uint8_t); + unsigned augmentationStringLength = 0; if (auto err = processAugmentationString(frameData + augmentationStringField, - cieInfo)) + cieInfo, augmentationStringLength)) return err; + if (cieInfo._offsetOfPersonality != ~0U) { + // If we have augmentation data for the personality function, then we may + // need to implicitly generate its relocation. + + // Parse the EH Data field which is pointer sized. + uint64_t EHDataField = augmentationStringField + augmentationStringLength; + const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch); + unsigned EHDataFieldSize = (cieInfo._mayHaveEH ? (is64 ? 8 : 4) : 0); + + // Parse Code Align Factor which is a ULEB128. + uint64_t CodeAlignField = EHDataField + EHDataFieldSize; + unsigned lengthFieldSize = 0; + llvm::decodeULEB128(frameData + CodeAlignField, &lengthFieldSize); + + // Parse Data Align Factor which is a SLEB128. + uint64_t DataAlignField = CodeAlignField + lengthFieldSize; + llvm::decodeSLEB128(frameData + DataAlignField, &lengthFieldSize); + + // Parse Return Address Register which is a byte. + uint64_t ReturnAddressField = DataAlignField + lengthFieldSize; + + // Parse the augmentation length which is a ULEB128. + uint64_t AugmentationLengthField = ReturnAddressField + 1; + uint64_t AugmentationLength = + llvm::decodeULEB128(frameData + AugmentationLengthField, + &lengthFieldSize); + + if (AugmentationLength != cieInfo._augmentationDataLength) + return llvm::make_error<GenericError>("CIE augmentation data length " + "mismatch"); + + // Get the start address of the augmentation data. + uint64_t AugmentationDataField = AugmentationLengthField + lengthFieldSize; + + // Parse the personality function from the augmentation data. + uint64_t PersonalityField = + AugmentationDataField + cieInfo._offsetOfPersonality; + + // Parse the personality encoding. + // FIXME: Verify that this is a 32-bit pcrel offset. + uint64_t PersonalityFunctionField = PersonalityField + 1; + + if (atom->begin() != atom->end()) { + // If we have an explicit relocation, then make sure it matches this + // offset as this is where we'd expect it to be applied to. + DefinedAtom::reference_iterator CurrentRef = atom->begin(); + if (CurrentRef->offsetInAtom() != PersonalityFunctionField) + return llvm::make_error<GenericError>("CIE personality reloc at " + "wrong offset"); + + if (++CurrentRef != atom->end()) + return llvm::make_error<GenericError>("CIE contains too many relocs"); + } else { + // Implicitly generate the personality function reloc. It's assumed to + // be a delta32 offset to a GOT entry. + // FIXME: Parse the encoding and check this. + int32_t funcDelta = read32(frameData + PersonalityFunctionField, isBig); + uint64_t funcAddress = ehFrameSection->address + offset + + PersonalityFunctionField; + funcAddress += funcDelta; + + const MachODefinedAtom *func = nullptr; + Reference::Addend addend; + func = findAtomCoveringAddress(normalizedFile, file, funcAddress, + &addend); + atom->addReference(Reference::KindNamespace::mach_o, handler.kindArch(), + handler.unwindRefToPersonalityFunctionKind(), + PersonalityFunctionField, func, addend); + } + } else if (atom->begin() != atom->end()) { + // Otherwise, we expect there to be no relocations in this atom as the only + // relocation would have been to the personality function. + return llvm::make_error<GenericError>("unexpected relocation in CIE"); + } + + cieInfos[atom] = std::move(cieInfo); - return std::error_code(); + return llvm::Error(); } -static std::error_code processFDE(const NormalizedFile &normalizedFile, - MachOFile &file, - mach_o::ArchHandler &handler, - const Section *ehFrameSection, - MachODefinedAtom *atom, - uint64_t offset, - const CIEInfoMap &cieInfos) { +static llvm::Error processFDE(const NormalizedFile &normalizedFile, + MachOFile &file, + mach_o::ArchHandler &handler, + const Section *ehFrameSection, + MachODefinedAtom *atom, + uint64_t offset, + const CIEInfoMap &cieInfos) { const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch); const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch); // Compiler wasn't lazy and actually told us what it meant. + // Unfortunately, the compiler may not have generated references for all of + // [cie, func, lsda] and so we still need to parse the FDE and add references + // for any the compiler didn't generate. if (atom->begin() != atom->end()) - return std::error_code(); + atom->sortReferences(); + + DefinedAtom::reference_iterator CurrentRef = atom->begin(); + + // This helper returns the reference (if one exists) at the offset we are + // currently processing. It automatically increments the ref iterator if we + // do return a ref, and throws an error if we pass over a ref without + // comsuming it. + auto currentRefGetter = [&CurrentRef, + &atom](uint64_t Offset)->const Reference* { + // If there are no more refs found, then we are done. + if (CurrentRef == atom->end()) + return nullptr; + + const Reference *Ref = *CurrentRef; + + // If we haven't reached the offset for this reference, then return that + // we don't yet have a reference to process. + if (Offset < Ref->offsetInAtom()) + return nullptr; + + // If the offset is equal, then we want to process this ref. + if (Offset == Ref->offsetInAtom()) { + ++CurrentRef; + return Ref; + } + + // The current ref is at an offset which is earlier than the current + // offset, then we failed to consume it when we should have. In this case + // throw an error. + llvm::report_fatal_error("Skipped reference when processing FDE"); + }; + + // Helper to either get the reference at this current location, and verify + // that it is of the expected type, or add a reference of that type. + // Returns the reference target. + auto verifyOrAddReference = [&](uint64_t targetAddress, + Reference::KindValue refKind, + uint64_t refAddress, + bool allowsAddend)->const Atom* { + if (auto *ref = currentRefGetter(refAddress)) { + // The compiler already emitted a relocation for the CIE ref. This should + // have been converted to the correct type of reference in + // get[Pair]ReferenceInfo(). + assert(ref->kindValue() == refKind && + "Incorrect EHFrame reference kind"); + return ref->target(); + } + Reference::Addend addend; + auto *target = findAtomCoveringAddress(normalizedFile, file, + targetAddress, &addend); + atom->addReference(Reference::KindNamespace::mach_o, handler.kindArch(), + refKind, refAddress, target, addend); + + if (!allowsAddend) + assert(!addend && "EHFrame reference cannot have addend"); + return target; + }; + + const uint8_t *startFrameData = atom->rawContent().data(); + const uint8_t *frameData = startFrameData; - const uint8_t *frameData = atom->rawContent().data(); uint32_t size = read32(frameData, isBig); uint64_t cieFieldInFDE = size == 0xffffffffU ? sizeof(uint32_t) + sizeof(uint64_t) @@ -770,13 +959,11 @@ static std::error_code processFDE(const NormalizedFile &normalizedFile, uint64_t cieAddress = ehFrameSection->address + offset + cieFieldInFDE; cieAddress -= cieDelta; - Reference::Addend addend; - const MachODefinedAtom *cie = - findAtomCoveringAddress(normalizedFile, file, cieAddress, &addend); - atom->addReference(cieFieldInFDE, handler.unwindRefToCIEKind(), cie, - addend, handler.kindArch()); - - assert(cie && cie->contentType() == DefinedAtom::typeCFI && !addend && + auto *cieRefTarget = verifyOrAddReference(cieAddress, + handler.unwindRefToCIEKind(), + cieFieldInFDE, false); + const MachODefinedAtom *cie = dyn_cast<MachODefinedAtom>(cieRefTarget); + assert(cie && cie->contentType() == DefinedAtom::typeCFI && "FDE's CIE field does not point at the start of a CIE."); const CIEInfo &cieInfo = cieInfos.find(cie)->second; @@ -792,10 +979,9 @@ static std::error_code processFDE(const NormalizedFile &normalizedFile, uint64_t rangeStart = ehFrameSection->address + offset + rangeFieldInFDE; rangeStart += functionFromFDE; - const Atom *func = - findAtomCoveringAddress(normalizedFile, file, rangeStart, &addend); - atom->addReference(rangeFieldInFDE, handler.unwindRefToFunctionKind(), - func, addend, handler.kindArch()); + verifyOrAddReference(rangeStart, + handler.unwindRefToFunctionKind(), + rangeFieldInFDE, true); // Handle the augmentation data if there is any. if (cieInfo._augmentationDataPresent) { @@ -807,7 +993,7 @@ static std::error_code processFDE(const NormalizedFile &normalizedFile, llvm::decodeULEB128(frameData + augmentationDataLengthFieldInFDE, &lengthFieldSize); - if (cieInfo._mayHaveLSDA && augmentationDataLength > 0) { + if (cieInfo._offsetOfLSDA != ~0U && augmentationDataLength > 0) { // Look at the augmentation data field. uint64_t augmentationDataFieldInFDE = @@ -818,20 +1004,19 @@ static std::error_code processFDE(const NormalizedFile &normalizedFile, uint64_t lsdaStart = ehFrameSection->address + offset + augmentationDataFieldInFDE + lsdaFromFDE; - const Atom *lsda = - findAtomCoveringAddress(normalizedFile, file, lsdaStart, &addend); - atom->addReference(augmentationDataFieldInFDE, - handler.unwindRefToFunctionKind(), - lsda, addend, handler.kindArch()); + + verifyOrAddReference(lsdaStart, + handler.unwindRefToFunctionKind(), + augmentationDataFieldInFDE, true); } } - return std::error_code(); + return llvm::Error(); } -std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile, - MachOFile &file, - mach_o::ArchHandler &handler) { +llvm::Error addEHFrameReferences(const NormalizedFile &normalizedFile, + MachOFile &file, + mach_o::ArchHandler &handler) { const Section *ehFrameSection = nullptr; for (auto §ion : normalizedFile.sections) @@ -843,9 +1028,9 @@ std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile, // No __eh_frame so nothing to do. if (!ehFrameSection) - return std::error_code(); + return llvm::Error(); - std::error_code ehFrameErr; + llvm::Error ehFrameErr; CIEInfoMap cieInfos; file.eachAtomInSection(*ehFrameSection, @@ -858,7 +1043,8 @@ std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile, const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch); if (ArchHandler::isDwarfCIE(isBig, atom)) - ehFrameErr = processCIE(normalizedFile, atom, cieInfos); + ehFrameErr = processCIE(normalizedFile, file, handler, ehFrameSection, + atom, offset, cieInfos); else ehFrameErr = processFDE(normalizedFile, file, handler, ehFrameSection, atom, offset, cieInfos); @@ -867,24 +1053,66 @@ std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile, return ehFrameErr; } +llvm::Error parseObjCImageInfo(const Section §, + const NormalizedFile &normalizedFile, + MachOFile &file) { + + // struct objc_image_info { + // uint32_t version; // initially 0 + // uint32_t flags; + // }; + + ArrayRef<uint8_t> content = sect.content; + if (content.size() != 8) + return llvm::make_error<GenericError>(sect.segmentName + "/" + + sect.sectionName + + " in file " + file.path() + + " should be 8 bytes in size"); + + const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch); + uint32_t version = read32(content.data(), isBig); + if (version) + return llvm::make_error<GenericError>(sect.segmentName + "/" + + sect.sectionName + + " in file " + file.path() + + " should have version=0"); + + uint32_t flags = read32(content.data() + 4, isBig); + if (flags & (MachOLinkingContext::objc_supports_gc | + MachOLinkingContext::objc_gc_only)) + return llvm::make_error<GenericError>(sect.segmentName + "/" + + sect.sectionName + + " in file " + file.path() + + " uses GC. This is not supported"); + + if (flags & MachOLinkingContext::objc_retainReleaseForSimulator) + file.setObjcConstraint(MachOLinkingContext::objc_retainReleaseForSimulator); + else + file.setObjcConstraint(MachOLinkingContext::objc_retainRelease); + + file.setSwiftVersion((flags >> 8) & 0xFF); + + return llvm::Error(); +} + /// Converts normalized mach-o file into an lld::File and lld::Atoms. -ErrorOr<std::unique_ptr<lld::File>> +llvm::Expected<std::unique_ptr<lld::File>> objectToAtoms(const NormalizedFile &normalizedFile, StringRef path, bool copyRefs) { std::unique_ptr<MachOFile> file(new MachOFile(path)); - if (std::error_code ec = normalizedObjectToAtoms( - file.get(), normalizedFile, copyRefs)) - return ec; + if (auto ec = normalizedObjectToAtoms(file.get(), normalizedFile, copyRefs)) + return std::move(ec); return std::unique_ptr<File>(std::move(file)); } -ErrorOr<std::unique_ptr<lld::File>> +llvm::Expected<std::unique_ptr<lld::File>> dylibToAtoms(const NormalizedFile &normalizedFile, StringRef path, bool copyRefs) { // Instantiate SharedLibraryFile object. std::unique_ptr<MachODylibFile> file(new MachODylibFile(path)); - normalizedDylibToAtoms(file.get(), normalizedFile, copyRefs); + if (auto ec = normalizedDylibToAtoms(file.get(), normalizedFile, copyRefs)) + return std::move(ec); return std::unique_ptr<File>(std::move(file)); } @@ -892,7 +1120,12 @@ dylibToAtoms(const NormalizedFile &normalizedFile, StringRef path, namespace normalized { -std::error_code +static bool isObjCImageInfo(const Section §) { + return (sect.segmentName == "__OBJC" && sect.sectionName == "__image_info") || + (sect.segmentName == "__DATA" && sect.sectionName == "__objc_imageinfo"); +} + +llvm::Error normalizedObjectToAtoms(MachOFile *file, const NormalizedFile &normalizedFile, bool copyRefs) { @@ -905,12 +1138,23 @@ normalizedObjectToAtoms(MachOFile *file, DEBUG(llvm::dbgs() << "Creating atoms: "; sect.dump()); if (isDebugInfoSection(sect)) continue; + + + // If the file contains an objc_image_info struct, then we should parse the + // ObjC flags and Swift version. + if (isObjCImageInfo(sect)) { + if (auto ec = parseObjCImageInfo(sect, normalizedFile, *file)) + return ec; + // We then skip adding atoms for this section as we use the ObjCPass to + // re-emit this data after it has been aggregated for all files. + continue; + } + bool customSectionName; DefinedAtom::ContentType atomType = atomTypeFromSection(sect, customSectionName); - if (std::error_code ec = - processSection(atomType, sect, customSectionName, normalizedFile, - *file, scatterable, copyRefs)) + if (auto ec = processSection(atomType, sect, customSectionName, + normalizedFile, *file, scatterable, copyRefs)) return ec; } // Create atoms from undefined symbols. @@ -931,9 +1175,9 @@ normalizedObjectToAtoms(MachOFile *file, for (auto § : normalizedFile.sections) { if (isDebugInfoSection(sect)) continue; - if (std::error_code ec = convertRelocs(sect, normalizedFile, scatterable, - *file, *handler)) - return ec; + if (llvm::Error ec = convertRelocs(sect, normalizedFile, scatterable, + *file, *handler)) + return ec; } // Add additional arch-specific References @@ -945,7 +1189,7 @@ normalizedObjectToAtoms(MachOFile *file, // providing unwind info for) and itself (FDE -> CIE). These aren't // represented in the relocations on some architectures, so we have to add // them back in manually there. - if (std::error_code ec = addEHFrameReferences(normalizedFile, *file, *handler)) + if (auto ec = addEHFrameReferences(normalizedFile, *file, *handler)) return ec; // Process mach-o data-in-code regions array. That information is encoded in @@ -955,25 +1199,26 @@ normalizedObjectToAtoms(MachOFile *file, ++nextIndex; const Section* s = findSectionCoveringAddress(normalizedFile, entry.offset); if (!s) { - return make_dynamic_error_code(Twine("LC_DATA_IN_CODE address (" - + Twine(entry.offset) - + ") is not in any section")); + return llvm::make_error<GenericError>(Twine("LC_DATA_IN_CODE address (" + + Twine(entry.offset) + + ") is not in any section")); } uint64_t offsetInSect = entry.offset - s->address; uint32_t offsetInAtom; MachODefinedAtom *atom = file->findAtomCoveringAddress(*s, offsetInSect, &offsetInAtom); if (offsetInAtom + entry.length > atom->size()) { - return make_dynamic_error_code(Twine("LC_DATA_IN_CODE entry (offset=" - + Twine(entry.offset) - + ", length=" - + Twine(entry.length) - + ") crosses atom boundary.")); + return llvm::make_error<GenericError>(Twine("LC_DATA_IN_CODE entry " + "(offset=" + + Twine(entry.offset) + + ", length=" + + Twine(entry.length) + + ") crosses atom boundary.")); } // Add reference that marks start of data-in-code. - atom->addReference(offsetInAtom, - handler->dataInCodeTransitionStart(*atom), atom, - entry.kind, handler->kindArch()); + atom->addReference(Reference::KindNamespace::mach_o, handler->kindArch(), + handler->dataInCodeTransitionStart(*atom), + offsetInAtom, atom, entry.kind); // Peek at next entry, if it starts where this one ends, skip ending ref. if (nextIndex < normalizedFile.dataInCode.size()) { @@ -987,19 +1232,26 @@ normalizedObjectToAtoms(MachOFile *file, continue; // Add reference that marks end of data-in-code. - atom->addReference(offsetInAtom+entry.length, - handler->dataInCodeTransitionEnd(*atom), atom, 0, - handler->kindArch()); + atom->addReference(Reference::KindNamespace::mach_o, handler->kindArch(), + handler->dataInCodeTransitionEnd(*atom), + offsetInAtom+entry.length, atom, 0); } + // Cache some attributes on the file for use later. + file->setFlags(normalizedFile.flags); + file->setArch(normalizedFile.arch); + file->setOS(normalizedFile.os); + file->setMinVersion(normalizedFile.minOSverson); + file->setMinVersionLoadCommandKind(normalizedFile.minOSVersionKind); + // Sort references in each atom to their canonical order. for (const DefinedAtom* defAtom : file->defined()) { reinterpret_cast<const SimpleDefinedAtom*>(defAtom)->sortReferences(); } - return std::error_code(); + return llvm::Error(); } -std::error_code +llvm::Error normalizedDylibToAtoms(MachODylibFile *file, const NormalizedFile &normalizedFile, bool copyRefs) { @@ -1027,7 +1279,7 @@ normalizedDylibToAtoms(MachODylibFile *file, if (dep.kind == llvm::MachO::LC_REEXPORT_DYLIB) file->addReExportedDylib(dep.path); } - return std::error_code(); + return llvm::Error(); } void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType, @@ -1058,7 +1310,7 @@ void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType, llvm_unreachable("content type not yet supported"); } -ErrorOr<std::unique_ptr<lld::File>> +llvm::Expected<std::unique_ptr<lld::File>> normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path, bool copyRefs) { switch (normalizedFile.fileType) { diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp index 0b92a68eeae8..66be77173983 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp +++ b/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp @@ -237,6 +237,29 @@ struct ScalarBitSetTraits<SectionAttr> { } }; +/// This is a custom formatter for SectionAlignment. Values are +/// the power to raise by, ie, the n in 2^n. +template <> struct ScalarTraits<SectionAlignment> { + static void output(const SectionAlignment &value, void *ctxt, + raw_ostream &out) { + out << llvm::format("%d", (uint32_t)value); + } + + static StringRef input(StringRef scalar, void *ctxt, + SectionAlignment &value) { + uint32_t alignment; + if (scalar.getAsInteger(0, alignment)) { + return "malformed alignment value"; + } + if (!llvm::isPowerOf2_32(alignment)) + return "alignment must be a power of 2"; + value = alignment; + return StringRef(); // returning empty string means success + } + + static bool mustQuote(StringRef) { return false; } +}; + template <> struct ScalarEnumerationTraits<NListType> { static void enumeration(IO &io, NListType &value) { @@ -276,7 +299,7 @@ struct MappingTraits<Section> { io.mapRequired("section", sect.sectionName); io.mapRequired("type", sect.type); io.mapOptional("attributes", sect.attributes); - io.mapOptional("alignment", sect.alignment, (uint16_t)1); + io.mapOptional("alignment", sect.alignment, (SectionAlignment)1); io.mapRequired("address", sect.address); if (isZeroFillSection(sect.type)) { // S_ZEROFILL sections use "size:" instead of "content:" @@ -311,6 +334,8 @@ struct MappingTraits<Section> { NormalizedFile *file = info->_normalizeMachOFile; assert(file != nullptr); size_t size = _normalizedContent.size(); + if (!size) + return None; uint8_t *bytes = file->ownedAllocations.Allocate<uint8_t>(size); std::copy(_normalizedContent.begin(), _normalizedContent.end(), bytes); return makeArrayRef(bytes, size); @@ -504,10 +529,11 @@ struct ScalarTraits<VMProtect> { template <> struct MappingTraits<Segment> { static void mapping(IO &io, Segment& seg) { - io.mapRequired("name", seg.name); - io.mapRequired("address", seg.address); - io.mapRequired("size", seg.size); - io.mapRequired("access", seg.access); + io.mapRequired("name", seg.name); + io.mapRequired("address", seg.address); + io.mapRequired("size", seg.size); + io.mapRequired("init-access", seg.init_access); + io.mapRequired("max-access", seg.max_access); } }; @@ -524,6 +550,14 @@ struct ScalarEnumerationTraits<LoadCommandType> { llvm::MachO::LC_LOAD_UPWARD_DYLIB); io.enumCase(value, "LC_LAZY_LOAD_DYLIB", llvm::MachO::LC_LAZY_LOAD_DYLIB); + io.enumCase(value, "LC_VERSION_MIN_MACOSX", + llvm::MachO::LC_VERSION_MIN_MACOSX); + io.enumCase(value, "LC_VERSION_MIN_IPHONEOS", + llvm::MachO::LC_VERSION_MIN_IPHONEOS); + io.enumCase(value, "LC_VERSION_MIN_TVOS", + llvm::MachO::LC_VERSION_MIN_TVOS); + io.enumCase(value, "LC_VERSION_MIN_WATCHOS", + llvm::MachO::LC_VERSION_MIN_WATCHOS); } }; @@ -692,6 +726,7 @@ struct MappingTraits<NormalizedFile> { io.mapOptional("source-version", file.sourceVersion, Hex64(0)); io.mapOptional("OS", file.os); io.mapOptional("min-os-version", file.minOSverson, PackedVersion(0)); + io.mapOptional("min-os-version-kind", file.minOSVersionKind, (LoadCommandType)0); io.mapOptional("sdk-version", file.sdkVersion, PackedVersion(0)); io.mapOptional("segments", file.segments); io.mapOptional("sections", file.sections); @@ -731,8 +766,21 @@ bool MachOYamlIOTaggedDocumentHandler::handledDocTag(llvm::yaml::IO &io, info->_normalizeMachOFile = &nf; MappingTraits<NormalizedFile>::mapping(io, nf); // Step 2: parse normalized mach-o struct into atoms. - ErrorOr<std::unique_ptr<lld::File>> foe = normalizedToAtoms(nf, info->_path, - true); + auto fileOrError = normalizedToAtoms(nf, info->_path, true); + + // Check that we parsed successfully. + if (!fileOrError) { + std::string buffer; + llvm::raw_string_ostream stream(buffer); + handleAllErrors(fileOrError.takeError(), + [&](const llvm::ErrorInfoBase &EI) { + EI.log(stream); + stream << "\n"; + }); + io.setError(stream.str()); + return false; + } + if (nf.arch != _arch) { io.setError(Twine("file is wrong architecture. Expected (" + MachOLinkingContext::nameFromArch(_arch) @@ -742,16 +790,8 @@ bool MachOYamlIOTaggedDocumentHandler::handledDocTag(llvm::yaml::IO &io, return false; } info->_normalizeMachOFile = nullptr; - - if (foe) { - // Transfer ownership to "out" File parameter. - std::unique_ptr<lld::File> f = std::move(foe.get()); - file = f.release(); - return true; - } else { - io.setError(foe.getError().message()); - return false; - } + file = fileOrError->release(); + return true; } @@ -759,7 +799,7 @@ bool MachOYamlIOTaggedDocumentHandler::handledDocTag(llvm::yaml::IO &io, namespace normalized { /// Parses a yaml encoded mach-o file to produce an in-memory normalized view. -ErrorOr<std::unique_ptr<NormalizedFile>> +llvm::Expected<std::unique_ptr<NormalizedFile>> readYaml(std::unique_ptr<MemoryBuffer> &mb) { // Make empty NormalizedFile. std::unique_ptr<NormalizedFile> f(new NormalizedFile()); @@ -773,8 +813,9 @@ readYaml(std::unique_ptr<MemoryBuffer> &mb) { yin >> *f; // Return error if there were parsing problems. - if (yin.error()) - return make_error_code(lld::YamlReaderError::illegal_value); + if (auto ec = yin.error()) + return llvm::make_error<GenericError>(Twine("YAML parsing error: ") + + ec.message()); // Hand ownership of instantiated NormalizedFile to caller. return std::move(f); diff --git a/lib/ReaderWriter/MachO/MachOPasses.h b/lib/ReaderWriter/MachO/MachOPasses.h index a73785418d5f..cd01d4aa2c93 100644 --- a/lib/ReaderWriter/MachO/MachOPasses.h +++ b/lib/ReaderWriter/MachO/MachOPasses.h @@ -21,6 +21,7 @@ void addStubsPass(PassManager &pm, const MachOLinkingContext &ctx); void addGOTPass(PassManager &pm, const MachOLinkingContext &ctx); void addTLVPass(PassManager &pm, const MachOLinkingContext &ctx); void addCompactUnwindPass(PassManager &pm, const MachOLinkingContext &ctx); +void addObjCPass(PassManager &pm, const MachOLinkingContext &ctx); void addShimPass(PassManager &pm, const MachOLinkingContext &ctx); } // namespace mach_o diff --git a/lib/ReaderWriter/MachO/ObjCPass.cpp b/lib/ReaderWriter/MachO/ObjCPass.cpp new file mode 100644 index 000000000000..ba24b3fecdf4 --- /dev/null +++ b/lib/ReaderWriter/MachO/ObjCPass.cpp @@ -0,0 +1,128 @@ +//===- lib/ReaderWriter/MachO/ObjCPass.cpp -------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +//===----------------------------------------------------------------------===// + +#include "ArchHandler.h" +#include "File.h" +#include "MachOPasses.h" +#include "lld/Core/DefinedAtom.h" +#include "lld/Core/File.h" +#include "lld/Core/LLVM.h" +#include "lld/Core/Reference.h" +#include "lld/Core/Simple.h" +#include "lld/ReaderWriter/MachOLinkingContext.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" + +namespace lld { +namespace mach_o { + +/// +/// ObjC Image Info Atom created by the ObjC pass. +/// +class ObjCImageInfoAtom : public SimpleDefinedAtom { +public: + ObjCImageInfoAtom(const File &file, + MachOLinkingContext::ObjCConstraint objCConstraint, + uint32_t swiftVersion) + : SimpleDefinedAtom(file) { + + Data.info.version = 0; + + switch (objCConstraint) { + case MachOLinkingContext::objc_unknown: + llvm_unreachable("Shouldn't run the objc pass without a constraint"); + case MachOLinkingContext::objc_supports_gc: + case MachOLinkingContext::objc_gc_only: + llvm_unreachable("GC is not supported"); + case MachOLinkingContext::objc_retainReleaseForSimulator: + // The retain/release for simulator flag is already the correct + // encoded value for the data so just set it here. + Data.info.flags = (uint32_t)objCConstraint; + break; + case MachOLinkingContext::objc_retainRelease: + // We don't need to encode this flag, so just leave the flags as 0. + Data.info.flags = 0; + break; + } + + Data.info.flags |= (swiftVersion << 8); + } + + ~ObjCImageInfoAtom() override = default; + + ContentType contentType() const override { + return DefinedAtom::typeObjCImageInfo; + } + + Alignment alignment() const override { + return 4; + } + + uint64_t size() const override { + return 8; + } + + ContentPermissions permissions() const override { + return DefinedAtom::permR__; + } + + ArrayRef<uint8_t> rawContent() const override { + return llvm::makeArrayRef(Data.bytes, size()); + } + +private: + + struct objc_image_info { + uint32_t version; + uint32_t flags; + }; + + union { + objc_image_info info; + uint8_t bytes[8]; + } Data; +}; + +class ObjCPass : public Pass { +public: + ObjCPass(const MachOLinkingContext &context) + : _ctx(context), + _file(*_ctx.make_file<MachOFile>("<mach-o objc pass>")) { + _file.setOrdinal(_ctx.getNextOrdinalAndIncrement()); + } + + llvm::Error perform(SimpleFile &mergedFile) override { + // Add the image info. + mergedFile.addAtom(*getImageInfo()); + + return llvm::Error(); + } + +private: + + const DefinedAtom* getImageInfo() { + return new (_file.allocator()) ObjCImageInfoAtom(_file, + _ctx.objcConstraint(), + _ctx.swiftVersion()); + } + + const MachOLinkingContext &_ctx; + MachOFile &_file; +}; + + + +void addObjCPass(PassManager &pm, const MachOLinkingContext &ctx) { + pm.add(llvm::make_unique<ObjCPass>(ctx)); +} + +} // end namespace mach_o +} // end namespace lld diff --git a/lib/ReaderWriter/MachO/SectCreateFile.h b/lib/ReaderWriter/MachO/SectCreateFile.h index 2e6e97c5433f..49e65f63151d 100644 --- a/lib/ReaderWriter/MachO/SectCreateFile.h +++ b/lib/ReaderWriter/MachO/SectCreateFile.h @@ -31,6 +31,8 @@ public: _combinedName((segName + "/" + sectName).str()), _content(std::move(content)) {} + ~SectCreateAtom() override = default; + uint64_t size() const override { return _content->getBufferSize(); } Scope scope() const override { return scopeGlobal; } @@ -59,7 +61,7 @@ public: std::unique_ptr<MemoryBuffer> _content; }; - SectCreateFile() : File("sectcreate", kindObject) {} + SectCreateFile() : File("sectcreate", kindSectCreateObject) {} void addSection(StringRef seg, StringRef sect, std::unique_ptr<MemoryBuffer> content) { @@ -67,22 +69,29 @@ public: new (allocator()) SectCreateAtom(*this, seg, sect, std::move(content))); } - const AtomVector<DefinedAtom> &defined() const override { + const AtomRange<DefinedAtom> defined() const override { return _definedAtoms; } - const AtomVector<UndefinedAtom> &undefined() const override { + const AtomRange<UndefinedAtom> undefined() const override { return _noUndefinedAtoms; } - const AtomVector<SharedLibraryAtom> &sharedLibrary() const override { + const AtomRange<SharedLibraryAtom> sharedLibrary() const override { return _noSharedLibraryAtoms; } - const AtomVector<AbsoluteAtom> &absolute() const override { + const AtomRange<AbsoluteAtom> absolute() const override { return _noAbsoluteAtoms; } + void clearAtoms() override { + _definedAtoms.clear(); + _noUndefinedAtoms.clear(); + _noSharedLibraryAtoms.clear(); + _noAbsoluteAtoms.clear(); + } + private: AtomVector<DefinedAtom> _definedAtoms; }; diff --git a/lib/ReaderWriter/MachO/ShimPass.cpp b/lib/ReaderWriter/MachO/ShimPass.cpp index df29e37c183b..cd5367146658 100644 --- a/lib/ReaderWriter/MachO/ShimPass.cpp +++ b/lib/ReaderWriter/MachO/ShimPass.cpp @@ -42,9 +42,12 @@ class ShimPass : public Pass { public: ShimPass(const MachOLinkingContext &context) : _ctx(context), _archHandler(_ctx.archHandler()), - _stubInfo(_archHandler.stubInfo()), _file("<mach-o shim pass>") {} + _stubInfo(_archHandler.stubInfo()), + _file(*_ctx.make_file<MachOFile>("<mach-o shim pass>")) { + _file.setOrdinal(_ctx.getNextOrdinalAndIncrement()); + } - std::error_code perform(SimpleFile &mergedFile) override { + llvm::Error perform(SimpleFile &mergedFile) override { // Scan all references in all atoms. for (const DefinedAtom *atom : mergedFile.defined()) { for (const Reference *ref : *atom) { @@ -63,7 +66,7 @@ public: } // Exit early if no shims needed. if (_targetToShim.empty()) - return std::error_code(); + return llvm::Error(); // Sort shim atoms so the layout order is stable. std::vector<const DefinedAtom *> shims; @@ -80,7 +83,7 @@ public: for (const DefinedAtom *shim : shims) mergedFile.addAtom(*shim); - return std::error_code(); + return llvm::Error(); } private: @@ -112,7 +115,7 @@ private: const MachOLinkingContext &_ctx; mach_o::ArchHandler &_archHandler; const ArchHandler::StubInfo &_stubInfo; - MachOFile _file; + MachOFile &_file; llvm::DenseMap<const Atom*, const DefinedAtom*> _targetToShim; }; diff --git a/lib/ReaderWriter/MachO/StubsPass.cpp b/lib/ReaderWriter/MachO/StubsPass.cpp index 1f61256a5b79..d53b78b24d14 100644 --- a/lib/ReaderWriter/MachO/StubsPass.cpp +++ b/lib/ReaderWriter/MachO/StubsPass.cpp @@ -37,6 +37,8 @@ public: LazyPointerAtom(const File &file, bool is64) : SimpleDefinedAtom(file), _is64(is64) { } + ~LazyPointerAtom() override = default; + ContentType contentType() const override { return DefinedAtom::typeLazyPointer; } @@ -68,11 +70,13 @@ private: // class NonLazyPointerAtom : public SimpleDefinedAtom { public: - NonLazyPointerAtom(const File &file, bool is64) - : SimpleDefinedAtom(file), _is64(is64) { } + NonLazyPointerAtom(const File &file, bool is64, ContentType contentType) + : SimpleDefinedAtom(file), _is64(is64), _contentType(contentType) { } + + ~NonLazyPointerAtom() override = default; ContentType contentType() const override { - return DefinedAtom::typeGOT; + return _contentType; } Alignment alignment() const override { @@ -95,6 +99,7 @@ public: private: const bool _is64; + const ContentType _contentType; }; // @@ -105,6 +110,8 @@ public: StubAtom(const File &file, const ArchHandler::StubInfo &stubInfo) : SimpleDefinedAtom(file), _stubInfo(stubInfo){ } + ~StubAtom() override = default; + ContentType contentType() const override { return DefinedAtom::typeStub; } @@ -137,6 +144,8 @@ public: StubHelperAtom(const File &file, const ArchHandler::StubInfo &stubInfo) : SimpleDefinedAtom(file), _stubInfo(stubInfo) { } + ~StubHelperAtom() override = default; + ContentType contentType() const override { return DefinedAtom::typeStubHelper; } @@ -170,12 +179,14 @@ public: StubHelperCommonAtom(const File &file, const ArchHandler::StubInfo &stubInfo) : SimpleDefinedAtom(file), _stubInfo(stubInfo) { } + ~StubHelperCommonAtom() override = default; + ContentType contentType() const override { return DefinedAtom::typeStubHelper; } Alignment alignment() const override { - return 1 << _stubInfo.codeAlignment; + return 1 << _stubInfo.stubHelperCommonAlignment; } uint64_t size() const override { @@ -199,12 +210,15 @@ class StubsPass : public Pass { public: StubsPass(const MachOLinkingContext &context) : _ctx(context), _archHandler(_ctx.archHandler()), - _stubInfo(_archHandler.stubInfo()), _file("<mach-o Stubs pass>") {} + _stubInfo(_archHandler.stubInfo()), + _file(*_ctx.make_file<MachOFile>("<mach-o Stubs pass>")) { + _file.setOrdinal(_ctx.getNextOrdinalAndIncrement()); + } - std::error_code perform(SimpleFile &mergedFile) override { + llvm::Error perform(SimpleFile &mergedFile) override { // Skip this pass if output format uses text relocations instead of stubs. if (!this->noTextRelocs()) - return std::error_code(); + return llvm::Error(); // Scan all references in all atoms. for (const DefinedAtom *atom : mergedFile.defined()) { @@ -231,15 +245,17 @@ public: // Exit early if no stubs needed. if (_targetToUses.empty()) - return std::error_code(); + return llvm::Error(); // First add help-common and GOT slots used by lazy binding. SimpleDefinedAtom *helperCommonAtom = new (_file.allocator()) StubHelperCommonAtom(_file, _stubInfo); SimpleDefinedAtom *helperCacheNLPAtom = - new (_file.allocator()) NonLazyPointerAtom(_file, _ctx.is64Bit()); + new (_file.allocator()) NonLazyPointerAtom(_file, _ctx.is64Bit(), + _stubInfo.stubHelperImageCacheContentType); SimpleDefinedAtom *helperBinderNLPAtom = - new (_file.allocator()) NonLazyPointerAtom(_file, _ctx.is64Bit()); + new (_file.allocator()) NonLazyPointerAtom(_file, _ctx.is64Bit(), + _stubInfo.stubHelperImageCacheContentType); addReference(helperCommonAtom, _stubInfo.stubHelperCommonReferenceToCache, helperCacheNLPAtom); addOptReference( @@ -307,7 +323,7 @@ public: lazyOffset += target->name().size() + 12; } - return std::error_code(); + return llvm::Error(); } private: @@ -351,7 +367,7 @@ private: const MachOLinkingContext &_ctx; mach_o::ArchHandler &_archHandler; const ArchHandler::StubInfo &_stubInfo; - MachOFile _file; + MachOFile &_file; TargetToUses _targetToUses; }; diff --git a/lib/ReaderWriter/MachO/TLVPass.cpp b/lib/ReaderWriter/MachO/TLVPass.cpp index aba222edcd27..7a8496c20a4e 100644 --- a/lib/ReaderWriter/MachO/TLVPass.cpp +++ b/lib/ReaderWriter/MachO/TLVPass.cpp @@ -30,6 +30,8 @@ public: TLVPEntryAtom(const File &file, bool is64, StringRef name) : SimpleDefinedAtom(file), _is64(is64), _name(name) {} + ~TLVPEntryAtom() override = default; + ContentType contentType() const override { return DefinedAtom::typeTLVInitializerPtr; } @@ -65,10 +67,12 @@ class TLVPass : public Pass { public: TLVPass(const MachOLinkingContext &context) : _ctx(context), _archHandler(_ctx.archHandler()), - _file("<mach-o TLV Pass>") {} + _file(*_ctx.make_file<MachOFile>("<mach-o TLV pass>")) { + _file.setOrdinal(_ctx.getNextOrdinalAndIncrement()); + } private: - std::error_code perform(SimpleFile &mergedFile) override { + llvm::Error perform(SimpleFile &mergedFile) override { bool allowTLV = _ctx.minOS("10.7", "1.0"); for (const DefinedAtom *atom : mergedFile.defined()) { @@ -77,7 +81,7 @@ private: continue; if (!allowTLV) - return make_dynamic_error_code( + return llvm::make_error<GenericError>( "targeted OS version does not support use of thread local " "variables in " + atom->name() + " for architecture " + _ctx.archName()); @@ -103,7 +107,7 @@ private: for (const TLVPEntryAtom *slot : entries) mergedFile.addAtom(*slot); - return std::error_code(); + return llvm::Error(); } const DefinedAtom *makeTLVPEntry(const Atom *target) { @@ -124,7 +128,7 @@ private: const MachOLinkingContext &_ctx; mach_o::ArchHandler &_archHandler; - MachOFile _file; + MachOFile &_file; llvm::DenseMap<const Atom*, const TLVPEntryAtom*> _targetToTLVP; }; diff --git a/lib/ReaderWriter/MachO/WriterMachO.cpp b/lib/ReaderWriter/MachO/WriterMachO.cpp index cce0a179608c..f08487f21ac1 100644 --- a/lib/ReaderWriter/MachO/WriterMachO.cpp +++ b/lib/ReaderWriter/MachO/WriterMachO.cpp @@ -28,17 +28,18 @@ class MachOWriter : public Writer { public: MachOWriter(const MachOLinkingContext &ctxt) : _ctx(ctxt) {} - std::error_code writeFile(const lld::File &file, StringRef path) override { + llvm::Error writeFile(const lld::File &file, StringRef path) override { // Construct empty normalized file from atoms. - ErrorOr<std::unique_ptr<NormalizedFile>> nFile = + llvm::Expected<std::unique_ptr<NormalizedFile>> nFile = normalized::normalizedFromAtoms(file, _ctx); - if (std::error_code ec = nFile.getError()) + if (auto ec = nFile.takeError()) return ec; // For testing, write out yaml form of normalized file. if (_ctx.printAtoms()) { std::unique_ptr<Writer> yamlWriter = createWriterYAML(_ctx); - yamlWriter->writeFile(file, "-"); + if (auto ec = yamlWriter->writeFile(file, "-")) + return ec; } // Write normalized file as mach-o binary. diff --git a/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp b/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp index 78c6797b713f..ee2a9ec10883 100644 --- a/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp +++ b/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp @@ -7,30 +7,41 @@ // //===----------------------------------------------------------------------===// +#include "lld/Core/AbsoluteAtom.h" #include "lld/Core/ArchiveLibraryFile.h" +#include "lld/Core/Atom.h" #include "lld/Core/DefinedAtom.h" #include "lld/Core/Error.h" #include "lld/Core/File.h" -#include "lld/Core/LLVM.h" +#include "lld/Core/LinkingContext.h" #include "lld/Core/Reader.h" #include "lld/Core/Reference.h" +#include "lld/Core/SharedLibraryAtom.h" #include "lld/Core/Simple.h" +#include "lld/Core/UndefinedAtom.h" #include "lld/Core/Writer.h" #include "lld/ReaderWriter/YamlContext.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/Support/Allocator.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <cstdint> +#include <cstring> #include <memory> #include <string> #include <system_error> +#include <vector> using llvm::yaml::MappingTraits; using llvm::yaml::ScalarEnumerationTraits; @@ -178,31 +189,10 @@ public: return nullptr; } - /// \brief Lookup a group parent when there is a reference of type - /// kindGroupChild. If there was no group-parent produce an appropriate - /// error. - const lld::Atom *lookupGroupParent(StringRef name) const { - NameToAtom::const_iterator pos = _groupMap.find(name); - if (pos != _groupMap.end()) - return pos->second; - _io.setError(Twine("no such group name: ") + name); - return nullptr; - } - private: typedef llvm::StringMap<const lld::Atom *> NameToAtom; void add(StringRef name, const lld::Atom *atom) { - if (const lld::DefinedAtom *da = dyn_cast<DefinedAtom>(atom)) { - if (da->isGroupParent()) { - if (_groupMap.count(name)) { - _io.setError(Twine("duplicate group name: ") + name); - } else { - _groupMap[name] = atom; - } - return; - } - } if (_nameMap.count(name)) { _io.setError(Twine("duplicate atom name: ") + name); } else { @@ -212,12 +202,11 @@ private: IO &_io; NameToAtom _nameMap; - NameToAtom _groupMap; }; /// Mapping of Atoms. template <typename T> class AtomList { - typedef lld::File::AtomVector<T> Ty; + using Ty = std::vector<OwningAtomPtr<T>>; public: typename Ty::iterator begin() { return _atoms.begin(); } @@ -229,7 +218,6 @@ public: enum FileKinds { fileKindObjectAtoms, // atom based object file encoded in yaml fileKindArchive, // static archive library encoded in yaml - fileKindObjectELF, // ELF object files encoded in yaml fileKindObjectMachO // mach-o object files encoded in yaml }; @@ -255,7 +243,7 @@ struct RefKind { Reference::KindValue value; }; -} // anonymous namespace +} // end anonymous namespace LLVM_YAML_IS_SEQUENCE_VECTOR(ArchMember) LLVM_YAML_IS_SEQUENCE_VECTOR(const lld::Reference *) @@ -294,7 +282,8 @@ template <> struct ScalarTraits<RefKind> { template <> struct ScalarEnumerationTraits<lld::File::Kind> { static void enumeration(IO &io, lld::File::Kind &value) { - io.enumCase(value, "object", lld::File::kindObject); + io.enumCase(value, "error-object", lld::File::kindErrorObject); + io.enumCase(value, "object", lld::File::kindMachObject); io.enumCase(value, "shared-library", lld::File::kindSharedLibrary); io.enumCase(value, "static-library", lld::File::kindArchiveLibrary); } @@ -417,6 +406,10 @@ template <> struct ScalarEnumerationTraits<lld::DefinedAtom::ContentType> { DefinedAtom::typeObjCClassPtr); io.enumCase(value, "objc-category-list", DefinedAtom::typeObjC2CategoryList); + io.enumCase(value, "objc-image-info", + DefinedAtom::typeObjCImageInfo); + io.enumCase(value, "objc-method-list", + DefinedAtom::typeObjCMethodList); io.enumCase(value, "objc-class1", DefinedAtom::typeObjC1Class); io.enumCase(value, "dtraceDOF", DefinedAtom::typeDTraceDOF); io.enumCase(value, "interposing-tuples", @@ -430,13 +423,7 @@ template <> struct ScalarEnumerationTraits<lld::DefinedAtom::ContentType> { io.enumCase(value, "tlv-initializer-ptr", DefinedAtom::typeTLVInitializerPtr); io.enumCase(value, "mach_header", DefinedAtom::typeMachHeader); - io.enumCase(value, "thread-data", DefinedAtom::typeThreadData); - io.enumCase(value, "thread-zero-fill",DefinedAtom::typeThreadZeroFill); - io.enumCase(value, "ro-note", DefinedAtom::typeRONote); - io.enumCase(value, "rw-note", DefinedAtom::typeRWNote); - io.enumCase(value, "no-alloc", DefinedAtom::typeNoAlloc); - io.enumCase(value, "group-comdat", DefinedAtom::typeGroupComdat); - io.enumCase(value, "gnu-linkonce", DefinedAtom::typeGnuLinkOnce); + io.enumCase(value, "dso_handle", DefinedAtom::typeDSOHandle); io.enumCase(value, "sectcreate", DefinedAtom::typeSectCreate); } }; @@ -512,7 +499,6 @@ template <> struct ScalarEnumerationTraits<FileKinds> { static void enumeration(IO &io, FileKinds &value) { io.enumCase(value, "object", fileKindObjectAtoms); io.enumCase(value, "archive", fileKindArchive); - io.enumCase(value, "object-elf", fileKindObjectELF); io.enumCase(value, "object-mach-o", fileKindObjectMachO); } }; @@ -528,10 +514,20 @@ template <> struct MappingTraits<ArchMember> { // Declare that an AtomList is a yaml sequence. template <typename T> struct SequenceTraits<AtomList<T> > { static size_t size(IO &io, AtomList<T> &seq) { return seq._atoms.size(); } - static const T *&element(IO &io, AtomList<T> &seq, size_t index) { + static T *&element(IO &io, AtomList<T> &seq, size_t index) { if (index >= seq._atoms.size()) seq._atoms.resize(index + 1); - return seq._atoms[index]; + return seq._atoms[index].get(); + } +}; + +// Declare that an AtomRange is a yaml sequence. +template <typename T> struct SequenceTraits<File::AtomRange<T> > { + static size_t size(IO &io, File::AtomRange<T> &seq) { return seq.size(); } + static T *&element(IO &io, File::AtomRange<T> &seq, size_t index) { + assert(io.outputting() && "AtomRange only used when outputting"); + assert(index < seq.size() && "Out of range access"); + return seq[index].get(); } }; @@ -583,39 +579,34 @@ template <> struct MappingTraits<const lld::File *> { const lld::File *denormalize(IO &io) { return this; } - const AtomVector<lld::DefinedAtom> &defined() const override { + const AtomRange<lld::DefinedAtom> defined() const override { return _noDefinedAtoms; } - const AtomVector<lld::UndefinedAtom> &undefined() const override { + const AtomRange<lld::UndefinedAtom> undefined() const override { return _noUndefinedAtoms; } - const AtomVector<lld::SharedLibraryAtom> & - sharedLibrary() const override { + const AtomRange<lld::SharedLibraryAtom> sharedLibrary() const override { return _noSharedLibraryAtoms; } - const AtomVector<lld::AbsoluteAtom> &absolute() const override { + const AtomRange<lld::AbsoluteAtom> absolute() const override { return _noAbsoluteAtoms; } - File *find(StringRef name, bool dataSymbolOnly) override { - for (const ArchMember &member : _members) { - for (const lld::DefinedAtom *atom : member._content->defined()) { - if (name == atom->name()) { - if (!dataSymbolOnly) - return const_cast<File *>(member._content); - switch (atom->contentType()) { - case lld::DefinedAtom::typeData: - case lld::DefinedAtom::typeZeroFill: - return const_cast<File *>(member._content); - default: - break; - } - } - } - } + void clearAtoms() override { + _noDefinedAtoms.clear(); + _noUndefinedAtoms.clear(); + _noSharedLibraryAtoms.clear(); + _noAbsoluteAtoms.clear(); + } + + File *find(StringRef name) override { + for (const ArchMember &member : _members) + for (const lld::DefinedAtom *atom : member._content->defined()) + if (name == atom->name()) + return const_cast<File *>(member._content); return nullptr; } @@ -630,36 +621,47 @@ template <> struct MappingTraits<const lld::File *> { class NormalizedFile : public lld::File { public: - NormalizedFile(IO &io) : File("", kindObject), _io(io), _rnb(nullptr) {} + NormalizedFile(IO &io) + : File("", kindNormalizedObject), _io(io), _rnb(nullptr), + _definedAtomsRef(_definedAtoms._atoms), + _undefinedAtomsRef(_undefinedAtoms._atoms), + _sharedLibraryAtomsRef(_sharedLibraryAtoms._atoms), + _absoluteAtomsRef(_absoluteAtoms._atoms) {} NormalizedFile(IO &io, const lld::File *file) - : File(file->path(), kindObject), _io(io), - _rnb(new RefNameBuilder(*file)), _path(file->path()) { - for (const lld::DefinedAtom *a : file->defined()) - _definedAtoms._atoms.push_back(a); - for (const lld::UndefinedAtom *a : file->undefined()) - _undefinedAtoms._atoms.push_back(a); - for (const lld::SharedLibraryAtom *a : file->sharedLibrary()) - _sharedLibraryAtoms._atoms.push_back(a); - for (const lld::AbsoluteAtom *a : file->absolute()) - _absoluteAtoms._atoms.push_back(a); + : File(file->path(), kindNormalizedObject), _io(io), + _rnb(new RefNameBuilder(*file)), _path(file->path()), + _definedAtomsRef(file->defined()), + _undefinedAtomsRef(file->undefined()), + _sharedLibraryAtomsRef(file->sharedLibrary()), + _absoluteAtomsRef(file->absolute()) { } + + ~NormalizedFile() override { + } + const lld::File *denormalize(IO &io); - const AtomVector<lld::DefinedAtom> &defined() const override { - return _definedAtoms._atoms; + const AtomRange<lld::DefinedAtom> defined() const override { + return _definedAtomsRef; + } + + const AtomRange<lld::UndefinedAtom> undefined() const override { + return _undefinedAtomsRef; } - const AtomVector<lld::UndefinedAtom> &undefined() const override { - return _undefinedAtoms._atoms; + const AtomRange<lld::SharedLibraryAtom> sharedLibrary() const override { + return _sharedLibraryAtomsRef; } - const AtomVector<lld::SharedLibraryAtom> & - sharedLibrary() const override { - return _sharedLibraryAtoms._atoms; + const AtomRange<lld::AbsoluteAtom> absolute() const override { + return _absoluteAtomsRef; } - const AtomVector<lld::AbsoluteAtom> &absolute() const override { - return _absoluteAtoms._atoms; + void clearAtoms() override { + _definedAtoms._atoms.clear(); + _undefinedAtoms._atoms.clear(); + _sharedLibraryAtoms._atoms.clear(); + _absoluteAtoms._atoms.clear(); } // Allocate a new copy of this string in _storage, so the strings @@ -677,6 +679,10 @@ template <> struct MappingTraits<const lld::File *> { AtomList<lld::UndefinedAtom> _undefinedAtoms; AtomList<lld::SharedLibraryAtom> _sharedLibraryAtoms; AtomList<lld::AbsoluteAtom> _absoluteAtoms; + AtomRange<lld::DefinedAtom> _definedAtomsRef; + AtomRange<lld::UndefinedAtom> _undefinedAtomsRef; + AtomRange<lld::SharedLibraryAtom> _sharedLibraryAtomsRef; + AtomRange<lld::AbsoluteAtom> _absoluteAtomsRef; llvm::BumpPtrAllocator _storage; }; @@ -693,20 +699,31 @@ template <> struct MappingTraits<const lld::File *> { } static void mappingAtoms(IO &io, const lld::File *&file) { - MappingNormalizationHeap<NormalizedFile, const lld::File *> keys(io, file); YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext()); + MappingNormalizationHeap<NormalizedFile, const lld::File *> + keys(io, file, nullptr); assert(info != nullptr); info->_file = keys.operator->(); io.mapOptional("path", keys->_path); - io.mapOptional("defined-atoms", keys->_definedAtoms); - io.mapOptional("undefined-atoms", keys->_undefinedAtoms); - io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtoms); - io.mapOptional("absolute-atoms", keys->_absoluteAtoms); + + if (io.outputting()) { + io.mapOptional("defined-atoms", keys->_definedAtomsRef); + io.mapOptional("undefined-atoms", keys->_undefinedAtomsRef); + io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtomsRef); + io.mapOptional("absolute-atoms", keys->_absoluteAtomsRef); + } else { + io.mapOptional("defined-atoms", keys->_definedAtoms); + io.mapOptional("undefined-atoms", keys->_undefinedAtoms); + io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtoms); + io.mapOptional("absolute-atoms", keys->_absoluteAtoms); + } } static void mappingArchive(IO &io, const lld::File *&file) { - MappingNormalizationHeap<NormArchiveFile, const lld::File *> keys(io, file); + YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext()); + MappingNormalizationHeap<NormArchiveFile, const lld::File *> + keys(io, file, &info->_file->allocator()); io.mapOptional("path", keys->_path); io.mapOptional("members", keys->_members); @@ -769,8 +786,9 @@ template <> struct MappingTraits<const lld::Reference *> { }; static void mapping(IO &io, const lld::Reference *&ref) { + YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext()); MappingNormalizationHeap<NormalizedReference, const lld::Reference *> keys( - io, ref); + io, ref, &info->_file->allocator()); io.mapRequired("kind", keys->_mappedKind); io.mapOptional("offset", keys->_offset); @@ -787,7 +805,7 @@ template <> struct MappingTraits<const lld::DefinedAtom *> { public: NormalizedAtom(IO &io) : _file(fileFromContext(io)), _name(), _refName(), _contentType(), - _alignment(1), _content(), _references(), _isGroupChild(false) { + _alignment(1), _content(), _references() { static uint32_t ordinalCounter = 1; _ordinal = ordinalCounter++; } @@ -810,6 +828,9 @@ template <> struct MappingTraits<const lld::DefinedAtom *> { for (uint8_t x : cont) _content.push_back(x); } + + ~NormalizedAtom() override = default; + const lld::DefinedAtom *denormalize(IO &io) { YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext()); assert(info != nullptr); @@ -827,7 +848,9 @@ template <> struct MappingTraits<const lld::DefinedAtom *> { << ", " << _name.size() << ")\n"); return this; } + void bind(const RefNameResolver &); + // Extract current File object from YAML I/O parsing context const lld::File &fileFromContext(IO &io) { YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext()); @@ -851,8 +874,6 @@ template <> struct MappingTraits<const lld::DefinedAtom *> { DynamicExport dynamicExport() const override { return _dynamicExport; } CodeModel codeModel() const override { return _codeModel; } ContentPermissions permissions() const override { return _permissions; } - void setGroupChild(bool val) { _isGroupChild = val; } - bool isGroupChild() const { return _isGroupChild; } ArrayRef<uint8_t> rawContent() const override { if (!occupiesDiskSpace()) return ArrayRef<uint8_t>(); @@ -883,6 +904,16 @@ template <> struct MappingTraits<const lld::DefinedAtom *> { it = reinterpret_cast<const void *>(index); } + void addReference(Reference::KindNamespace ns, + Reference::KindArch arch, + Reference::KindValue kindValue, uint64_t off, + const Atom *target, Reference::Addend a) override { + assert(target && "trying to create reference to nothing"); + auto node = new (file().allocator()) SimpleReference(ns, arch, kindValue, + off, target, a); + _references.push_back(node); + } + const lld::File &_file; StringRef _name; StringRef _refName; @@ -902,16 +933,15 @@ template <> struct MappingTraits<const lld::DefinedAtom *> { StringRef _sectionName; uint64_t _sectionSize; std::vector<const lld::Reference *> _references; - bool _isGroupChild; }; static void mapping(IO &io, const lld::DefinedAtom *&atom) { + YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext()); MappingNormalizationHeap<NormalizedAtom, const lld::DefinedAtom *> keys( - io, atom); + io, atom, &info->_file->allocator()); if (io.outputting()) { // If writing YAML, check if atom needs a ref-name. typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile; - YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext()); assert(info != nullptr); NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file); assert(f); @@ -951,18 +981,27 @@ template <> struct MappingTraits<const lld::DefinedAtom *> { } }; +template <> struct MappingTraits<lld::DefinedAtom *> { + static void mapping(IO &io, lld::DefinedAtom *&atom) { + const lld::DefinedAtom *atomPtr = atom; + MappingTraits<const lld::DefinedAtom *>::mapping(io, atomPtr); + atom = const_cast<lld::DefinedAtom *>(atomPtr); + } +}; + // YAML conversion for const lld::UndefinedAtom* template <> struct MappingTraits<const lld::UndefinedAtom *> { class NormalizedAtom : public lld::UndefinedAtom { public: NormalizedAtom(IO &io) - : _file(fileFromContext(io)), _name(), _canBeNull(canBeNullNever), - _fallback(nullptr) {} + : _file(fileFromContext(io)), _name(), _canBeNull(canBeNullNever) {} NormalizedAtom(IO &io, const lld::UndefinedAtom *atom) : _file(fileFromContext(io)), _name(atom->name()), - _canBeNull(atom->canBeNull()), _fallback(atom->fallback()) {} + _canBeNull(atom->canBeNull()) {} + + ~NormalizedAtom() override = default; const lld::UndefinedAtom *denormalize(IO &io) { YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext()); @@ -990,29 +1029,33 @@ template <> struct MappingTraits<const lld::UndefinedAtom *> { const lld::File &file() const override { return _file; } StringRef name() const override { return _name; } CanBeNull canBeNull() const override { return _canBeNull; } - const UndefinedAtom *fallback() const override { return _fallback; } const lld::File &_file; StringRef _name; CanBeNull _canBeNull; - const UndefinedAtom *_fallback; }; static void mapping(IO &io, const lld::UndefinedAtom *&atom) { + YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext()); MappingNormalizationHeap<NormalizedAtom, const lld::UndefinedAtom *> keys( - io, atom); + io, atom, &info->_file->allocator()); io.mapRequired("name", keys->_name); io.mapOptional("can-be-null", keys->_canBeNull, lld::UndefinedAtom::canBeNullNever); - io.mapOptional("fallback", keys->_fallback, - (const lld::UndefinedAtom *)nullptr); + } +}; + +template <> struct MappingTraits<lld::UndefinedAtom *> { + static void mapping(IO &io, lld::UndefinedAtom *&atom) { + const lld::UndefinedAtom *atomPtr = atom; + MappingTraits<const lld::UndefinedAtom *>::mapping(io, atomPtr); + atom = const_cast<lld::UndefinedAtom *>(atomPtr); } }; // YAML conversion for const lld::SharedLibraryAtom* template <> struct MappingTraits<const lld::SharedLibraryAtom *> { - class NormalizedAtom : public lld::SharedLibraryAtom { public: NormalizedAtom(IO &io) @@ -1023,6 +1066,8 @@ template <> struct MappingTraits<const lld::SharedLibraryAtom *> { _loadName(atom->loadName()), _canBeNull(atom->canBeNullAtRuntime()), _type(atom->type()), _size(atom->size()) {} + ~NormalizedAtom() override = default; + const lld::SharedLibraryAtom *denormalize(IO &io) { YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext()); assert(info != nullptr); @@ -1066,8 +1111,9 @@ template <> struct MappingTraits<const lld::SharedLibraryAtom *> { static void mapping(IO &io, const lld::SharedLibraryAtom *&atom) { + YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext()); MappingNormalizationHeap<NormalizedAtom, const lld::SharedLibraryAtom *> - keys(io, atom); + keys(io, atom, &info->_file->allocator()); io.mapRequired("name", keys->_name); io.mapOptional("load-name", keys->_loadName); @@ -1077,6 +1123,14 @@ template <> struct MappingTraits<const lld::SharedLibraryAtom *> { } }; +template <> struct MappingTraits<lld::SharedLibraryAtom *> { + static void mapping(IO &io, lld::SharedLibraryAtom *&atom) { + const lld::SharedLibraryAtom *atomPtr = atom; + MappingTraits<const lld::SharedLibraryAtom *>::mapping(io, atomPtr); + atom = const_cast<lld::SharedLibraryAtom *>(atomPtr); + } +}; + // YAML conversion for const lld::AbsoluteAtom* template <> struct MappingTraits<const lld::AbsoluteAtom *> { @@ -1087,6 +1141,9 @@ template <> struct MappingTraits<const lld::AbsoluteAtom *> { NormalizedAtom(IO &io, const lld::AbsoluteAtom *atom) : _file(fileFromContext(io)), _name(atom->name()), _scope(atom->scope()), _value(atom->value()) {} + + ~NormalizedAtom() override = default; + const lld::AbsoluteAtom *denormalize(IO &io) { YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext()); assert(info != nullptr); @@ -1122,8 +1179,9 @@ template <> struct MappingTraits<const lld::AbsoluteAtom *> { }; static void mapping(IO &io, const lld::AbsoluteAtom *&atom) { + YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext()); MappingNormalizationHeap<NormalizedAtom, const lld::AbsoluteAtom *> keys( - io, atom); + io, atom, &info->_file->allocator()); if (io.outputting()) { typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile; @@ -1144,8 +1202,16 @@ template <> struct MappingTraits<const lld::AbsoluteAtom *> { } }; -} // namespace llvm -} // namespace yaml +template <> struct MappingTraits<lld::AbsoluteAtom *> { + static void mapping(IO &io, lld::AbsoluteAtom *&atom) { + const lld::AbsoluteAtom *atomPtr = atom; + MappingTraits<const lld::AbsoluteAtom *>::mapping(io, atomPtr); + atom = const_cast<lld::AbsoluteAtom *>(atomPtr); + } +}; + +} // end namespace llvm +} // end namespace yaml RefNameResolver::RefNameResolver(const lld::File *file, IO &io) : _io(io) { typedef MappingTraits<const lld::DefinedAtom *>::NormalizedAtom @@ -1186,13 +1252,6 @@ MappingTraits<const lld::File *>::NormalizedFile::denormalize(IO &io) { normAtom->bind(nameResolver); } - _definedAtoms._atoms.erase( - std::remove_if(_definedAtoms._atoms.begin(), _definedAtoms._atoms.end(), - [](const DefinedAtom *a) { - return ((const NormalizedAtom *)a)->isGroupChild(); - }), - _definedAtoms._atoms.end()); - return this; } @@ -1208,14 +1267,7 @@ inline void MappingTraits<const lld::DefinedAtom *>::NormalizedAtom::bind( inline void MappingTraits<const lld::Reference *>::NormalizedReference::bind( const RefNameResolver &resolver) { - typedef MappingTraits<const lld::DefinedAtom *>::NormalizedAtom NormalizedAtom; - _target = resolver.lookup(_targetName); - - if (_mappedKind.ns == lld::Reference::KindNamespace::all && - _mappedKind.value == lld::Reference::kindGroupChild) { - ((NormalizedAtom *)const_cast<Atom *>(_target))->setGroupChild(true); - } } inline StringRef @@ -1240,12 +1292,12 @@ class Writer : public lld::Writer { public: Writer(const LinkingContext &context) : _ctx(context) {} - std::error_code writeFile(const lld::File &file, StringRef outPath) override { + llvm::Error writeFile(const lld::File &file, StringRef outPath) override { // Create stream to path. std::error_code ec; llvm::raw_fd_ostream out(outPath, ec, llvm::sys::fs::F_Text); if (ec) - return ec; + return llvm::errorCodeToError(ec); // Create yaml Output writer, using yaml options for context. YamlContext yamlContext; @@ -1257,7 +1309,7 @@ public: const lld::File *fileRef = &file; yout << fileRef; - return std::error_code(); + return llvm::Error(); } private: @@ -1330,7 +1382,7 @@ private: const Registry &_registry; }; -} // anonymous namespace +} // end anonymous namespace void Registry::addSupportYamlFiles() { add(std::unique_ptr<Reader>(new YAMLReader(*this))); |