diff options
| author | Lang Hames <lhames@gmail.com> | 2016-06-25 00:29:54 +0000 |
|---|---|---|
| committer | Lang Hames <lhames@gmail.com> | 2016-06-25 00:29:54 +0000 |
| commit | 3b3b4d792f181be5b8323558565e6804dec76f4d (patch) | |
| tree | 1949403da3f9238acf934fd3e8380ecef018d9f8 | |
| parent | c79ad577fb6aa2a02c83c8787a9f2a41e80de2cc (diff) | |
| download | bcm5719-llvm-3b3b4d792f181be5b8323558565e6804dec76f4d.tar.gz bcm5719-llvm-3b3b4d792f181be5b8323558565e6804dec76f4d.zip | |
[lld][MachO] Add support for x86-64 negDelta64 references and fix negDelta32.
These references are used to implement MachO/x64-64 subtractor relocations
where the minuend is being fixed up, rather than the subtrahend. The 64-bit
version was not previously supported, the 32-bit version was partially
implemented but contained bugs not caught by existing test cases. This
patch fixes both functionality and test coverage.
llvm-svn: 273759
| -rw-r--r-- | lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp | 96 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/MachO/File.h | 2 | ||||
| -rw-r--r-- | lld/test/mach-o/parse-data-relocs-x86_64.yaml | 125 |
3 files changed, 146 insertions, 77 deletions
diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp index d8485d43a5f..c36982a77b1 100644 --- a/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp +++ b/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp @@ -203,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: @@ -224,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, @@ -254,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), @@ -438,27 +438,6 @@ 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"); - } -} - llvm::Error ArchHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1, const normalized::Relocation &reloc2, @@ -471,35 +450,61 @@ 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 llvm::make_error<GenericError>("unknown pair"); const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; uint64_t targetAddress; const lld::Atom *fromTarget; if (auto ec = atomFromSymbolIndex(reloc1.symbol, &fromTarget)) return ec; - if (fromTarget != inAtom) - return llvm::make_error<GenericError>("pointer diff not in base atom"); - switch (*kind) { - case delta64: + + 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; + 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 delta32: + } + 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; + 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 delta64Anon: + } + 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"); } } @@ -583,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; @@ -687,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"); @@ -808,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/lld/lib/ReaderWriter/MachO/File.h b/lld/lib/ReaderWriter/MachO/File.h index 64a0fcf8284..cf9c0a63806 100644 --- a/lld/lib/ReaderWriter/MachO/File.h +++ b/lld/lib/ReaderWriter/MachO/File.h @@ -247,6 +247,8 @@ private: offAndAtom.atom = atom; _sectionAtoms[inSection].push_back(offAndAtom); addAtom(*atom); +// llvm::dbgs() << "In " << inSection->sectionName << ": Added " +// << atom << " (" << atom->name() << ")\n"; } typedef llvm::DenseMap<const normalized::Section *, 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 6aa36893367..72a256ef1f0 100644 --- a/lld/test/mach-o/parse-data-relocs-x86_64.yaml +++ b/lld/test/mach-o/parse-data-relocs-x86_64.yaml @@ -76,6 +76,13 @@ sections: # Note the addend here is -16 because that is the offset from here back # to _d. 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +# .quad . - _foo +# This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED. +# The subtractor references _d which is the first nonlocal label in this +# section. The unsigned references _foo. +# Note the addend here is -16 because that is the offset from here back +# to _d. + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # .quad L1 # This is a X86_64_RELOC_UNSIGNED without extern set. # In this case, we encode the section number for L1 in the relocation, and @@ -95,121 +102,146 @@ sections: # section. The unsigned references _foo. # Note the addend here is -40 because that is the offset from here back # to _d. - 0xD8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, # .quad _foo + 4 - . # This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED. # The subtractor references _d which is the first nonlocal label in this # section. The unsigned references _foo. -# Note the addend here is -44. It would have been -48 because that +# Note the addend here is -52. It would have been -56 because that # would take us from the address of this relocation back to _d. But as -# we also add 4 for the offset, we get -44. - 0xD4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +# we also add 4 for the offset, we get -52. + 0xCC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, # .quad L1 - . # This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED. # The subtractor references _d which is the first nonlocal label in this # section. The unsigned does not have extern set, so the relocation # number is the section number for L1. -# Note the addend here is -54. Of that, -56 would be the offset from +# Note the addend here is -62. Of that, -64 would be the offset from # this location from _d. The remaining 2 is the absolute address # of L1. - 0xCA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, # .long _foo - . # This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED. # The subtractor references _d which is the first nonlocal label in this # section. The unsigned references _foo. -# Note the addend here is -64 because that is the offset from here back +# Note the addend here is -72 because that is the offset from here back +# to _d. + 0xB8, 0xFF, 0xFF, 0xFF, +# .long . - _foo +# This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED. +# The subtractor references _d which is the first nonlocal label in this +# section. The unsigned references _foo. +# Note the addend here is -76 because that is the offset from here back # to _d. - 0xC0, 0xFF, 0xFF, 0xFF, + 0xB4, 0xFF, 0xFF, 0xFF, # .long _foo + 4 - . # This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED. # The subtractor references _d which is the first nonlocal label in this # section. The unsigned references _foo. -# Note the addend here is -64. It would have been -68 because that +# Note the addend here is -76. It would have been -80 because that # would take us from the address of this relocation back to _d. But as -# we also add 4 for the offset, we get -64. - 0xC0, 0xFF, 0xFF, 0xFF, +# we also add 4 for the offset, we get -76. + 0xB4, 0xFF, 0xFF, 0xFF, # .long L1 - . # This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED. # The subtractor references _d which is the first nonlocal label in this # section. The unsigned does not have extern set, so the relocation # number is the section number for L1. -# Note the addend here is -70. Of that, -72 would be the offset from +# Note the addend here is -82. Of that, -84 would be the offset from # this location from _d. The remaining 2 is the absolute address # of L1. - 0xBA, 0xFF, 0xFF, 0xFF ] + 0xAE, 0xFF, 0xFF, 0xFF ] relocations: - - offset: 0x00000048 + - offset: 0x00000054 type: X86_64_RELOC_SUBTRACTOR length: 2 pc-rel: false extern: true symbol: 2 - - offset: 0x00000048 + - offset: 0x00000054 type: X86_64_RELOC_UNSIGNED length: 2 pc-rel: false extern: false symbol: 2 - - offset: 0x00000044 + - offset: 0x00000050 type: X86_64_RELOC_SUBTRACTOR length: 2 pc-rel: false extern: true symbol: 2 - - offset: 0x00000044 + - offset: 0x00000050 type: X86_64_RELOC_UNSIGNED length: 2 pc-rel: false extern: true symbol: 0 - - offset: 0x00000040 + - offset: 0x0000004C + type: X86_64_RELOC_SUBTRACTOR + length: 2 + pc-rel: false + extern: true + symbol: 0 + - offset: 0x0000004C + type: X86_64_RELOC_UNSIGNED + length: 2 + pc-rel: false + extern: true + symbol: 2 + - offset: 0x00000048 type: X86_64_RELOC_SUBTRACTOR length: 2 pc-rel: false extern: true symbol: 2 - - offset: 0x00000040 + - offset: 0x00000048 type: X86_64_RELOC_UNSIGNED length: 2 pc-rel: false extern: true symbol: 0 - - offset: 0x00000038 + - offset: 0x00000040 type: X86_64_RELOC_SUBTRACTOR length: 3 pc-rel: false extern: true symbol: 2 - - offset: 0x00000038 + - offset: 0x00000040 type: X86_64_RELOC_UNSIGNED length: 3 pc-rel: false extern: false symbol: 2 - - offset: 0x00000030 + - offset: 0x00000038 type: X86_64_RELOC_SUBTRACTOR length: 3 pc-rel: false extern: true symbol: 2 - - offset: 0x00000030 + - offset: 0x00000038 type: X86_64_RELOC_UNSIGNED length: 3 pc-rel: false extern: true symbol: 0 - - offset: 0x00000028 + - offset: 0x00000030 type: X86_64_RELOC_SUBTRACTOR length: 3 pc-rel: false extern: true symbol: 2 - - offset: 0x00000028 + - offset: 0x00000030 type: X86_64_RELOC_UNSIGNED length: 3 pc-rel: false extern: true symbol: 0 + - offset: 0x00000028 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 2 - offset: 0x00000020 type: X86_64_RELOC_UNSIGNED length: 3 @@ -217,10 +249,16 @@ sections: extern: false symbol: 2 - offset: 0x00000018 + type: X86_64_RELOC_SUBTRACTOR + length: 3 + pc-rel: false + extern: true + symbol: 0 + - offset: 0x00000018 type: X86_64_RELOC_UNSIGNED length: 3 pc-rel: false - extern: false + extern: true symbol: 2 - offset: 0x00000010 type: X86_64_RELOC_SUBTRACTOR @@ -266,12 +304,13 @@ page-size: 0x00000000 # CHECK:defined-atoms: # CHECK: - name: _d # CHECK: type: data -# CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00, 04, 00, 00, 00, -# CHECK: 00, 00, 00, 00, F0, FF, FF, FF, FF, FF, FF, FF, -# CHECK: {{..}}, {{..}}, 00, 00, 00, 00, 00, 00, {{..}}, {{..}}, 00, 00, -# CHECK: 00, 00, 00, 00, D8, FF, FF, FF, FF, FF, FF, FF, -# CHECK: D4, FF, FF, FF, FF, FF, FF, FF, {{..}}, {{..}}, {{..}}, {{..}}, -# CHECK: {{..}}, {{..}}, {{..}}, {{..}}, C0, FF, FF, FF, C0, FF, FF, FF, +# CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00, 04, 00, 00, 00, +# CHECK: 00, 00, 00, 00, F0, FF, FF, FF, FF, FF, FF, FF, +# CHECK: 18, 00, 00, 00, 00, 00, 00, 00, {{..}}, {{..}}, 00, 00, +# CHECK: 00, 00, 00, 00, {{..}}, {{..}}, 00, 00, 00, 00, 00, 00, +# CHECK: D0, FF, FF, FF, FF, FF, FF, FF, CC, FF, FF, FF, +# CHECK: FF, FF, FF, FF, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, +# CHECK: B8, FF, FF, FF, B4, FF, FF, FF, B4, FF, FF, FF, # CHECK: {{..}}, {{..}}, {{..}}, {{..}} ] # CHECK: dead-strip: never # CHECK: references: @@ -285,32 +324,38 @@ page-size: 0x00000000 # CHECK: - kind: delta64 # CHECK: offset: 16 # CHECK: target: _foo -# CHECK: - kind: pointer64Anon +# CHECK: - kind: negDelta64 # CHECK: offset: 24 -# CHECK: target: L003 +# CHECK: target: _foo # CHECK: - kind: pointer64Anon # CHECK: offset: 32 # CHECK: target: L003 +# CHECK: - kind: pointer64Anon +# CHECK: offset: 40 +# CHECK: target: L003 # CHECK: addend: 2 # CHECK: - kind: delta64 -# CHECK: offset: 40 +# CHECK: offset: 48 # CHECK: target: _foo # CHECK: - kind: delta64 -# CHECK: offset: 48 +# CHECK: offset: 56 # CHECK: target: _foo # CHECK: addend: 4 # CHECK: - kind: delta64Anon -# CHECK: offset: 56 +# CHECK: offset: 64 # CHECK: target: L003 # CHECK: - kind: delta32 -# CHECK: offset: 64 +# CHECK: offset: 72 +# CHECK: target: _foo +# CHECK: - kind: negDelta32 +# CHECK: offset: 76 # CHECK: target: _foo # CHECK: - kind: delta32 -# CHECK: offset: 68 +# CHECK: offset: 80 # CHECK: target: _foo # CHECK: addend: 4 # CHECK: - kind: delta32Anon -# CHECK: offset: 72 +# CHECK: offset: 84 # CHECK: target: L003 # CHECK: - name: _foo # CHECK: content: [ C3 ] |

