From 3f69076278421d731a80804a743f89c72384b379 Mon Sep 17 00:00:00 2001 From: Nick Kledzik Date: Fri, 27 Jun 2014 18:25:01 +0000 Subject: [PATCH] [mach-o] refactor x86_64 relocation handling. This is first step in reworking how mach-o relocations are processed. The existing KindHandler is going to become a delgate/helper object for processing architecture specific references. The KindHandler knows how to convert mach-o relocations into References and back, as well, as fixing up the content the relocation is on. One of the messy things about mach-o relocations is that they sometime come in pairs, but the pairs still convert to one lld::Reference. So, the conversion has to detect pairs (arch specific) and change the stride. llvm-svn: 211921 --- lld/lib/ReaderWriter/MachO/Atoms.h | 10 +- lld/lib/ReaderWriter/MachO/File.h | 80 ++++- .../MachO/MachONormalizedFileBinaryReader.cpp | 2 +- .../MachO/MachONormalizedFileFromAtoms.cpp | 8 +- .../MachO/MachONormalizedFileToAtoms.cpp | 222 +++++++++++-- lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp | 355 ++++++++++++++++++--- lld/lib/ReaderWriter/MachO/ReferenceKinds.h | 133 +++++++- lld/lib/ReaderWriter/MachO/StubAtoms_x86_64.hpp | 26 +- lld/test/darwin/hello-world.objtxt | 4 +- lld/test/darwin/native-and-mach-o.objtxt | 2 +- lld/test/mach-o/parse-cfstring64.yaml | 25 +- lld/test/mach-o/parse-data-relocs-x86_64.yaml | 223 +++++++++++++ lld/test/mach-o/parse-initializers64.yaml | 18 +- lld/test/mach-o/parse-text-relocs-x86_64.yaml | 138 ++++++++ 14 files changed, 1127 insertions(+), 119 deletions(-) create mode 100644 lld/test/mach-o/parse-data-relocs-x86_64.yaml create mode 100644 lld/test/mach-o/parse-text-relocs-x86_64.yaml diff --git a/lld/lib/ReaderWriter/MachO/Atoms.h b/lld/lib/ReaderWriter/MachO/Atoms.h index 3d07390..9db091e 100644 --- a/lld/lib/ReaderWriter/MachO/Atoms.h +++ b/lld/lib/ReaderWriter/MachO/Atoms.h @@ -49,11 +49,17 @@ public: } ArrayRef rawContent() const override { - // Zerofill atoms have a content pointer which is null. - assert(_content.data() != nullptr); + // Note: Zerofill atoms have a content pointer which is null. return _content; } + 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 _content; diff --git a/lld/lib/ReaderWriter/MachO/File.h b/lld/lib/ReaderWriter/MachO/File.h index 9c507e8..fcd6ecd1 100644 --- a/lld/lib/ReaderWriter/MachO/File.h +++ b/lld/lib/ReaderWriter/MachO/File.h @@ -10,6 +10,8 @@ #ifndef LLD_READER_WRITER_MACHO_FILE_H #define LLD_READER_WRITER_MACHO_FILE_H +#include "llvm/ADT/StringMap.h" + #include "Atoms.h" #include "lld/Core/Simple.h" @@ -17,13 +19,19 @@ namespace lld { namespace mach_o { +using lld::mach_o::normalized::Section; + class MachOFile : public SimpleFile { public: MachOFile(StringRef path) : SimpleFile(path) {} void addDefinedAtom(StringRef name, Atom::Scope scope, DefinedAtom::ContentType type, DefinedAtom::Merge merge, - ArrayRef content, bool copyRefs) { + uint64_t sectionOffset, uint64_t contentSize, + bool copyRefs, const Section *inSection) { + assert(sectionOffset+contentSize <= inSection->content.size()); + ArrayRef content = inSection->content.slice(sectionOffset, + contentSize); if (copyRefs) { // Make a copy of the atom's name and content that is owned by this file. name = name.copy(_allocator); @@ -33,13 +41,18 @@ public: new (_allocator) MachODefinedAtom(*this, name, scope, type, merge, content); addAtom(*atom); + _sectionAtoms[inSection].push_back({sectionOffset, atom}); } void addDefinedAtomInCustomSection(StringRef name, Atom::Scope scope, DefinedAtom::ContentType type, DefinedAtom::Merge merge, - ArrayRef content, StringRef sectionName, - bool copyRefs) { - if (copyRefs) { + uint64_t sectionOffset, uint64_t contentSize, + StringRef sectionName, bool copyRefs, + const Section *inSection) { + assert(sectionOffset+contentSize <= inSection->content.size()); + ArrayRef content = inSection->content.slice(sectionOffset, + contentSize); + if (copyRefs) { // Make a copy of the atom's name and content that is owned by this file. name = name.copy(_allocator); content = content.copy(_allocator); @@ -49,10 +62,12 @@ public: new (_allocator) MachODefinedCustomSectionAtom(*this, name, scope, type, merge, content, sectionName); addAtom(*atom); + _sectionAtoms[inSection].push_back({sectionOffset, atom}); } - void addZeroFillDefinedAtom(StringRef name, Atom::Scope scope, uint64_t size, - bool copyRefs) { + void addZeroFillDefinedAtom(StringRef name, Atom::Scope scope, + uint64_t sectionOffset, uint64_t size, + bool copyRefs, const Section *inSection) { if (copyRefs) { // Make a copy of the atom's name and content that is owned by this file. name = name.copy(_allocator); @@ -60,6 +75,7 @@ public: MachODefinedAtom *atom = new (_allocator) MachODefinedAtom(*this, name, scope, size); addAtom(*atom); + _sectionAtoms[inSection].push_back({sectionOffset, atom}); } void addUndefinedAtom(StringRef name, bool copyRefs) { @@ -70,6 +86,7 @@ public: SimpleUndefinedAtom *atom = new (_allocator) SimpleUndefinedAtom(*this, name); addAtom(*atom); + _undefAtoms[name] = atom; } void addTentativeDefAtom(StringRef name, Atom::Scope scope, uint64_t size, @@ -81,13 +98,58 @@ public: MachOTentativeDefAtom *atom = new (_allocator) MachOTentativeDefAtom(*this, name, scope, size, align); addAtom(*atom); + _undefAtoms[name] = atom; } - - + + /// Search this file for an the atom from 'section' that covers + /// 'offsetInSect'. Returns nullptr is no atom found. + MachODefinedAtom *findAtomCoveringAddress(const Section §ion, + uint64_t offsetInSect, + uint32_t *foundOffsetAtom=nullptr) { + auto pos = _sectionAtoms.find(§ion); + if (pos == _sectionAtoms.end()) + return nullptr; + auto vec = pos->second; + assert(offsetInSect < section.content.size()); + // Vector of atoms for section are already sorted, so do binary search. + auto atomPos = std::lower_bound(vec.begin(), vec.end(), offsetInSect, + [offsetInSect](const SectionOffsetAndAtom &ao, + uint64_t targetAddr) -> bool { + // Each atom has a start offset of its slice of the + // section's content. This compare function must return true + // iff the atom's range is before the offset being searched for. + uint64_t atomsEndOffset = ao.offset+ao.atom->rawContent().size(); + return (atomsEndOffset <= offsetInSect); + }); + if (atomPos == vec.end()) + return nullptr; + if (foundOffsetAtom) + *foundOffsetAtom = offsetInSect - atomPos->offset; + return atomPos->atom; + } + + /// Searches this file for an UndefinedAtom named 'name'. Returns + /// nullptr is no such atom found. + const lld::Atom *findUndefAtom(StringRef name) { + auto pos = _undefAtoms.find(name); + if (pos == _undefAtoms.end()) + return nullptr; + return pos->second; + } + private: - llvm::BumpPtrAllocator _allocator; + struct SectionOffsetAndAtom { uint64_t offset; MachODefinedAtom *atom; }; + typedef llvm::DenseMap> SectionToAtoms; + typedef llvm::StringMap NameToAtom; + + llvm::BumpPtrAllocator _allocator; + SectionToAtoms _sectionAtoms; + NameToAtom _undefAtoms; }; + + } // end namespace mach_o } // end namespace lld diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp index 1dca168..a328ec4 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp @@ -339,7 +339,7 @@ readBinary(std::unique_ptr &mb, sout.value = sin->n_value; if (sout.type == N_UNDF) f->undefinedSymbols.push_back(sout); - else if (sout.scope == (SymbolScope)N_EXT) + else if (sin->n_type & N_EXT) f->globalSymbols.push_back(sout); else f->localSymbols.push_back(sout); diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp index 726092c..f187df9 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp @@ -498,6 +498,7 @@ void Util::copySegmentInfo(NormalizedFile &file) { } void Util::appendSection(SectionInfo *si, NormalizedFile &file) { + const bool rMode = (_context.outputMachOType() == llvm::MachO::MH_OBJECT); // Add new empty section to end of file.sections. Section temp; file.sections.push_back(std::move(temp)); @@ -528,9 +529,14 @@ void Util::appendSection(SectionInfo *si, NormalizedFile &file) { if ( ref->target() != nullptr ) targetAddress = _atomToAddress[ref->target()]; uint64_t fixupAddress = _atomToAddress[ai.atom] + offset; - _context.kindHandler().applyFixup( + if ( rMode ) { + // FIXME: Need a handler method to update content for .o file + // output and any needed section relocations. + } else { + _context.kindHandler().applyFixup( ref->kindNamespace(), ref->kindArch(), ref->kindValue(), ref->addend(), &atomContent[offset], fixupAddress, targetAddress); + } } } } diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp index a582c97..61d68fa 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp @@ -24,11 +24,13 @@ #include "MachONormalizedFileBinaryUtils.h" #include "File.h" #include "Atoms.h" +#include "ReferenceKinds.h" #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" #include "llvm/Support/MachO.h" +#include "llvm/Support/Format.h" using namespace llvm::MachO; using namespace lld::mach_o::normalized; @@ -57,12 +59,14 @@ const MachORelocatableSectionToAtomType sectsToAtomType[] = { ENTRY("", "", S_CSTRING_LITERALS, typeCString), ENTRY("__TEXT", "__ustring", S_REGULAR, typeUTF16String), ENTRY("__TEXT", "__const", S_REGULAR, typeConstant), + ENTRY("__TEXT", "__const_coal", S_COALESCED, typeConstant), ENTRY("__TEXT", "__eh_frame", S_COALESCED, typeCFI), ENTRY("__TEXT", "__literal4", S_4BYTE_LITERALS, typeLiteral4), ENTRY("__TEXT", "__literal8", S_8BYTE_LITERALS, typeLiteral8), ENTRY("__TEXT", "__literal16", S_16BYTE_LITERALS, typeLiteral16), ENTRY("__TEXT", "__gcc_except_tab", S_REGULAR, typeLSDA), ENTRY("__DATA", "__data", S_REGULAR, typeData), + ENTRY("__DATA", "__datacoal_nt", S_COALESCED, typeData), ENTRY("__DATA", "__const", S_REGULAR, typeConstData), ENTRY("__DATA", "__cfstring", S_REGULAR, typeCFString), ENTRY("__DATA", "__mod_init_func", S_MOD_INIT_FUNC_POINTERS, @@ -108,7 +112,8 @@ enum AtomizeModel { atomizeUTF8, atomizeUTF16, atomizeCFI, - atomizeCU + atomizeCU, + atomizeCFString }; /// Returns info on how to atomize a section of the specified ContentType. @@ -151,8 +156,8 @@ void sectionParseInfo(DefinedAtom::ContentType atomType, atomizeFixedSize), ENTRY(typeLiteral16, 16, scopeLinkageUnit, mergeByContent, atomizeFixedSize), - ENTRY(typeCFString, 16, scopeLinkageUnit, mergeByContent, - atomizeFixedSize), + ENTRY(typeCFString, 4, scopeLinkageUnit, mergeByContent, + atomizeCFString), ENTRY(typeInitializerPtr, 4, scopeTranslationUnit, mergeNo, atomizePointerSize), ENTRY(typeTerminatorPtr, 4, scopeTranslationUnit, mergeNo, @@ -218,12 +223,12 @@ void atomFromSymbol(DefinedAtom::ContentType atomType, const Section §ion, // Mach-O symbol table does have size in it. Instead the size is the // difference between this and the next symbol. uint64_t size = nextSymbolAddr - symbolAddr; + uint64_t offset = symbolAddr - section.address; if (section.type == llvm::MachO::S_ZEROFILL) { - file.addZeroFillDefinedAtom(symbolName, symbolScope, size, copyRefs); + file.addZeroFillDefinedAtom(symbolName, symbolScope, offset, size, copyRefs, + §ion); } else { - uint64_t offset = symbolAddr - section.address; - ArrayRef atomContent = section.content.slice(offset, size); - DefinedAtom::Merge merge = (symbolDescFlags & N_WEAK_DEF) + DefinedAtom::Merge merge = (symbolDescFlags & N_WEAK_DEF) ? DefinedAtom::mergeAsWeak : DefinedAtom::mergeNo; if (atomType == DefinedAtom::typeUnknown) { // Mach-O needs a segment and section name. Concatentate those two @@ -232,14 +237,15 @@ void atomFromSymbol(DefinedAtom::ContentType atomType, const Section §ion, std::string segSectName = section.segmentName.str() + "/" + section.sectionName.str(); file.addDefinedAtomInCustomSection(symbolName, symbolScope, atomType, - merge, atomContent, segSectName, true); + merge, offset, size, segSectName, true, + §ion); } else { - if ((atomType == lld::DefinedAtom::typeCode) && + if ((atomType == lld::DefinedAtom::typeCode) && (symbolDescFlags & N_SYMBOL_RESOLVER)) { - atomType = lld::DefinedAtom::typeResolver; + atomType = lld::DefinedAtom::typeResolver; } file.addDefinedAtom(symbolName, symbolScope, atomType, merge, - atomContent, copyRefs); + offset, size, copyRefs, §ion); } } } @@ -264,10 +270,14 @@ std::error_code processSymboledSection(DefinedAtom::ContentType atomType, // Sort symbols. std::sort(symbols.begin(), symbols.end(), [](const Symbol *lhs, const Symbol *rhs) -> bool { + if (lhs == rhs) + return false; // First by address. - if (lhs->value != rhs->value) - return lhs->value < rhs->value; - // If same address, one is an alias. Sort by scope. + uint64_t lhsAddr = lhs->value; + uint64_t rhsAddr = rhs->value; + if (lhsAddr != rhsAddr) + return lhsAddr < rhsAddr; + // If same address, one is an alias so sort by scope. Atom::Scope lScope = atomScope(lhs->scope); Atom::Scope rScope = atomScope(rhs->scope); if (lScope != rScope) @@ -278,19 +288,25 @@ std::error_code processSymboledSection(DefinedAtom::ContentType atomType, // Debug logging of symbols. //for (const Symbol *sym : symbols) - // llvm::errs() << "sym: " << sym->value << ", " << sym->name << "\n"; + // llvm::errs() << " sym: " + // << llvm::format("0x%08llx ", (uint64_t)sym->value) + // << ", " << sym->name << "\n"; // If section has no symbols and no content, there are no atoms. if (symbols.empty() && section.content.empty()) return std::error_code(); - uint64_t anonAtomEnd = symbols.empty() - ? section.address + section.content.size() - : (uint64_t)symbols.front()->value; - if (anonAtomEnd != section.address) { + if (symbols.empty()) { + // Section has no symbols, put all content in one anoymous atom. + atomFromSymbol(atomType, section, file, section.address, StringRef(), + 0, Atom::scopeTranslationUnit, + section.address + section.content.size(), copyRefs); + } + else if (symbols.front()->value != section.address) { // Section has anonymous content before first symbol. - atomFromSymbol(atomType, section, file, section.address, StringRef(), 0, - Atom::scopeTranslationUnit, anonAtomEnd, copyRefs); + atomFromSymbol(atomType, section, file, section.address, StringRef(), + 0, Atom::scopeTranslationUnit, symbols.front()->value, + copyRefs); } const Symbol *lastSym = nullptr; @@ -347,7 +363,7 @@ std::error_code processSection(DefinedAtom::ContentType atomType, break; case atomizePointerSize: // Break section up into atoms each the size of a pointer. - size = is64 ? 8 : 4;; + size = is64 ? 8 : 4; break; case atomizeUTF8: // Break section up into zero terminated c-strings. @@ -387,6 +403,10 @@ std::error_code processSection(DefinedAtom::ContentType atomType, // Break section up into compact unwind entries. size = is64 ? 32 : 20; break; + case atomizeCFString: + // Break section up into compact unwind entries. + size = is64 ? 32 : 16; + break; case atomizeAtSymbols: break; } @@ -396,21 +416,153 @@ std::error_code processSection(DefinedAtom::ContentType atomType, + " is malformed. The last atom is " "not zero terminated."); } - ArrayRef byteContent = section.content.slice(offset, size); - file.addDefinedAtom(StringRef(), scope, atomType, merge, byteContent, - copyRefs); + file.addDefinedAtom(StringRef(), scope, atomType, merge, offset, size, + copyRefs, §ion); offset += size; } } return std::error_code(); } +// 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, + MachOFile &file, + KindHandler &handler) { + // Utility function for KindHandler to find atom by its address. + auto atomByAddr = [&] (uint32_t sectIndex, uint64_t addr, + const lld::Atom **atom, Reference::Addend *addend) + -> std::error_code { + if (sectIndex > normalizedFile.sections.size()) + return make_dynamic_error_code(Twine("out of range section " + "index (") + Twine(sectIndex) + ")"); + const Section § = normalizedFile.sections[sectIndex-1]; + uint32_t offsetInTarget; + uint64_t offsetInSect = addr - sect.address; + *atom = file.findAtomCoveringAddress(sect, offsetInSect, &offsetInTarget); + *addend = offsetInTarget; + return std::error_code(); + }; + + // Utility function for KindHandler to find atom by its symbol index. + auto atomBySymbol = [&] (uint32_t symbolIndex, const lld::Atom **result) + -> std::error_code { + // Find symbol from index. + const Symbol *sym = nullptr; + uint32_t numLocal = normalizedFile.localSymbols.size(); + uint32_t numGlobal = normalizedFile.globalSymbols.size(); + uint32_t numUndef = normalizedFile.undefinedSymbols.size(); + if (symbolIndex < numLocal) { + sym = &normalizedFile.localSymbols[symbolIndex]; + } else if (symbolIndex < numLocal+numGlobal) { + sym = &normalizedFile.globalSymbols[symbolIndex-numLocal]; + } else if (symbolIndex < numLocal+numGlobal+numUndef) { + sym = &normalizedFile.undefinedSymbols[symbolIndex-numLocal-numGlobal]; + } else { + return make_dynamic_error_code(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 (") + + Twine(sym->sect) + ") out of range "); + const Section &symSection = normalizedFile.sections[sym->sect-1]; + uint64_t targetOffsetInSect = sym->value - symSection.address; + MachODefinedAtom *target = file.findAtomCoveringAddress(symSection, + targetOffsetInSect); + if (target) { + *result = target; + return std::error_code(); + } + return make_dynamic_error_code(Twine("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 make_dynamic_error_code(Twine("no undefined atom found for sym")); + } else { + // Search undefs + return make_dynamic_error_code(Twine("no atom found for symbol")); + } + }; + + const bool swap = !MachOLinkingContext::isHostEndian(normalizedFile.arch); + // Use old-school iterator so that paired relocations can be grouped. + for (auto it=section.relocations.begin(), e=section.relocations.end(); + it != e; ++it) { + 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) + + ") is larger than section size (" + + Twine(section.content.size()) + ")"); + uint32_t offsetInAtom; + MachODefinedAtom *inAtom = file.findAtomCoveringAddress(section, + reloc.offset, + &offsetInAtom); + if (!inAtom) + return make_dynamic_error_code(Twine("no atom at r_address")); + uint64_t fixupAddress = section.address + reloc.offset; + + const lld::Atom *target = nullptr; + Reference::Addend addend = 0; + Reference::KindValue kind; + std::error_code relocErr; + if (handler.isPairedReloc(reloc)) { + // Handle paired relocations together. + relocErr = handler.getPairReferenceInfo(reloc, *++it, inAtom, + offsetInAtom, fixupAddress, swap, + atomByAddr, atomBySymbol, &kind, + &target, &addend); + } + else { + // Use KindHandler to convert relocation record into information + // needed to instantiate an lld::Reference object. + relocErr = handler.getReferenceInfo(reloc, inAtom, offsetInAtom, + fixupAddress,swap, 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(reloc.length) + + ", r_pcrel=" + Twine(reloc.pcRel) + + (!reloc.scattered ? (Twine(", r_symbolnum=") + Twine(reloc.symbol)) + : (Twine(", r_scattered=1, r_value=") + + Twine(reloc.value))) + + ")" ); + } else { + // Instantiate an lld::Reference object and add to its atom. + inAtom->addReference(offsetInAtom, kind, target, addend); + } + } + return std::error_code(); +} + +bool isDebugInfoSection(const Section §ion) { + if ((section.attributes & S_ATTR_DEBUG) == 0) + return false; + return section.segmentName.equals("__DWARF"); +} + +/// Converts normalized mach-o file into an lld::File and lld::Atoms. ErrorOr> normalizedObjectToAtoms(const NormalizedFile &normalizedFile, StringRef path, bool copyRefs) { std::unique_ptr file(new MachOFile(path)); // Create atoms from each section. for (auto § : normalizedFile.sections) { + if (isDebugInfoSection(sect)) + continue; DefinedAtom::ContentType atomType = atomTypeFromSection(sect); if (std::error_code ec = processSection(atomType, sect, normalizedFile, *file, copyRefs)) @@ -427,6 +579,26 @@ normalizedObjectToAtoms(const NormalizedFile &normalizedFile, StringRef path, } } + // TEMP BEGIN: until all KindHandlers switched to new interface. + if (normalizedFile.arch != lld::MachOLinkingContext::arch_x86_64) + return std::unique_ptr(std::move(file)); + // TEMP END + + // Convert mach-o relocations to References + std::unique_ptr handler + = KindHandler::create(normalizedFile.arch); + for (auto § : normalizedFile.sections) { + if (isDebugInfoSection(sect)) + continue; + if (std::error_code ec = convertRelocs(sect, normalizedFile, *file, *handler)) + return ec; + } + + // Sort references in each atom to their canonical order. + for (const DefinedAtom* defAtom : file->defined()) { + reinterpret_cast(defAtom)->sortReferences(); + } + return std::unique_ptr(std::move(file)); } diff --git a/lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp b/lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp index 0e87fb5..cb450203 100644 --- a/lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp +++ b/lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp @@ -9,7 +9,7 @@ #include "ReferenceKinds.h" - +#include "MachONormalizedFileBinaryUtils.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" @@ -18,6 +18,7 @@ #include "llvm/Support/ErrorHandling.h" using namespace llvm::MachO; +using namespace lld::mach_o::normalized; namespace lld { namespace mach_o { @@ -48,6 +49,64 @@ KindHandler::create(MachOLinkingContext::Arch arch) { } } +KindHandler::RelocPattern KindHandler::relocPattern(const Relocation &reloc) { + assert((reloc.type & 0xFFF0) == 0); + uint16_t result = reloc.type; + if (reloc.scattered) + result |= rScattered; + if (reloc.pcRel) + result |= rPcRel; + if (reloc.isExtern) + result |= rExtern; + switch(reloc.length) { + case 0: + break; + case 1: + result |= rLength2; + break; + case 2: + result |= rLength4; + break; + case 3: + result |= rLength8; + break; + default: + llvm_unreachable("bad r_length"); + } + return result; +} + +bool KindHandler::isPairedReloc(const Relocation &reloc) { + llvm_unreachable("abstract"); +} + +std::error_code +KindHandler::getReferenceInfo(const 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) { + llvm_unreachable("abstract"); +} + +std::error_code +KindHandler::getPairReferenceInfo(const normalized::Relocation &reloc1, + const normalized::Relocation &reloc2, + 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) { + llvm_unreachable("abstract"); +} + //===----------------------------------------------------------------------===// // KindHandler_x86_64 //===----------------------------------------------------------------------===// @@ -56,38 +115,226 @@ KindHandler_x86_64::~KindHandler_x86_64() { } const Registry::KindStrings KindHandler_x86_64::kindStrings[] = { - LLD_KIND_STRING_ENTRY(X86_64_RELOC_UNSIGNED), - LLD_KIND_STRING_ENTRY(X86_64_RELOC_BRANCH), - LLD_KIND_STRING_ENTRY(X86_64_RELOC_SIGNED), - LLD_KIND_STRING_ENTRY(X86_64_RELOC_SIGNED_1), - LLD_KIND_STRING_ENTRY(X86_64_RELOC_SIGNED_2), - LLD_KIND_STRING_ENTRY(X86_64_RELOC_SIGNED_4), - LLD_KIND_STRING_ENTRY(X86_64_RELOC_GOT_LOAD), - LLD_KIND_STRING_ENTRY(X86_64_RELOC_GOT), - LLD_KIND_STRING_ENTRY(X86_64_RELOC_TLV), - LLD_KIND_STRING_ENTRY(LLD_X86_64_RELOC_GOT_LOAD_NOW_LEA), - LLD_KIND_STRING_ENTRY(LLD_X86_64_RELOC_TLV_NOW_LEA), - LLD_KIND_STRING_ENTRY(LLD_X86_64_RELOC_LAZY_TARGET), - LLD_KIND_STRING_ENTRY(LLD_X86_64_RELOC_LAZY_IMMEDIATE), + LLD_KIND_STRING_ENTRY(invalid), + LLD_KIND_STRING_ENTRY(branch32), + LLD_KIND_STRING_ENTRY(ripRel32), + LLD_KIND_STRING_ENTRY(ripRel32Minus1), + LLD_KIND_STRING_ENTRY(ripRel32Minus2), + LLD_KIND_STRING_ENTRY(ripRel32Minus4), + LLD_KIND_STRING_ENTRY(ripRel32Anon), + LLD_KIND_STRING_ENTRY(ripRel32GotLoad), + LLD_KIND_STRING_ENTRY(ripRel32GotLoadNowLea), + LLD_KIND_STRING_ENTRY(ripRel32Got), + LLD_KIND_STRING_ENTRY(lazyPointer), + LLD_KIND_STRING_ENTRY(lazyImmediateLocation), + 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_END }; - + bool KindHandler_x86_64::isCallSite(const Reference &ref) { - return (ref.kindValue() == X86_64_RELOC_BRANCH); + if (ref.kindNamespace() != Reference::KindNamespace::mach_o) + return false; + assert(ref.kindArch() == Reference::KindArch::x86_64); + return (ref.kindValue() == branch32); } bool KindHandler_x86_64::isPointer(const Reference &ref) { - return (ref.kindValue() == X86_64_RELOC_UNSIGNED); + if (ref.kindNamespace() != Reference::KindNamespace::mach_o) + return false; + assert(ref.kindArch() == Reference::KindArch::x86_64); + return (ref.kindValue() == pointer64); } bool KindHandler_x86_64::isLazyImmediate(const Reference &ref) { - return (ref.kindValue() == LLD_X86_64_RELOC_LAZY_IMMEDIATE); + if (ref.kindNamespace() != Reference::KindNamespace::mach_o) + return false; + assert(ref.kindArch() == Reference::KindArch::x86_64); + return (ref.kindValue() == lazyImmediateLocation); } bool KindHandler_x86_64::isLazyTarget(const Reference &ref) { - return (ref.kindValue() == LLD_X86_64_RELOC_LAZY_TARGET); + if (ref.kindNamespace() != Reference::KindNamespace::mach_o) + return false; + assert(ref.kindArch() == Reference::KindArch::x86_64); + return (ref.kindValue() == lazyPointer); +} + +bool KindHandler_x86_64::isPairedReloc(const Relocation &reloc) { + return (reloc.type == X86_64_RELOC_SUBTRACTOR); +} + +static int32_t readS32(bool swap, const uint8_t *addr) { + return read32(swap, *reinterpret_cast(addr)); } +static int64_t readS64(bool swap, const uint8_t *addr) { + return read64(swap, *reinterpret_cast(addr)); +} + +Reference::KindValue +KindHandler_x86_64::kindFromReloc(const Relocation &reloc) { + switch(relocPattern(reloc)) { + case X86_64_RELOC_BRANCH | rPcRel | rExtern | rLength4: + return branch32; + case X86_64_RELOC_SIGNED | rPcRel | rExtern | rLength4: + return ripRel32; + case X86_64_RELOC_SIGNED | rPcRel | rLength4: + return ripRel32Anon; + case X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4: + return ripRel32Minus1; + case X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4: + return ripRel32Minus2; + case X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4: + return ripRel32Minus4; + case X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4: + return ripRel32GotLoad; + case X86_64_RELOC_GOT | rPcRel | rExtern | rLength4: + return ripRel32Got; + case X86_64_RELOC_UNSIGNED | rExtern | rLength8: + return pointer64; + case X86_64_RELOC_UNSIGNED | rLength8: + return pointer64Anon; + default: + return invalid; + } + +} + + +std::error_code +KindHandler_x86_64::getReferenceInfo(const 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) { + typedef std::error_code E; + *kind = kindFromReloc(reloc); + if (*kind == invalid) + return make_dynamic_error_code(Twine("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)) + return ec; + *addend = readS32(swap, fixupContent); + return std::error_code(); + case ripRel32Minus1: + if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + return ec; + *addend = readS32(swap, fixupContent) + 1; + return std::error_code(); + case ripRel32Minus2: + if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + return ec; + *addend = readS32(swap, fixupContent) + 2; + return std::error_code(); + case ripRel32Minus4: + if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + return ec; + *addend = readS32(swap, fixupContent) + 4; + return std::error_code(); + case ripRel32Anon: + targetAddress = fixupAddress + 4 + readS32(swap, fixupContent); + return atomFromAddress(reloc.symbol, targetAddress, target, addend); + case ripRel32GotLoad: + case ripRel32Got: + if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + return ec; + *addend = 0; + return std::error_code(); + case pointer64: + if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + return ec; + *addend = readS64(swap, fixupContent); + return std::error_code(); + case pointer64Anon: + targetAddress = readS64(swap, fixupContent); + return atomFromAddress(reloc.symbol, targetAddress, target, addend); + default: + llvm_unreachable("bad reloc kind"); + } +} + + +Reference::KindValue +KindHandler_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 +KindHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1, + const normalized::Relocation &reloc2, + 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) { + *kind = kindFromRelocPair(reloc1, reloc2); + if (*kind == invalid) + return make_dynamic_error_code(Twine("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)) + return ec; + if (fromTarget != inAtom) + return make_dynamic_error_code(Twine("pointer diff not in base atom")); + switch (*kind) { + case delta64: + if (E ec = atomFromSymbolIndex(reloc2.symbol, target)) + return ec; + *addend = readS64(swap, fixupContent) + offsetInAtom; + return std::error_code(); + case delta32: + if (E ec = atomFromSymbolIndex(reloc2.symbol, target)) + return ec; + *addend = readS32(swap, fixupContent) + offsetInAtom; + return std::error_code(); + case delta64Anon: + targetAddress = offsetInAtom + readS64(swap, fixupContent); + return atomFromAddress(reloc2.symbol, targetAddress, target, addend); + case delta32Anon: + targetAddress = offsetInAtom + readS32(swap, fixupContent); + return atomFromAddress(reloc2.symbol, targetAddress, target, addend); + default: + llvm_unreachable("bad reloc pair kind"); + } +} + + + void KindHandler_x86_64::applyFixup(Reference::KindNamespace ns, Reference::KindArch arch, Reference::KindValue kindValue, @@ -100,39 +347,43 @@ void KindHandler_x86_64::applyFixup(Reference::KindNamespace ns, int32_t *loc32 = reinterpret_cast(location); uint64_t* loc64 = reinterpret_cast(location); switch (kindValue) { - case X86_64_RELOC_BRANCH: - case X86_64_RELOC_SIGNED: - case X86_64_RELOC_GOT_LOAD: - case X86_64_RELOC_GOT: - case X86_64_RELOC_TLV: - *loc32 = (targetAddress - (fixupAddress+4)) + addend; - break; - case X86_64_RELOC_UNSIGNED: - *loc64 = targetAddress + addend; - break; - case X86_64_RELOC_SIGNED_1: - *loc32 = (targetAddress - (fixupAddress+5)) + addend; - break; - case X86_64_RELOC_SIGNED_2: - *loc32 = (targetAddress - (fixupAddress+6)) + addend; - break; - case X86_64_RELOC_SIGNED_4: - *loc32 = (targetAddress - (fixupAddress+8)) + addend; - break; - case LLD_X86_64_RELOC_SIGNED_32: - *loc32 = (targetAddress - fixupAddress) + addend; - break; - case LLD_X86_64_RELOC_GOT_LOAD_NOW_LEA: - case LLD_X86_64_RELOC_TLV_NOW_LEA: - // Change MOVQ to LEA - assert(location[-2] == 0x8B); - location[-2] = 0x8D; - *loc32 = (targetAddress - (fixupAddress+4)) + addend; - break; - case LLD_X86_64_RELOC_LAZY_TARGET: - case LLD_X86_64_RELOC_LAZY_IMMEDIATE: - // do nothing - break; + case branch32: + case ripRel32: + case ripRel32Got: + case ripRel32GotLoad: + *loc32 = (targetAddress - (fixupAddress+4)) + addend; + break; + case pointer64: + case pointer64Anon: + *loc64 = targetAddress + addend; + break; + case ripRel32Minus1: + *loc32 = (targetAddress - (fixupAddress+5)) + addend; + break; + case ripRel32Minus2: + *loc32 = (targetAddress - (fixupAddress+6)) + addend; + break; + case ripRel32Minus4: + *loc32 = (targetAddress - (fixupAddress+8)) + addend; + break; + case delta32: + case delta32Anon: + *loc32 = (targetAddress - fixupAddress) + addend; + break; + case delta64: + case delta64Anon: + *loc64 = (targetAddress - fixupAddress) + addend; + break; + case ripRel32GotLoadNowLea: + // Change MOVQ to LEA + assert(location[-2] == 0x8B); + location[-2] = 0x8D; + *loc32 = (targetAddress - (fixupAddress+4)) + addend; + break; + case lazyPointer: + case lazyImmediateLocation: + // do nothing + break; default: llvm_unreachable("invalid x86_64 Reference Kind"); break; diff --git a/lld/lib/ReaderWriter/MachO/ReferenceKinds.h b/lld/lib/ReaderWriter/MachO/ReferenceKinds.h index adc1961..994c384 100644 --- a/lld/lib/ReaderWriter/MachO/ReferenceKinds.h +++ b/lld/lib/ReaderWriter/MachO/ReferenceKinds.h @@ -8,6 +8,8 @@ //===----------------------------------------------------------------------===// +#include "MachONormalizedFile.h" + #include "lld/Core/LLVM.h" #include "lld/Core/Reference.h" #include "lld/ReaderWriter/MachOLinkingContext.h" @@ -20,15 +22,9 @@ namespace lld { namespace mach_o { + // Additional Reference Kind values used internally. enum { - LLD_X86_64_RELOC_GOT_LOAD_NOW_LEA = 100, - LLD_X86_64_RELOC_TLV_NOW_LEA = 101, - LLD_X86_64_RELOC_LAZY_TARGET = 102, - LLD_X86_64_RELOC_LAZY_IMMEDIATE = 103, - LLD_X86_64_RELOC_SIGNED_32 = 104, -}; -enum { LLD_X86_RELOC_BRANCH32 = 100, // CALL or JMP 32-bit pc-rel LLD_X86_RELOC_ABS32 = 101, // 32-bit absolute addr in instruction LLD_X86_RELOC_FUNC_REL32 = 102, // 32-bit target from start of func @@ -62,6 +58,53 @@ public: virtual bool isPointer(const Reference &) = 0; virtual bool isLazyImmediate(const Reference &) = 0; virtual bool isLazyTarget(const Reference &) = 0; + + /// Returns true if the specified relocation is paired to the next relocation. + virtual bool isPairedReloc(const normalized::Relocation &); + + /// Prototype for a helper function. Given a sectionIndex and address, + /// finds the atom and offset with that atom of that address. + typedef std::function + FindAtomBySectionAndAddress; + + /// Prototype for a helper function. Given a symbolIndex, finds the atom + /// representing that symbol. + typedef std::function 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 + 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); + + /// Analyzes a pair of relocations 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 + getPairReferenceInfo(const normalized::Relocation &reloc1, + const normalized::Relocation &reloc2, + 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); + + /// Fixup an atom when generating a final linked binary. virtual void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch, Reference::KindValue kindValue, uint64_t addend, uint8_t *location, uint64_t fixupAddress, @@ -69,6 +112,20 @@ public: protected: KindHandler(); + + // Handy way to pack mach-o r_type and other bit fields into one 16-bit value. + typedef uint16_t RelocPattern; + enum { + rScattered = 0x8000, + rPcRel = 0x4000, + rExtern = 0x2000, + rLength1 = 0x0000, + rLength2 = 0x0100, + rLength4 = 0x0200, + rLength8 = 0x0300 + }; + static RelocPattern relocPattern(const normalized::Relocation &reloc); + }; @@ -82,10 +139,72 @@ public: bool isPointer(const Reference &) override; bool isLazyImmediate(const Reference &) override; bool isLazyTarget(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 + getPairReferenceInfo(const normalized::Relocation &reloc1, + const normalized::Relocation &reloc2, + 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; + virtual void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch, Reference::KindValue kindValue, uint64_t addend, uint8_t *location, uint64_t fixupAddress, uint64_t targetAddress) override; + +private: + friend class X86_64LazyPointerAtom; + friend class X86_64StubHelperAtom; + friend class X86_64StubAtom; + friend class X86_64StubHelperCommonAtom; + friend class X86_64NonLazyPointerAtom; + + enum : Reference::KindValue { + invalid, /// for error condition + + // Kinds found in mach-o .o files: + branch32, /// ex: call _foo + ripRel32, /// ex: movq _foo(%rip), %rax + ripRel32Minus1, /// ex: movb $0x12, _foo(%rip) + ripRel32Minus2, /// ex: movw $0x1234, _foo(%rip) + ripRel32Minus4, /// ex: movl $0x12345678, _foo(%rip) + ripRel32Anon, /// ex: movq L1(%rip), %rax + ripRel32GotLoad, /// ex: movq _foo@GOTPCREL(%rip), %rax + ripRel32Got, /// ex: pushq _foo@GOTPCREL(%rip) + pointer64, /// ex: .quad _foo + pointer64Anon, /// ex: .quad L1 + delta64, /// ex: .quad _foo - . + delta32, /// ex: .long _foo - . + delta64Anon, /// ex: .quad L1 - . + delta32Anon, /// ex: .long L1 - . + + // Kinds introduced by Passes: + ripRel32GotLoadNowLea, /// Target of GOT load is in linkage unit so + /// "movq _foo@GOTPCREL(%rip), %rax" can be changed + /// to "leaq _foo(%rip), %rax + lazyPointer, /// Location contains a lazy pointer. + lazyImmediateLocation, /// Location contains immediate value used in stub. + }; + + Reference::KindValue kindFromReloc(const normalized::Relocation &reloc); + Reference::KindValue kindFromRelocPair(const normalized::Relocation &reloc1, + const normalized::Relocation &reloc2); + + }; class KindHandler_x86 : public KindHandler { diff --git a/lld/lib/ReaderWriter/MachO/StubAtoms_x86_64.hpp b/lld/lib/ReaderWriter/MachO/StubAtoms_x86_64.hpp index dcd309b..6608732 100644 --- a/lld/lib/ReaderWriter/MachO/StubAtoms_x86_64.hpp +++ b/lld/lib/ReaderWriter/MachO/StubAtoms_x86_64.hpp @@ -33,7 +33,8 @@ public: X86_64StubAtom(const File &file, const Atom &lazyPointer) : SimpleDefinedAtom(file) { this->addReference(Reference::KindNamespace::mach_o, - Reference::KindArch::x86_64, X86_64_RELOC_SIGNED, 2, + Reference::KindArch::x86_64, + KindHandler_x86_64::ripRel32, 2, &lazyPointer, 0); } @@ -66,11 +67,11 @@ public: const Atom &binder) : SimpleDefinedAtom(file) { this->addReference(Reference::KindNamespace::mach_o, - Reference::KindArch::x86_64, X86_64_RELOC_SIGNED, 3, - &cache, 0); + Reference::KindArch::x86_64, + KindHandler_x86_64::ripRel32, 3, &cache, 0); this->addReference(Reference::KindNamespace::mach_o, - Reference::KindArch::x86_64, X86_64_RELOC_SIGNED, 11, - &binder, 0); + Reference::KindArch::x86_64, + KindHandler_x86_64::ripRel32, 11, &binder, 0); } ContentType contentType() const override { @@ -105,9 +106,10 @@ public: : SimpleDefinedAtom(file) { this->addReference(Reference::KindNamespace::mach_o, Reference::KindArch::x86_64, - LLD_X86_64_RELOC_LAZY_IMMEDIATE, 1, this, 0); + KindHandler_x86_64::lazyImmediateLocation, 1, this, 0); this->addReference(Reference::KindNamespace::mach_o, - Reference::KindArch::x86_64, X86_64_RELOC_SIGNED, 6, + Reference::KindArch::x86_64, + KindHandler_x86_64::ripRel32, 6, &helperCommon, 0); } @@ -141,11 +143,11 @@ public: const Atom &shlib) : SimpleDefinedAtom(file) { this->addReference(Reference::KindNamespace::mach_o, - Reference::KindArch::x86_64, X86_64_RELOC_UNSIGNED, 0, - &helper, 0); + Reference::KindArch::x86_64, + KindHandler_x86_64::pointer64, 0, &helper, 0); this->addReference(Reference::KindNamespace::mach_o, Reference::KindArch::x86_64, - LLD_X86_64_RELOC_LAZY_TARGET, 0, &shlib, 0); + KindHandler_x86_64::lazyPointer, 0, &shlib, 0); } ContentType contentType() const override { @@ -182,8 +184,8 @@ public: X86_64NonLazyPointerAtom(const File &file, const Atom &shlib) : SimpleDefinedAtom(file) { this->addReference(Reference::KindNamespace::mach_o, - Reference::KindArch::x86_64, X86_64_RELOC_UNSIGNED, 0, - &shlib, 0); + Reference::KindArch::x86_64, + KindHandler_x86_64::pointer64, 0, &shlib, 0); } ContentType contentType() const override { diff --git a/lld/test/darwin/hello-world.objtxt b/lld/test/darwin/hello-world.objtxt index 72cd6b5..7d13b4b 100644 --- a/lld/test/darwin/hello-world.objtxt +++ b/lld/test/darwin/hello-world.objtxt @@ -14,10 +14,10 @@ defined-atoms: 31, C0, 5D, C3 ] references: - offset: 7 - kind: X86_64_RELOC_SIGNED + kind: ripRel32 target: LC1 - offset: 12 - kind: X86_64_RELOC_BRANCH + kind: branch32 target: _printf - ref-name: LC1 diff --git a/lld/test/darwin/native-and-mach-o.objtxt b/lld/test/darwin/native-and-mach-o.objtxt index b94bf85..f8e118d 100644 --- a/lld/test/darwin/native-and-mach-o.objtxt +++ b/lld/test/darwin/native-and-mach-o.objtxt @@ -13,7 +13,7 @@ defined-atoms: 00, 00, 00, 31, C0, 5D, C3 ] references: - offset: 7 - kind: X86_64_RELOC_BRANCH + kind: branch32 target: _foo undefined-atoms: diff --git a/lld/test/mach-o/parse-cfstring64.yaml b/lld/test/mach-o/parse-cfstring64.yaml index ebb02a7..fbd674d 100644 --- a/lld/test/mach-o/parse-cfstring64.yaml +++ b/lld/test/mach-o/parse-cfstring64.yaml @@ -72,20 +72,37 @@ undefined-symbols: value: 0x0000000000000000 ... -# CHECK: defined-atoms: -# CHECK: - scope: hidden +# CHECK:defined-atoms: +# CHECK: - ref-name: L000 +# CHECK: scope: hidden # CHECK: type: c-string # CHECK: content: [ 68, 65, 6C, 6C, 6F, 00 ] # CHECK: merge: by-content -# CHECK: - scope: hidden +# CHECK: - ref-name: L001 +# CHECK: scope: hidden # CHECK: type: c-string # CHECK: content: [ 74, 68, 65, 72, 65, 00 ] # CHECK: merge: by-content # CHECK: - scope: hidden # CHECK: type: cfstring # CHECK: merge: by-content +# CHECK: references: +# CHECK: - kind: pointer64 +# CHECK: offset: 0 +# CHECK: target: ___CFConstantStringClassReference +# CHECK: - kind: pointer64 +# CHECK: offset: 16 +# CHECK: target: L000 # CHECK: - scope: hidden # CHECK: type: cfstring # CHECK: merge: by-content -# CHECK:undefined-atoms: +# CHECK: references: +# CHECK: - kind: pointer64 +# CHECK: offset: 0 +# CHECK: target: ___CFConstantStringClassReference +# CHECK: - kind: pointer64 +# CHECK: offset: 16 +# CHECK: target: L001 +# CHECK:undefined-atoms: # CHECK: - name: ___CFConstantStringClassReference + diff --git a/lld/test/mach-o/parse-data-relocs-x86_64.yaml b/lld/test/mach-o/parse-data-relocs-x86_64.yaml new file mode 100644 index 0000000..ffc9e477 --- /dev/null +++ b/lld/test/mach-o/parse-data-relocs-x86_64.yaml @@ -0,0 +1,223 @@ +# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s +# +# Test parsing of x86_64 data relocations. +# +#_foo: +# ret +# +#_bar: +# ret +# +# .section __DATA,__custom +#L1: +# .quad 0 +# +# .data +#_d: +# .quad _foo +# .quad _foo+4 +# .quad _foo - . +# .quad L1 +# .quad L1 + 2 +# .quad _foo - . +# .quad _foo + 4 - . +# .quad L1 - . +# .long _foo - . +# .long _foo + 4 - . +# .long L1 - . +# + +--- !mach-o +arch: x86_64 +file-type: MH_OBJECT +flags: [ ] +has-UUID: false +OS: unknown +sections: + - segment: __TEXT + section: __text + type: S_REGULAR + attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ] + address: 0x0000000000000000 + content: [ 0xC3, 0xC3 ] + - segment: __DATA + section: __custom + type: S_REGULAR + attributes: [ ] + address: 0x0000000000000002 + content: [ 0x00, 0x00, 0x00, 0x00 ] + - segment: __DATA + section: __data + type: S_REGULAR + attributes: [ ] + alignment: 3 + address: 0x0000000000000008 + content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xDC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xD2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC8, 0xFF, 0xFF, 0xFF, 0xC8, 0xFF, 0xFF, 0xFF, + 0xC2, 0xFF, 0xFF, 0xFF ] + relocations: + - offset: 0x00000040 + type: X86_64_RELOC_SUBTRACTOR + length: 2 + pc-rel: false + extern: true + symbol: 2 + - offset: 0x00000040 + type: X86_64_RELOC_UNSIGNED + length: 2 + pc-rel: false + extern: false + symbol: 2 + - offset: 0x0000003C + type: X86_64_RELOC_SUBTRACTOR + length: 2 + pc-rel: false + extern: true + symbol: 2 + - offset: 0x0000003C + type: X86_64_RELOC_UNSIGNED + length: 2 + pc-rel: false + extern: true + symbol: 0 + - offset: 0x00000038 + type: X86_64_RELOC_SUBTRACTOR + length: 2 + pc-rel: false + extern: true + symbol: 2 + - offset: 0x00000038 + type: X86_64_RELOC_UNSIGNED + length: 2 + pc-rel: false + extern: true + symbol: 0 + - offset: 0x00000030 + type: X86_64_RELOC_SUBTRACTOR + length: 3 + pc-rel: false + extern: true + symbol: 2 + - offset: 0x00000030 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 2 + - offset: 0x00000028 + type: X86_64_RELOC_SUBTRACTOR + length: 3 + pc-rel: false + extern: true + symbol: 2 + - offset: 0x00000028 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 0 + - offset: 0x00000020 + type: X86_64_RELOC_SUBTRACTOR + length: 3 + pc-rel: false + extern: true + symbol: 2 + - offset: 0x00000020 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 0 + - offset: 0x00000018 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 2 + - offset: 0x00000010 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 2 + - offset: 0x00000008 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 0 + - offset: 0x00000000 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 0 +local-symbols: + - name: _foo + type: N_SECT + sect: 1 + value: 0x0000000000000000 + - name: _bar + type: N_SECT + sect: 1 + value: 0x0000000000000001 + - name: _d + type: N_SECT + sect: 3 + value: 0x0000000000000008 +... + + +# CHECK: defined-atoms: +# CHECK: - name: _d +# CHECK: type: data +# CHECK: references: +# CHECK: - kind: pointer64 +# CHECK: offset: 0 +# CHECK: target: _foo +# CHECK: - kind: pointer64 +# CHECK: offset: 8 +# CHECK: target: _foo +# CHECK: addend: 4 +# CHECK: - kind: pointer64Anon +# CHECK: offset: 16 +# CHECK: target: L003 +# CHECK: - kind: pointer64Anon +# CHECK: offset: 24 +# CHECK: target: L003 +# CHECK: addend: 2 +# CHECK: - kind: delta64 +# CHECK: offset: 32 +# CHECK: target: _foo +# CHECK: - kind: delta64 +# CHECK: offset: 40 +# CHECK: target: _foo +# CHECK: addend: 4 +# CHECK: - kind: delta64Anon +# CHECK: offset: 48 +# CHECK: target: L003 +# CHECK: - kind: delta32 +# CHECK: offset: 56 +# CHECK: target: _foo +# CHECK: - kind: delta32 +# CHECK: offset: 60 +# CHECK: target: _foo +# CHECK: addend: 4 +# CHECK: - kind: delta32Anon +# CHECK: offset: 64 +# CHECK: target: L003 +# CHECK: - name: _foo +# CHECK: content: [ C3 ] +# CHECK: - name: _bar +# CHECK: content: [ C3 ] +# CHECK: - ref-name: L003 +# CHECK: type: unknown +# CHECK: content: [ 00, 00, 00, 00 ] +# CHECK: section-choice: custom-required +# CHECK: section-name: __DATA/__custom diff --git a/lld/test/mach-o/parse-initializers64.yaml b/lld/test/mach-o/parse-initializers64.yaml index d44ce1f..5ebd8da 100644 --- a/lld/test/mach-o/parse-initializers64.yaml +++ b/lld/test/mach-o/parse-initializers64.yaml @@ -32,13 +32,13 @@ sections: length: 3 pc-rel: false extern: true - symbol: 1 + symbol: 0 - offset: 0x00000008 type: X86_64_RELOC_UNSIGNED length: 3 pc-rel: false extern: true - symbol: 2 + symbol: 1 - segment: __DATA section: __mod_term_func type: S_MOD_TERM_FUNC_POINTERS @@ -52,7 +52,7 @@ sections: length: 3 pc-rel: false extern: true - symbol: 3 + symbol: 2 global-symbols: - name: _init type: N_SECT @@ -76,12 +76,24 @@ global-symbols: # CHECK: - type: initializer-pointer # CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ] # CHECK: dead-strip: never +# CHECK: references: +# CHECK: - kind: pointer64 +# CHECK: offset: 0 +# CHECK: target: _init # CHECK: - type: initializer-pointer # CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ] # CHECK: dead-strip: never +# CHECK: references: +# CHECK: - kind: pointer64 +# CHECK: offset: 0 +# CHECK: target: _init2 # CHECK: - type: terminator-pointer # CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ] # CHECK: dead-strip: never +# CHECK: references: +# CHECK: - kind: pointer64 +# CHECK: offset: 0 +# CHECK: target: _term # CHECK: - name: _init # CHECK: scope: global # CHECK: content: [ 55, 48, 89, E5, 5D, C3 ] diff --git a/lld/test/mach-o/parse-text-relocs-x86_64.yaml b/lld/test/mach-o/parse-text-relocs-x86_64.yaml new file mode 100644 index 0000000..e3b9cf2 --- /dev/null +++ b/lld/test/mach-o/parse-text-relocs-x86_64.yaml @@ -0,0 +1,138 @@ +# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s +# +# Test parsing of x86_64 text relocations. +# +#_test: +# call _foo +# call _foo+4 +# movq _foo@GOTPCREL(%rip), %rax +# pushq _foo@GOTPCREL(%rip) +# movl _foo(%rip), %eax +# movl _foo+4(%rip), %eax +# movb $0x12, _foo(%rip) +# movw $0x1234, _foo(%rip) +# movl $0x12345678, _foo(%rip) +# + +--- !mach-o +arch: x86_64 +file-type: MH_OBJECT +flags: [ ] +has-UUID: false +OS: unknown +sections: + - segment: __TEXT + section: __text + type: S_REGULAR + attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ] + address: 0x0000000000000000 + content: [ 0xE8, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x04, 0x00, + 0x00, 0x00, 0x48, 0x8B, 0x05, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0x35, 0x00, 0x00, 0x00, 0x00, 0x8B, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x05, 0x04, + 0x00, 0x00, 0x00, 0xC6, 0x05, 0xFF, 0xFF, 0xFF, + 0xFF, 0x12, 0x66, 0xC7, 0x05, 0xFE, 0xFF, 0xFF, + 0xFF, 0x34, 0x12, 0xC7, 0x05, 0xFC, 0xFF, 0xFF, + 0xFF, 0x78, 0x56, 0x34, 0x12 ] + relocations: + - offset: 0x00000035 + type: X86_64_RELOC_SIGNED_4 + length: 2 + pc-rel: true + extern: true + symbol: 1 + - offset: 0x0000002D + type: X86_64_RELOC_SIGNED_2 + length: 2 + pc-rel: true + extern: true + symbol: 1 + - offset: 0x00000025 + type: X86_64_RELOC_SIGNED_1 + length: 2 + pc-rel: true + extern: true + symbol: 1 + - offset: 0x0000001F + type: X86_64_RELOC_SIGNED + length: 2 + pc-rel: true + extern: true + symbol: 1 + - offset: 0x00000019 + type: X86_64_RELOC_SIGNED + length: 2 + pc-rel: true + extern: true + symbol: 1 + - offset: 0x00000013 + type: X86_64_RELOC_GOT + length: 2 + pc-rel: true + extern: true + symbol: 1 + - offset: 0x0000000D + type: X86_64_RELOC_GOT_LOAD + length: 2 + pc-rel: true + extern: true + symbol: 1 + - offset: 0x00000006 + type: X86_64_RELOC_BRANCH + length: 2 + pc-rel: true + extern: true + symbol: 1 + - offset: 0x00000001 + type: X86_64_RELOC_BRANCH + length: 2 + pc-rel: true + extern: true + symbol: 1 +local-symbols: + - name: _test + type: N_SECT + sect: 1 + value: 0x0000000000000000 +undefined-symbols: + - name: _foo + type: N_UNDF + scope: [ N_EXT ] + value: 0x0000000000000000 +... +# CHECK: defined-atoms: +# CHECK: - name: _test +# CHECK: references: +# CHECK: - kind: branch32 +# CHECK: offset: 1 +# CHECK: target: _foo +# CHECK: - kind: branch32 +# CHECK: offset: 6 +# CHECK: target: _foo +# CHECK: addend: 4 +# CHECK: - kind: ripRel32GotLoad +# CHECK: offset: 13 +# CHECK: target: _foo +# CHECK: - kind: ripRel32Got +# CHECK: offset: 19 +# CHECK: target: _foo +# CHECK: - kind: ripRel32 +# CHECK: offset: 25 +# CHECK: target: _foo +# CHECK: - kind: ripRel32 +# CHECK: offset: 31 +# CHECK: target: _foo +# CHECK: addend: 4 +# CHECK: - kind: ripRel32Minus1 +# CHECK: offset: 37 +# CHECK: target: _foo +# CHECK-NOT: addend: +# CHECK: - kind: ripRel32Minus2 +# CHECK: offset: 45 +# CHECK: target: _foo +# CHECK-NOT: addend: +# CHECK: - kind: ripRel32Minus4 +# CHECK: offset: 53 +# CHECK: target: _foo +# CHECK-NOT: addend: + -- 2.7.4