summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/lib/ReaderWriter/MachO/ArchHandler.cpp38
-rw-r--r--lld/lib/ReaderWriter/MachO/ArchHandler.h44
-rw-r--r--lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp88
-rw-r--r--lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp209
-rw-r--r--lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp234
-rw-r--r--lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp101
-rw-r--r--lld/test/mach-o/parse-data-relocs-x86_64.yaml10
-rw-r--r--lld/test/mach-o/parse-relocs-x86.yaml11
-rw-r--r--lld/test/mach-o/parse-text-relocs-x86_64.yaml10
9 files changed, 638 insertions, 107 deletions
diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler.cpp
index 8dfafc6478b..f5fdb1baa46 100644
--- a/lld/lib/ReaderWriter/MachO/ArchHandler.cpp
+++ b/lld/lib/ReaderWriter/MachO/ArchHandler.cpp
@@ -86,6 +86,44 @@ ArchHandler::RelocPattern ArchHandler::relocPattern(const Relocation &reloc) {
return result;
}
+normalized::Relocation
+ArchHandler::relocFromPattern(ArchHandler::RelocPattern pattern) {
+ normalized::Relocation result;
+ result.offset = 0;
+ result.scattered = (pattern & rScattered);
+ result.type = (RelocationInfoType)(pattern & 0xF);
+ result.pcRel = (pattern & rPcRel);
+ result.isExtern = (pattern & rExtern);
+ result.value = 0;
+ result.symbol = 0;
+ switch (pattern & 0x300) {
+ case rLength1:
+ result.length = 0;
+ break;
+ case rLength2:
+ result.length = 1;
+ break;
+ case rLength4:
+ result.length = 2;
+ break;
+ case rLength8:
+ result.length = 3;
+ break;
+ }
+ return result;
+}
+
+void ArchHandler::appendReloc(normalized::Relocations &relocs, uint32_t offset,
+ uint32_t symbol, uint32_t value,
+ RelocPattern pattern) {
+ normalized::Relocation reloc = relocFromPattern(pattern);
+ reloc.offset = offset;
+ reloc.symbol = symbol;
+ reloc.value = value;
+ relocs.push_back(reloc);
+}
+
+
int16_t ArchHandler::readS16(bool swap, const uint8_t *addr) {
return read16(swap, *reinterpret_cast<const uint16_t*>(addr));
}
diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler.h b/lld/lib/ReaderWriter/MachO/ArchHandler.h
index 8a097a024e0..cf479c83a00 100644
--- a/lld/lib/ReaderWriter/MachO/ArchHandler.h
+++ b/lld/lib/ReaderWriter/MachO/ArchHandler.h
@@ -105,11 +105,37 @@ public:
const lld::Atom **target,
Reference::Addend *addend) = 0;
- /// 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,
- uint64_t targetAddress, uint64_t inAtomAddress) = 0;
+ /// Prototype for a helper function. Given an atom, finds the symbol table
+ /// index for it in the output file.
+ typedef std::function<uint32_t (const Atom &atom)> FindSymbolIndexForAtom;
+
+ /// Prototype for a helper function. Given an atom, finds the index
+ /// of the section that will contain the atom.
+ typedef std::function<uint32_t (const Atom &atom)> FindSectionIndexForAtom;
+
+ /// Prototype for a helper function. Given an atom, finds the address
+ /// assigned to it in the output file.
+ typedef std::function<uint64_t (const Atom &atom)> FindAddressForAtom;
+
+ /// Some architectures require local symbols on anonymous atoms.
+ virtual bool needsLocalSymbolInRelocatableFile(const DefinedAtom *atom) {
+ return false;
+ }
+
+ /// Copy raw content then apply all fixup References on an Atom.
+ virtual void generateAtomContent(const DefinedAtom &atom, bool relocatable,
+ FindAddressForAtom findAddress,
+ uint8_t *atomContentBuffer) = 0;
+
+ /// Used in -r mode to convert a Reference to a mach-o relocation.
+ virtual void appendSectionRelocations(const DefinedAtom &atom,
+ uint64_t atomSectionOffset,
+ const Reference &ref,
+ FindSymbolIndexForAtom,
+ FindSectionIndexForAtom,
+ FindAddressForAtom,
+ normalized::Relocations&) = 0;
+
struct ReferenceInfo {
Reference::KindArch arch;
@@ -161,7 +187,15 @@ protected:
rLength4 = 0x0200,
rLength8 = 0x0300
};
+ /// Extract RelocPattern from normalized mach-o relocation.
static RelocPattern relocPattern(const normalized::Relocation &reloc);
+ /// Create normalized Relocation initialized from pattern.
+ static normalized::Relocation relocFromPattern(RelocPattern pattern);
+ /// One liner to add a relocation.
+ static void appendReloc(normalized::Relocations &relocs, uint32_t offset,
+ uint32_t symbol, uint32_t value,
+ RelocPattern pattern);
+
static int16_t readS16(bool swap, const uint8_t *addr);
static int32_t readS32(bool swap, const uint8_t *addr);
diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
index a1e6b83c83d..16088589b14 100644
--- a/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
+++ b/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
@@ -57,11 +57,18 @@ public:
const lld::Atom **target,
Reference::Addend *addend) override;
- void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch,
- Reference::KindValue kindValue, uint64_t addend,
- uint8_t *location, uint64_t fixupAddress,
- uint64_t targetAddress, uint64_t inAtomAddress)
- override;
+ void generateAtomContent(const DefinedAtom &atom, bool relocatable,
+ FindAddressForAtom findAddress,
+ uint8_t *atomContentBuffer) override;
+
+ void appendSectionRelocations(const DefinedAtom &atom,
+ uint64_t atomSectionOffset,
+ const Reference &ref,
+ FindSymbolIndexForAtom,
+ FindSectionIndexForAtom,
+ FindAddressForAtom,
+ normalized::Relocations &) override;
+
private:
static const Registry::KindStrings _sKindStrings[];
@@ -96,6 +103,14 @@ private:
uint32_t clearThumbBit(uint32_t value, const Atom *target);
uint32_t setDisplacementInArmBranch(uint32_t instruction, int32_t disp);
+ void applyFixupFinal(const Reference &ref, uint8_t *location,
+ uint64_t fixupAddress, uint64_t targetAddress,
+ uint64_t inAtomAddress);
+
+ void applyFixupRelocatable(const Reference &ref, uint8_t *location,
+ uint64_t fixupAddress,
+ uint64_t targetAddress,
+ uint64_t inAtomAddress);
const bool _swap;
};
@@ -594,19 +609,17 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
return std::error_code();
}
-void ArchHandler_arm::applyFixup(Reference::KindNamespace ns,
- Reference::KindArch arch,
- Reference::KindValue kindValue,
- uint64_t addend, uint8_t *location,
- uint64_t fixupAddress, uint64_t targetAddress,
- uint64_t inAtomAddress) {
- if (ns != Reference::KindNamespace::mach_o)
+void ArchHandler_arm::applyFixupFinal(const Reference &ref, uint8_t *location,
+ uint64_t fixupAddress,
+ uint64_t targetAddress,
+ uint64_t inAtomAddress) {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
return;
- assert(arch == Reference::KindArch::ARM);
+ assert(ref.kindArch() == Reference::KindArch::ARM);
int32_t *loc32 = reinterpret_cast<int32_t *>(location);
int32_t displacement;
// FIXME: these writes may need a swap.
- switch (kindValue) {
+ switch (ref.kindValue()) {
case thumb_b22:
// FIXME
break;
@@ -623,7 +636,7 @@ void ArchHandler_arm::applyFixup(Reference::KindNamespace ns,
// FIXME
break;
case arm_b24:
- displacement = (targetAddress - (fixupAddress + 8)) + addend;
+ displacement = (targetAddress - (fixupAddress + 8)) + ref.addend();
*loc32 = setDisplacementInArmBranch(*loc32, displacement);
break;
case arm_movw:
@@ -654,6 +667,51 @@ void ArchHandler_arm::applyFixup(Reference::KindNamespace ns,
}
}
+void ArchHandler_arm::generateAtomContent(const DefinedAtom &atom,
+ bool relocatable,
+ FindAddressForAtom findAddress,
+ uint8_t *atomContentBuffer) {
+ // Copy raw bytes.
+ memcpy(atomContentBuffer, atom.rawContent().data(), atom.size());
+ // Apply fix-ups.
+ for (const Reference *ref : atom) {
+ uint32_t offset = ref->offsetInAtom();
+ const Atom *target = ref->target();
+ uint64_t targetAddress = 0;
+ if (isa<DefinedAtom>(target))
+ targetAddress = findAddress(*target);
+ uint64_t atomAddress = findAddress(atom);
+ uint64_t fixupAddress = atomAddress + offset;
+ if (relocatable) {
+ applyFixupRelocatable(*ref, &atomContentBuffer[offset],
+ fixupAddress, targetAddress,
+ atomAddress);
+ } else {
+ applyFixupFinal(*ref, &atomContentBuffer[offset],
+ fixupAddress, targetAddress,
+ atomAddress);
+ }
+ }
+}
+
+void ArchHandler_arm::applyFixupRelocatable(const Reference &ref,
+ uint8_t *location,
+ uint64_t fixupAddress,
+ uint64_t targetAddress,
+ uint64_t inAtomAddress) {
+ // FIXME: to do
+}
+
+void ArchHandler_arm::appendSectionRelocations(const DefinedAtom &atom,
+ uint64_t atomSectionOffset,
+ const Reference &ref,
+ FindSymbolIndexForAtom,
+ FindSectionIndexForAtom,
+ FindAddressForAtom,
+ normalized::Relocations &) {
+ // FIXME: to do
+}
+
std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_arm() {
return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_arm());
}
diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
index db7d03648ca..4cb043ec8eb 100644
--- a/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
+++ b/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
@@ -57,11 +57,17 @@ public:
const lld::Atom **target,
Reference::Addend *addend) override;
- void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch,
- Reference::KindValue kindValue, uint64_t addend,
- uint8_t *location, uint64_t fixupAddress,
- uint64_t targetAddress, uint64_t inAtomAddress)
- override;
+ void generateAtomContent(const DefinedAtom &atom, bool relocatable,
+ FindAddressForAtom findAddress,
+ uint8_t *atomContentBuffer) override;
+
+ void appendSectionRelocations(const DefinedAtom &atom,
+ uint64_t atomSectionOffset,
+ const Reference &ref,
+ FindSymbolIndexForAtom symbolIndexForAtom,
+ FindSectionIndexForAtom sectionIndexForAtom,
+ FindAddressForAtom addressForAtom,
+ normalized::Relocations &relocs) override;
private:
static const Registry::KindStrings _sKindStrings[];
@@ -83,6 +89,17 @@ private:
lazyImmediateLocation, /// Location contains immediate value used in stub.
};
+ static bool useExternalRelocationTo(const Atom &target);
+
+ void applyFixupFinal(const Reference &ref, uint8_t *location,
+ uint64_t fixupAddress, uint64_t targetAddress,
+ uint64_t inAtomAddress);
+
+ void applyFixupRelocatable(const Reference &ref, uint8_t *location,
+ uint64_t fixupAddress,
+ uint64_t targetAddress,
+ uint64_t inAtomAddress);
+
const bool _swap;
};
@@ -246,12 +263,10 @@ ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
Reference::Addend offsetInTo;
Reference::Addend offsetInFrom;
switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
- case((GENERIC_RELOC_SECTDIFF | rScattered | rLength4) << 16 |
- GENERIC_RELOC_PAIR | rScattered | rLength4)
- :
- case((GENERIC_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
- GENERIC_RELOC_PAIR | rScattered | rLength4)
- :
+ case ((GENERIC_RELOC_SECTDIFF | rScattered | rLength4) << 16 |
+ GENERIC_RELOC_PAIR | rScattered | rLength4):
+ case ((GENERIC_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
+ GENERIC_RELOC_PAIR | rScattered | rLength4):
toAddress = reloc1.value;
fromAddress = reloc2.value;
value = readS32(swap, fixupContent);
@@ -285,33 +300,58 @@ ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
}
}
-void ArchHandler_x86::applyFixup(Reference::KindNamespace ns,
- Reference::KindArch arch,
- Reference::KindValue kindValue,
- uint64_t addend, uint8_t *location,
- uint64_t fixupAddress, uint64_t targetAddress,
- uint64_t inAtomAddress) {
- if (ns != Reference::KindNamespace::mach_o)
+void ArchHandler_x86::generateAtomContent(const DefinedAtom &atom,
+ bool relocatable,
+ FindAddressForAtom findAddress,
+ uint8_t *atomContentBuffer) {
+ // Copy raw bytes.
+ memcpy(atomContentBuffer, atom.rawContent().data(), atom.size());
+ // Apply fix-ups.
+ for (const Reference *ref : atom) {
+ uint32_t offset = ref->offsetInAtom();
+ const Atom *target = ref->target();
+ uint64_t targetAddress = 0;
+ if (isa<DefinedAtom>(target))
+ targetAddress = findAddress(*target);
+ uint64_t atomAddress = findAddress(atom);
+ uint64_t fixupAddress = atomAddress + offset;
+ if (relocatable) {
+ applyFixupRelocatable(*ref, &atomContentBuffer[offset],
+ fixupAddress, targetAddress,
+ atomAddress);
+ } else {
+ applyFixupFinal(*ref, &atomContentBuffer[offset],
+ fixupAddress, targetAddress,
+ atomAddress);
+ }
+ }
+}
+
+void ArchHandler_x86::applyFixupFinal(const Reference &ref, uint8_t *location,
+ uint64_t fixupAddress,
+ uint64_t targetAddress,
+ uint64_t inAtomAddress) {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
return;
- assert(arch == Reference::KindArch::x86);
+ assert(ref.kindArch() == Reference::KindArch::x86);
int32_t *loc32 = reinterpret_cast<int32_t *>(location);
int16_t *loc16 = reinterpret_cast<int16_t *>(location);
- switch (kindValue) {
+ switch (ref.kindValue()) {
case branch32:
- write32(*loc32, _swap, (targetAddress - (fixupAddress + 4)) + addend);
+ write32(*loc32, _swap, (targetAddress - (fixupAddress + 4)) + ref.addend());
break;
case branch16:
- write16(*loc16, _swap, (targetAddress - (fixupAddress + 4)) + addend);
+ write16(*loc16, _swap, (targetAddress - (fixupAddress + 2)) + ref.addend());
break;
case pointer32:
case abs32:
- write32(*loc32, _swap, targetAddress + addend);
+ write32(*loc32, _swap, targetAddress + ref.addend());
break;
case funcRel32:
- write32(*loc32, _swap, targetAddress - inAtomAddress + addend); // FIXME
+ write32(*loc32, _swap, targetAddress - inAtomAddress + ref.addend());
break;
case delta32:
- write32(*loc32, _swap, targetAddress - fixupAddress + addend);
+ write32(*loc32, _swap, targetAddress - fixupAddress + ref.addend());
break;
case lazyPointer:
case lazyImmediateLocation:
@@ -323,6 +363,125 @@ void ArchHandler_x86::applyFixup(Reference::KindNamespace ns,
}
}
+void ArchHandler_x86::applyFixupRelocatable(const Reference &ref,
+ uint8_t *location,
+ uint64_t fixupAddress,
+ uint64_t targetAddress,
+ uint64_t inAtomAddress) {
+ int32_t *loc32 = reinterpret_cast<int32_t *>(location);
+ int16_t *loc16 = reinterpret_cast<int16_t *>(location);
+ switch (ref.kindValue()) {
+ case branch32:
+ write32(*loc32, _swap, ref.addend() - (fixupAddress + 4));
+ break;
+ case branch16:
+ write16(*loc16, _swap, ref.addend() - (fixupAddress + 2));
+ break;
+ case pointer32:
+ case abs32:
+ write32(*loc32, _swap, targetAddress + ref.addend());
+ break;
+ case funcRel32:
+ write32(*loc32, _swap, targetAddress - inAtomAddress + ref.addend()); // FIXME
+ break;
+ case delta32:
+ write32(*loc32, _swap, targetAddress - fixupAddress + ref.addend());
+ break;
+ case lazyPointer:
+ case lazyImmediateLocation:
+ // do nothing
+ break;
+ default:
+ llvm_unreachable("invalid x86 Reference Kind");
+ break;
+ }
+}
+
+bool ArchHandler_x86::useExternalRelocationTo(const Atom &target) {
+ // Undefined symbols are referenced via external relocations.
+ if (isa<UndefinedAtom>(&target))
+ return true;
+ if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&target)) {
+ switch (defAtom->merge()) {
+ case DefinedAtom::mergeAsTentative:
+ // Tentative definitions are referenced via external relocations.
+ return true;
+ case DefinedAtom::mergeAsWeak:
+ case DefinedAtom::mergeAsWeakAndAddressUsed:
+ // Global weak-defs are referenced via external relocations.
+ return (defAtom->scope() == DefinedAtom::scopeGlobal);
+ default:
+ break;
+ }
+ }
+ // Everything else is reference via an internal relocation.
+ return false;
+}
+
+
+void ArchHandler_x86::appendSectionRelocations(
+ const DefinedAtom &atom,
+ uint64_t atomSectionOffset,
+ const Reference &ref,
+ FindSymbolIndexForAtom symbolIndexForAtom,
+ FindSectionIndexForAtom sectionIndexForAtom,
+ FindAddressForAtom addressForAtom,
+ normalized::Relocations &relocs) {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return;
+ assert(ref.kindArch() == Reference::KindArch::x86);
+ uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
+ bool useExternalReloc = useExternalRelocationTo(*ref.target());
+ switch (ref.kindValue()) {
+ case branch32:
+ if (useExternalReloc)
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength4);
+ else
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+ GENERIC_RELOC_VANILLA | rPcRel | rLength4);
+ break;
+ case branch16:
+ if (useExternalReloc)
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2);
+ else
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+ GENERIC_RELOC_VANILLA | rPcRel | rLength2);
+ break;
+ case pointer32:
+ case abs32:
+ if (useExternalReloc)
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ GENERIC_RELOC_VANILLA | rExtern | rLength4);
+ else
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+ GENERIC_RELOC_VANILLA | rLength4);
+ break;
+ case funcRel32:
+ appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+ GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
+ appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) - ref.addend(),
+ GENERIC_RELOC_PAIR | rScattered | rLength4);
+ break;
+ case delta32:
+ appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+ GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
+ appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) + ref.offsetInAtom(),
+ GENERIC_RELOC_PAIR | rScattered | rLength4);
+ break;
+ case lazyPointer:
+ case lazyImmediateLocation:
+ llvm_unreachable("lazy reference kind implies Stubs pass was run");
+ break;
+ default:
+ llvm_unreachable("unknown x86 Reference Kind");
+ break;
+
+ }
+}
+
+
std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86() {
return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86());
}
diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
index 5f1cddb4ef9..4fc8000797b 100644
--- a/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
+++ b/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
@@ -84,12 +84,22 @@ public:
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, uint64_t inAtomAddress)
- override;
+
+ virtual bool needsLocalSymbolInRelocatableFile(const DefinedAtom *atom) {
+ return (atom->contentType() == DefinedAtom::typeCString);
+ }
+
+ void generateAtomContent(const DefinedAtom &atom, bool relocatable,
+ FindAddressForAtom findAddress,
+ uint8_t *atomContentBuffer) override;
+
+ void appendSectionRelocations(const DefinedAtom &atom,
+ uint64_t atomSectionOffset,
+ const Reference &ref,
+ FindSymbolIndexForAtom symbolIndexForAtom,
+ FindSectionIndexForAtom sectionIndexForAtom,
+ FindAddressForAtom addressForAtom,
+ normalized::Relocations &relocs) override;
private:
static const Registry::KindStrings _sKindStrings[];
@@ -126,6 +136,15 @@ private:
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,
+ uint64_t inAtomAddress);
+
+ void applyFixupRelocatable(const Reference &ref, uint8_t *location,
+ uint64_t fixupAddress,
+ uint64_t targetAddress,
+ uint64_t inAtomAddress);
+
const bool _swap;
};
@@ -357,51 +376,76 @@ ArchHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1,
}
}
-void ArchHandler_x86_64::applyFixup(Reference::KindNamespace ns,
- Reference::KindArch arch,
- Reference::KindValue kindValue,
- uint64_t addend, uint8_t *location,
- uint64_t fixupAddress,
- uint64_t targetAddress,
- uint64_t inAtomAddress) {
- if (ns != Reference::KindNamespace::mach_o)
+void ArchHandler_x86_64::generateAtomContent(const DefinedAtom &atom,
+ bool relocatable,
+ FindAddressForAtom findAddress,
+ uint8_t *atomContentBuffer) {
+ // Copy raw bytes.
+ memcpy(atomContentBuffer, atom.rawContent().data(), atom.size());
+ // Apply fix-ups.
+ for (const Reference *ref : atom) {
+ uint32_t offset = ref->offsetInAtom();
+ const Atom *target = ref->target();
+ uint64_t targetAddress = 0;
+ if (isa<DefinedAtom>(target))
+ targetAddress = findAddress(*target);
+ uint64_t atomAddress = findAddress(atom);
+ uint64_t fixupAddress = atomAddress + offset;
+ if (relocatable) {
+ applyFixupRelocatable(*ref, &atomContentBuffer[offset],
+ fixupAddress, targetAddress,
+ atomAddress);
+ } else {
+ applyFixupFinal(*ref, &atomContentBuffer[offset],
+ fixupAddress, targetAddress,
+ atomAddress);
+ }
+ }
+}
+
+void ArchHandler_x86_64::applyFixupFinal(const Reference &ref,
+ uint8_t *location,
+ uint64_t fixupAddress,
+ uint64_t targetAddress,
+ uint64_t inAtomAddress) {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
return;
- assert(arch == Reference::KindArch::x86_64);
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
int32_t *loc32 = reinterpret_cast<int32_t *>(location);
uint64_t *loc64 = reinterpret_cast<uint64_t *>(location);
- switch (kindValue) {
+ switch (ref.kindValue()) {
case branch32:
case ripRel32:
case ripRel32Got:
case ripRel32GotLoad:
- write32(*loc32, _swap, (targetAddress - (fixupAddress + 4)) + addend);
+ write32(*loc32, _swap, (targetAddress - (fixupAddress + 4)) + ref.addend());
break;
case pointer64:
case pointer64Anon:
- write64(*loc64, _swap, targetAddress + addend);
+ write64(*loc64, _swap, targetAddress + ref.addend());
break;
case ripRel32Minus1:
- write32(*loc32, _swap, (targetAddress - (fixupAddress + 5)) + addend);
+ write32(*loc32, _swap, (targetAddress - (fixupAddress + 5)) + ref.addend());
break;
case ripRel32Minus2:
- write32(*loc32, _swap, (targetAddress - (fixupAddress + 6)) + addend);
+ write32(*loc32, _swap, (targetAddress - (fixupAddress + 6)) + ref.addend());
break;
case ripRel32Minus4:
- write32(*loc32, _swap, (targetAddress - (fixupAddress + 8)) + addend);
+ write32(*loc32, _swap, (targetAddress - (fixupAddress + 8)) + ref.addend());
break;
case delta32:
case delta32Anon:
- write32(*loc32, _swap, (targetAddress - fixupAddress) + addend);
+ write32(*loc32, _swap, (targetAddress - fixupAddress) + ref.addend());
break;
case delta64:
case delta64Anon:
- write64(*loc64, _swap, (targetAddress - fixupAddress) + addend);
+ write64(*loc64, _swap, (targetAddress - fixupAddress) + ref.addend());
break;
case ripRel32GotLoadNowLea:
// Change MOVQ to LEA
assert(location[-2] == 0x8B);
location[-2] = 0x8D;
- write32(*loc32, _swap, (targetAddress - (fixupAddress + 4)) + addend);
+ write32(*loc32, _swap, (targetAddress - (fixupAddress + 4)) + ref.addend());
break;
case lazyPointer:
case lazyImmediateLocation:
@@ -413,6 +457,148 @@ void ArchHandler_x86_64::applyFixup(Reference::KindNamespace ns,
}
}
+
+void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref,
+ uint8_t *location,
+ uint64_t fixupAddress,
+ uint64_t targetAddress,
+ uint64_t inAtomAddress) {
+ int32_t *loc32 = reinterpret_cast<int32_t *>(location);
+ uint64_t *loc64 = reinterpret_cast<uint64_t *>(location);
+ switch (ref.kindValue()) {
+ case branch32:
+ case ripRel32:
+ case ripRel32Got:
+ case ripRel32GotLoad:
+ write32(*loc32, _swap, ref.addend());
+ break;
+ case pointer64:
+ write64(*loc64, _swap, ref.addend());
+ break;
+ case pointer64Anon:
+ write64(*loc64, _swap, targetAddress + ref.addend());
+ break;
+ case ripRel32Minus1:
+ write32(*loc32, _swap, ref.addend() - 1);
+ break;
+ case ripRel32Minus2:
+ write32(*loc32, _swap, ref.addend() - 2);
+ break;
+ case ripRel32Minus4:
+ write32(*loc32, _swap, ref.addend() - 4);
+ break;
+ case delta32:
+ write32(*loc32, _swap, ref.addend() + inAtomAddress - fixupAddress);
+ break;
+ case delta32Anon:
+ write32(*loc32, _swap, (targetAddress - fixupAddress) + ref.addend());
+ break;
+ case delta64:
+ write64(*loc64, _swap, ref.addend() + inAtomAddress - fixupAddress);
+ break;
+ case delta64Anon:
+ write64(*loc64, _swap, (targetAddress - fixupAddress) + ref.addend());
+ break;
+ case ripRel32GotLoadNowLea:
+ llvm_unreachable("ripRel32GotLoadNowLea implies GOT pass was run");
+ break;
+ case lazyPointer:
+ case lazyImmediateLocation:
+ llvm_unreachable("lazy reference kind implies Stubs pass was run");
+ break;
+ default:
+ llvm_unreachable("unknown x86_64 Reference Kind");
+ break;
+ }
+}
+
+void ArchHandler_x86_64::appendSectionRelocations(
+ const DefinedAtom &atom,
+ uint64_t atomSectionOffset,
+ const Reference &ref,
+ FindSymbolIndexForAtom symbolIndexForAtom,
+ FindSectionIndexForAtom sectionIndexForAtom,
+ FindAddressForAtom addressForAtom,
+ normalized::Relocations &relocs) {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return;
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
+ uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
+ switch (ref.kindValue()) {
+ case branch32:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_BRANCH | rPcRel | rExtern | rLength4);
+ break;
+ case ripRel32:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_SIGNED | rPcRel | rExtern | rLength4 );
+ break;
+ case ripRel32Got:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_GOT | rPcRel | rExtern | rLength4 );
+ break;
+ case ripRel32GotLoad:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4 );
+ break;
+ case pointer64:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_UNSIGNED | rExtern | rLength8);
+ break;
+ case pointer64Anon:
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_UNSIGNED | rLength8);
+ break;
+ case ripRel32Minus1:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4 );
+ break;
+ case ripRel32Minus2:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4 );
+ break;
+ case ripRel32Minus4:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4 );
+ break;
+ case delta32:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+ X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 );
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_UNSIGNED | rExtern | rLength4 );
+ break;
+ case delta32Anon:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+ X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 );
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_UNSIGNED | rLength4 );
+ break;
+ case delta64:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+ X86_64_RELOC_SUBTRACTOR | rExtern | rLength8 );
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_UNSIGNED | rExtern | rLength8 );
+ break;
+ case delta64Anon:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+ X86_64_RELOC_SUBTRACTOR | rExtern | rLength8 );
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_UNSIGNED | rLength8 );
+ break;
+ case ripRel32GotLoadNowLea:
+ llvm_unreachable("ripRel32GotLoadNowLea implies GOT pass was run");
+ break;
+ case lazyPointer:
+ case lazyImmediateLocation:
+ llvm_unreachable("lazy reference kind implies Stubs pass was run");
+ break;
+ default:
+ llvm_unreachable("unknown x86_64 Reference Kind");
+ break;
+ }
+}
+
+
std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86_64() {
return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86_64());
}
diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
index 0a306800001..17dc4701ca1 100644
--- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
+++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
@@ -88,7 +88,8 @@ SegmentInfo::SegmentInfo(StringRef n)
class Util {
public:
- Util(const MachOLinkingContext &ctxt) : _context(ctxt), _entryAtom(nullptr) {}
+ Util(const MachOLinkingContext &ctxt) : _context(ctxt),
+ _archHandler(ctxt.archHandler()), _entryAtom(nullptr) {}
void assignAtomsToSections(const lld::File &atomFile);
void organizeSections();
@@ -128,8 +129,7 @@ private:
const Atom *targetOfStub(const DefinedAtom *stubAtom);
bool belongsInGlobalSymbolsSection(const DefinedAtom* atom);
void appendSection(SectionInfo *si, NormalizedFile &file);
- void appendReloc(const DefinedAtom *atom, const Reference *ref,
- Relocations &relocations);
+ uint32_t sectionIndexForAtom(const Atom *atom);
static uint64_t alignTo(uint64_t value, uint8_t align2);
typedef llvm::DenseMap<const Atom*, uint32_t> AtomToIndex;
@@ -147,6 +147,7 @@ private:
};
const MachOLinkingContext &_context;
+ mach_o::ArchHandler &_archHandler;
llvm::BumpPtrAllocator _allocator;
std::vector<SectionInfo*> _sectionInfos;
std::vector<SegmentInfo*> _segmentInfos;
@@ -509,6 +510,14 @@ void Util::copySegmentInfo(NormalizedFile &file) {
void Util::appendSection(SectionInfo *si, NormalizedFile &file) {
const bool rMode = (_context.outputMachOType() == llvm::MachO::MH_OBJECT);
+
+ // Utility function for ArchHandler to find address of atom in output file.
+ auto addrForAtom = [&] (const Atom &atom) -> uint64_t {
+ auto pos = _atomToAddress.find(&atom);
+ assert(pos != _atomToAddress.end());
+ return pos->second;
+ };
+
// Add new empty section to end of file.sections.
Section temp;
file.sections.push_back(std::move(temp));
@@ -528,28 +537,9 @@ void Util::appendSection(SectionInfo *si, NormalizedFile &file) {
uint8_t *sectionContent = file.ownedAllocations.Allocate<uint8_t>(si->size);
normSect->content = llvm::makeArrayRef(sectionContent, si->size);
for (AtomInfo &ai : si->atomsAndOffsets) {
- // Copy raw bytes.
uint8_t *atomContent = reinterpret_cast<uint8_t*>
(&sectionContent[ai.offsetInSection]);
- memcpy(atomContent, ai.atom->rawContent().data(), ai.atom->size());
- // Apply fix-ups.
- for (const Reference *ref : *ai.atom) {
- uint32_t offset = ref->offsetInAtom();
- uint64_t targetAddress = 0;
- if ( ref->target() != nullptr )
- targetAddress = _atomToAddress[ref->target()];
- uint64_t atomAddress = _atomToAddress[ai.atom];
- uint64_t fixupAddress = atomAddress + offset;
- if ( rMode ) {
- // FIXME: Need a handler method to update content for .o file
- // output and any needed section relocations.
- } else {
- _context.archHandler().applyFixup(
- ref->kindNamespace(), ref->kindArch(), ref->kindValue(),
- ref->addend(), &atomContent[offset], fixupAddress, targetAddress,
- atomAddress);
- }
- }
+ _archHandler.generateAtomContent(*ai.atom, rMode, addrForAtom, atomContent);
}
}
@@ -647,6 +637,7 @@ bool Util::belongsInGlobalSymbolsSection(const DefinedAtom* atom) {
}
void Util::addSymbols(const lld::File &atomFile, NormalizedFile &file) {
+ bool rMode = (_context.outputMachOType() == llvm::MachO::MH_OBJECT);
// Mach-O symbol table has three regions: locals, globals, undefs.
// Add all local (non-global) symbols in address order
@@ -667,14 +658,31 @@ void Util::addSymbols(const lld::File &atomFile, NormalizedFile &file) {
sym.sect = sect->finalSectionIndex;
sym.desc = 0;
sym.value = _atomToAddress[atom];
+ _atomToSymbolIndex[atom] = file.localSymbols.size();
file.localSymbols.push_back(sym);
}
+ } else if (rMode && _archHandler.needsLocalSymbolInRelocatableFile(atom)){
+ // Create 'Lxxx' labels for anonymous atoms if archHandler says so.
+ static unsigned tempNum = 1;
+ char tmpName[16];
+ sprintf(tmpName, "L%04u", tempNum++);
+ StringRef tempRef(tmpName);
+ Symbol sym;
+ sym.name = tempRef.copy(file.ownedAllocations);
+ sym.type = N_SECT;
+ sym.scope = 0;
+ sym.sect = sect->finalSectionIndex;
+ sym.desc = 0;
+ sym.value = _atomToAddress[atom];
+ _atomToSymbolIndex[atom] = file.localSymbols.size();
+ file.localSymbols.push_back(sym);
}
}
}
// Sort global symbol alphabetically, then add to symbol table.
std::sort(globals.begin(), globals.end(), AtomSorter());
+ const uint32_t globalStartIndex = file.localSymbols.size();
for (AtomAndIndex &ai : globals) {
Symbol sym;
sym.name = ai.atom->name();
@@ -683,6 +691,7 @@ void Util::addSymbols(const lld::File &atomFile, NormalizedFile &file) {
sym.sect = ai.index;
sym.desc = descBits(static_cast<const DefinedAtom*>(ai.atom));
sym.value = _atomToAddress[ai.atom];
+ _atomToSymbolIndex[ai.atom] = globalStartIndex + file.globalSymbols.size();
file.globalSymbols.push_back(sym);
}
@@ -715,7 +724,7 @@ void Util::addSymbols(const lld::File &atomFile, NormalizedFile &file) {
const Atom *Util::targetOfLazyPointer(const DefinedAtom *lpAtom) {
for (const Reference *ref : *lpAtom) {
- if (_context.archHandler().isLazyPointer(*ref)) {
+ if (_archHandler.isLazyPointer(*ref)) {
return ref->target();
}
}
@@ -838,21 +847,51 @@ void Util::segIndexForSection(const SectionInfo *sect, uint8_t &segmentIndex,
}
-void Util::appendReloc(const DefinedAtom *atom, const Reference *ref,
- Relocations &relocations) {
- // TODO: convert Reference to normalized relocation
+uint32_t Util::sectionIndexForAtom(const Atom *atom) {
+ uint64_t address = _atomToAddress[atom];
+ uint32_t index = 1;
+ for (const SectionInfo *si : _sectionInfos) {
+ if ((si->address <= address) && (address < si->address+si->size))
+ return index;
+ ++index;
+ }
+ llvm_unreachable("atom not in any section");
}
void Util::addSectionRelocs(const lld::File &, NormalizedFile &file) {
if (_context.outputMachOType() != llvm::MachO::MH_OBJECT)
return;
+
+ // Utility function for ArchHandler to find symbol index for an atom.
+ auto symIndexForAtom = [&] (const Atom &atom) -> uint32_t {
+ auto pos = _atomToSymbolIndex.find(&atom);
+ assert(pos != _atomToSymbolIndex.end());
+ return pos->second;
+ };
+
+ // Utility function for ArchHandler to find section index for an atom.
+ auto sectIndexForAtom = [&] (const Atom &atom) -> uint32_t {
+ return sectionIndexForAtom(&atom);
+ };
+
+ // Utility function for ArchHandler to find address of atom in output file.
+ auto addressForAtom = [&] (const Atom &atom) -> uint64_t {
+ auto pos = _atomToAddress.find(&atom);
+ assert(pos != _atomToAddress.end());
+ return pos->second;
+ };
+
for (SectionInfo *si : _sectionInfos) {
Section &normSect = file.sections[si->normalizedSectionIndex];
for (const AtomInfo &info : si->atomsAndOffsets) {
const DefinedAtom *atom = info.atom;
for (const Reference *ref : *atom) {
- appendReloc(atom, ref, normSect.relocations);
+ _archHandler.appendSectionRelocations(*atom, info.offsetInSection, *ref,
+ symIndexForAtom,
+ sectIndexForAtom,
+ addressForAtom,
+ normSect.relocations);
}
}
}
@@ -873,7 +912,7 @@ void Util::addRebaseAndBindingInfo(const lld::File &atomFile,
uint64_t segmentOffset = _atomToAddress[atom] + ref->offsetInAtom()
- segmentStartAddr;
const Atom* targ = ref->target();
- if (_context.archHandler().isPointer(*ref)) {
+ if (_archHandler.isPointer(*ref)) {
// A pointer to a DefinedAtom requires rebasing.
if (dyn_cast<DefinedAtom>(targ)) {
RebaseLocation rebase;
@@ -895,13 +934,13 @@ void Util::addRebaseAndBindingInfo(const lld::File &atomFile,
nFile.bindingInfo.push_back(bind);
}
}
- if (_context.archHandler().isLazyPointer(*ref)) {
+ if (_archHandler.isLazyPointer(*ref)) {
BindLocation bind;
bind.segIndex = segmentIndex;
bind.segOffset = segmentOffset;
bind.kind = llvm::MachO::BIND_TYPE_POINTER;
bind.canBeNull = false; //sa->canBeNullAtRuntime();
- bind.ordinal = 1;
+ bind.ordinal = 1; // FIXME
bind.symbolName = targ->name();
bind.addend = ref->addend();
nFile.lazyBindingInfo.push_back(bind);
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 ffc9e4777cf..6ba2e48d285 100644
--- a/lld/test/mach-o/parse-data-relocs-x86_64.yaml
+++ b/lld/test/mach-o/parse-data-relocs-x86_64.yaml
@@ -1,6 +1,12 @@
-# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+# 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
#
-# Test parsing of x86_64 data relocations.
+# Test parsing and writing of x86_64 text relocations.
+#
+# The first step tests if the supplied mach-o file is parsed into the correct
+# set of references. The second step verifies relocations can be round-tripped
+# by writing to a new .o file, then parsing that file which should result in
+# the same references.
#
#_foo:
# ret
diff --git a/lld/test/mach-o/parse-relocs-x86.yaml b/lld/test/mach-o/parse-relocs-x86.yaml
index c9feb244d75..546a9e9a07d 100644
--- a/lld/test/mach-o/parse-relocs-x86.yaml
+++ b/lld/test/mach-o/parse-relocs-x86.yaml
@@ -1,9 +1,14 @@
-# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s \
+# RUN: && lld -flavor darwin -arch i386 -r -print_atoms %t -o %t2 | FileCheck %s
#
-# Test parsing of x86 relocations.
+# Test parsing and writing of x86 relocations.
#
-# .text
+# The first step tests if the supplied mach-o file is parsed into the correct
+# set of references. The second step verifies relocations can be round-tripped
+# by writing to a new .o file, then parsing that file which should result in
+# the same references.
#
+# .text
#_test:
# call _undef
# call _undef+2
diff --git a/lld/test/mach-o/parse-text-relocs-x86_64.yaml b/lld/test/mach-o/parse-text-relocs-x86_64.yaml
index e3b9cf292de..b2a3d5de016 100644
--- a/lld/test/mach-o/parse-text-relocs-x86_64.yaml
+++ b/lld/test/mach-o/parse-text-relocs-x86_64.yaml
@@ -1,6 +1,12 @@
-# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s \
+# RUN: && lld -flavor darwin -arch x86_64 -r -print_atoms %t -o %t2 | FileCheck %s
#
-# Test parsing of x86_64 text relocations.
+# Test parsing and writing of x86_64 text relocations.
+#
+# The first step tests if the supplied mach-o file is parsed into the correct
+# set of references. The second step verifies relocations can be round-tripped
+# by writing to a new .o file, then parsing that file which should result in
+# the same references.
#
#_test:
# call _foo
OpenPOWER on IntegriCloud