summaryrefslogtreecommitdiff
path: root/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp')
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp113
1 files changed, 97 insertions, 16 deletions
diff --git a/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
index 81fe1af42d7e..c57a00359e33 100644
--- a/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
+++ b/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
@@ -30,8 +30,8 @@ using llvm::support::little64_t;
class ArchHandler_x86_64 : public ArchHandler {
public:
- ArchHandler_x86_64();
- virtual ~ArchHandler_x86_64();
+ ArchHandler_x86_64() = default;
+ ~ArchHandler_x86_64() override = default;
const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
@@ -59,6 +59,19 @@ public:
}
}
+ bool isTLVAccess(const Reference &ref) const override {
+ assert(ref.kindNamespace() == Reference::KindNamespace::mach_o);
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
+ return ref.kindValue() == ripRel32Tlv;
+ }
+
+ void updateReferenceToTLV(const Reference *ref) override {
+ assert(ref->kindNamespace() == Reference::KindNamespace::mach_o);
+ assert(ref->kindArch() == Reference::KindArch::x86_64);
+ assert(ref->kindValue() == ripRel32Tlv);
+ const_cast<Reference*>(ref)->setKindValue(ripRel32);
+ }
+
/// Used by GOTPass to update GOT References
void updateReferenceToGOT(const Reference *ref, bool targetNowGOT) override {
assert(ref->kindNamespace() == Reference::KindNamespace::mach_o);
@@ -82,9 +95,11 @@ public:
bool needsCompactUnwind() override {
return true;
}
+
Reference::KindValue imageOffsetKind() override {
return imageOffset;
}
+
Reference::KindValue imageOffsetKindIndirect() override {
return imageOffsetGot;
}
@@ -168,8 +183,12 @@ private:
ripRel32Minus2, /// ex: movw $0x1234, _foo(%rip)
ripRel32Minus4, /// ex: movl $0x12345678, _foo(%rip)
ripRel32Anon, /// ex: movq L1(%rip), %rax
+ ripRel32Minus1Anon, /// ex: movb $0x12, L1(%rip)
+ ripRel32Minus2Anon, /// ex: movw $0x1234, L1(%rip)
+ ripRel32Minus4Anon, /// ex: movw $0x12345678, L1(%rip)
ripRel32GotLoad, /// ex: movq _foo@GOTPCREL(%rip), %rax
ripRel32Got, /// ex: pushq _foo@GOTPCREL(%rip)
+ ripRel32Tlv, /// ex: movq _foo@TLVP(%rip), %rdi
pointer64, /// ex: .quad _foo
pointer64Anon, /// ex: .quad L1
delta64, /// ex: .quad _foo - .
@@ -192,6 +211,8 @@ private:
/// relocatable object (yay for implicit contracts!).
unwindInfoToEhFrame, /// Fix low 24 bits of compact unwind encoding to
/// refer to __eh_frame entry.
+ tlvInitSectionOffset /// Location contains offset tlv init-value atom
+ /// within the __thread_data section.
};
Reference::KindValue kindFromReloc(const normalized::Relocation &reloc);
@@ -209,18 +230,18 @@ private:
uint64_t inAtomAddress);
};
-
-ArchHandler_x86_64::ArchHandler_x86_64() { }
-
-ArchHandler_x86_64::~ArchHandler_x86_64() { }
-
const Registry::KindStrings ArchHandler_x86_64::_sKindStrings[] = {
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(ripRel32Anon),
+ LLD_KIND_STRING_ENTRY(ripRel32Minus1Anon),
+ LLD_KIND_STRING_ENTRY(ripRel32Minus2Anon),
+ LLD_KIND_STRING_ENTRY(ripRel32Minus4Anon),
+ LLD_KIND_STRING_ENTRY(ripRel32GotLoad),
LLD_KIND_STRING_ENTRY(ripRel32GotLoadNowLea),
- LLD_KIND_STRING_ENTRY(ripRel32Got), LLD_KIND_STRING_ENTRY(lazyPointer),
+ LLD_KIND_STRING_ENTRY(ripRel32Got), LLD_KIND_STRING_ENTRY(ripRel32Tlv),
+ 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),
@@ -229,6 +250,7 @@ const Registry::KindStrings ArchHandler_x86_64::_sKindStrings[] = {
LLD_KIND_STRING_ENTRY(imageOffset), LLD_KIND_STRING_ENTRY(imageOffsetGot),
LLD_KIND_STRING_ENTRY(unwindFDEToFunction),
LLD_KIND_STRING_ENTRY(unwindInfoToEhFrame),
+ LLD_KIND_STRING_ENTRY(tlvInitSectionOffset),
LLD_KIND_STRING_END
};
@@ -301,14 +323,22 @@ ArchHandler_x86_64::kindFromReloc(const Relocation &reloc) {
return ripRel32Anon;
case X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4:
return ripRel32Minus1;
+ case X86_64_RELOC_SIGNED_1 | rPcRel | rLength4:
+ return ripRel32Minus1Anon;
case X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4:
return ripRel32Minus2;
+ case X86_64_RELOC_SIGNED_2 | rPcRel | rLength4:
+ return ripRel32Minus2Anon;
case X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4:
return ripRel32Minus4;
+ case X86_64_RELOC_SIGNED_4 | rPcRel | rLength4:
+ return ripRel32Minus4Anon;
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_TLV | rPcRel | rExtern | rLength4:
+ return ripRel32Tlv;
case X86_64_RELOC_UNSIGNED | rExtern | rLength8:
return pointer64;
case X86_64_RELOC_UNSIGNED | rLength8:
@@ -331,7 +361,7 @@ ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc,
typedef std::error_code E;
*kind = kindFromReloc(reloc);
if (*kind == invalid)
- return make_dynamic_error_code(Twine("unknown type"));
+ return make_dynamic_error_code("unknown type");
const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
uint64_t targetAddress;
switch (*kind) {
@@ -359,16 +389,34 @@ ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc,
case ripRel32Anon:
targetAddress = fixupAddress + 4 + *(const little32_t *)fixupContent;
return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ case ripRel32Minus1Anon:
+ targetAddress = fixupAddress + 5 + *(const little32_t *)fixupContent;
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ case ripRel32Minus2Anon:
+ targetAddress = fixupAddress + 6 + *(const little32_t *)fixupContent;
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ case ripRel32Minus4Anon:
+ targetAddress = fixupAddress + 8 + *(const little32_t *)fixupContent;
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
case ripRel32GotLoad:
case ripRel32Got:
+ case ripRel32Tlv:
if (E ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = *(const little32_t *)fixupContent;
return std::error_code();
+ case tlvInitSectionOffset:
case pointer64:
if (E ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
- *addend = *(const little64_t *)fixupContent;
+ // 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.
+ if (inAtom->contentType() == DefinedAtom::typeThunkTLV &&
+ offsetInAtom == 16) {
+ *kind = tlvInitSectionOffset;
+ assert(*addend == 0 && "TLV-init has non-zero addend?");
+ } else
+ *addend = *(const little64_t *)fixupContent;
return std::error_code();
case pointer64Anon:
targetAddress = *(const little64_t *)fixupContent;
@@ -413,7 +461,7 @@ ArchHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1,
Reference::Addend *addend) {
*kind = kindFromRelocPair(reloc1, reloc2);
if (*kind == invalid)
- return make_dynamic_error_code(Twine("unknown pair"));
+ return make_dynamic_error_code("unknown pair");
const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
typedef std::error_code E;
uint64_t targetAddress;
@@ -421,7 +469,7 @@ ArchHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1,
if (E ec = atomFromSymbolIndex(reloc1.symbol, &fromTarget))
return ec;
if (fromTarget != inAtom)
- return make_dynamic_error_code(Twine("pointer diff not in base atom"));
+ return make_dynamic_error_code("pointer diff not in base atom");
switch (*kind) {
case delta64:
if (E ec = atomFromSymbolIndex(reloc2.symbol, target))
@@ -486,19 +534,26 @@ void ArchHandler_x86_64::applyFixupFinal(
case ripRel32Anon:
case ripRel32Got:
case ripRel32GotLoad:
+ case ripRel32Tlv:
*loc32 = targetAddress - (fixupAddress + 4) + ref.addend();
return;
case pointer64:
case pointer64Anon:
*loc64 = targetAddress + ref.addend();
return;
+ case tlvInitSectionOffset:
+ *loc64 = targetAddress - findSectionAddress(*ref.target()) + ref.addend();
+ return;
case ripRel32Minus1:
+ case ripRel32Minus1Anon:
*loc32 = targetAddress - (fixupAddress + 5) + ref.addend();
return;
case ripRel32Minus2:
+ case ripRel32Minus2Anon:
*loc32 = targetAddress - (fixupAddress + 6) + ref.addend();
return;
case ripRel32Minus4:
+ case ripRel32Minus4Anon:
*loc32 = targetAddress - (fixupAddress + 8) + ref.addend();
return;
case delta32:
@@ -542,7 +597,6 @@ void ArchHandler_x86_64::applyFixupFinal(
llvm_unreachable("invalid x86_64 Reference Kind");
}
-
void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref,
uint8_t *loc,
uint64_t fixupAddress,
@@ -558,11 +612,13 @@ void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref,
case ripRel32:
case ripRel32Got:
case ripRel32GotLoad:
+ case ripRel32Tlv:
*loc32 = ref.addend();
return;
case ripRel32Anon:
*loc32 = (targetAddress - (fixupAddress + 4)) + ref.addend();
return;
+ case tlvInitSectionOffset:
case pointer64:
*loc64 = ref.addend();
return;
@@ -572,12 +628,21 @@ void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref,
case ripRel32Minus1:
*loc32 = ref.addend() - 1;
return;
+ case ripRel32Minus1Anon:
+ *loc32 = (targetAddress - (fixupAddress + 5)) + ref.addend();
+ return;
case ripRel32Minus2:
*loc32 = ref.addend() - 2;
return;
+ case ripRel32Minus2Anon:
+ *loc32 = (targetAddress - (fixupAddress + 6)) + ref.addend();
+ return;
case ripRel32Minus4:
*loc32 = ref.addend() - 4;
return;
+ case ripRel32Minus4Anon:
+ *loc32 = (targetAddress - (fixupAddress + 8)) + ref.addend();
+ return;
case delta32:
*loc32 = ref.addend() + inAtomAddress - fixupAddress;
return;
@@ -638,7 +703,7 @@ void ArchHandler_x86_64::appendSectionRelocations(
return;
case ripRel32Anon:
appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
- X86_64_RELOC_SIGNED | rPcRel | rLength4 );
+ X86_64_RELOC_SIGNED | rPcRel | rLength4 );
return;
case ripRel32Got:
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
@@ -648,6 +713,11 @@ void ArchHandler_x86_64::appendSectionRelocations(
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4 );
return;
+ case ripRel32Tlv:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_TLV | rPcRel | rExtern | rLength4 );
+ return;
+ case tlvInitSectionOffset:
case pointer64:
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
X86_64_RELOC_UNSIGNED | rExtern | rLength8);
@@ -660,14 +730,26 @@ void ArchHandler_x86_64::appendSectionRelocations(
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4 );
return;
+ case ripRel32Minus1Anon:
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_SIGNED_1 | rPcRel | rLength4 );
+ return;
case ripRel32Minus2:
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4 );
return;
+ case ripRel32Minus2Anon:
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_SIGNED_2 | rPcRel | rLength4 );
+ return;
case ripRel32Minus4:
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4 );
return;
+ case ripRel32Minus4Anon:
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_SIGNED_4 | rPcRel | rLength4 );
+ return;
case delta32:
appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 );
@@ -714,7 +796,6 @@ void ArchHandler_x86_64::appendSectionRelocations(
llvm_unreachable("unknown x86_64 Reference Kind");
}
-
std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86_64() {
return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86_64());
}