From 9133f8c76d27c350bfc625319558f2f9cd2f8c03 Mon Sep 17 00:00:00 2001 From: Nick Kledzik Date: Tue, 21 Oct 2014 23:45:37 +0000 Subject: [PATCH] [mach-o] Support missing MH_SUBSECTIONS_VIA_SYMBOLS All compiler generated mach-o object files are marked with MH_SUBSECTIONS_VIA_SYMBOLS. But hand written assembly files need to opt-in if they are written correctly. The flag means the linker can break up a sections at symbol addresses and dead strip or re-order functions. This change recognizes object files without the flag and marks its atoms as not dead strippable and adds a layout-after chain of references so that the atoms cannot be re-ordered. llvm-svn: 220348 --- lld/lib/ReaderWriter/MachO/ArchHandler.h | 2 +- lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp | 5 +- lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp | 4 +- lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp | 3 +- lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp | 3 +- .../MachO/MachONormalizedFileToAtoms.cpp | 51 +++++++++++++----- lld/test/mach-o/arm-subsections-via-symbols.yaml | 60 ++++++++++++++++++++++ lld/test/mach-o/parse-data-relocs-x86_64.yaml | 3 +- 8 files changed, 109 insertions(+), 22 deletions(-) create mode 100644 lld/test/mach-o/arm-subsections-via-symbols.yaml diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler.h b/lld/lib/ReaderWriter/MachO/ArchHandler.h index 2f4a3cb..0dedf81 100644 --- a/lld/lib/ReaderWriter/MachO/ArchHandler.h +++ b/lld/lib/ReaderWriter/MachO/ArchHandler.h @@ -134,7 +134,7 @@ public: const normalized::Relocation &reloc2, const DefinedAtom *inAtom, uint32_t offsetInAtom, - uint64_t fixupAddress, bool swap, + uint64_t fixupAddress, bool swap, bool scatterable, FindAtomBySectionAndAddress atomFromAddress, FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind, diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp index 64d3fbe..c4fc879 100644 --- a/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp +++ b/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp @@ -77,7 +77,7 @@ public: const normalized::Relocation &reloc2, const DefinedAtom *inAtom, uint32_t offsetInAtom, - uint64_t fixupAddress, bool swap, + uint64_t fixupAddress, bool swap, bool scatterable, FindAtomBySectionAndAddress atomFromAddress, FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind, @@ -627,6 +627,7 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1, const DefinedAtom *inAtom, uint32_t offsetInAtom, uint64_t fixupAddress, bool swap, + bool scatterable, FindAtomBySectionAndAddress atomFromAddr, FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind, @@ -795,7 +796,7 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1, ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom); if (ec) return ec; - if (fromTarget != inAtom) + if (scatterable && (fromTarget != inAtom)) return make_dynamic_error_code(Twine("SECTDIFF relocation where " "subtrahend label is not in atom")); *kind = delta32; diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp index c70ee8e..330f182 100644 --- a/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp +++ b/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp @@ -120,7 +120,7 @@ public: const normalized::Relocation &reloc2, const DefinedAtom *inAtom, uint32_t offsetInAtom, - uint64_t fixupAddress, bool swap, + uint64_t fixupAddress, bool swap, bool scatterable, FindAtomBySectionAndAddress atomFromAddress, FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind, @@ -418,7 +418,7 @@ std::error_code ArchHandler_arm64::getReferenceInfo( std::error_code ArchHandler_arm64::getPairReferenceInfo( const normalized::Relocation &reloc1, const normalized::Relocation &reloc2, const DefinedAtom *inAtom, uint32_t offsetInAtom, uint64_t fixupAddress, - bool swap, FindAtomBySectionAndAddress atomFromAddress, + 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]; diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp index abc8d79..1d6b6c0 100644 --- a/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp +++ b/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp @@ -80,7 +80,7 @@ public: const normalized::Relocation &reloc2, const DefinedAtom *inAtom, uint32_t offsetInAtom, - uint64_t fixupAddress, bool swap, + uint64_t fixupAddress, bool swap, bool scatterable, FindAtomBySectionAndAddress atomFromAddress, FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind, @@ -337,6 +337,7 @@ ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1, const DefinedAtom *inAtom, uint32_t offsetInAtom, uint64_t fixupAddress, bool swap, + bool scatterable, FindAtomBySectionAndAddress atomFromAddr, FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind, diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp index 193b3e8..352bc12 100644 --- a/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp +++ b/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp @@ -122,7 +122,7 @@ public: const normalized::Relocation &reloc2, const DefinedAtom *inAtom, uint32_t offsetInAtom, - uint64_t fixupAddress, bool swap, + uint64_t fixupAddress, bool swap, bool scatterable, FindAtomBySectionAndAddress atomFromAddress, FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind, @@ -401,6 +401,7 @@ ArchHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1, const DefinedAtom *inAtom, uint32_t offsetInAtom, uint64_t fixupAddress, bool swap, + bool scatterable, FindAtomBySectionAndAddress atomFromAddress, FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind, diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp index 3875c62..ba8a08b 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp @@ -220,12 +220,12 @@ void appendSymbolsInSection(const std::vector &inSymbols, void atomFromSymbol(DefinedAtom::ContentType atomType, const Section §ion, MachOFile &file, uint64_t symbolAddr, StringRef symbolName, uint16_t symbolDescFlags, Atom::Scope symbolScope, - uint64_t nextSymbolAddr, bool copyRefs) { + uint64_t nextSymbolAddr, bool scatterable, bool copyRefs) { // 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; - bool noDeadStrip = (symbolDescFlags & N_NO_DEAD_STRIP); + bool noDeadStrip = (symbolDescFlags & N_NO_DEAD_STRIP) || !scatterable; if (section.type == llvm::MachO::S_ZEROFILL) { file.addZeroFillDefinedAtom(symbolName, symbolScope, offset, size, noDeadStrip, copyRefs, §ion); @@ -256,7 +256,8 @@ void atomFromSymbol(DefinedAtom::ContentType atomType, const Section §ion, std::error_code processSymboledSection(DefinedAtom::ContentType atomType, const Section §ion, const NormalizedFile &normalizedFile, - MachOFile &file, bool copyRefs) { + MachOFile &file, bool scatterable, + bool copyRefs) { // Find section's index. uint32_t sectIndex = 1; for (auto § : normalizedFile.sections) { @@ -309,13 +310,14 @@ std::error_code processSymboledSection(DefinedAtom::ContentType atomType, // 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); + section.address + section.content.size(), + scatterable, 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, symbols.front()->value, - copyRefs); + scatterable, copyRefs); } const Symbol *lastSym = nullptr; @@ -328,7 +330,7 @@ std::error_code processSymboledSection(DefinedAtom::ContentType atomType, || !lastSym->name.startswith("ltmp")) { atomFromSymbol(atomType, section, file, lastSym->value, lastSym->name, lastSym->desc, atomScope(lastSym->scope), sym->value, - copyRefs); + scatterable, copyRefs); } } lastSym = sym; @@ -336,8 +338,23 @@ std::error_code processSymboledSection(DefinedAtom::ContentType atomType, if (lastSym != nullptr) { atomFromSymbol(atomType, section, file, lastSym->value, lastSym->name, lastSym->desc, atomScope(lastSym->scope), - section.address + section.content.size(), copyRefs); + section.address + section.content.size(), + scatterable, copyRefs); } + + // If object built without .subsections_via_symbols, add reference chain. + if (!scatterable) { + MachODefinedAtom *prevAtom = nullptr; + file.eachAtomInSection(section, + [&](MachODefinedAtom *atom, uint64_t offset)->void { + if (prevAtom) + prevAtom->addReference(0, Reference::kindLayoutAfter, atom, 0, + Reference::KindArch::all, + Reference::KindNamespace::all); + prevAtom = atom; + }); + } + return std::error_code(); } @@ -345,7 +362,8 @@ std::error_code processSection(DefinedAtom::ContentType atomType, const Section §ion, bool customSectionName, const NormalizedFile &normalizedFile, - MachOFile &file, bool copyRefs) { + MachOFile &file, bool scatterable, + bool copyRefs) { const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch); const bool swap = !MachOLinkingContext::isHostEndian(normalizedFile.arch); @@ -368,7 +386,7 @@ std::error_code processSection(DefinedAtom::ContentType atomType, if (atomizeModel == atomizeAtSymbols) { // Break section up into atoms each with a fixed size. return processSymboledSection(atomType, section, normalizedFile, file, - copyRefs); + scatterable, copyRefs); } else { const uint32_t *cfi; unsigned int size; @@ -483,6 +501,7 @@ findAtomCoveringAddress(const NormalizedFile &normalizedFile, MachOFile &file, // creates corresponding lld::Reference objects. std::error_code convertRelocs(const Section §ion, const NormalizedFile &normalizedFile, + bool scatterable, MachOFile &file, ArchHandler &handler) { // Utility function for ArchHandler to find atom by its address. @@ -577,9 +596,10 @@ std::error_code convertRelocs(const Section §ion, if (handler.isPairedReloc(reloc)) { // Handle paired relocations together. relocErr = handler.getPairReferenceInfo(reloc, *++it, inAtom, - offsetInAtom, fixupAddress, swap, - atomByAddr, atomBySymbol, &kind, - &target, &addend); + offsetInAtom, fixupAddress, swap, + scatterable, atomByAddr, + atomBySymbol, &kind, + &target, &addend); } else { // Use ArchHandler to convert relocation record into information @@ -697,6 +717,8 @@ ErrorOr> normalizedObjectToAtoms(const NormalizedFile &normalizedFile, StringRef path, bool copyRefs) { std::unique_ptr file(new MachOFile(path)); + bool scatterable = ((normalizedFile.flags & MH_SUBSECTIONS_VIA_SYMBOLS) != 0); + // Create atoms from each section. for (auto § : normalizedFile.sections) { if (isDebugInfoSection(sect)) @@ -706,7 +728,7 @@ normalizedObjectToAtoms(const NormalizedFile &normalizedFile, StringRef path, customSectionName); if (std::error_code ec = processSection(atomType, sect, customSectionName, normalizedFile, - *file, copyRefs)) + *file, scatterable, copyRefs)) return ec; } // Create atoms from undefined symbols. @@ -726,7 +748,8 @@ normalizedObjectToAtoms(const NormalizedFile &normalizedFile, StringRef path, for (auto § : normalizedFile.sections) { if (isDebugInfoSection(sect)) continue; - if (std::error_code ec = convertRelocs(sect, normalizedFile, *file, *handler)) + if (std::error_code ec = convertRelocs(sect, normalizedFile, scatterable, + *file, *handler)) return ec; } diff --git a/lld/test/mach-o/arm-subsections-via-symbols.yaml b/lld/test/mach-o/arm-subsections-via-symbols.yaml new file mode 100644 index 0000000..b704568 --- /dev/null +++ b/lld/test/mach-o/arm-subsections-via-symbols.yaml @@ -0,0 +1,60 @@ +# RUN: lld -flavor darwin -arch armv7 %s -r -print_atoms -o %t | FileCheck %s +# +# Test that assembly written without .subsections_via_symbols is parsed so +# that atoms are non-dead-strip and there is a layout-after references +# chaining atoms together. +# + +--- !mach-o +arch: armv7 +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 ] + alignment: 2 + address: 0x0000000000000000 + content: [ 0x04, 0x10, 0x9F, 0xE5, 0x04, 0x20, 0x9F, 0xE5, + 0x1E, 0xFF, 0x2F, 0xE1, 0x78, 0x56, 0x34, 0x12, + 0x21, 0x43, 0x65, 0x87 ] +local-symbols: + - name: constants1 + type: N_SECT + sect: 1 + value: 0x000000000000000C + - name: constants2 + type: N_SECT + sect: 1 + value: 0x0000000000000010 +global-symbols: + - name: _foo + type: N_SECT + scope: [ N_EXT ] + sect: 1 + value: 0x0000000000000000 +... + + +# CHECK:defined-atoms: +# CHECK: - name: _foo +# CHECK: scope: global +# CHECK: content: [ 04, 10, 9F, E5, 04, 20, 9F, E5, 1E, FF, 2F, E1 ] +# CHECK: dead-strip: never +# CHECK: references: +# CHECK: - kind: layout-after +# CHECK: offset: 0 +# CHECK: target: constants1 +# CHECK: - name: constants1 +# CHECK: content: [ 78, 56, 34, 12 ] +# CHECK: dead-strip: never +# CHECK: references: +# CHECK: - kind: layout-after +# CHECK: offset: 0 +# CHECK: target: constants2 +# CHECK: - name: constants2 +# CHECK: content: [ 21, 43, 65, 87 ] +# CHECK: dead-strip: never diff --git a/lld/test/mach-o/parse-data-relocs-x86_64.yaml b/lld/test/mach-o/parse-data-relocs-x86_64.yaml index 6ba2e48..ae93c1b 100644 --- a/lld/test/mach-o/parse-data-relocs-x86_64.yaml +++ b/lld/test/mach-o/parse-data-relocs-x86_64.yaml @@ -1,3 +1,4 @@ + # RUN: lld -flavor darwin -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s \ # RUN: && lld -flavor darwin -arch x86_64 %t -r -print_atoms -o %t2 | FileCheck %s # @@ -36,7 +37,7 @@ --- !mach-o arch: x86_64 file-type: MH_OBJECT -flags: [ ] +flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ] has-UUID: false OS: unknown sections: -- 2.7.4