aboutsummaryrefslogtreecommitdiff
path: root/lib/ReaderWriter/MachO
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ReaderWriter/MachO')
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler.h29
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_arm.cpp131
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_arm64.cpp122
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_x86.cpp74
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp178
-rw-r--r--lib/ReaderWriter/MachO/Atoms.h32
-rw-r--r--lib/ReaderWriter/MachO/CMakeLists.txt2
-rw-r--r--lib/ReaderWriter/MachO/CompactUnwindPass.cpp33
-rw-r--r--lib/ReaderWriter/MachO/ExecutableAtoms.h108
-rw-r--r--lib/ReaderWriter/MachO/File.h93
-rw-r--r--lib/ReaderWriter/MachO/FlatNamespaceFile.h28
-rw-r--r--lib/ReaderWriter/MachO/GOTPass.cpp12
-rw-r--r--lib/ReaderWriter/MachO/LayoutPass.cpp47
-rw-r--r--lib/ReaderWriter/MachO/LayoutPass.h39
-rw-r--r--lib/ReaderWriter/MachO/MachOLinkingContext.cpp216
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFile.h32
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp44
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h46
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp461
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp268
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp608
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp81
-rw-r--r--lib/ReaderWriter/MachO/MachOPasses.h1
-rw-r--r--lib/ReaderWriter/MachO/ObjCPass.cpp128
-rw-r--r--lib/ReaderWriter/MachO/SectCreateFile.h19
-rw-r--r--lib/ReaderWriter/MachO/ShimPass.cpp13
-rw-r--r--lib/ReaderWriter/MachO/StubsPass.cpp40
-rw-r--r--lib/ReaderWriter/MachO/TLVPass.cpp14
-rw-r--r--lib/ReaderWriter/MachO/WriterMachO.cpp9
29 files changed, 2050 insertions, 858 deletions
diff --git a/lib/ReaderWriter/MachO/ArchHandler.h b/lib/ReaderWriter/MachO/ArchHandler.h
index 120f5dfd4cd2..70a63bd1004b 100644
--- a/lib/ReaderWriter/MachO/ArchHandler.h
+++ b/lib/ReaderWriter/MachO/ArchHandler.h
@@ -7,18 +7,19 @@
//
//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
+#define LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
+
#include "Atoms.h"
#include "File.h"
#include "MachONormalizedFile.h"
#include "lld/Core/LLVM.h"
+#include "lld/Core/Error.h"
#include "lld/Core/Reference.h"
#include "lld/Core/Simple.h"
#include "lld/ReaderWriter/MachOLinkingContext.h"
#include "llvm/ADT/Triple.h"
-#ifndef LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
-#define LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
-
namespace lld {
namespace mach_o {
@@ -78,6 +79,11 @@ public:
/// actually be used.
virtual uint32_t dwarfCompactUnwindType() = 0;
+ /// Reference from an __eh_frame CIE atom to its personality function it's
+ /// describing. Usually pointer-sized and PC-relative, but differs in whether
+ /// it needs to be in relocatable objects.
+ virtual Reference::KindValue unwindRefToPersonalityFunctionKind() = 0;
+
/// Reference from an __eh_frame FDE to the CIE it's based on.
virtual Reference::KindValue unwindRefToCIEKind() = 0;
@@ -92,6 +98,10 @@ public:
/// __eh_frame.
virtual Reference::KindValue unwindRefToEhFrameKind() = 0;
+ /// Returns a pointer sized reference kind. On 64-bit targets this will
+ /// likely be something like pointer64, and pointer32 on 32-bit targets.
+ virtual Reference::KindValue pointerKind() = 0;
+
virtual const Atom *fdeTargetFunction(const DefinedAtom *fde);
/// Used by normalizedFromAtoms() to know where to generated rebasing and
@@ -107,20 +117,20 @@ public:
/// Prototype for a helper function. Given a sectionIndex and address,
/// finds the atom and offset with that atom of that address.
- typedef std::function<std::error_code (uint32_t sectionIndex, uint64_t addr,
+ typedef std::function<llvm::Error (uint32_t sectionIndex, uint64_t addr,
const lld::Atom **, Reference::Addend *)>
FindAtomBySectionAndAddress;
/// Prototype for a helper function. Given a symbolIndex, finds the atom
/// representing that symbol.
- typedef std::function<std::error_code (uint32_t symbolIndex,
+ typedef std::function<llvm::Error (uint32_t symbolIndex,
const lld::Atom **)> 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
+ virtual llvm::Error
getReferenceInfo(const normalized::Relocation &reloc,
const DefinedAtom *inAtom,
uint32_t offsetInAtom,
@@ -135,7 +145,7 @@ public:
/// (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
+ virtual llvm::Error
getPairReferenceInfo(const normalized::Relocation &reloc1,
const normalized::Relocation &reloc2,
const DefinedAtom *inAtom,
@@ -169,7 +179,7 @@ public:
FindAddressForAtom findAddress,
FindAddressForAtom findSectionAddress,
uint64_t imageBaseAddress,
- uint8_t *atomContentBuffer) = 0;
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) = 0;
/// Used in -r mode to convert a Reference to a mach-o relocation.
virtual void appendSectionRelocations(const DefinedAtom &atom,
@@ -251,7 +261,10 @@ public:
ReferenceInfo stubHelperReferenceToImm;
ReferenceInfo stubHelperReferenceToHelperCommon;
+ DefinedAtom::ContentType stubHelperImageCacheContentType;
+
uint32_t stubHelperCommonSize;
+ uint8_t stubHelperCommonAlignment;
uint8_t stubHelperCommonBytes[36];
ReferenceInfo stubHelperCommonReferenceToCache;
OptionalRefInfo optStubHelperCommonReferenceToCache;
diff --git a/lib/ReaderWriter/MachO/ArchHandler_arm.cpp b/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
index 4e15a2d434c6..3286fe064535 100644
--- a/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
+++ b/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
@@ -51,6 +51,10 @@ public:
return invalid;
}
+ Reference::KindValue unwindRefToPersonalityFunctionKind() override {
+ return invalid;
+ }
+
Reference::KindValue unwindRefToCIEKind() override {
return invalid;
}
@@ -63,21 +67,25 @@ public:
return invalid;
}
+ Reference::KindValue pointerKind() override {
+ return invalid;
+ }
+
uint32_t dwarfCompactUnwindType() override {
// FIXME
return -1;
}
- 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
+ llvm::Error 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;
+ llvm::Error
getPairReferenceInfo(const normalized::Relocation &reloc1,
const normalized::Relocation &reloc2,
const DefinedAtom *inAtom,
@@ -93,7 +101,7 @@ public:
FindAddressForAtom findAddress,
FindAddressForAtom findSectionAddress,
uint64_t imageBaseAddress,
- uint8_t *atomContentBuffer) override;
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
void appendSectionRelocations(const DefinedAtom &atom,
uint64_t atomSectionOffset,
@@ -256,8 +264,13 @@ const ArchHandler::StubInfo ArchHandler_arm::_sStubInfoArmPIC = {
{ Reference::KindArch::ARM, lazyImmediateLocation, 8, 0 },
{ Reference::KindArch::ARM, arm_b24, 4, 0 },
+ // Stub helper image cache content type
+ DefinedAtom::typeGOT,
+
// Stub Helper-Common size and code
36,
+ // Stub helper alignment
+ 2,
{ // push lazy-info-offset
0x04, 0xC0, 0x2D, 0xE5, // str ip, [sp, #-4]!
// push address of dyld_mageLoaderCache
@@ -505,13 +518,12 @@ uint32_t ArchHandler_arm::clearThumbBit(uint32_t value, const Atom *target) {
return value;
}
-std::error_code ArchHandler_arm::getReferenceInfo(
+llvm::Error ArchHandler_arm::getReferenceInfo(
const Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom,
uint64_t fixupAddress, bool isBig,
FindAtomBySectionAndAddress atomFromAddress,
FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind,
const lld::Atom **target, Reference::Addend *addend) {
- typedef std::error_code E;
const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
uint64_t targetAddress;
uint32_t instruction = *(const ulittle32_t *)fixupContent;
@@ -523,12 +535,12 @@ std::error_code ArchHandler_arm::getReferenceInfo(
*kind = thumb_b22;
else
*kind = thumb_bl22;
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
// Instruction contains branch to addend.
displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
*addend = fixupAddress + 4 + displacement;
- return std::error_code();
+ return llvm::Error();
case ARM_THUMB_RELOC_BR22 | rPcRel | rLength4:
// ex: bl _foo (and _foo is defined)
if ((instruction & 0xD000F800) == 0x9000F000)
@@ -546,12 +558,12 @@ std::error_code ArchHandler_arm::getReferenceInfo(
*kind = thumb_bl22;
displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
targetAddress = fixupAddress + 4 + displacement;
- if (E ec = atomFromAddress(0, reloc.value, target, addend))
+ if (auto ec = atomFromAddress(0, reloc.value, target, addend))
return ec;
// reloc.value is target atom's address. Instruction contains branch
// to atom+addend.
*addend += (targetAddress - reloc.value);
- return std::error_code();
+ return llvm::Error();
case ARM_RELOC_BR24 | rPcRel | rExtern | rLength4:
// ex: bl _foo (and _foo is undefined)
if (((instruction & 0x0F000000) == 0x0A000000)
@@ -559,12 +571,12 @@ std::error_code ArchHandler_arm::getReferenceInfo(
*kind = arm_b24;
else
*kind = arm_bl24;
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
// Instruction contains branch to addend.
displacement = getDisplacementFromArmBranch(instruction);
*addend = fixupAddress + 8 + displacement;
- return std::error_code();
+ return llvm::Error();
case ARM_RELOC_BR24 | rPcRel | rLength4:
// ex: bl _foo (and _foo is defined)
if (((instruction & 0x0F000000) == 0x0A000000)
@@ -584,40 +596,40 @@ std::error_code ArchHandler_arm::getReferenceInfo(
*kind = arm_bl24;
displacement = getDisplacementFromArmBranch(instruction);
targetAddress = fixupAddress + 8 + displacement;
- if (E ec = atomFromAddress(0, reloc.value, target, addend))
+ if (auto ec = atomFromAddress(0, reloc.value, target, addend))
return ec;
// reloc.value is target atom's address. Instruction contains branch
// to atom+addend.
*addend += (targetAddress - reloc.value);
- return std::error_code();
+ return llvm::Error();
case ARM_RELOC_VANILLA | rExtern | rLength4:
// ex: .long _foo (and _foo is undefined)
*kind = pointer32;
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = instruction;
- return std::error_code();
+ return llvm::Error();
case ARM_RELOC_VANILLA | rLength4:
// ex: .long _foo (and _foo is defined)
*kind = pointer32;
- if (E ec = atomFromAddress(reloc.symbol, instruction, target, addend))
+ if (auto ec = atomFromAddress(reloc.symbol, instruction, target, addend))
return ec;
*addend = clearThumbBit((uint32_t) * addend, *target);
- return std::error_code();
+ return llvm::Error();
case ARM_RELOC_VANILLA | rScattered | rLength4:
// ex: .long _foo+a (and _foo is defined)
*kind = pointer32;
- if (E ec = atomFromAddress(0, reloc.value, target, addend))
+ if (auto ec = atomFromAddress(0, reloc.value, target, addend))
return ec;
*addend += (clearThumbBit(instruction, *target) - reloc.value);
- return std::error_code();
+ return llvm::Error();
default:
- return make_dynamic_error_code("unsupported arm relocation type");
+ return llvm::make_error<GenericError>("unsupported arm relocation type");
}
- return std::error_code();
+ return llvm::Error();
}
-std::error_code
+llvm::Error
ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
const normalized::Relocation &reloc2,
const DefinedAtom *inAtom,
@@ -770,10 +782,9 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
pointerDiff = true;
break;
default:
- return make_dynamic_error_code("unsupported arm relocation pair");
+ return llvm::make_error<GenericError>("unsupported arm relocation pair");
}
const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
- std::error_code ec;
uint32_t instruction = *(const ulittle32_t *)fixupContent;
uint32_t value;
uint32_t fromAddress;
@@ -786,14 +797,12 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
if (pointerDiff) {
toAddress = reloc1.value;
fromAddress = reloc2.value;
- ec = atomFromAddr(0, toAddress, target, &offsetInTo);
- if (ec)
+ if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
return ec;
- ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
- if (ec)
+ if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
return ec;
if (scatterable && (fromTarget != inAtom))
- return make_dynamic_error_code(
+ return llvm::make_error<GenericError>(
"SECTDIFF relocation where subtrahend label is not in atom");
*kind = delta32;
value = clearThumbBit(instruction, *target);
@@ -801,35 +810,33 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
} else if (funcRel) {
toAddress = reloc1.value;
fromAddress = reloc2.value;
- ec = atomFromAddr(0, toAddress, target, &offsetInTo);
- if (ec)
+ if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
return ec;
- ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
- if (ec)
+ if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
return ec;
if (fromTarget != inAtom)
- return make_dynamic_error_code("ARM_RELOC_HALF_SECTDIFF relocation "
- "where subtrahend label is not in atom");
+ return llvm::make_error<GenericError>("ARM_RELOC_HALF_SECTDIFF relocation"
+ " where subtrahend label is not in atom");
other16 = (reloc2.offset & 0xFFFF);
if (thumbReloc) {
if (top) {
if (!isThumbMovt(instruction))
- return make_dynamic_error_code("expected movt instruction");
+ return llvm::make_error<GenericError>("expected movt instruction");
}
else {
if (!isThumbMovw(instruction))
- return make_dynamic_error_code("expected movw instruction");
+ return llvm::make_error<GenericError>("expected movw instruction");
}
instruction16 = getWordFromThumbMov(instruction);
}
else {
if (top) {
if (!isArmMovt(instruction))
- return make_dynamic_error_code("expected movt instruction");
+ return llvm::make_error<GenericError>("expected movt instruction");
}
else {
if (!isArmMovw(instruction))
- return make_dynamic_error_code("expected movw instruction");
+ return llvm::make_error<GenericError>("expected movw instruction");
}
instruction16 = getWordFromArmMov(instruction);
}
@@ -840,28 +847,28 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
value = clearThumbBit(value, *target);
int64_t ta = (int64_t) value - (toAddress - fromAddress);
*addend = ta - offsetInFrom;
- return std::error_code();
+ return llvm::Error();
} else {
uint32_t sectIndex;
if (thumbReloc) {
if (top) {
if (!isThumbMovt(instruction))
- return make_dynamic_error_code("expected movt instruction");
+ return llvm::make_error<GenericError>("expected movt instruction");
}
else {
if (!isThumbMovw(instruction))
- return make_dynamic_error_code("expected movw instruction");
+ return llvm::make_error<GenericError>("expected movw instruction");
}
instruction16 = getWordFromThumbMov(instruction);
}
else {
if (top) {
if (!isArmMovt(instruction))
- return make_dynamic_error_code("expected movt instruction");
+ return llvm::make_error<GenericError>("expected movt instruction");
}
else {
if (!isArmMovw(instruction))
- return make_dynamic_error_code("expected movw instruction");
+ return llvm::make_error<GenericError>("expected movw instruction");
}
instruction16 = getWordFromArmMov(instruction);
}
@@ -871,8 +878,7 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
else
value = (other16 << 16) | instruction16;
if (reloc1.isExtern) {
- ec = atomFromSymbolIndex(reloc1.symbol, target);
- if (ec)
+ if (auto ec = atomFromSymbolIndex(reloc1.symbol, target))
return ec;
*addend = value;
} else {
@@ -883,14 +889,13 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
toAddress = value;
sectIndex = reloc1.symbol;
}
- ec = atomFromAddr(sectIndex, toAddress, target, &offsetInTo);
- if (ec)
+ if (auto ec = atomFromAddr(sectIndex, toAddress, target, &offsetInTo))
return ec;
*addend = value - toAddress;
}
}
- return std::error_code();
+ return llvm::Error();
}
void ArchHandler_arm::applyFixupFinal(const Reference &ref, uint8_t *loc,
@@ -1006,9 +1011,10 @@ void ArchHandler_arm::generateAtomContent(const DefinedAtom &atom,
FindAddressForAtom findAddress,
FindAddressForAtom findSectionAddress,
uint64_t imageBaseAddress,
- uint8_t *atomContentBuffer) {
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
// Copy raw bytes.
- memcpy(atomContentBuffer, atom.rawContent().data(), atom.size());
+ std::copy(atom.rawContent().begin(), atom.rawContent().end(),
+ atomContentBuffer.begin());
// Apply fix-ups.
bool thumbMode = false;
for (const Reference *ref : atom) {
@@ -1384,7 +1390,8 @@ void ArchHandler_arm::appendSectionRelocations(
void ArchHandler_arm::addAdditionalReferences(MachODefinedAtom &atom) {
if (atom.isThumb()) {
- atom.addReference(0, modeThumbCode, &atom, 0, Reference::KindArch::ARM);
+ atom.addReference(Reference::KindNamespace::mach_o,
+ Reference::KindArch::ARM, modeThumbCode, 0, &atom, 0);
}
}
@@ -1415,6 +1422,8 @@ public:
_name = tmp.copy(file.allocator());
}
+ ~Thumb2ToArmShimAtom() override = default;
+
StringRef name() const override {
return _name;
}
@@ -1458,6 +1467,8 @@ public:
_name = tmp.copy(file.allocator());
}
+ ~ArmToThumbShimAtom() override = default;
+
StringRef name() const override {
return _name;
}
diff --git a/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp b/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
index 778f6f4add74..a61f6aac05e1 100644
--- a/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
+++ b/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
@@ -53,6 +53,9 @@ public:
case delta32ToGOT:
canBypassGOT = false;
return true;
+ case unwindCIEToPersonalityFunction:
+ canBypassGOT = false;
+ return true;
case imageOffsetGot:
canBypassGOT = false;
return true;
@@ -108,6 +111,10 @@ public:
return imageOffsetGot;
}
+ Reference::KindValue unwindRefToPersonalityFunctionKind() override {
+ return unwindCIEToPersonalityFunction;
+ }
+
Reference::KindValue unwindRefToCIEKind() override {
return negDelta32;
}
@@ -120,20 +127,24 @@ public:
return unwindInfoToEhFrame;
}
+ Reference::KindValue pointerKind() override {
+ return pointer64;
+ }
+
uint32_t dwarfCompactUnwindType() override {
return 0x03000000;
}
- std::error_code getReferenceInfo(const normalized::Relocation &reloc,
- const DefinedAtom *inAtom,
- uint32_t offsetInAtom,
- uint64_t fixupAddress, bool isBig,
- FindAtomBySectionAndAddress atomFromAddress,
- FindAtomBySymbolIndex atomFromSymbolIndex,
- Reference::KindValue *kind,
- const lld::Atom **target,
- Reference::Addend *addend) override;
- std::error_code
+ llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool isBig,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) override;
+ llvm::Error
getPairReferenceInfo(const normalized::Relocation &reloc1,
const normalized::Relocation &reloc2,
const DefinedAtom *inAtom,
@@ -153,7 +164,7 @@ public:
FindAddressForAtom findAddress,
FindAddressForAtom findSectionAddress,
uint64_t imageBaseAddress,
- uint8_t *atomContentBuffer) override;
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
void appendSectionRelocations(const DefinedAtom &atom,
uint64_t atomSectionOffset,
@@ -197,6 +208,9 @@ private:
imageOffset, /// Location contains offset of atom in final image
imageOffsetGot, /// Location contains offset of GOT entry for atom in
/// final image (typically personality function).
+ unwindCIEToPersonalityFunction, /// Nearly delta32ToGOT, but cannot be
+ /// rematerialized in relocatable object
+ /// (yay for implicit contracts!).
unwindFDEToFunction, /// Nearly delta64, but cannot be rematerialized in
/// relocatable object (yay for implicit contracts!).
unwindInfoToEhFrame, /// Fix low 24 bits of compact unwind encoding to
@@ -244,6 +258,7 @@ const Registry::KindStrings ArchHandler_arm64::_sKindStrings[] = {
LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
LLD_KIND_STRING_ENTRY(imageOffset),
LLD_KIND_STRING_ENTRY(imageOffsetGot),
+ LLD_KIND_STRING_ENTRY(unwindCIEToPersonalityFunction),
LLD_KIND_STRING_ENTRY(unwindFDEToFunction),
LLD_KIND_STRING_ENTRY(unwindInfoToEhFrame),
@@ -279,8 +294,13 @@ const ArchHandler::StubInfo ArchHandler_arm64::_sStubInfo = {
{ Reference::KindArch::AArch64, lazyImmediateLocation, 8, 0 },
{ Reference::KindArch::AArch64, branch26, 4, 0 },
+ // Stub helper image cache content type
+ DefinedAtom::typeGOT,
+
// Stub Helper-Common size and code
24,
+ // Stub helper alignment
+ 2,
{ 0x11, 0x00, 0x00, 0x90, // ADRP X17, dyld_ImageLoaderCache@page
0x31, 0x02, 0x00, 0x91, // ADD X17, X17, dyld_ImageLoaderCache@pageoff
0xF0, 0x47, 0xBF, 0xA9, // STP X16/X17, [SP, #-16]!
@@ -355,7 +375,7 @@ uint32_t ArchHandler_arm64::setImm12(uint32_t instruction, uint32_t offset) {
return (instruction & 0xFFC003FF) | imm12;
}
-std::error_code ArchHandler_arm64::getReferenceInfo(
+llvm::Error ArchHandler_arm64::getReferenceInfo(
const Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom,
uint64_t fixupAddress, bool isBig,
FindAtomBySectionAndAddress atomFromAddress,
@@ -369,56 +389,56 @@ std::error_code ArchHandler_arm64::getReferenceInfo(
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = 0;
- return std::error_code();
+ return llvm::Error();
case ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4:
// ex: adrp x1, _foo@PAGE
*kind = page21;
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = 0;
- return std::error_code();
+ return llvm::Error();
case ARM64_RELOC_PAGEOFF12 | rExtern | rLength4:
// ex: ldr x0, [x1, _foo@PAGEOFF]
*kind = offset12KindFromInstruction(*(const little32_t *)fixupContent);
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = 0;
- return std::error_code();
+ return llvm::Error();
case ARM64_RELOC_GOT_LOAD_PAGE21 | rPcRel | rExtern | rLength4:
// ex: adrp x1, _foo@GOTPAGE
*kind = gotPage21;
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = 0;
- return std::error_code();
+ return llvm::Error();
case ARM64_RELOC_GOT_LOAD_PAGEOFF12 | rExtern | rLength4:
// ex: ldr x0, [x1, _foo@GOTPAGEOFF]
*kind = gotOffset12;
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = 0;
- return std::error_code();
+ return llvm::Error();
case ARM64_RELOC_TLVP_LOAD_PAGE21 | rPcRel | rExtern | rLength4:
// ex: adrp x1, _foo@TLVPAGE
*kind = tlvPage21;
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = 0;
- return std::error_code();
+ return llvm::Error();
case ARM64_RELOC_TLVP_LOAD_PAGEOFF12 | rExtern | rLength4:
// ex: ldr x0, [x1, _foo@TLVPAGEOFF]
*kind = tlvOffset12;
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = 0;
- return std::error_code();
+ return llvm::Error();
case ARM64_RELOC_UNSIGNED | rExtern | rLength8:
// ex: .quad _foo + N
*kind = pointer64;
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = *(const little64_t *)fixupContent;
- return std::error_code();
+ return llvm::Error();
case ARM64_RELOC_UNSIGNED | rLength8:
// ex: .quad Lfoo + N
*kind = pointer64;
@@ -430,27 +450,33 @@ std::error_code ArchHandler_arm64::getReferenceInfo(
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = 0;
- return std::error_code();
+ return llvm::Error();
case ARM64_RELOC_POINTER_TO_GOT | rPcRel | rExtern | rLength4:
// ex: .long _foo@GOT - .
- *kind = delta32ToGOT;
+
+ // If we are in an .eh_frame section, then the kind of the relocation should
+ // not be delta32ToGOT. It may instead be unwindCIEToPersonalityFunction.
+ if (inAtom->contentType() == DefinedAtom::typeCFI)
+ *kind = unwindCIEToPersonalityFunction;
+ else
+ *kind = delta32ToGOT;
+
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = 0;
- return std::error_code();
+ return llvm::Error();
default:
- return make_dynamic_error_code("unsupported arm64 relocation type");
+ return llvm::make_error<GenericError>("unsupported arm64 relocation type");
}
}
-std::error_code ArchHandler_arm64::getPairReferenceInfo(
+llvm::Error ArchHandler_arm64::getPairReferenceInfo(
const normalized::Relocation &reloc1, const normalized::Relocation &reloc2,
const DefinedAtom *inAtom, uint32_t offsetInAtom, uint64_t fixupAddress,
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];
- const uint32_t *cont32 = reinterpret_cast<const uint32_t *>(fixupContent);
switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
case ((ARM64_RELOC_ADDEND | rLength4) << 16 |
ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4):
@@ -459,7 +485,7 @@ std::error_code ArchHandler_arm64::getPairReferenceInfo(
if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
return ec;
*addend = reloc1.symbol;
- return std::error_code();
+ return llvm::Error();
case ((ARM64_RELOC_ADDEND | rLength4) << 16 |
ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4):
// ex: adrp x1, _foo@PAGE
@@ -467,26 +493,36 @@ std::error_code ArchHandler_arm64::getPairReferenceInfo(
if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
return ec;
*addend = reloc1.symbol;
- return std::error_code();
+ return llvm::Error();
case ((ARM64_RELOC_ADDEND | rLength4) << 16 |
- ARM64_RELOC_PAGEOFF12 | rExtern | rLength4):
+ ARM64_RELOC_PAGEOFF12 | rExtern | rLength4): {
// ex: ldr w0, [x1, _foo@PAGEOFF]
- *kind = offset12KindFromInstruction(*cont32);
+ uint32_t cont32 = (int32_t)*(const little32_t *)fixupContent;
+ *kind = offset12KindFromInstruction(cont32);
if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
return ec;
*addend = reloc1.symbol;
- return std::error_code();
+ return llvm::Error();
+ }
case ((ARM64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
ARM64_RELOC_UNSIGNED | rExtern | rLength8):
// ex: .quad _foo - .
- *kind = delta64;
if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
return ec;
+
+ // If we are in an .eh_frame section, then the kind of the relocation should
+ // not be delta64. It may instead be unwindFDEToFunction.
+ if (inAtom->contentType() == DefinedAtom::typeCFI)
+ *kind = unwindFDEToFunction;
+ else
+ *kind = delta64;
+
// The offsets of the 2 relocations must match
if (reloc1.offset != reloc2.offset)
- return make_dynamic_error_code("paired relocs must have the same offset");
+ return llvm::make_error<GenericError>(
+ "paired relocs must have the same offset");
*addend = (int64_t)*(const little64_t *)fixupContent + offsetInAtom;
- return std::error_code();
+ return llvm::Error();
case ((ARM64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
ARM64_RELOC_UNSIGNED | rExtern | rLength4):
// ex: .quad _foo - .
@@ -494,18 +530,19 @@ std::error_code ArchHandler_arm64::getPairReferenceInfo(
if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
return ec;
*addend = (int32_t)*(const little32_t *)fixupContent + offsetInAtom;
- return std::error_code();
+ return llvm::Error();
default:
- return make_dynamic_error_code("unsupported arm64 relocation pair");
+ return llvm::make_error<GenericError>("unsupported arm64 relocation pair");
}
}
void ArchHandler_arm64::generateAtomContent(
const DefinedAtom &atom, bool relocatable, FindAddressForAtom findAddress,
FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress,
- uint8_t *atomContentBuffer) {
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
// Copy raw bytes.
- memcpy(atomContentBuffer, atom.rawContent().data(), atom.size());
+ std::copy(atom.rawContent().begin(), atom.rawContent().end(),
+ atomContentBuffer.begin());
// Apply fix-ups.
#ifndef NDEBUG
if (atom.begin() != atom.end()) {
@@ -620,6 +657,7 @@ void ArchHandler_arm64::applyFixupFinal(const Reference &ref, uint8_t *loc,
return;
case delta32:
case delta32ToGOT:
+ case unwindCIEToPersonalityFunction:
*loc32 = (targetAddress - fixupAddress) + ref.addend();
return;
case negDelta32:
@@ -710,6 +748,13 @@ void ArchHandler_arm64::applyFixupRelocatable(const Reference &ref,
case delta32ToGOT:
*loc32 = inAtomAddress - fixupAddress;
return;
+ case unwindCIEToPersonalityFunction:
+ // We don't emit unwindCIEToPersonalityFunction in -r mode as they are
+ // implicitly generated from the data in the __eh_frame section. So here we
+ // need to use the targetAddress so that we can generate the full relocation
+ // when we parse again later.
+ *loc32 = targetAddress - fixupAddress;
+ return;
case addOffset12:
llvm_unreachable("lazy reference kind implies GOT pass was run");
case lazyPointer:
@@ -832,6 +877,7 @@ void ArchHandler_arm64::appendSectionRelocations(
case imageOffset:
case imageOffsetGot:
llvm_unreachable("deltas from mach_header can only be in final images");
+ case unwindCIEToPersonalityFunction:
case unwindFDEToFunction:
case unwindInfoToEhFrame:
case negDelta32:
diff --git a/lib/ReaderWriter/MachO/ArchHandler_x86.cpp b/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
index 7aac2584d078..15f1f793b5d7 100644
--- a/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
+++ b/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
@@ -58,6 +58,10 @@ public:
return invalid;
}
+ Reference::KindValue unwindRefToPersonalityFunctionKind() override {
+ return invalid;
+ }
+
Reference::KindValue unwindRefToCIEKind() override {
return negDelta32;
}
@@ -70,20 +74,24 @@ public:
return invalid;
}
+ Reference::KindValue pointerKind() override {
+ return invalid;
+ }
+
uint32_t dwarfCompactUnwindType() override {
return 0x04000000U;
}
- 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
+ llvm::Error 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;
+ llvm::Error
getPairReferenceInfo(const normalized::Relocation &reloc1,
const normalized::Relocation &reloc2,
const DefinedAtom *inAtom,
@@ -99,7 +107,7 @@ public:
FindAddressForAtom findAddress,
FindAddressForAtom findSectionAddress,
uint64_t imageBaseAddress,
- uint8_t *atomContentBuffer) override;
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
void appendSectionRelocations(const DefinedAtom &atom,
uint64_t atomSectionOffset,
@@ -212,8 +220,13 @@ const ArchHandler::StubInfo ArchHandler_x86::_sStubInfo = {
{ Reference::KindArch::x86, lazyImmediateLocation, 1, 0 },
{ Reference::KindArch::x86, branch32, 6, 0 },
+ // Stub helper image cache content type
+ DefinedAtom::typeNonLazyPointer,
+
// Stub Helper-Common size and code
12,
+ // Stub helper alignment
+ 2,
{ 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $dyld_ImageLoaderCache
0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *_fast_lazy_bind
0x90 }, // nop
@@ -238,7 +251,7 @@ bool ArchHandler_x86::isPairedReloc(const Relocation &reloc) {
(reloc.type == GENERIC_RELOC_SECTDIFF);
}
-std::error_code
+llvm::Error
ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
const DefinedAtom *inAtom,
uint32_t offsetInAtom,
@@ -248,7 +261,6 @@ ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
Reference::KindValue *kind,
const lld::Atom **target,
Reference::Addend *addend) {
- typedef std::error_code E;
DefinedAtom::ContentPermissions perms;
const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
uint64_t targetAddress;
@@ -256,7 +268,7 @@ ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength4:
// ex: call _foo (and _foo undefined)
*kind = branch32;
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = fixupAddress + 4 + (int32_t)*(const little32_t *)fixupContent;
break;
@@ -272,14 +284,14 @@ ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
*kind = branch32;
targetAddress =
fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent;
- if (E ec = atomFromAddress(0, reloc.value, target, addend))
+ if (auto ec = atomFromAddress(0, reloc.value, target, addend))
return ec;
*addend = targetAddress - reloc.value;
break;
case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2:
// ex: callw _foo (and _foo undefined)
*kind = branch16;
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = fixupAddress + 2 + (int16_t)*(const little16_t *)fixupContent;
break;
@@ -295,7 +307,7 @@ ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
*kind = branch16;
targetAddress =
fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent;
- if (E ec = atomFromAddress(0, reloc.value, target, addend))
+ if (auto ec = atomFromAddress(0, reloc.value, target, addend))
return ec;
*addend = targetAddress - reloc.value;
break;
@@ -306,7 +318,7 @@ ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
*kind =
((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
: pointer32;
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = *(const ulittle32_t *)fixupContent;
break;
@@ -326,17 +338,17 @@ ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
*kind =
((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
: pointer32;
- if (E ec = atomFromAddress(0, reloc.value, target, addend))
+ if (auto ec = atomFromAddress(0, reloc.value, target, addend))
return ec;
*addend = *(const ulittle32_t *)fixupContent - reloc.value;
break;
default:
- return make_dynamic_error_code("unsupported i386 relocation type");
+ return llvm::make_error<GenericError>("unsupported i386 relocation type");
}
- return std::error_code();
+ return llvm::Error();
}
-std::error_code
+llvm::Error
ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
const normalized::Relocation &reloc2,
const DefinedAtom *inAtom,
@@ -349,7 +361,6 @@ ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
const lld::Atom **target,
Reference::Addend *addend) {
const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
- std::error_code ec;
DefinedAtom::ContentPermissions perms = inAtom->permissions();
uint32_t fromAddress;
uint32_t toAddress;
@@ -365,15 +376,13 @@ ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
toAddress = reloc1.value;
fromAddress = reloc2.value;
value = *(const little32_t *)fixupContent;
- ec = atomFromAddr(0, toAddress, target, &offsetInTo);
- if (ec)
+ if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
return ec;
- ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
- if (ec)
+ if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
return ec;
if (fromTarget != inAtom) {
if (*target != inAtom)
- return make_dynamic_error_code(
+ return llvm::make_error<GenericError>(
"SECTDIFF relocation where neither target is in atom");
*kind = negDelta32;
*addend = toAddress - value - fromAddress;
@@ -394,10 +403,10 @@ ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
*addend = fromAddress + value - toAddress;
}
}
- return std::error_code();
+ return llvm::Error();
break;
default:
- return make_dynamic_error_code("unsupported i386 relocation type");
+ return llvm::make_error<GenericError>("unsupported i386 relocation type");
}
}
@@ -406,9 +415,10 @@ void ArchHandler_x86::generateAtomContent(const DefinedAtom &atom,
FindAddressForAtom findAddress,
FindAddressForAtom findSectionAddress,
uint64_t imageBaseAddress,
- uint8_t *atomContentBuffer) {
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
// Copy raw bytes.
- memcpy(atomContentBuffer, atom.rawContent().data(), atom.size());
+ std::copy(atom.rawContent().begin(), atom.rawContent().end(),
+ atomContentBuffer.begin());
// Apply fix-ups.
for (const Reference *ref : atom) {
uint32_t offset = ref->offsetInAtom();
diff --git a/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
index 8b4d1cf38cba..c36982a77b13 100644
--- a/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
+++ b/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
@@ -104,6 +104,10 @@ public:
return imageOffsetGot;
}
+ Reference::KindValue unwindRefToPersonalityFunctionKind() override {
+ return ripRel32Got;
+ }
+
Reference::KindValue unwindRefToCIEKind() override {
return negDelta32;
}
@@ -116,6 +120,10 @@ public:
return unwindInfoToEhFrame;
}
+ Reference::KindValue pointerKind() override {
+ return pointer64;
+ }
+
uint32_t dwarfCompactUnwindType() override {
return 0x04000000U;
}
@@ -130,16 +138,16 @@ public:
bool isPointer(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
+ llvm::Error 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;
+ llvm::Error
getPairReferenceInfo(const normalized::Relocation &reloc1,
const normalized::Relocation &reloc2,
const DefinedAtom *inAtom,
@@ -159,7 +167,7 @@ public:
FindAddressForAtom findAddress,
FindAddressForAtom findSectionAddress,
uint64_t imageBase,
- uint8_t *atomContentBuffer) override;
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
void appendSectionRelocations(const DefinedAtom &atom,
uint64_t atomSectionOffset,
@@ -195,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:
@@ -216,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,
@@ -246,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),
@@ -280,8 +288,13 @@ const ArchHandler::StubInfo ArchHandler_x86_64::_sStubInfo = {
{ Reference::KindArch::x86_64, lazyImmediateLocation, 1, 0 },
{ Reference::KindArch::x86_64, branch32, 6, 0 },
+ // Stub helper image cache content type
+ DefinedAtom::typeNonLazyPointer,
+
// Stub Helper-Common size and code
16,
+ // Stub helper alignment
+ 2,
{ 0x4C, 0x8D, 0x1D, 0x00, 0x00, 0x00, 0x00, // leaq cache(%rip),%r11
0x41, 0x53, // push %r11
0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *binder(%rip)
@@ -348,7 +361,7 @@ ArchHandler_x86_64::kindFromReloc(const Relocation &reloc) {
}
}
-std::error_code
+llvm::Error
ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc,
const DefinedAtom *inAtom,
uint32_t offsetInAtom,
@@ -358,34 +371,33 @@ ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc,
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("unknown type");
+ return llvm::make_error<GenericError>("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))
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = *(const little32_t *)fixupContent;
- return std::error_code();
+ return llvm::Error();
case ripRel32Minus1:
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = (int32_t)*(const little32_t *)fixupContent + 1;
- return std::error_code();
+ return llvm::Error();
case ripRel32Minus2:
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = (int32_t)*(const little32_t *)fixupContent + 2;
- return std::error_code();
+ return llvm::Error();
case ripRel32Minus4:
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = (int32_t)*(const little32_t *)fixupContent + 4;
- return std::error_code();
+ return llvm::Error();
case ripRel32Anon:
targetAddress = fixupAddress + 4 + *(const little32_t *)fixupContent;
return atomFromAddress(reloc.symbol, targetAddress, target, addend);
@@ -401,13 +413,13 @@ ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc,
case ripRel32GotLoad:
case ripRel32Got:
case ripRel32Tlv:
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = *(const little32_t *)fixupContent;
- return std::error_code();
+ return llvm::Error();
case tlvInitSectionOffset:
case pointer64:
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
// 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.
@@ -417,7 +429,7 @@ ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc,
assert(*addend == 0 && "TLV-init has non-zero addend?");
} else
*addend = *(const little64_t *)fixupContent;
- return std::error_code();
+ return llvm::Error();
case pointer64Anon:
targetAddress = *(const little64_t *)fixupContent;
return atomFromAddress(reloc.symbol, targetAddress, target, addend);
@@ -426,28 +438,7 @@ 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");
- }
-}
-
-std::error_code
+llvm::Error
ArchHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1,
const normalized::Relocation &reloc2,
const DefinedAtom *inAtom,
@@ -459,45 +450,71 @@ 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 make_dynamic_error_code("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))
+ if (auto ec = atomFromSymbolIndex(reloc1.symbol, &fromTarget))
return ec;
- if (fromTarget != inAtom)
- return make_dynamic_error_code("pointer diff not in base atom");
- switch (*kind) {
- case delta64:
- if (E ec = atomFromSymbolIndex(reloc2.symbol, target))
+
+ 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;
- return std::error_code();
- case delta32:
- if (E ec = atomFromSymbolIndex(reloc2.symbol, target))
+ 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 ((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;
- return std::error_code();
- case delta64Anon:
+ 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 ((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");
}
}
void ArchHandler_x86_64::generateAtomContent(
const DefinedAtom &atom, bool relocatable, FindAddressForAtom findAddress,
FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress,
- uint8_t *atomContentBuffer) {
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
// Copy raw bytes.
- memcpy(atomContentBuffer, atom.rawContent().data(), atom.size());
+ std::copy(atom.rawContent().begin(), atom.rawContent().end(),
+ atomContentBuffer.begin());
// Apply fix-ups.
for (const Reference *ref : atom) {
uint32_t offset = ref->offsetInAtom();
@@ -571,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;
@@ -675,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");
@@ -796,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/lib/ReaderWriter/MachO/Atoms.h b/lib/ReaderWriter/MachO/Atoms.h
index 9f2e5acad99a..573efca9f6f9 100644
--- a/lib/ReaderWriter/MachO/Atoms.h
+++ b/lib/ReaderWriter/MachO/Atoms.h
@@ -1,4 +1,4 @@
-//===- lib/ReaderWriter/MachO/Atoms.h -------------------------------------===//
+//===- lib/ReaderWriter/MachO/Atoms.h ---------------------------*- C++ -*-===//
//
// The LLVM Linker
//
@@ -10,10 +10,21 @@
#ifndef LLD_READER_WRITER_MACHO_ATOMS_H
#define LLD_READER_WRITER_MACHO_ATOMS_H
+#include "lld/Core/Atom.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/SharedLibraryAtom.h"
#include "lld/Core/Simple.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include <cstdint>
+#include <string>
namespace lld {
+
+class File;
+
namespace mach_o {
+
class MachODefinedAtom : public SimpleDefinedAtom {
public:
MachODefinedAtom(const File &f, const StringRef name, Scope scope,
@@ -32,6 +43,8 @@ public:
_contentType(type), _scope(scope), _merge(mergeNo), _thumb(false),
_noDeadStrip(noDeadStrip) {}
+ ~MachODefinedAtom() override = default;
+
uint64_t size() const override { return _content.size(); }
ContentType contentType() const override { return _contentType; }
@@ -61,15 +74,6 @@ public:
bool isThumb() const { return _thumb; }
- 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<uint8_t> _content;
@@ -92,6 +96,8 @@ public:
content, align),
_sectionName(sectionName) {}
+ ~MachODefinedCustomSectionAtom() override = default;
+
SectionChoice sectionChoice() const override {
return DefinedAtom::sectionCustomRequired;
}
@@ -110,6 +116,8 @@ public:
: SimpleDefinedAtom(f), _name(name), _scope(scope), _size(size),
_align(align) {}
+ ~MachOTentativeDefAtom() override = default;
+
uint64_t size() const override { return _size; }
Merge merge() const override { return DefinedAtom::mergeAsTentative; }
@@ -167,7 +175,7 @@ private:
StringRef _dylibInstallName;
};
-} // namespace mach_o
-} // namespace lld
+} // end namespace mach_o
+} // end namespace lld
#endif // LLD_READER_WRITER_MACHO_ATOMS_H
diff --git a/lib/ReaderWriter/MachO/CMakeLists.txt b/lib/ReaderWriter/MachO/CMakeLists.txt
index a389ca51ddfd..70f451c997b3 100644
--- a/lib/ReaderWriter/MachO/CMakeLists.txt
+++ b/lib/ReaderWriter/MachO/CMakeLists.txt
@@ -13,6 +13,7 @@ add_lld_library(lldMachO
MachONormalizedFileFromAtoms.cpp
MachONormalizedFileToAtoms.cpp
MachONormalizedFileYAML.cpp
+ ObjCPass.cpp
ShimPass.cpp
StubsPass.cpp
TLVPass.cpp
@@ -22,6 +23,7 @@ add_lld_library(lldMachO
lldYAML
LLVMObject
LLVMSupport
+ ${PTHREAD_LIB}
)
include_directories(.)
diff --git a/lib/ReaderWriter/MachO/CompactUnwindPass.cpp b/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
index 4b8644a67e70..6f5ab83dbda6 100644
--- a/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
+++ b/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
@@ -59,7 +59,7 @@ struct CompactUnwindEntry {
};
struct UnwindInfoPage {
- std::vector<CompactUnwindEntry> entries;
+ ArrayRef<CompactUnwindEntry> entries;
};
}
@@ -88,6 +88,8 @@ public:
addSecondLevelPages(pages);
}
+ ~UnwindInfoAtom() override = default;
+
ContentType contentType() const override {
return DefinedAtom::typeProcessedUnwindInfo;
}
@@ -179,7 +181,7 @@ public:
}
// Finally, write out the final sentinel index
- CompactUnwindEntry &finalEntry = pages[pages.size() - 1].entries.back();
+ auto &finalEntry = pages[pages.size() - 1].entries.back();
addImageReference(_topLevelIndexOffset +
3 * pages.size() * sizeof(uint32_t),
finalEntry.rangeStart, finalEntry.rangeLength);
@@ -273,11 +275,13 @@ class CompactUnwindPass : public Pass {
public:
CompactUnwindPass(const MachOLinkingContext &context)
: _ctx(context), _archHandler(_ctx.archHandler()),
- _file("<mach-o Compact Unwind Pass>"),
- _isBig(MachOLinkingContext::isBigEndian(_ctx.arch())) {}
+ _file(*_ctx.make_file<MachOFile>("<mach-o Compact Unwind Pass>")),
+ _isBig(MachOLinkingContext::isBigEndian(_ctx.arch())) {
+ _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ }
private:
- std::error_code perform(SimpleFile &mergedFile) override {
+ llvm::Error perform(SimpleFile &mergedFile) override {
DEBUG(llvm::dbgs() << "MachO Compact Unwind pass\n");
std::map<const Atom *, CompactUnwindEntry> unwindLocs;
@@ -294,7 +298,7 @@ private:
// Skip rest of pass if no unwind info.
if (unwindLocs.empty() && dwarfFrames.empty())
- return std::error_code();
+ return llvm::Error();
// FIXME: if there are more than 4 personality functions then we need to
// defer to DWARF info for the ones we don't put in the list. They should
@@ -321,26 +325,23 @@ private:
// boundaries. That might be worth doing, or perhaps we could perform some
// minor balancing for expected number of lookups.
std::vector<UnwindInfoPage> pages;
- unsigned pageStart = 0;
+ auto remainingInfos = llvm::makeArrayRef(unwindInfos);
do {
pages.push_back(UnwindInfoPage());
// FIXME: we only create regular pages at the moment. These can hold up to
// 1021 entries according to the documentation.
- unsigned entriesInPage =
- std::min(1021U, (unsigned)unwindInfos.size() - pageStart);
+ unsigned entriesInPage = std::min(1021U, (unsigned)remainingInfos.size());
- std::copy(unwindInfos.begin() + pageStart,
- unwindInfos.begin() + pageStart + entriesInPage,
- std::back_inserter(pages.back().entries));
- pageStart += entriesInPage;
+ pages.back().entries = remainingInfos.slice(0, entriesInPage);
+ remainingInfos = remainingInfos.slice(entriesInPage);
DEBUG(llvm::dbgs()
<< " Page from " << pages.back().entries[0].rangeStart->name()
<< " to " << pages.back().entries.back().rangeStart->name() << " + "
<< llvm::format("0x%x", pages.back().entries.back().rangeLength)
<< " has " << entriesInPage << " entries\n");
- } while (pageStart < unwindInfos.size());
+ } while (!remainingInfos.empty());
auto *unwind = new (_file.allocator())
UnwindInfoAtom(_archHandler, _file, _isBig, personalities,
@@ -352,7 +353,7 @@ private:
return atom->contentType() == DefinedAtom::typeCompactUnwindInfo;
});
- return std::error_code();
+ return llvm::Error();
}
void collectCompactUnwindEntries(
@@ -568,7 +569,7 @@ private:
const MachOLinkingContext &_ctx;
mach_o::ArchHandler &_archHandler;
- MachOFile _file;
+ MachOFile &_file;
bool _isBig;
};
diff --git a/lib/ReaderWriter/MachO/ExecutableAtoms.h b/lib/ReaderWriter/MachO/ExecutableAtoms.h
index 2e99af903dbd..acced33b7e74 100644
--- a/lib/ReaderWriter/MachO/ExecutableAtoms.h
+++ b/lib/ReaderWriter/MachO/ExecutableAtoms.h
@@ -11,10 +11,10 @@
#define LLD_READER_WRITER_MACHO_EXECUTABLE_ATOMS_H
#include "Atoms.h"
+#include "File.h"
#include "llvm/Support/MachO.h"
-#include "lld/Core/ArchiveLibraryFile.h"
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/File.h"
#include "lld/Core/LinkingContext.h"
@@ -34,7 +34,7 @@ namespace mach_o {
class CEntryFile : public SimpleFile {
public:
CEntryFile(const MachOLinkingContext &context)
- : SimpleFile("C entry"),
+ : SimpleFile("C entry", kindCEntryObject),
_undefMain(*this, context.entrySymbolName()) {
this->addAtom(_undefMain);
}
@@ -51,7 +51,7 @@ private:
class StubHelperFile : public SimpleFile {
public:
StubHelperFile(const MachOLinkingContext &context)
- : SimpleFile("stub runtime"),
+ : SimpleFile("stub runtime", kindStubHelperObject),
_undefBinder(*this, context.binderSymbolName()) {
this->addAtom(_undefBinder);
}
@@ -65,66 +65,88 @@ private:
// MachHeaderAliasFile lazily instantiates the magic symbols that mark the start
// of the mach_header for final linked images.
//
-class MachHeaderAliasFile : public ArchiveLibraryFile {
+class MachHeaderAliasFile : public SimpleFile {
public:
MachHeaderAliasFile(const MachOLinkingContext &context)
- : ArchiveLibraryFile("mach_header symbols") {
- switch (context.outputMachOType()) {
- case llvm::MachO::MH_EXECUTE:
- _machHeaderSymbolName = "__mh_execute_header";
- break;
- case llvm::MachO::MH_DYLIB:
- _machHeaderSymbolName = "__mh_dylib_header";
- break;
- case llvm::MachO::MH_BUNDLE:
- _machHeaderSymbolName = "__mh_bundle_header";
- break;
- case llvm::MachO::MH_DYLINKER:
- _machHeaderSymbolName = "__mh_dylinker_header";
- break;
- case llvm::MachO::MH_PRELOAD:
- _machHeaderSymbolName = "__mh_preload_header";
- break;
- default:
- llvm_unreachable("no mach_header symbol for file type");
- }
- }
-
- std::error_code
- parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
- return std::error_code();
- }
-
- File *find(StringRef sym, bool dataSymbolOnly) override {
- if (sym.equals("___dso_handle") || sym.equals(_machHeaderSymbolName)) {
+ : SimpleFile("mach_header symbols", kindHeaderObject) {
+ StringRef machHeaderSymbolName;
+ DefinedAtom::Scope symbolScope = DefinedAtom::scopeLinkageUnit;
+ StringRef dsoHandleName;
+ switch (context.outputMachOType()) {
+ case llvm::MachO::MH_OBJECT:
+ machHeaderSymbolName = "__mh_object_header";
+ break;
+ case llvm::MachO::MH_EXECUTE:
+ machHeaderSymbolName = "__mh_execute_header";
+ symbolScope = DefinedAtom::scopeGlobal;
+ dsoHandleName = "___dso_handle";
+ break;
+ case llvm::MachO::MH_FVMLIB:
+ llvm_unreachable("no mach_header symbol for file type");
+ case llvm::MachO::MH_CORE:
+ llvm_unreachable("no mach_header symbol for file type");
+ case llvm::MachO::MH_PRELOAD:
+ llvm_unreachable("no mach_header symbol for file type");
+ case llvm::MachO::MH_DYLIB:
+ machHeaderSymbolName = "__mh_dylib_header";
+ dsoHandleName = "___dso_handle";
+ break;
+ case llvm::MachO::MH_DYLINKER:
+ machHeaderSymbolName = "__mh_dylinker_header";
+ dsoHandleName = "___dso_handle";
+ break;
+ case llvm::MachO::MH_BUNDLE:
+ machHeaderSymbolName = "__mh_bundle_header";
+ dsoHandleName = "___dso_handle";
+ break;
+ case llvm::MachO::MH_DYLIB_STUB:
+ llvm_unreachable("no mach_header symbol for file type");
+ case llvm::MachO::MH_DSYM:
+ llvm_unreachable("no mach_header symbol for file type");
+ case llvm::MachO::MH_KEXT_BUNDLE:
+ dsoHandleName = "___dso_handle";
+ break;
+ }
+ if (!machHeaderSymbolName.empty())
_definedAtoms.push_back(new (allocator()) MachODefinedAtom(
- *this, sym, DefinedAtom::scopeLinkageUnit,
- DefinedAtom::typeMachHeader, DefinedAtom::mergeNo, false, false,
+ *this, machHeaderSymbolName, symbolScope,
+ DefinedAtom::typeMachHeader, DefinedAtom::mergeNo, false,
+ true /* noDeadStrip */,
ArrayRef<uint8_t>(), DefinedAtom::Alignment(4096)));
- return this;
- }
- return nullptr;
+
+ if (!dsoHandleName.empty())
+ _definedAtoms.push_back(new (allocator()) MachODefinedAtom(
+ *this, dsoHandleName, DefinedAtom::scopeLinkageUnit,
+ DefinedAtom::typeDSOHandle, DefinedAtom::mergeNo, false,
+ true /* noDeadStrip */,
+ ArrayRef<uint8_t>(), DefinedAtom::Alignment(1)));
}
- const AtomVector<DefinedAtom> &defined() const override {
+ const AtomRange<DefinedAtom> defined() const override {
return _definedAtoms;
}
- const AtomVector<UndefinedAtom> &undefined() const override {
+ const AtomRange<UndefinedAtom> undefined() const override {
return _noUndefinedAtoms;
}
- const AtomVector<SharedLibraryAtom> &sharedLibrary() const override {
+ const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
return _noSharedLibraryAtoms;
}
- const AtomVector<AbsoluteAtom> &absolute() const override {
+ const AtomRange<AbsoluteAtom> absolute() const override {
return _noAbsoluteAtoms;
}
+ void clearAtoms() override {
+ _definedAtoms.clear();
+ _noUndefinedAtoms.clear();
+ _noSharedLibraryAtoms.clear();
+ _noAbsoluteAtoms.clear();
+ }
+
private:
mutable AtomVector<DefinedAtom> _definedAtoms;
- StringRef _machHeaderSymbolName;
};
} // namespace mach_o
diff --git a/lib/ReaderWriter/MachO/File.h b/lib/ReaderWriter/MachO/File.h
index c97dfa142b8d..64a0fcf82844 100644
--- a/lib/ReaderWriter/MachO/File.h
+++ b/lib/ReaderWriter/MachO/File.h
@@ -14,6 +14,7 @@
#include "MachONormalizedFile.h"
#include "lld/Core/SharedLibraryFile.h"
#include "lld/Core/Simple.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
#include <unordered_map>
@@ -25,9 +26,10 @@ using lld::mach_o::normalized::Section;
class MachOFile : public SimpleFile {
public:
MachOFile(std::unique_ptr<MemoryBuffer> mb, MachOLinkingContext *ctx)
- : SimpleFile(mb->getBufferIdentifier()), _mb(std::move(mb)), _ctx(ctx) {}
+ : SimpleFile(mb->getBufferIdentifier(), File::kindMachObject),
+ _mb(std::move(mb)), _ctx(ctx) {}
- MachOFile(StringRef path) : SimpleFile(path) {}
+ MachOFile(StringRef path) : SimpleFile(path, File::kindMachObject) {}
void addDefinedAtom(StringRef name, Atom::Scope scope,
DefinedAtom::ContentType type, DefinedAtom::Merge merge,
@@ -187,16 +189,51 @@ public:
visitor(offAndAtom.atom, offAndAtom.offset);
}
+ MachOLinkingContext::Arch arch() const { return _arch; }
+ void setArch(MachOLinkingContext::Arch arch) { _arch = arch; }
+
+ MachOLinkingContext::OS OS() const { return _os; }
+ void setOS(MachOLinkingContext::OS os) { _os = os; }
+
+ MachOLinkingContext::ObjCConstraint objcConstraint() const {
+ return _objcConstraint;
+ }
+ void setObjcConstraint(MachOLinkingContext::ObjCConstraint v) {
+ _objcConstraint = v;
+ }
+
+ uint32_t minVersion() const { return _minVersion; }
+ void setMinVersion(uint32_t v) { _minVersion = v; }
+
+ LoadCommandType minVersionLoadCommandKind() const {
+ return _minVersionLoadCommandKind;
+ }
+ void setMinVersionLoadCommandKind(LoadCommandType v) {
+ _minVersionLoadCommandKind = v;
+ }
+
+ uint32_t swiftVersion() const { return _swiftVersion; }
+ void setSwiftVersion(uint32_t v) { _swiftVersion = v; }
+
+ bool subsectionsViaSymbols() const {
+ return _flags & llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
+ }
+ void setFlags(normalized::FileFlags v) { _flags = v; }
+
+ /// Methods for support type inquiry through isa, cast, and dyn_cast:
+ static inline bool classof(const File *F) {
+ return F->kind() == File::kindMachObject;
+ }
+
protected:
std::error_code doParse() override {
// Convert binary file to normalized mach-o.
auto normFile = normalized::readBinary(_mb, _ctx->arch());
- if (std::error_code ec = normFile.getError())
- return ec;
+ if (auto ec = normFile.takeError())
+ return llvm::errorToErrorCode(std::move(ec));
// Convert normalized mach-o to atoms.
- if (std::error_code ec = normalized::normalizedObjectToAtoms(
- this, **normFile, false))
- return ec;
+ if (auto ec = normalized::normalizedObjectToAtoms(this, **normFile, false))
+ return llvm::errorToErrorCode(std::move(ec));
return std::error_code();
}
@@ -220,6 +257,14 @@ private:
MachOLinkingContext *_ctx;
SectionToAtoms _sectionAtoms;
NameToAtom _undefAtoms;
+ MachOLinkingContext::Arch _arch = MachOLinkingContext::arch_unknown;
+ MachOLinkingContext::OS _os = MachOLinkingContext::OS::unknown;
+ uint32_t _minVersion = 0;
+ LoadCommandType _minVersionLoadCommandKind = (LoadCommandType)0;
+ MachOLinkingContext::ObjCConstraint _objcConstraint =
+ MachOLinkingContext::objc_unknown;
+ uint32_t _swiftVersion = 0;
+ normalized::FileFlags _flags = llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
};
class MachODylibFile : public SharedLibraryFile {
@@ -230,7 +275,7 @@ public:
MachODylibFile(StringRef path) : SharedLibraryFile(path) {}
- const SharedLibraryAtom *exports(StringRef name, bool isData) const override {
+ OwningAtomPtr<SharedLibraryAtom> exports(StringRef name) const override {
// Pass down _installName so that if this requested symbol
// is re-exported through this dylib, the SharedLibraryAtom's loadName()
// is this dylib installName and not the implementation dylib's.
@@ -273,35 +318,39 @@ public:
std::error_code doParse() override {
// Convert binary file to normalized mach-o.
auto normFile = normalized::readBinary(_mb, _ctx->arch());
- if (std::error_code ec = normFile.getError())
- return ec;
+ if (auto ec = normFile.takeError())
+ return llvm::errorToErrorCode(std::move(ec));
// Convert normalized mach-o to atoms.
- if (std::error_code ec = normalized::normalizedDylibToAtoms(
- this, **normFile, false))
- return ec;
+ if (auto ec = normalized::normalizedDylibToAtoms(this, **normFile, false))
+ return llvm::errorToErrorCode(std::move(ec));
return std::error_code();
}
private:
- const SharedLibraryAtom *exports(StringRef name,
+ OwningAtomPtr<SharedLibraryAtom> exports(StringRef name,
StringRef installName) const {
// First, check if requested symbol is directly implemented by this dylib.
auto entry = _nameToAtom.find(name);
if (entry != _nameToAtom.end()) {
- if (!entry->second.atom) {
- // Lazily create SharedLibraryAtom.
- entry->second.atom =
- new (allocator()) MachOSharedLibraryAtom(*this, name, installName,
- entry->second.weakDef);
- }
- return entry->second.atom;
+ // FIXME: Make this map a set and only used in assert builds.
+ // Note, its safe to assert here as the resolver is the only client of
+ // this API and it only requests exports for undefined symbols.
+ // If we return from here we are no longer undefined so we should never
+ // get here again.
+ assert(!entry->second.atom && "Duplicate shared library export");
+ bool weakDef = entry->second.weakDef;
+ auto *atom = new (allocator()) MachOSharedLibraryAtom(*this, name,
+ installName,
+ weakDef);
+ entry->second.atom = atom;
+ return atom;
}
// Next, check if symbol is implemented in some re-exported dylib.
for (const ReExportedDylib &dylib : _reExportedDylibs) {
assert(dylib.file);
auto atom = dylib.file->exports(name, installName);
- if (atom)
+ if (atom.get())
return atom;
}
diff --git a/lib/ReaderWriter/MachO/FlatNamespaceFile.h b/lib/ReaderWriter/MachO/FlatNamespaceFile.h
index 6c6a9262ba2e..76d295841c9d 100644
--- a/lib/ReaderWriter/MachO/FlatNamespaceFile.h
+++ b/lib/ReaderWriter/MachO/FlatNamespaceFile.h
@@ -25,34 +25,34 @@ public:
FlatNamespaceFile(const MachOLinkingContext &context)
: SharedLibraryFile("flat namespace") { }
- const SharedLibraryAtom *exports(StringRef name,
- bool dataSymbolOnly) const override {
- _sharedLibraryAtoms.push_back(
- new (allocator()) MachOSharedLibraryAtom(*this, name, getDSOName(),
- false));
-
- return _sharedLibraryAtoms.back();
+ OwningAtomPtr<SharedLibraryAtom> exports(StringRef name) const override {
+ return new (allocator()) MachOSharedLibraryAtom(*this, name, getDSOName(),
+ false);
}
StringRef getDSOName() const override { return "flat-namespace"; }
- const AtomVector<DefinedAtom> &defined() const override {
+ const AtomRange<DefinedAtom> defined() const override {
return _noDefinedAtoms;
}
- const AtomVector<UndefinedAtom> &undefined() const override {
+ const AtomRange<UndefinedAtom> undefined() const override {
return _noUndefinedAtoms;
}
- const AtomVector<SharedLibraryAtom> &sharedLibrary() const override {
- return _sharedLibraryAtoms;
+ const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
+ return _noSharedLibraryAtoms;
}
- const AtomVector<AbsoluteAtom> &absolute() const override {
+ const AtomRange<AbsoluteAtom> absolute() const override {
return _noAbsoluteAtoms;
}
-private:
- mutable AtomVector<SharedLibraryAtom> _sharedLibraryAtoms;
+ void clearAtoms() override {
+ _noDefinedAtoms.clear();
+ _noUndefinedAtoms.clear();
+ _noSharedLibraryAtoms.clear();
+ _noAbsoluteAtoms.clear();
+ }
};
} // namespace mach_o
diff --git a/lib/ReaderWriter/MachO/GOTPass.cpp b/lib/ReaderWriter/MachO/GOTPass.cpp
index a5816277dd71..6cdca0a9e055 100644
--- a/lib/ReaderWriter/MachO/GOTPass.cpp
+++ b/lib/ReaderWriter/MachO/GOTPass.cpp
@@ -54,6 +54,8 @@ public:
GOTEntryAtom(const File &file, bool is64, StringRef name)
: SimpleDefinedAtom(file), _is64(is64), _name(name) { }
+ ~GOTEntryAtom() override = default;
+
ContentType contentType() const override {
return DefinedAtom::typeGOT;
}
@@ -91,10 +93,12 @@ class GOTPass : public Pass {
public:
GOTPass(const MachOLinkingContext &context)
: _ctx(context), _archHandler(_ctx.archHandler()),
- _file("<mach-o GOT Pass>") {}
+ _file(*_ctx.make_file<MachOFile>("<mach-o GOT Pass>")) {
+ _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ }
private:
- std::error_code perform(SimpleFile &mergedFile) override {
+ llvm::Error perform(SimpleFile &mergedFile) override {
// Scan all references in all atoms.
for (const DefinedAtom *atom : mergedFile.defined()) {
for (const Reference *ref : *atom) {
@@ -130,7 +134,7 @@ private:
for (const GOTEntryAtom *slot : entries)
mergedFile.addAtom(*slot);
- return std::error_code();
+ return llvm::Error();
}
bool shouldReplaceTargetWithGOTAtom(const Atom *target, bool canBypassGOT) {
@@ -167,7 +171,7 @@ private:
const MachOLinkingContext &_ctx;
mach_o::ArchHandler &_archHandler;
- MachOFile _file;
+ MachOFile &_file;
llvm::DenseMap<const Atom*, const GOTEntryAtom*> _targetToGOT;
};
diff --git a/lib/ReaderWriter/MachO/LayoutPass.cpp b/lib/ReaderWriter/MachO/LayoutPass.cpp
index 0c14ee9d39ab..dd2ee8567ec9 100644
--- a/lib/ReaderWriter/MachO/LayoutPass.cpp
+++ b/lib/ReaderWriter/MachO/LayoutPass.cpp
@@ -17,6 +17,7 @@
#include "llvm/Support/Debug.h"
#include <algorithm>
#include <set>
+#include <utility>
using namespace lld;
@@ -133,7 +134,7 @@ static void checkReachabilityFromRoot(AtomToAtomT &followOnRoots,
}
}
-static void printDefinedAtoms(const SimpleFile::DefinedAtomRange &atomRange) {
+static void printDefinedAtoms(const File::AtomRange<DefinedAtom> &atomRange) {
for (const DefinedAtom *atom : atomRange) {
llvm::dbgs() << " file=" << atom->file().path()
<< ", name=" << atom->name()
@@ -146,7 +147,7 @@ static void printDefinedAtoms(const SimpleFile::DefinedAtomRange &atomRange) {
/// Verify that the followon chain is sane. Should not be called in
/// release binary.
-void LayoutPass::checkFollowonChain(SimpleFile::DefinedAtomRange &range) {
+void LayoutPass::checkFollowonChain(const File::AtomRange<DefinedAtom> &range) {
ScopedTask task(getDefaultDomain(), "LayoutPass::checkFollowonChain");
// Verify that there's no cycle in follow-on chain.
@@ -176,8 +177,8 @@ static bool compareAtomsSub(const LayoutPass::SortKey &lc,
const LayoutPass::SortKey &rc,
LayoutPass::SortOverride customSorter,
std::string &reason) {
- const DefinedAtom *left = lc._atom;
- const DefinedAtom *right = rc._atom;
+ const DefinedAtom *left = lc._atom.get();
+ const DefinedAtom *right = rc._atom.get();
if (left == right) {
reason = "same";
return false;
@@ -252,14 +253,15 @@ static bool compareAtoms(const LayoutPass::SortKey &lc,
bool result = compareAtomsSub(lc, rc, customSorter, reason);
DEBUG({
StringRef comp = result ? "<" : ">=";
- llvm::dbgs() << "Layout: '" << lc._atom->name() << "' " << comp << " '"
- << rc._atom->name() << "' (" << reason << ")\n";
+ llvm::dbgs() << "Layout: '" << lc._atom.get()->name()
+ << "' " << comp << " '"
+ << rc._atom.get()->name() << "' (" << reason << ")\n";
});
return result;
}
LayoutPass::LayoutPass(const Registry &registry, SortOverride sorter)
- : _registry(registry), _customSorter(sorter) {}
+ : _registry(registry), _customSorter(std::move(sorter)) {}
// Returns the atom immediately followed by the given atom in the followon
// chain.
@@ -329,12 +331,12 @@ void LayoutPass::setChainRoot(const DefinedAtom *targetAtom,
/// d) If the targetAtom is part of a different chain and the root of the
/// targetAtom until the targetAtom has all atoms of size 0, then chain the
/// targetAtoms and its tree to the current chain
-void LayoutPass::buildFollowOnTable(SimpleFile::DefinedAtomRange &range) {
+void LayoutPass::buildFollowOnTable(const File::AtomRange<DefinedAtom> &range) {
ScopedTask task(getDefaultDomain(), "LayoutPass::buildFollowOnTable");
// Set the initial size of the followon and the followonNext hash to the
// number of atoms that we have.
- _followOnRoots.resize(range.size());
- _followOnNexts.resize(range.size());
+ _followOnRoots.reserve(range.size());
+ _followOnNexts.reserve(range.size());
for (const DefinedAtom *ai : range) {
for (const Reference *r : *ai) {
if (r->kindNamespace() != lld::Reference::KindNamespace::all ||
@@ -397,7 +399,8 @@ void LayoutPass::buildFollowOnTable(SimpleFile::DefinedAtomRange &range) {
/// assigning ordinals to each atom, if the atoms have their ordinals
/// already assigned skip the atom and move to the next. This is the
/// main map thats used to sort the atoms while comparing two atoms together
-void LayoutPass::buildOrdinalOverrideMap(SimpleFile::DefinedAtomRange &range) {
+void
+LayoutPass::buildOrdinalOverrideMap(const File::AtomRange<DefinedAtom> &range) {
ScopedTask task(getDefaultDomain(), "LayoutPass::buildOrdinalOverrideMap");
uint64_t index = 0;
for (const DefinedAtom *ai : range) {
@@ -417,31 +420,31 @@ void LayoutPass::buildOrdinalOverrideMap(SimpleFile::DefinedAtomRange &range) {
}
std::vector<LayoutPass::SortKey>
-LayoutPass::decorate(SimpleFile::DefinedAtomRange &atomRange) const {
+LayoutPass::decorate(File::AtomRange<DefinedAtom> &atomRange) const {
std::vector<SortKey> ret;
- for (const DefinedAtom *atom : atomRange) {
- auto ri = _followOnRoots.find(atom);
- auto oi = _ordinalOverrideMap.find(atom);
- const DefinedAtom *root = (ri == _followOnRoots.end()) ? atom : ri->second;
+ for (OwningAtomPtr<DefinedAtom> &atom : atomRange.owning_ptrs()) {
+ auto ri = _followOnRoots.find(atom.get());
+ auto oi = _ordinalOverrideMap.find(atom.get());
+ const auto *root = (ri == _followOnRoots.end()) ? atom.get() : ri->second;
uint64_t override = (oi == _ordinalOverrideMap.end()) ? 0 : oi->second;
- ret.push_back(SortKey(atom, root, override));
+ ret.push_back(SortKey(std::move(atom), root, override));
}
return ret;
}
-void LayoutPass::undecorate(SimpleFile::DefinedAtomRange &atomRange,
+void LayoutPass::undecorate(File::AtomRange<DefinedAtom> &atomRange,
std::vector<SortKey> &keys) const {
size_t i = 0;
for (SortKey &k : keys)
- atomRange[i++] = k._atom;
+ atomRange[i++] = std::move(k._atom);
}
/// Perform the actual pass
-std::error_code LayoutPass::perform(SimpleFile &mergedFile) {
+llvm::Error LayoutPass::perform(SimpleFile &mergedFile) {
DEBUG(llvm::dbgs() << "******** Laying out atoms:\n");
// sort the atoms
ScopedTask task(getDefaultDomain(), "LayoutPass");
- SimpleFile::DefinedAtomRange atomRange = mergedFile.definedAtoms();
+ File::AtomRange<DefinedAtom> atomRange = mergedFile.defined();
// Build follow on tables
buildFollowOnTable(atomRange);
@@ -471,7 +474,7 @@ std::error_code LayoutPass::perform(SimpleFile &mergedFile) {
});
DEBUG(llvm::dbgs() << "******** Finished laying out atoms\n");
- return std::error_code();
+ return llvm::Error();
}
void addLayoutPass(PassManager &pm, const MachOLinkingContext &ctx) {
diff --git a/lib/ReaderWriter/MachO/LayoutPass.h b/lib/ReaderWriter/MachO/LayoutPass.h
index d6072b0ca4fb..c18777eded0a 100644
--- a/lib/ReaderWriter/MachO/LayoutPass.h
+++ b/lib/ReaderWriter/MachO/LayoutPass.h
@@ -33,11 +33,31 @@ namespace mach_o {
class LayoutPass : public Pass {
public:
struct SortKey {
- SortKey(const DefinedAtom *atom, const DefinedAtom *root, uint64_t override)
- : _atom(atom), _root(root), _override(override) {}
- const DefinedAtom *_atom;
+ SortKey(OwningAtomPtr<DefinedAtom> &&atom,
+ const DefinedAtom *root, uint64_t override)
+ : _atom(std::move(atom)), _root(root), _override(override) {}
+ OwningAtomPtr<DefinedAtom> _atom;
const DefinedAtom *_root;
uint64_t _override;
+
+ // Note, these are only here to appease MSVC bots which didn't like
+ // the same methods being implemented/deleted in OwningAtomPtr.
+ SortKey(SortKey &&key) : _atom(std::move(key._atom)), _root(key._root),
+ _override(key._override) {
+ key._root = nullptr;
+ }
+
+ SortKey &operator=(SortKey &&key) {
+ _atom = std::move(key._atom);
+ _root = key._root;
+ key._root = nullptr;
+ _override = key._override;
+ return *this;
+ }
+
+ private:
+ SortKey(const SortKey &) = delete;
+ void operator=(const SortKey&) = delete;
};
typedef std::function<bool (const DefinedAtom *left, const DefinedAtom *right,
@@ -46,17 +66,17 @@ public:
LayoutPass(const Registry &registry, SortOverride sorter);
/// Sorts atoms in mergedFile by content type then by command line order.
- std::error_code perform(SimpleFile &mergedFile) override;
+ llvm::Error perform(SimpleFile &mergedFile) override;
~LayoutPass() override = default;
private:
// Build the followOn atoms chain as specified by the kindLayoutAfter
// reference type
- void buildFollowOnTable(SimpleFile::DefinedAtomRange &range);
+ void buildFollowOnTable(const File::AtomRange<DefinedAtom> &range);
// Build a map of Atoms to ordinals for sorting the atoms
- void buildOrdinalOverrideMap(SimpleFile::DefinedAtomRange &range);
+ void buildOrdinalOverrideMap(const File::AtomRange<DefinedAtom> &range);
const Registry &_registry;
SortOverride _customSorter;
@@ -84,12 +104,13 @@ private:
void setChainRoot(const DefinedAtom *targetAtom, const DefinedAtom *root);
- std::vector<SortKey> decorate(SimpleFile::DefinedAtomRange &atomRange) const;
- void undecorate(SimpleFile::DefinedAtomRange &atomRange,
+ std::vector<SortKey> decorate(File::AtomRange<DefinedAtom> &atomRange) const;
+
+ void undecorate(File::AtomRange<DefinedAtom> &atomRange,
std::vector<SortKey> &keys) const;
// Check if the follow-on graph is a correct structure. For debugging only.
- void checkFollowonChain(SimpleFile::DefinedAtomRange &range);
+ void checkFollowonChain(const File::AtomRange<DefinedAtom> &range);
};
} // namespace mach_o
diff --git a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
index 1c97c5a39d3f..05375f145d34 100644
--- a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
+++ b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
@@ -35,6 +35,7 @@
#endif
using lld::mach_o::ArchHandler;
+using lld::mach_o::MachOFile;
using lld::mach_o::MachODylibFile;
using namespace llvm::MachO;
@@ -75,6 +76,35 @@ bool MachOLinkingContext::parsePackedVersion(StringRef str, uint32_t &result) {
return false;
}
+bool MachOLinkingContext::parsePackedVersion(StringRef str, uint64_t &result) {
+ result = 0;
+
+ if (str.empty())
+ return false;
+
+ SmallVector<StringRef, 5> parts;
+ llvm::SplitString(str, parts, ".");
+
+ unsigned long long num;
+ if (llvm::getAsUnsignedInteger(parts[0], 10, num))
+ return true;
+ if (num > 0xFFFFFF)
+ return true;
+ result = num << 40;
+
+ unsigned Shift = 30;
+ for (StringRef str : llvm::makeArrayRef(parts).slice(1)) {
+ if (llvm::getAsUnsignedInteger(str, 10, num))
+ return true;
+ if (num > 0x3FF)
+ return true;
+ result |= (num << Shift);
+ Shift -= 10;
+ }
+
+ return false;
+}
+
MachOLinkingContext::ArchInfo MachOLinkingContext::_s_archInfos[] = {
{ "x86_64", arch_x86_64, true, CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL },
{ "i386", arch_x86, true, CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL },
@@ -139,44 +169,52 @@ bool MachOLinkingContext::sliceFromFatFile(MemoryBufferRef mb, uint32_t &offset,
return mach_o::normalized::sliceFromFatFile(mb, _arch, offset, size);
}
-MachOLinkingContext::MachOLinkingContext()
- : _outputMachOType(MH_EXECUTE), _outputMachOTypeStatic(false),
- _doNothing(false), _pie(false), _arch(arch_unknown), _os(OS::macOSX),
- _osMinVersion(0), _pageZeroSize(0), _pageSize(4096), _baseAddress(0),
- _stackSize(0), _compatibilityVersion(0), _currentVersion(0),
- _flatNamespace(false), _undefinedMode(UndefinedMode::error),
- _deadStrippableDylib(false), _printAtoms(false), _testingFileUsage(false),
- _keepPrivateExterns(false), _demangle(false), _archHandler(nullptr),
- _exportMode(ExportMode::globals),
- _debugInfoMode(DebugInfoMode::addDebugMap), _orderFileEntries(0),
- _flatNamespaceFile(nullptr) {}
-
-MachOLinkingContext::~MachOLinkingContext() {}
+MachOLinkingContext::MachOLinkingContext() {}
+
+MachOLinkingContext::~MachOLinkingContext() {
+ // Atoms are allocated on BumpPtrAllocator's on File's.
+ // As we transfer atoms from one file to another, we need to clear all of the
+ // atoms before we remove any of the BumpPtrAllocator's.
+ auto &nodes = getNodes();
+ for (unsigned i = 0, e = nodes.size(); i != e; ++i) {
+ FileNode *node = dyn_cast<FileNode>(nodes[i].get());
+ if (!node)
+ continue;
+ File *file = node->getFile();
+ file->clearAtoms();
+ }
+}
void MachOLinkingContext::configure(HeaderFileType type, Arch arch, OS os,
- uint32_t minOSVersion) {
+ uint32_t minOSVersion,
+ bool exportDynamicSymbols) {
_outputMachOType = type;
_arch = arch;
_os = os;
_osMinVersion = minOSVersion;
// If min OS not specified on command line, use reasonable defaults.
- if (minOSVersion == 0) {
- switch (_arch) {
- case arch_x86_64:
- case arch_x86:
- parsePackedVersion("10.8", _osMinVersion);
- _os = MachOLinkingContext::OS::macOSX;
- break;
- case arch_armv6:
- case arch_armv7:
- case arch_armv7s:
- case arch_arm64:
- parsePackedVersion("7.0", _osMinVersion);
- _os = MachOLinkingContext::OS::iOS;
- break;
- default:
- break;
+ // Note that we only do sensible defaults when emitting something other than
+ // object and preload.
+ if (_outputMachOType != llvm::MachO::MH_OBJECT &&
+ _outputMachOType != llvm::MachO::MH_PRELOAD) {
+ if (minOSVersion == 0) {
+ switch (_arch) {
+ case arch_x86_64:
+ case arch_x86:
+ parsePackedVersion("10.8", _osMinVersion);
+ _os = MachOLinkingContext::OS::macOSX;
+ break;
+ case arch_armv6:
+ case arch_armv7:
+ case arch_armv7s:
+ case arch_arm64:
+ parsePackedVersion("7.0", _osMinVersion);
+ _os = MachOLinkingContext::OS::iOS;
+ break;
+ default:
+ break;
+ }
}
}
@@ -217,9 +255,10 @@ void MachOLinkingContext::configure(HeaderFileType type, Arch arch, OS os,
case OS::unknown:
break;
}
+ setGlobalsAreDeadStripRoots(exportDynamicSymbols);
break;
case llvm::MachO::MH_DYLIB:
- setGlobalsAreDeadStripRoots(true);
+ setGlobalsAreDeadStripRoots(exportDynamicSymbols);
break;
case llvm::MachO::MH_BUNDLE:
break;
@@ -325,6 +364,11 @@ bool MachOLinkingContext::needsCompactUnwindPass() const {
}
}
+bool MachOLinkingContext::needsObjCPass() const {
+ // ObjC pass is only needed if any of the inputs were ObjC.
+ return _objcConstraint != objc_unknown;
+}
+
bool MachOLinkingContext::needsShimPass() const {
// Shim pass only used in final executables.
if (_outputMachOType == MH_OBJECT)
@@ -368,9 +412,11 @@ bool MachOLinkingContext::minOS(StringRef mac, StringRef iOS) const {
return false;
return _osMinVersion >= parsedVersion;
case OS::unknown:
- break;
+ // If we don't know the target, then assume that we don't meet the min OS.
+ // This matches the ld64 behaviour
+ return false;
}
- llvm_unreachable("target not configured for iOS or MacOSX");
+ llvm_unreachable("invalid OS enum");
}
bool MachOLinkingContext::addEntryPointLoadCommand() const {
@@ -484,7 +530,7 @@ void MachOLinkingContext::addFrameworkSearchDir(StringRef fwPath,
_frameworkDirs.push_back(fwPath);
}
-ErrorOr<StringRef>
+llvm::Optional<StringRef>
MachOLinkingContext::searchDirForLibrary(StringRef path,
StringRef libName) const {
SmallString<256> fullPath;
@@ -494,7 +540,7 @@ MachOLinkingContext::searchDirForLibrary(StringRef path,
llvm::sys::path::append(fullPath, libName);
if (fileExists(fullPath))
return fullPath.str().copy(_allocator);
- return make_error_code(llvm::errc::no_such_file_or_directory);
+ return llvm::None;
}
// Search for dynamic library
@@ -509,21 +555,23 @@ MachOLinkingContext::searchDirForLibrary(StringRef path,
if (fileExists(fullPath))
return fullPath.str().copy(_allocator);
- return make_error_code(llvm::errc::no_such_file_or_directory);
+ return llvm::None;
}
-ErrorOr<StringRef> MachOLinkingContext::searchLibrary(StringRef libName) const {
+llvm::Optional<StringRef>
+MachOLinkingContext::searchLibrary(StringRef libName) const {
SmallString<256> path;
for (StringRef dir : searchDirs()) {
- ErrorOr<StringRef> ec = searchDirForLibrary(dir, libName);
- if (ec)
- return ec;
+ llvm::Optional<StringRef> searchDir = searchDirForLibrary(dir, libName);
+ if (searchDir)
+ return searchDir;
}
- return make_error_code(llvm::errc::no_such_file_or_directory);
+ return llvm::None;
}
-ErrorOr<StringRef> MachOLinkingContext::findPathForFramework(StringRef fwName) const{
+llvm::Optional<StringRef>
+MachOLinkingContext::findPathForFramework(StringRef fwName) const{
SmallString<256> fullPath;
for (StringRef dir : frameworkDirs()) {
fullPath.assign(dir);
@@ -532,7 +580,7 @@ ErrorOr<StringRef> MachOLinkingContext::findPathForFramework(StringRef fwName) c
return fullPath.str().copy(_allocator);
}
- return make_error_code(llvm::errc::no_such_file_or_directory);
+ return llvm::None;
}
bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) {
@@ -589,6 +637,10 @@ bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) {
}
void MachOLinkingContext::addPasses(PassManager &pm) {
+ // objc pass should be before layout pass. Otherwise test cases may contain
+ // no atoms which confuses the layout pass.
+ if (needsObjCPass())
+ mach_o::addObjCPass(pm, *this);
mach_o::addLayoutPass(pm, *this);
if (needsStubsPass())
mach_o::addStubsPass(pm, *this);
@@ -656,9 +708,8 @@ MachODylibFile* MachOLinkingContext::findIndirectDylib(StringRef path) {
if (leafName.startswith("lib") && leafName.endswith(".dylib")) {
// FIXME: Need to enhance searchLibrary() to only look for .dylib
auto libPath = searchLibrary(leafName);
- if (!libPath.getError()) {
- return loadIndirectDylib(libPath.get());
- }
+ if (libPath)
+ return loadIndirectDylib(libPath.getValue());
}
// Try full path with sysroot.
@@ -990,4 +1041,77 @@ void MachOLinkingContext::finalizeInputFiles() {
elements.push_back(llvm::make_unique<GroupEnd>(numLibs));
}
+llvm::Error MachOLinkingContext::handleLoadedFile(File &file) {
+ auto *machoFile = dyn_cast<MachOFile>(&file);
+ if (!machoFile)
+ return llvm::Error();
+
+ // Check that the arch of the context matches that of the file.
+ // Also set the arch of the context if it didn't have one.
+ if (_arch == arch_unknown) {
+ _arch = machoFile->arch();
+ } else if (machoFile->arch() != arch_unknown && machoFile->arch() != _arch) {
+ // Archs are different.
+ return llvm::make_error<GenericError>(file.path() +
+ Twine(" cannot be linked due to incompatible architecture"));
+ }
+
+ // Check that the OS of the context matches that of the file.
+ // Also set the OS of the context if it didn't have one.
+ if (_os == OS::unknown) {
+ _os = machoFile->OS();
+ } else if (machoFile->OS() != OS::unknown && machoFile->OS() != _os) {
+ // OSes are different.
+ return llvm::make_error<GenericError>(file.path() +
+ Twine(" cannot be linked due to incompatible operating systems"));
+ }
+
+ // Check that if the objc info exists, that it is compatible with the target
+ // OS.
+ switch (machoFile->objcConstraint()) {
+ case objc_unknown:
+ // The file is not compiled with objc, so skip the checks.
+ break;
+ case objc_gc_only:
+ case objc_supports_gc:
+ llvm_unreachable("GC support should already have thrown an error");
+ case objc_retainReleaseForSimulator:
+ // The file is built with simulator objc, so make sure that the context
+ // is also building with simulator support.
+ if (_os != OS::iOS_simulator)
+ return llvm::make_error<GenericError>(file.path() +
+ Twine(" cannot be linked. It contains ObjC built for the simulator"
+ " while we are linking a non-simulator target"));
+ assert((_objcConstraint == objc_unknown ||
+ _objcConstraint == objc_retainReleaseForSimulator) &&
+ "Must be linking with retain/release for the simulator");
+ _objcConstraint = objc_retainReleaseForSimulator;
+ break;
+ case objc_retainRelease:
+ // The file is built without simulator objc, so make sure that the
+ // context is also building without simulator support.
+ if (_os == OS::iOS_simulator)
+ return llvm::make_error<GenericError>(file.path() +
+ Twine(" cannot be linked. It contains ObjC built for a non-simulator"
+ " target while we are linking a simulator target"));
+ assert((_objcConstraint == objc_unknown ||
+ _objcConstraint == objc_retainRelease) &&
+ "Must be linking with retain/release for a non-simulator target");
+ _objcConstraint = objc_retainRelease;
+ break;
+ }
+
+ // Check that the swift version of the context matches that of the file.
+ // Also set the swift version of the context if it didn't have one.
+ if (!_swiftVersion) {
+ _swiftVersion = machoFile->swiftVersion();
+ } else if (machoFile->swiftVersion() &&
+ machoFile->swiftVersion() != _swiftVersion) {
+ // Swift versions are different.
+ return llvm::make_error<GenericError>("different swift versions");
+ }
+
+ return llvm::Error();
+}
+
} // end namespace lld
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFile.h b/lib/ReaderWriter/MachO/MachONormalizedFile.h
index cccf180f1043..92a21f7ef83d 100644
--- a/lib/ReaderWriter/MachO/MachONormalizedFile.h
+++ b/lib/ReaderWriter/MachO/MachONormalizedFile.h
@@ -39,6 +39,9 @@
/// +-------+
///
+#ifndef LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H
+#define LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H
+
#include "lld/Core/Error.h"
#include "lld/Core/LLVM.h"
#include "lld/ReaderWriter/MachOLinkingContext.h"
@@ -50,9 +53,6 @@
#include "llvm/Support/MachO.h"
#include "llvm/Support/YAMLTraits.h"
-#ifndef LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H
-#define LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H
-
using llvm::BumpPtrAllocator;
using llvm::yaml::Hex64;
using llvm::yaml::Hex32;
@@ -105,6 +105,9 @@ typedef std::vector<uint32_t> IndirectSymbols;
/// A typedef so that YAML I/O can encode/decode section attributes.
LLVM_YAML_STRONG_TYPEDEF(uint32_t, SectionAttr)
+/// A typedef so that YAML I/O can encode/decode section alignment.
+LLVM_YAML_STRONG_TYPEDEF(uint16_t, SectionAlignment)
+
/// Mach-O has a 32-bit and 64-bit section record. This normalized form
/// can support either kind.
struct Section {
@@ -115,7 +118,7 @@ struct Section {
StringRef sectionName;
SectionType type;
SectionAttr attributes;
- uint16_t alignment;
+ SectionAlignment alignment;
Hex64 address;
ArrayRef<uint8_t> content;
Relocations relocations;
@@ -172,7 +175,8 @@ struct Segment {
StringRef name;
Hex64 address;
Hex64 size;
- VMProtect access;
+ VMProtect init_access;
+ VMProtect max_access;
};
/// Only used in normalized final linked images to specify on which dylibs
@@ -245,6 +249,8 @@ struct NormalizedFile {
PackedVersion compatVersion = 0; // dylibs only
PackedVersion currentVersion = 0; // dylibs only
bool hasUUID = false;
+ bool hasMinVersionLoadCommand = false;
+ bool generateDataInCodeLoadCommand = false;
std::vector<StringRef> rpaths;
Hex64 entryAddress = 0;
Hex64 stackSize = 0;
@@ -252,6 +258,7 @@ struct NormalizedFile {
Hex64 sourceVersion = 0;
PackedVersion minOSverson = 0;
PackedVersion sdkVersion = 0;
+ LoadCommandType minOSVersionKind = (LoadCommandType)0;
// Maps to load commands with LINKEDIT content (final linked images only).
Hex32 pageSize = 0;
@@ -260,6 +267,7 @@ struct NormalizedFile {
std::vector<BindLocation> weakBindingInfo;
std::vector<BindLocation> lazyBindingInfo;
std::vector<Export> exportInfo;
+ std::vector<uint8_t> functionStarts;
std::vector<DataInCode> dataInCode;
// TODO:
@@ -281,40 +289,40 @@ bool sliceFromFatFile(MemoryBufferRef mb, MachOLinkingContext::Arch arch,
uint32_t &offset, uint32_t &size);
/// Reads a mach-o file and produces an in-memory normalized view.
-ErrorOr<std::unique_ptr<NormalizedFile>>
+llvm::Expected<std::unique_ptr<NormalizedFile>>
readBinary(std::unique_ptr<MemoryBuffer> &mb,
const MachOLinkingContext::Arch arch);
/// Takes in-memory normalized view and writes a mach-o object file.
-std::error_code writeBinary(const NormalizedFile &file, StringRef path);
+llvm::Error writeBinary(const NormalizedFile &file, StringRef path);
size_t headerAndLoadCommandsSize(const NormalizedFile &file);
/// Parses a yaml encoded mach-o file to produce an in-memory normalized view.
-ErrorOr<std::unique_ptr<NormalizedFile>>
+llvm::Expected<std::unique_ptr<NormalizedFile>>
readYaml(std::unique_ptr<MemoryBuffer> &mb);
/// Writes a yaml encoded mach-o files given an in-memory normalized view.
std::error_code writeYaml(const NormalizedFile &file, raw_ostream &out);
-std::error_code
+llvm::Error
normalizedObjectToAtoms(MachOFile *file,
const NormalizedFile &normalizedFile,
bool copyRefs);
-std::error_code
+llvm::Error
normalizedDylibToAtoms(MachODylibFile *file,
const NormalizedFile &normalizedFile,
bool copyRefs);
/// Takes in-memory normalized dylib or object and parses it into lld::File
-ErrorOr<std::unique_ptr<lld::File>>
+llvm::Expected<std::unique_ptr<lld::File>>
normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path,
bool copyRefs);
/// Takes atoms and generates a normalized macho-o view.
-ErrorOr<std::unique_ptr<NormalizedFile>>
+llvm::Expected<std::unique_ptr<NormalizedFile>>
normalizedFromAtoms(const lld::File &atomFile, const MachOLinkingContext &ctxt);
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
index 1013d3ddaef3..a17de5be1742 100644
--- a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
@@ -53,7 +53,7 @@ namespace mach_o {
namespace normalized {
// Utility to call a lambda expression on each load command.
-static std::error_code forEachLoadCommand(
+static llvm::Error forEachLoadCommand(
StringRef lcRange, unsigned lcCount, bool isBig, bool is64,
std::function<bool(uint32_t cmd, uint32_t size, const char *lc)> func) {
const char* p = lcRange.begin();
@@ -67,15 +67,15 @@ static std::error_code forEachLoadCommand(
slc = &lcCopy;
}
if ( (p + slc->cmdsize) > lcRange.end() )
- return make_error_code(llvm::errc::executable_format_error);
+ return llvm::make_error<GenericError>("Load command exceeds range");
if (func(slc->cmd, slc->cmdsize, p))
- return std::error_code();
+ return llvm::Error();
p += slc->cmdsize;
}
- return std::error_code();
+ return llvm::Error();
}
static std::error_code appendRelocations(Relocations &relocs, StringRef buffer,
@@ -199,7 +199,7 @@ bool sliceFromFatFile(MemoryBufferRef mb, MachOLinkingContext::Arch arch,
}
/// Reads a mach-o file and produces an in-memory normalized view.
-ErrorOr<std::unique_ptr<NormalizedFile>>
+llvm::Expected<std::unique_ptr<NormalizedFile>>
readBinary(std::unique_ptr<MemoryBuffer> &mb,
const MachOLinkingContext::Arch arch) {
// Make empty NormalizedFile.
@@ -220,7 +220,7 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
// Determine endianness and pointer size for mach-o file.
bool is64, isBig;
if (!isMachOHeader(mh, is64, isBig))
- return make_error_code(llvm::errc::executable_format_error);
+ return llvm::make_error<GenericError>("File is not a mach-o");
// Endian swap header, if needed.
mach_header headerCopy;
@@ -237,12 +237,13 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
start + (is64 ? sizeof(mach_header_64) : sizeof(mach_header));
StringRef lcRange(lcStart, smh->sizeofcmds);
if (lcRange.end() > (start + objSize))
- return make_error_code(llvm::errc::executable_format_error);
+ return llvm::make_error<GenericError>("Load commands exceed file size");
// Get architecture from mach_header.
f->arch = MachOLinkingContext::archFromCpuType(smh->cputype, smh->cpusubtype);
if (f->arch != arch) {
- return make_dynamic_error_code(Twine("file is wrong architecture. Expected "
+ return llvm::make_error<GenericError>(
+ Twine("file is wrong architecture. Expected "
"(" + MachOLinkingContext::nameFromArch(arch)
+ ") found ("
+ MachOLinkingContext::nameFromArch(f->arch)
@@ -256,9 +257,9 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
// Pre-scan load commands looking for indirect symbol table.
uint32_t indirectSymbolTableOffset = 0;
uint32_t indirectSymbolTableCount = 0;
- std::error_code ec = forEachLoadCommand(lcRange, lcCount, isBig, is64,
- [&](uint32_t cmd, uint32_t size,
- const char *lc) -> bool {
+ auto ec = forEachLoadCommand(lcRange, lcCount, isBig, is64,
+ [&](uint32_t cmd, uint32_t size,
+ const char *lc) -> bool {
if (cmd == LC_DYSYMTAB) {
const dysymtab_command *d = reinterpret_cast<const dysymtab_command*>(lc);
indirectSymbolTableOffset = read32(&d->indirectsymoff, isBig);
@@ -268,7 +269,7 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
return false;
});
if (ec)
- return ec;
+ return std::move(ec);
// Walk load commands looking for segments/sections and the symbol table.
const data_in_code_entry *dataInCode = nullptr;
@@ -380,11 +381,11 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
reinterpret_cast<const nlist_64 *>(start + symOffset);
// Convert each nlist_64 to a lld::mach_o::normalized::Symbol.
for(uint32_t i=0; i < symCount; ++i) {
- const nlist_64 *sin = &symbols[i];
nlist_64 tempSym;
- if (isBig != llvm::sys::IsBigEndianHost) {
- tempSym = *sin; swapStruct(tempSym); sin = &tempSym;
- }
+ memcpy(&tempSym, &symbols[i], sizeof(nlist_64));
+ const nlist_64 *sin = &tempSym;
+ if (isBig != llvm::sys::IsBigEndianHost)
+ swapStruct(tempSym);
Symbol sout;
if (sin->n_strx > strSize)
return true;
@@ -471,11 +472,20 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
case LC_DYLD_INFO_ONLY:
dyldInfo = reinterpret_cast<const dyld_info_command*>(lc);
break;
+ case LC_VERSION_MIN_MACOSX:
+ case LC_VERSION_MIN_IPHONEOS:
+ case LC_VERSION_MIN_WATCHOS:
+ case LC_VERSION_MIN_TVOS:
+ // If we are emitting an object file, then we may take the load command
+ // kind from these commands and pass it on to the output
+ // file.
+ f->minOSVersionKind = (LoadCommandType)cmd;
+ break;
}
return false;
});
if (ec)
- return ec;
+ return std::move(ec);
if (dataInCode) {
// Convert on-disk data_in_code_entry array to DataInCode vector.
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h
index 1226860b021e..86823efa33c9 100644
--- a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h
@@ -7,6 +7,8 @@
//
//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
+#define LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
#include "MachONormalizedFile.h"
#include "lld/Core/Error.h"
@@ -16,16 +18,54 @@
#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Host.h"
+#include "llvm/Support/LEB128.h"
#include "llvm/Support/MachO.h"
#include <system_error>
-#ifndef LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
-#define LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
-
namespace lld {
namespace mach_o {
namespace normalized {
+class ByteBuffer {
+public:
+ ByteBuffer() : _ostream(_bytes) { }
+
+ void append_byte(uint8_t b) {
+ _ostream << b;
+ }
+ void append_uleb128(uint64_t value) {
+ llvm::encodeULEB128(value, _ostream);
+ }
+ void append_uleb128Fixed(uint64_t value, unsigned byteCount) {
+ unsigned min = llvm::getULEB128Size(value);
+ assert(min <= byteCount);
+ unsigned pad = byteCount - min;
+ llvm::encodeULEB128(value, _ostream, pad);
+ }
+ void append_sleb128(int64_t value) {
+ llvm::encodeSLEB128(value, _ostream);
+ }
+ void append_string(StringRef str) {
+ _ostream << str;
+ append_byte(0);
+ }
+ void align(unsigned alignment) {
+ while ( (_ostream.tell() % alignment) != 0 )
+ append_byte(0);
+ }
+ size_t size() {
+ return _ostream.tell();
+ }
+ const uint8_t *bytes() {
+ return reinterpret_cast<const uint8_t*>(_ostream.str().data());
+ }
+
+private:
+ SmallVector<char, 128> _bytes;
+ // Stream ivar must be after SmallVector ivar to construct properly.
+ llvm::raw_svector_ostream _ostream;
+};
+
using namespace llvm::support::endian;
using llvm::sys::getSwappedBytes;
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
index 4ecfece0629e..f3e159684e15 100644
--- a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
@@ -25,6 +25,8 @@
#include "MachONormalizedFileBinaryUtils.h"
#include "lld/Core/Error.h"
#include "lld/Core/LLVM.h"
+#include "llvm/ADT/ilist.h"
+#include "llvm/ADT/ilist_node.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
@@ -35,7 +37,6 @@
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/Host.h"
-#include "llvm/Support/LEB128.h"
#include "llvm/Support/MachO.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
@@ -50,6 +51,72 @@ namespace lld {
namespace mach_o {
namespace normalized {
+struct TrieNode; // Forward declaration.
+
+struct TrieEdge : public llvm::ilist_node<TrieEdge> {
+ TrieEdge(StringRef s, TrieNode *node) : _subString(s), _child(node) {}
+
+ StringRef _subString;
+ struct TrieNode *_child;
+};
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
+
+
+namespace llvm {
+ using lld::mach_o::normalized::TrieEdge;
+ template <>
+ struct ilist_traits<TrieEdge>
+ : public ilist_default_traits<TrieEdge> {
+ private:
+ mutable ilist_half_node<TrieEdge> Sentinel;
+ public:
+ TrieEdge *createSentinel() const {
+ return static_cast<TrieEdge*>(&Sentinel);
+ }
+ void destroySentinel(TrieEdge *) const {}
+
+ TrieEdge *provideInitialHead() const { return createSentinel(); }
+ TrieEdge *ensureHead(TrieEdge*) const { return createSentinel(); }
+ static void noteHead(TrieEdge*, TrieEdge*) {}
+ void deleteNode(TrieEdge *N) {}
+
+ private:
+ void createNode(const TrieEdge &);
+ };
+} // namespace llvm
+
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+struct TrieNode {
+ typedef llvm::ilist<TrieEdge> TrieEdgeList;
+
+ TrieNode(StringRef s)
+ : _cummulativeString(s), _address(0), _flags(0), _other(0),
+ _trieOffset(0), _hasExportInfo(false) {}
+ ~TrieNode() = default;
+
+ void addSymbol(const Export &entry, BumpPtrAllocator &allocator,
+ std::vector<TrieNode *> &allNodes);
+ bool updateOffset(uint32_t &offset);
+ void appendToByteBuffer(ByteBuffer &out);
+
+private:
+ StringRef _cummulativeString;
+ TrieEdgeList _children;
+ uint64_t _address;
+ uint64_t _flags;
+ uint64_t _other;
+ StringRef _importedName;
+ uint32_t _trieOffset;
+ bool _hasExportInfo;
+};
+
/// Utility class for writing a mach-o binary file given an in-memory
/// normalized file.
class MachOFileLayout {
@@ -66,13 +133,13 @@ public:
/// Writes the normalized file as a binary mach-o file to the specified
/// path. This does not have a stream interface because the generated
/// file may need the 'x' bit set.
- std::error_code writeBinary(StringRef path);
+ llvm::Error writeBinary(StringRef path);
private:
uint32_t loadCommandsSize(uint32_t &count);
void buildFileOffsets();
void writeMachHeader();
- std::error_code writeLoadCommands();
+ llvm::Error writeLoadCommands();
void writeSectionContent();
void writeRelocations();
void writeSymbolTable();
@@ -80,6 +147,7 @@ private:
void writeBindingInfo();
void writeLazyBindingInfo();
void writeExportInfo();
+ void writeFunctionStartsInfo();
void writeDataInCodeInfo();
void writeLinkEditContent();
void buildLinkEditInfo();
@@ -87,6 +155,7 @@ private:
void buildBindInfo();
void buildLazyBindInfo();
void buildExportTrie();
+ void computeFunctionStartsSize();
void computeDataInCodeSize();
void computeSymbolTableSizes();
void buildSectionRelocations();
@@ -110,83 +179,12 @@ private:
};
template <typename T>
- std::error_code writeSingleSegmentLoadCommand(uint8_t *&lc);
- template <typename T> std::error_code writeSegmentLoadCommands(uint8_t *&lc);
+ llvm::Error writeSingleSegmentLoadCommand(uint8_t *&lc);
+ template <typename T> llvm::Error writeSegmentLoadCommands(uint8_t *&lc);
uint32_t pointerAlign(uint32_t value);
static StringRef dyldPath();
- class ByteBuffer {
- public:
- ByteBuffer() : _ostream(_bytes) { }
-
- void append_byte(uint8_t b) {
- _ostream << b;
- }
- void append_uleb128(uint64_t value) {
- llvm::encodeULEB128(value, _ostream);
- }
- void append_uleb128Fixed(uint64_t value, unsigned byteCount) {
- unsigned min = llvm::getULEB128Size(value);
- assert(min <= byteCount);
- unsigned pad = byteCount - min;
- llvm::encodeULEB128(value, _ostream, pad);
- }
- void append_sleb128(int64_t value) {
- llvm::encodeSLEB128(value, _ostream);
- }
- void append_string(StringRef str) {
- _ostream << str;
- append_byte(0);
- }
- void align(unsigned alignment) {
- while ( (_ostream.tell() % alignment) != 0 )
- append_byte(0);
- }
- size_t size() {
- return _ostream.tell();
- }
- const uint8_t *bytes() {
- return reinterpret_cast<const uint8_t*>(_ostream.str().data());
- }
-
- private:
- SmallVector<char, 128> _bytes;
- // Stream ivar must be after SmallVector ivar to construct properly.
- llvm::raw_svector_ostream _ostream;
- };
-
- struct TrieNode; // Forward declaration.
-
- struct TrieEdge {
- TrieEdge(StringRef s, TrieNode *node) : _subString(s), _child(node) {}
-
- StringRef _subString;
- struct TrieNode *_child;
- };
-
- struct TrieNode {
- TrieNode(StringRef s)
- : _cummulativeString(s), _address(0), _flags(0), _other(0),
- _trieOffset(0), _hasExportInfo(false) {}
- ~TrieNode() = default;
-
- void addSymbol(const Export &entry, BumpPtrAllocator &allocator,
- std::vector<TrieNode *> &allNodes);
- bool updateOffset(uint32_t &offset);
- void appendToByteBuffer(ByteBuffer &out);
-
- private:
- StringRef _cummulativeString;
- std::list<TrieEdge> _children;
- uint64_t _address;
- uint64_t _flags;
- uint64_t _other;
- StringRef _importedName;
- uint32_t _trieOffset;
- bool _hasExportInfo;
- };
-
struct SegExtraInfo {
uint32_t fileOffset;
uint32_t fileSize;
@@ -209,6 +207,7 @@ private:
uint32_t _countOfLoadCommands;
uint32_t _endOfLoadCommands;
uint32_t _startOfRelocations;
+ uint32_t _startOfFunctionStarts;
uint32_t _startOfDataInCode;
uint32_t _startOfSymbols;
uint32_t _startOfIndirectSymbols;
@@ -219,6 +218,7 @@ private:
uint32_t _symbolTableUndefinesStartIndex;
uint32_t _symbolStringPoolSize;
uint32_t _symbolTableSize;
+ uint32_t _functionStartsSize;
uint32_t _dataInCodeSize;
uint32_t _indirectSymbolTableCount;
// Used in object file creation only
@@ -255,7 +255,7 @@ StringRef MachOFileLayout::dyldPath() {
}
uint32_t MachOFileLayout::pointerAlign(uint32_t value) {
- return llvm::RoundUpToAlignment(value, _is64 ? 8 : 4);
+ return llvm::alignTo(value, _is64 ? 8 : 4);
}
@@ -280,7 +280,15 @@ MachOFileLayout::MachOFileLayout(const NormalizedFile &file)
+ file.sections.size() * sectsSize
+ sizeof(symtab_command);
_countOfLoadCommands = 2;
- if (!_file.dataInCode.empty()) {
+ if (file.hasMinVersionLoadCommand) {
+ _endOfLoadCommands += sizeof(version_min_command);
+ _countOfLoadCommands++;
+ }
+ if (!_file.functionStarts.empty()) {
+ _endOfLoadCommands += sizeof(linkedit_data_command);
+ _countOfLoadCommands++;
+ }
+ if (_file.generateDataInCodeLoadCommand) {
_endOfLoadCommands += sizeof(linkedit_data_command);
_countOfLoadCommands++;
}
@@ -292,7 +300,7 @@ MachOFileLayout::MachOFileLayout(const NormalizedFile &file)
if (isZeroFillSection(sect.type))
_sectInfo[&sect].fileOffset = 0;
else {
- offset = llvm::RoundUpToAlignment(offset, sect.alignment);
+ offset = llvm::alignTo(offset, sect.alignment);
_sectInfo[&sect].fileOffset = offset;
offset += sect.content.size();
}
@@ -301,11 +309,13 @@ MachOFileLayout::MachOFileLayout(const NormalizedFile &file)
_endOfSectionsContent = offset;
computeSymbolTableSizes();
+ computeFunctionStartsSize();
computeDataInCodeSize();
// Align start of relocations.
_startOfRelocations = pointerAlign(_endOfSectionsContent);
- _startOfDataInCode = _startOfRelocations + relocCount * 8;
+ _startOfFunctionStarts = _startOfRelocations + relocCount * 8;
+ _startOfDataInCode = _startOfFunctionStarts + _functionStartsSize;
_startOfSymbols = _startOfDataInCode + _dataInCodeSize;
// Add Indirect symbol table.
_startOfIndirectSymbols = _startOfSymbols + _symbolTableSize;
@@ -346,7 +356,8 @@ MachOFileLayout::MachOFileLayout(const NormalizedFile &file)
_endOfLazyBindingInfo = _startOfLazyBindingInfo + _lazyBindingInfo.size();
_startOfExportTrie = _endOfLazyBindingInfo;
_endOfExportTrie = _startOfExportTrie + _exportTrie.size();
- _startOfDataInCode = _endOfExportTrie;
+ _startOfFunctionStarts = _endOfExportTrie;
+ _startOfDataInCode = _startOfFunctionStarts + _functionStartsSize;
_startOfSymbols = _startOfDataInCode + _dataInCodeSize;
_startOfIndirectSymbols = _startOfSymbols + _symbolTableSize;
_startOfSymbolStrings = _startOfIndirectSymbols
@@ -368,6 +379,7 @@ MachOFileLayout::MachOFileLayout(const NormalizedFile &file)
<< " endOfLazyBindingInfo=" << _endOfLazyBindingInfo << "\n"
<< " startOfExportTrie=" << _startOfExportTrie << "\n"
<< " endOfExportTrie=" << _endOfExportTrie << "\n"
+ << " startOfFunctionStarts=" << _startOfFunctionStarts << "\n"
<< " startOfDataInCode=" << _startOfDataInCode << "\n"
<< " startOfSymbols=" << _startOfSymbols << "\n"
<< " startOfSymbolStrings=" << _startOfSymbolStrings << "\n"
@@ -389,9 +401,6 @@ uint32_t MachOFileLayout::loadCommandsSize(uint32_t &count) {
count += _file.segments.size();
// Add section record for each section.
size += _file.sections.size() * sectionSize;
- // Add one LC_SEGMENT for implicit __LINKEDIT segment
- size += segCommandSize;
- ++count;
// If creating a dylib, add LC_ID_DYLIB.
if (_file.fileType == llvm::MachO::MH_DYLIB) {
@@ -413,10 +422,25 @@ uint32_t MachOFileLayout::loadCommandsSize(uint32_t &count) {
++count;
}
- // If main executable add LC_LOAD_DYLINKER and LC_MAIN
+ // If main executable add LC_LOAD_DYLINKER
if (_file.fileType == llvm::MachO::MH_EXECUTE) {
size += pointerAlign(sizeof(dylinker_command) + dyldPath().size()+1);
++count;
+ }
+
+ // Add LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_WATCHOS,
+ // LC_VERSION_MIN_TVOS
+ if (_file.hasMinVersionLoadCommand) {
+ size += sizeof(version_min_command);
+ ++count;
+ }
+
+ // Add LC_SOURCE_VERSION
+ size += sizeof(source_version_command);
+ ++count;
+
+ // If main executable add LC_MAIN
+ if (_file.fileType == llvm::MachO::MH_EXECUTE) {
size += sizeof(entry_point_command);
++count;
}
@@ -433,8 +457,15 @@ uint32_t MachOFileLayout::loadCommandsSize(uint32_t &count) {
++count;
}
- // Add LC_DATA_IN_CODE if needed
- if (!_file.dataInCode.empty()) {
+ // Add LC_FUNCTION_STARTS if needed
+ if (!_file.functionStarts.empty()) {
+ size += sizeof(linkedit_data_command);
+ ++count;
+ }
+
+ // Add LC_DATA_IN_CODE if requested. Note, we do encode zero length entries.
+ // FIXME: Zero length entries is only to match ld64. Should we change this?
+ if (_file.generateDataInCodeLoadCommand) {
size += sizeof(linkedit_data_command);
++count;
}
@@ -517,7 +548,7 @@ void MachOFileLayout::buildFileOffsets() {
llvm::dbgs() << "buildFileOffsets()\n");
for (const Segment &sg : _file.segments) {
_segInfo[&sg].fileOffset = fileOffset;
- if ((_seg1addr == INT64_MAX) && sg.access)
+ if ((_seg1addr == INT64_MAX) && sg.init_access)
_seg1addr = sg.address;
DEBUG_WITH_TYPE("MachOFileLayout",
llvm::dbgs() << " segment=" << sg.name
@@ -525,7 +556,7 @@ void MachOFileLayout::buildFileOffsets() {
uint32_t segFileSize = 0;
// A segment that is not zero-fill must use a least one page of disk space.
- if (sg.access)
+ if (sg.init_access)
segFileSize = _file.pageSize;
for (const Section *s : _segInfo[&sg].sections) {
uint32_t sectOffset = s->address - sg.address;
@@ -539,10 +570,11 @@ void MachOFileLayout::buildFileOffsets() {
<< ", fileOffset=" << fileOffset << "\n");
}
- _segInfo[&sg].fileSize = llvm::RoundUpToAlignment(segFileSize,
- _file.pageSize);
- fileOffset = llvm::RoundUpToAlignment(fileOffset + segFileSize,
- _file.pageSize);
+ // round up all segments to page aligned, except __LINKEDIT
+ if (!sg.name.equals("__LINKEDIT")) {
+ _segInfo[&sg].fileSize = llvm::alignTo(segFileSize, _file.pageSize);
+ fileOffset = llvm::alignTo(fileOffset + segFileSize, _file.pageSize);
+ }
_addressOfLinkEdit = sg.address + sg.size;
}
_startOfLinkEdit = fileOffset;
@@ -553,10 +585,23 @@ size_t MachOFileLayout::size() const {
}
void MachOFileLayout::writeMachHeader() {
+ auto cpusubtype = MachOLinkingContext::cpuSubtypeFromArch(_file.arch);
+ // dynamic x86 executables on newer OS version should also set the
+ // CPU_SUBTYPE_LIB64 mask in the CPU subtype.
+ // FIXME: Check that this is a dynamic executable, not a static one.
+ if (_file.fileType == llvm::MachO::MH_EXECUTE &&
+ cpusubtype == CPU_SUBTYPE_X86_64_ALL &&
+ _file.os == MachOLinkingContext::OS::macOSX) {
+ uint32_t version;
+ bool failed = MachOLinkingContext::parsePackedVersion("10.5", version);
+ if (!failed && _file.minOSverson >= version)
+ cpusubtype |= CPU_SUBTYPE_LIB64;
+ }
+
mach_header *mh = reinterpret_cast<mach_header*>(_buffer);
mh->magic = _is64 ? llvm::MachO::MH_MAGIC_64 : llvm::MachO::MH_MAGIC;
mh->cputype = MachOLinkingContext::cpuTypeFromArch(_file.arch);
- mh->cpusubtype = MachOLinkingContext::cpuSubtypeFromArch(_file.arch);
+ mh->cpusubtype = cpusubtype;
mh->filetype = _file.fileType;
mh->ncmds = _countOfLoadCommands;
mh->sizeofcmds = _endOfLoadCommands - _startOfLoadCommands;
@@ -583,7 +628,7 @@ uint32_t MachOFileLayout::indirectSymbolElementSize(const Section &sect) {
}
template <typename T>
-std::error_code MachOFileLayout::writeSingleSegmentLoadCommand(uint8_t *&lc) {
+llvm::Error MachOFileLayout::writeSingleSegmentLoadCommand(uint8_t *&lc) {
typename T::command* seg = reinterpret_cast<typename T::command*>(lc);
seg->cmd = T::LC;
seg->cmdsize = sizeof(typename T::command)
@@ -623,15 +668,37 @@ std::error_code MachOFileLayout::writeSingleSegmentLoadCommand(uint8_t *&lc) {
++sout;
}
lc = next;
- return std::error_code();
+ return llvm::Error();
}
template <typename T>
-std::error_code MachOFileLayout::writeSegmentLoadCommands(uint8_t *&lc) {
+llvm::Error MachOFileLayout::writeSegmentLoadCommands(uint8_t *&lc) {
uint32_t indirectSymRunningIndex = 0;
for (const Segment &seg : _file.segments) {
- // Write segment command with trailing sections.
+ // Link edit has no sections and a custom range of address, so handle it
+ // specially.
SegExtraInfo &segInfo = _segInfo[&seg];
+ if (seg.name.equals("__LINKEDIT")) {
+ size_t linkeditSize = _endOfLinkEdit - _startOfLinkEdit;
+ typename T::command* cmd = reinterpret_cast<typename T::command*>(lc);
+ cmd->cmd = T::LC;
+ cmd->cmdsize = sizeof(typename T::command);
+ uint8_t *next = lc + cmd->cmdsize;
+ setString16("__LINKEDIT", cmd->segname);
+ cmd->vmaddr = _addressOfLinkEdit;
+ cmd->vmsize = llvm::alignTo(linkeditSize, _file.pageSize);
+ cmd->fileoff = _startOfLinkEdit;
+ cmd->filesize = linkeditSize;
+ cmd->initprot = seg.init_access;
+ cmd->maxprot = seg.max_access;
+ cmd->nsects = 0;
+ cmd->flags = 0;
+ if (_swap)
+ swapStruct(*cmd);
+ lc = next;
+ continue;
+ }
+ // Write segment command with trailing sections.
typename T::command* cmd = reinterpret_cast<typename T::command*>(lc);
cmd->cmd = T::LC;
cmd->cmdsize = sizeof(typename T::command)
@@ -642,8 +709,8 @@ std::error_code MachOFileLayout::writeSegmentLoadCommands(uint8_t *&lc) {
cmd->vmsize = seg.size;
cmd->fileoff = segInfo.fileOffset;
cmd->filesize = segInfo.fileSize;
- cmd->maxprot = seg.access;
- cmd->initprot = seg.access;
+ cmd->initprot = seg.init_access;
+ cmd->maxprot = seg.max_access;
cmd->nsects = segInfo.sections.size();
cmd->flags = 0;
if (_swap)
@@ -671,36 +738,52 @@ std::error_code MachOFileLayout::writeSegmentLoadCommands(uint8_t *&lc) {
}
lc = reinterpret_cast<uint8_t*>(next);
}
- // Add implicit __LINKEDIT segment
- size_t linkeditSize = _endOfLinkEdit - _startOfLinkEdit;
- typename T::command* cmd = reinterpret_cast<typename T::command*>(lc);
- cmd->cmd = T::LC;
- cmd->cmdsize = sizeof(typename T::command);
- uint8_t *next = lc + cmd->cmdsize;
- setString16("__LINKEDIT", cmd->segname);
- cmd->vmaddr = _addressOfLinkEdit;
- cmd->vmsize = llvm::RoundUpToAlignment(linkeditSize, _file.pageSize);
- cmd->fileoff = _startOfLinkEdit;
- cmd->filesize = linkeditSize;
- cmd->maxprot = VM_PROT_READ;
- cmd->initprot = VM_PROT_READ;
- cmd->nsects = 0;
- cmd->flags = 0;
+ return llvm::Error();
+}
+
+static void writeVersionMinLoadCommand(const NormalizedFile &_file,
+ bool _swap,
+ uint8_t *&lc) {
+ if (!_file.hasMinVersionLoadCommand)
+ return;
+ version_min_command *vm = reinterpret_cast<version_min_command*>(lc);
+ switch (_file.os) {
+ case MachOLinkingContext::OS::unknown:
+ vm->cmd = _file.minOSVersionKind;
+ vm->cmdsize = sizeof(version_min_command);
+ vm->version = _file.minOSverson;
+ vm->sdk = 0;
+ break;
+ case MachOLinkingContext::OS::macOSX:
+ vm->cmd = LC_VERSION_MIN_MACOSX;
+ vm->cmdsize = sizeof(version_min_command);
+ vm->version = _file.minOSverson;
+ vm->sdk = _file.sdkVersion;
+ break;
+ case MachOLinkingContext::OS::iOS:
+ case MachOLinkingContext::OS::iOS_simulator:
+ vm->cmd = LC_VERSION_MIN_IPHONEOS;
+ vm->cmdsize = sizeof(version_min_command);
+ vm->version = _file.minOSverson;
+ vm->sdk = _file.sdkVersion;
+ break;
+ }
if (_swap)
- swapStruct(*cmd);
- lc = next;
- return std::error_code();
+ swapStruct(*vm);
+ lc += sizeof(version_min_command);
}
-std::error_code MachOFileLayout::writeLoadCommands() {
- std::error_code ec;
+llvm::Error MachOFileLayout::writeLoadCommands() {
uint8_t *lc = &_buffer[_startOfLoadCommands];
if (_file.fileType == llvm::MachO::MH_OBJECT) {
// Object files have one unnamed segment which holds all sections.
- if (_is64)
- ec = writeSingleSegmentLoadCommand<MachO64Trait>(lc);
- else
- ec = writeSingleSegmentLoadCommand<MachO32Trait>(lc);
+ if (_is64) {
+ if (auto ec = writeSingleSegmentLoadCommand<MachO64Trait>(lc))
+ return ec;
+ } else {
+ if (auto ec = writeSingleSegmentLoadCommand<MachO32Trait>(lc))
+ return ec;
+ }
// Add LC_SYMTAB with symbol table info
symtab_command* st = reinterpret_cast<symtab_command*>(lc);
st->cmd = LC_SYMTAB;
@@ -713,8 +796,25 @@ std::error_code MachOFileLayout::writeLoadCommands() {
if (_swap)
swapStruct(*st);
lc += sizeof(symtab_command);
- // Add LC_DATA_IN_CODE if needed.
- if (_dataInCodeSize != 0) {
+
+ // Add LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS,
+ // LC_VERSION_MIN_WATCHOS, LC_VERSION_MIN_TVOS
+ writeVersionMinLoadCommand(_file, _swap, lc);
+
+ // Add LC_FUNCTION_STARTS if needed.
+ if (_functionStartsSize != 0) {
+ linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc);
+ dl->cmd = LC_FUNCTION_STARTS;
+ dl->cmdsize = sizeof(linkedit_data_command);
+ dl->dataoff = _startOfFunctionStarts;
+ dl->datasize = _functionStartsSize;
+ if (_swap)
+ swapStruct(*dl);
+ lc += sizeof(linkedit_data_command);
+ }
+
+ // Add LC_DATA_IN_CODE if requested.
+ if (_file.generateDataInCodeLoadCommand) {
linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc);
dl->cmd = LC_DATA_IN_CODE;
dl->cmdsize = sizeof(linkedit_data_command);
@@ -726,10 +826,13 @@ std::error_code MachOFileLayout::writeLoadCommands() {
}
} else {
// Final linked images have sections under segments.
- if (_is64)
- ec = writeSegmentLoadCommands<MachO64Trait>(lc);
- else
- ec = writeSegmentLoadCommands<MachO32Trait>(lc);
+ if (_is64) {
+ if (auto ec = writeSegmentLoadCommands<MachO64Trait>(lc))
+ return ec;
+ } else {
+ if (auto ec = writeSegmentLoadCommands<MachO32Trait>(lc))
+ return ec;
+ }
// Add LC_ID_DYLIB command for dynamic libraries.
if (_file.fileType == llvm::MachO::MH_DYLIB) {
@@ -809,7 +912,7 @@ std::error_code MachOFileLayout::writeLoadCommands() {
lc += sizeof(dysymtab_command);
}
- // If main executable, add LC_LOAD_DYLINKER and LC_MAIN.
+ // If main executable, add LC_LOAD_DYLINKER
if (_file.fileType == llvm::MachO::MH_EXECUTE) {
// Build LC_LOAD_DYLINKER load command.
uint32_t size=pointerAlign(sizeof(dylinker_command)+dyldPath().size()+1);
@@ -822,14 +925,39 @@ std::error_code MachOFileLayout::writeLoadCommands() {
memcpy(lc+sizeof(dylinker_command), dyldPath().data(), dyldPath().size());
lc[sizeof(dylinker_command)+dyldPath().size()] = '\0';
lc += size;
+ }
+
+ // Add LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_WATCHOS,
+ // LC_VERSION_MIN_TVOS
+ writeVersionMinLoadCommand(_file, _swap, lc);
+
+ // Add LC_SOURCE_VERSION
+ {
+ // Note, using a temporary here to appease UB as we may not be aligned
+ // enough for a struct containing a uint64_t when emitting a 32-bit binary
+ source_version_command sv;
+ sv.cmd = LC_SOURCE_VERSION;
+ sv.cmdsize = sizeof(source_version_command);
+ sv.version = _file.sourceVersion;
+ if (_swap)
+ swapStruct(sv);
+ memcpy(lc, &sv, sizeof(source_version_command));
+ lc += sizeof(source_version_command);
+ }
+
+ // If main executable, add LC_MAIN.
+ if (_file.fileType == llvm::MachO::MH_EXECUTE) {
// Build LC_MAIN load command.
- entry_point_command* ep = reinterpret_cast<entry_point_command*>(lc);
- ep->cmd = LC_MAIN;
- ep->cmdsize = sizeof(entry_point_command);
- ep->entryoff = _file.entryAddress - _seg1addr;
- ep->stacksize = _file.stackSize;
+ // Note, using a temporary here to appease UB as we may not be aligned
+ // enough for a struct containing a uint64_t when emitting a 32-bit binary
+ entry_point_command ep;
+ ep.cmd = LC_MAIN;
+ ep.cmdsize = sizeof(entry_point_command);
+ ep.entryoff = _file.entryAddress - _seg1addr;
+ ep.stacksize = _file.stackSize;
if (_swap)
- swapStruct(*ep);
+ swapStruct(ep);
+ memcpy(lc, &ep, sizeof(entry_point_command));
lc += sizeof(entry_point_command);
}
@@ -865,8 +993,20 @@ std::error_code MachOFileLayout::writeLoadCommands() {
lc += size;
}
- // Add LC_DATA_IN_CODE if needed.
- if (_dataInCodeSize != 0) {
+ // Add LC_FUNCTION_STARTS if needed.
+ if (_functionStartsSize != 0) {
+ linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc);
+ dl->cmd = LC_FUNCTION_STARTS;
+ dl->cmdsize = sizeof(linkedit_data_command);
+ dl->dataoff = _startOfFunctionStarts;
+ dl->datasize = _functionStartsSize;
+ if (_swap)
+ swapStruct(*dl);
+ lc += sizeof(linkedit_data_command);
+ }
+
+ // Add LC_DATA_IN_CODE if requested.
+ if (_file.generateDataInCodeLoadCommand) {
linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc);
dl->cmd = LC_DATA_IN_CODE;
dl->cmdsize = sizeof(linkedit_data_command);
@@ -877,7 +1017,7 @@ std::error_code MachOFileLayout::writeLoadCommands() {
lc += sizeof(linkedit_data_command);
}
}
- return ec;
+ return llvm::Error();
}
void MachOFileLayout::writeSectionContent() {
@@ -936,6 +1076,13 @@ void MachOFileLayout::appendSymbols(const std::vector<Symbol> &symbols,
}
}
+void MachOFileLayout::writeFunctionStartsInfo() {
+ if (!_functionStartsSize)
+ return;
+ memcpy(&_buffer[_startOfFunctionStarts], _file.functionStarts.data(),
+ _functionStartsSize);
+}
+
void MachOFileLayout::writeDataInCodeInfo() {
uint32_t offset = _startOfDataInCode;
for (const DataInCode &entry : _file.dataInCode) {
@@ -1011,6 +1158,7 @@ void MachOFileLayout::buildLinkEditInfo() {
buildLazyBindInfo();
buildExportTrie();
computeSymbolTableSizes();
+ computeFunctionStartsSize();
computeDataInCodeSize();
}
@@ -1079,9 +1227,9 @@ void MachOFileLayout::buildLazyBindInfo() {
_lazyBindingInfo.align(_is64 ? 8 : 4);
}
-void MachOFileLayout::TrieNode::addSymbol(const Export& entry,
- BumpPtrAllocator &allocator,
- std::vector<TrieNode*> &allNodes) {
+void TrieNode::addSymbol(const Export& entry,
+ BumpPtrAllocator &allocator,
+ std::vector<TrieNode*> &allNodes) {
StringRef partialStr = entry.name.drop_front(_cummulativeString.size());
for (TrieEdge &edge : _children) {
StringRef edgeStr = edge._subString;
@@ -1110,7 +1258,7 @@ void MachOFileLayout::TrieNode::addSymbol(const Export& entry,
abEdge._subString = abEdgeStr;
abEdge._child = bNode;
auto *bcEdge = new (allocator) TrieEdge(bcEdgeStr, cNode);
- bNode->_children.push_back(std::move(*bcEdge));
+ bNode->_children.insert(bNode->_children.end(), bcEdge);
bNode->addSymbol(entry, allocator, allNodes);
return;
}
@@ -1125,7 +1273,7 @@ void MachOFileLayout::TrieNode::addSymbol(const Export& entry,
// No commonality with any existing child, make a new edge.
auto *newNode = new (allocator) TrieNode(entry.name.copy(allocator));
auto *newEdge = new (allocator) TrieEdge(partialStr, newNode);
- _children.push_back(std::move(*newEdge));
+ _children.insert(_children.end(), newEdge);
DEBUG_WITH_TYPE("trie-builder", llvm::dbgs()
<< "new TrieNode('" << entry.name << "') with edge '"
<< partialStr << "' from node='"
@@ -1139,7 +1287,7 @@ void MachOFileLayout::TrieNode::addSymbol(const Export& entry,
allNodes.push_back(newNode);
}
-bool MachOFileLayout::TrieNode::updateOffset(uint32_t& offset) {
+bool TrieNode::updateOffset(uint32_t& offset) {
uint32_t nodeSize = 1; // Length when no export info
if (_hasExportInfo) {
if (_flags & EXPORT_SYMBOL_FLAGS_REEXPORT) {
@@ -1171,7 +1319,7 @@ bool MachOFileLayout::TrieNode::updateOffset(uint32_t& offset) {
return result;
}
-void MachOFileLayout::TrieNode::appendToByteBuffer(ByteBuffer &out) {
+void TrieNode::appendToByteBuffer(ByteBuffer &out) {
if (_hasExportInfo) {
if (_flags & EXPORT_SYMBOL_FLAGS_REEXPORT) {
if (!_importedName.empty()) {
@@ -1290,6 +1438,10 @@ void MachOFileLayout::computeSymbolTableSizes() {
}
}
+void MachOFileLayout::computeFunctionStartsSize() {
+ _functionStartsSize = _file.functionStarts.size();
+}
+
void MachOFileLayout::computeDataInCodeSize() {
_dataInCodeSize = _file.dataInCode.size() * sizeof(data_in_code_entry);
}
@@ -1297,6 +1449,7 @@ void MachOFileLayout::computeDataInCodeSize() {
void MachOFileLayout::writeLinkEditContent() {
if (_file.fileType == llvm::MachO::MH_OBJECT) {
writeRelocations();
+ writeFunctionStartsInfo();
writeDataInCodeInfo();
writeSymbolTable();
} else {
@@ -1305,15 +1458,16 @@ void MachOFileLayout::writeLinkEditContent() {
writeLazyBindingInfo();
// TODO: add weak binding info
writeExportInfo();
+ writeFunctionStartsInfo();
writeDataInCodeInfo();
writeSymbolTable();
}
}
-std::error_code MachOFileLayout::writeBinary(StringRef path) {
+llvm::Error MachOFileLayout::writeBinary(StringRef path) {
// Check for pending error from constructor.
if (_ec)
- return _ec;
+ return llvm::errorCodeToError(_ec);
// Create FileOutputBuffer with calculated size.
unsigned flags = 0;
if (_file.fileType != llvm::MachO::MH_OBJECT)
@@ -1321,23 +1475,22 @@ std::error_code MachOFileLayout::writeBinary(StringRef path) {
ErrorOr<std::unique_ptr<llvm::FileOutputBuffer>> fobOrErr =
llvm::FileOutputBuffer::create(path, size(), flags);
if (std::error_code ec = fobOrErr.getError())
- return ec;
+ return llvm::errorCodeToError(ec);
std::unique_ptr<llvm::FileOutputBuffer> &fob = *fobOrErr;
// Write content.
_buffer = fob->getBufferStart();
writeMachHeader();
- std::error_code ec = writeLoadCommands();
- if (ec)
+ if (auto ec = writeLoadCommands())
return ec;
writeSectionContent();
writeLinkEditContent();
fob->commit();
- return std::error_code();
+ return llvm::Error();
}
/// Takes in-memory normalized view and writes a mach-o object file.
-std::error_code writeBinary(const NormalizedFile &file, StringRef path) {
+llvm::Error writeBinary(const NormalizedFile &file, StringRef path) {
MachOFileLayout layout(file);
return layout.writeBinary(path);
}
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
index 575bc1a2b3a9..4775c75f7211 100644
--- a/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
@@ -92,23 +92,27 @@ struct SegmentInfo {
StringRef name;
uint64_t address;
uint64_t size;
- uint32_t access;
+ uint32_t init_access;
+ uint32_t max_access;
std::vector<SectionInfo*> sections;
uint32_t normalizedSegmentIndex;
};
SegmentInfo::SegmentInfo(StringRef n)
- : name(n), address(0), size(0), access(0), normalizedSegmentIndex(0) {
+ : name(n), address(0), size(0), init_access(0), max_access(0),
+ normalizedSegmentIndex(0) {
}
class Util {
public:
Util(const MachOLinkingContext &ctxt)
: _ctx(ctxt), _archHandler(ctxt.archHandler()), _entryAtom(nullptr),
- _hasTLVDescriptors(false) {}
+ _hasTLVDescriptors(false), _subsectionsViaSymbols(true) {}
~Util();
- void assignAtomsToSections(const lld::File &atomFile);
+ void processDefinedAtoms(const lld::File &atomFile);
+ void processAtomAttributes(const DefinedAtom *atom);
+ void assignAtomToSection(const DefinedAtom *atom);
void organizeSections();
void assignAddressesToSections(const NormalizedFile &file);
uint32_t fileFlags();
@@ -116,16 +120,29 @@ public:
void copySectionInfo(NormalizedFile &file);
void updateSectionInfo(NormalizedFile &file);
void buildAtomToAddressMap();
- std::error_code addSymbols(const lld::File &atomFile, NormalizedFile &file);
+ llvm::Error addSymbols(const lld::File &atomFile, NormalizedFile &file);
void addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file);
void addRebaseAndBindingInfo(const lld::File &, NormalizedFile &file);
void addExportInfo(const lld::File &, NormalizedFile &file);
void addSectionRelocs(const lld::File &, NormalizedFile &file);
+ void addFunctionStarts(const lld::File &, NormalizedFile &file);
void buildDataInCodeArray(const lld::File &, NormalizedFile &file);
void addDependentDylibs(const lld::File &, NormalizedFile &file);
void copyEntryPointAddress(NormalizedFile &file);
void copySectionContent(NormalizedFile &file);
+ bool allSourceFilesHaveMinVersions() const {
+ return _allSourceFilesHaveMinVersions;
+ }
+
+ uint32_t minVersion() const {
+ return _minVersion;
+ }
+
+ LoadCommandType minVersionCommandType() const {
+ return _minVersionCommandType;
+ }
+
private:
typedef std::map<DefinedAtom::ContentType, SectionInfo*> TypeToSection;
typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress;
@@ -147,9 +164,9 @@ private:
uint8_t &segmentIndex, uint64_t &segmentStartAddr);
const Atom *targetOfLazyPointer(const DefinedAtom *lpAtom);
const Atom *targetOfStub(const DefinedAtom *stubAtom);
- std::error_code getSymbolTableRegion(const DefinedAtom* atom,
- bool &inGlobalsRegion,
- SymbolScope &symbolScope);
+ llvm::Error getSymbolTableRegion(const DefinedAtom* atom,
+ bool &inGlobalsRegion,
+ SymbolScope &symbolScope);
void appendSection(SectionInfo *si, NormalizedFile &file);
uint32_t sectionIndexForAtom(const Atom *atom);
@@ -180,6 +197,10 @@ private:
AtomToIndex _atomToSymbolIndex;
std::vector<const Atom *> _machHeaderAliasAtoms;
bool _hasTLVDescriptors;
+ bool _subsectionsViaSymbols;
+ bool _allSourceFilesHaveMinVersions = true;
+ LoadCommandType _minVersionCommandType = (LoadCommandType)0;
+ uint32_t _minVersion = 0;
};
Util::~Util() {
@@ -239,6 +260,7 @@ struct MachOFinalSectionFromAtomType {
const MachOFinalSectionFromAtomType sectsToAtomType[] = {
ENTRY("__TEXT", "__text", S_REGULAR, typeCode),
+ ENTRY("__TEXT", "__text", S_REGULAR, typeMachHeader),
ENTRY("__TEXT", "__cstring", S_CSTRING_LITERALS, typeCString),
ENTRY("__TEXT", "__ustring", S_REGULAR, typeUTF16String),
ENTRY("__TEXT", "__const", S_REGULAR, typeConstant),
@@ -261,6 +283,8 @@ const MachOFinalSectionFromAtomType sectsToAtomType[] = {
typeTerminatorPtr),
ENTRY("__DATA", "__got", S_NON_LAZY_SYMBOL_POINTERS,
typeGOT),
+ ENTRY("__DATA", "__nl_symbol_ptr", S_NON_LAZY_SYMBOL_POINTERS,
+ typeNonLazyPointer),
ENTRY("__DATA", "__thread_vars", S_THREAD_LOCAL_VARIABLES,
typeThunkTLV),
ENTRY("__DATA", "__thread_data", S_THREAD_LOCAL_REGULAR,
@@ -280,10 +304,11 @@ SectionInfo *Util::getFinalSection(DefinedAtom::ContentType atomType) {
continue;
SectionAttr sectionAttrs = 0;
switch (atomType) {
+ case DefinedAtom::typeMachHeader:
case DefinedAtom::typeCode:
case DefinedAtom::typeStub:
case DefinedAtom::typeStubHelper:
- sectionAttrs = S_ATTR_PURE_INSTRUCTIONS;
+ sectionAttrs = S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS;
break;
case DefinedAtom::typeThunkTLV:
_hasTLVDescriptors = true;
@@ -366,27 +391,85 @@ void Util::appendAtom(SectionInfo *sect, const DefinedAtom *atom) {
sect->size = offset + atom->size();
}
-void Util::assignAtomsToSections(const lld::File &atomFile) {
+void Util::processDefinedAtoms(const lld::File &atomFile) {
for (const DefinedAtom *atom : atomFile.defined()) {
- if (atom->contentType() == DefinedAtom::typeMachHeader)
- _machHeaderAliasAtoms.push_back(atom);
+ processAtomAttributes(atom);
+ assignAtomToSection(atom);
+ }
+}
+
+void Util::processAtomAttributes(const DefinedAtom *atom) {
+ if (auto *machoFile = dyn_cast<mach_o::MachOFile>(&atom->file())) {
+ // If the file doesn't use subsections via symbols, then make sure we don't
+ // add that flag to the final output file if we have a relocatable file.
+ if (!machoFile->subsectionsViaSymbols())
+ _subsectionsViaSymbols = false;
+
+ // All the source files must have min versions for us to output an object
+ // file with a min version.
+ if (auto v = machoFile->minVersion())
+ _minVersion = std::max(_minVersion, v);
else
- appendAtom(sectionForAtom(atom), atom);
+ _allSourceFilesHaveMinVersions = false;
+
+ // If we don't have a platform load command, but one of the source files
+ // does, then take the one from the file.
+ if (!_minVersionCommandType)
+ if (auto v = machoFile->minVersionLoadCommandKind())
+ _minVersionCommandType = v;
}
}
+void Util::assignAtomToSection(const DefinedAtom *atom) {
+ if (atom->contentType() == DefinedAtom::typeMachHeader) {
+ _machHeaderAliasAtoms.push_back(atom);
+ // Assign atom to this section with this offset.
+ AtomInfo ai = {atom, 0};
+ sectionForAtom(atom)->atomsAndOffsets.push_back(ai);
+ } else if (atom->contentType() == DefinedAtom::typeDSOHandle)
+ _machHeaderAliasAtoms.push_back(atom);
+ else
+ appendAtom(sectionForAtom(atom), atom);
+}
+
SegmentInfo *Util::segmentForName(StringRef segName) {
for (SegmentInfo *si : _segmentInfos) {
if ( si->name.equals(segName) )
return si;
}
auto *info = new (_allocator) SegmentInfo(segName);
+
+ // Set the initial segment protection.
if (segName.equals("__TEXT"))
- info->access = VM_PROT_READ | VM_PROT_EXECUTE;
- else if (segName.equals("__DATA"))
- info->access = VM_PROT_READ | VM_PROT_WRITE;
+ info->init_access = VM_PROT_READ | VM_PROT_EXECUTE;
else if (segName.equals("__PAGEZERO"))
- info->access = 0;
+ info->init_access = 0;
+ else if (segName.equals("__LINKEDIT"))
+ info->init_access = VM_PROT_READ;
+ else {
+ // All others default to read-write
+ info->init_access = VM_PROT_READ | VM_PROT_WRITE;
+ }
+
+ // Set max segment protection
+ // Note, its overkill to use a switch statement here, but makes it so much
+ // easier to use switch coverage to catch new cases.
+ switch (_ctx.os()) {
+ case lld::MachOLinkingContext::OS::unknown:
+ case lld::MachOLinkingContext::OS::macOSX:
+ case lld::MachOLinkingContext::OS::iOS_simulator:
+ if (segName.equals("__PAGEZERO")) {
+ info->max_access = 0;
+ break;
+ }
+ // All others default to all
+ info->max_access = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
+ break;
+ case lld::MachOLinkingContext::OS::iOS:
+ // iPhoneOS always uses same protection for max and initial
+ info->max_access = info->init_access;
+ break;
+ }
_segmentInfos.push_back(info);
return info;
}
@@ -436,6 +519,8 @@ void Util::organizeSections() {
default:
break;
}
+ segmentForName("__LINKEDIT");
+
// Group sections into segments.
for (SectionInfo *si : _sectionInfos) {
SegmentInfo *seg = segmentForName(si->segmentName);
@@ -465,10 +550,10 @@ void Util::organizeSections() {
void Util::layoutSectionsInSegment(SegmentInfo *seg, uint64_t &addr) {
seg->address = addr;
for (SectionInfo *sect : seg->sections) {
- sect->address = llvm::RoundUpToAlignment(addr, sect->alignment);
+ sect->address = llvm::alignTo(addr, sect->alignment);
addr = sect->address + sect->size;
}
- seg->size = llvm::RoundUpToAlignment(addr - seg->address, _ctx.pageSize());
+ seg->size = llvm::alignTo(addr - seg->address, _ctx.pageSize());
}
// __TEXT segment lays out backwards so padding is at front after load commands.
@@ -488,10 +573,10 @@ void Util::layoutSectionsInTextSegment(size_t hlcSize, SegmentInfo *seg,
// Start assigning section address starting at padded offset.
addr += (padding + hlcSize);
for (SectionInfo *sect : seg->sections) {
- sect->address = llvm::RoundUpToAlignment(addr, sect->alignment);
+ sect->address = llvm::alignTo(addr, sect->alignment);
addr = sect->address + sect->size;
}
- seg->size = llvm::RoundUpToAlignment(addr - seg->address, _ctx.pageSize());
+ seg->size = llvm::alignTo(addr - seg->address, _ctx.pageSize());
}
void Util::assignAddressesToSections(const NormalizedFile &file) {
@@ -511,7 +596,7 @@ void Util::assignAddressesToSections(const NormalizedFile &file) {
} else
layoutSectionsInSegment(seg, address);
- address = llvm::RoundUpToAlignment(address, _ctx.pageSize());
+ address = llvm::alignTo(address, _ctx.pageSize());
}
DEBUG_WITH_TYPE("WriterMachO-norm",
llvm::dbgs() << "assignAddressesToSections()\n";
@@ -536,7 +621,8 @@ void Util::copySegmentInfo(NormalizedFile &file) {
seg.name = sgi->name;
seg.address = sgi->address;
seg.size = sgi->size;
- seg.access = sgi->access;
+ seg.init_access = sgi->init_access;
+ seg.max_access = sgi->max_access;
file.segments.push_back(seg);
}
}
@@ -583,11 +669,20 @@ void Util::copySectionContent(NormalizedFile &file) {
continue;
}
// Copy content from atoms to content buffer for section.
- uint8_t *sectionContent = file.ownedAllocations.Allocate<uint8_t>(si->size);
- normSect->content = llvm::makeArrayRef(sectionContent, si->size);
+ llvm::MutableArrayRef<uint8_t> sectionContent;
+ if (si->size) {
+ uint8_t *sectContent = file.ownedAllocations.Allocate<uint8_t>(si->size);
+ sectionContent = llvm::MutableArrayRef<uint8_t>(sectContent, si->size);
+ normSect->content = sectionContent;
+ }
for (AtomInfo &ai : si->atomsAndOffsets) {
- uint8_t *atomContent = reinterpret_cast<uint8_t*>
- (&sectionContent[ai.offsetInSection]);
+ if (!ai.atom->size()) {
+ assert(ai.atom->begin() == ai.atom->end() &&
+ "Cannot have references without content");
+ continue;
+ }
+ auto atomContent = sectionContent.slice(ai.offsetInSection,
+ ai.atom->size());
_archHandler.generateAtomContent(*ai.atom, r, addrForAtom,
sectionAddrForAtom, _ctx.baseAddress(),
atomContent);
@@ -620,6 +715,11 @@ void Util::updateSectionInfo(NormalizedFile &file) {
}
void Util::copyEntryPointAddress(NormalizedFile &nFile) {
+ if (!_entryAtom) {
+ nFile.entryAddress = 0;
+ return;
+ }
+
if (_ctx.outputTypeHasEntry()) {
if (_archHandler.isThumbFunction(*_entryAtom))
nFile.entryAddress = (_atomToAddress[_entryAtom] | 1);
@@ -703,6 +803,8 @@ uint16_t Util::descBits(const DefinedAtom* atom) {
}
if (atom->contentType() == lld::DefinedAtom::typeResolver)
desc |= N_SYMBOL_RESOLVER;
+ if (atom->contentType() == lld::DefinedAtom::typeMachHeader)
+ desc |= REFERENCED_DYNAMICALLY;
if (_archHandler.isThumbFunction(*atom))
desc |= N_ARM_THUMB_DEF;
if (atom->deadStrip() == DefinedAtom::deadStripNever) {
@@ -718,56 +820,56 @@ bool Util::AtomSorter::operator()(const AtomAndIndex &left,
return (left.atom->name().compare(right.atom->name()) < 0);
}
-std::error_code Util::getSymbolTableRegion(const DefinedAtom* atom,
- bool &inGlobalsRegion,
- SymbolScope &scope) {
+llvm::Error Util::getSymbolTableRegion(const DefinedAtom* atom,
+ bool &inGlobalsRegion,
+ SymbolScope &scope) {
bool rMode = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT);
switch (atom->scope()) {
case Atom::scopeTranslationUnit:
scope = 0;
inGlobalsRegion = false;
- return std::error_code();
+ return llvm::Error();
case Atom::scopeLinkageUnit:
if ((_ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) &&
_ctx.exportSymbolNamed(atom->name())) {
- return make_dynamic_error_code(Twine("cannot export hidden symbol ")
- + atom->name());
+ return llvm::make_error<GenericError>(
+ Twine("cannot export hidden symbol ") + atom->name());
}
if (rMode) {
if (_ctx.keepPrivateExterns()) {
// -keep_private_externs means keep in globals region as N_PEXT.
scope = N_PEXT | N_EXT;
inGlobalsRegion = true;
- return std::error_code();
+ return llvm::Error();
}
}
// scopeLinkageUnit symbols are no longer global once linked.
scope = N_PEXT;
inGlobalsRegion = false;
- return std::error_code();
+ return llvm::Error();
case Atom::scopeGlobal:
if (_ctx.exportRestrictMode()) {
if (_ctx.exportSymbolNamed(atom->name())) {
scope = N_EXT;
inGlobalsRegion = true;
- return std::error_code();
+ return llvm::Error();
} else {
scope = N_PEXT;
inGlobalsRegion = false;
- return std::error_code();
+ return llvm::Error();
}
} else {
scope = N_EXT;
inGlobalsRegion = true;
- return std::error_code();
+ return llvm::Error();
}
break;
}
llvm_unreachable("atom->scope() unknown enum value");
}
-std::error_code Util::addSymbols(const lld::File &atomFile,
- NormalizedFile &file) {
+llvm::Error Util::addSymbols(const lld::File &atomFile,
+ NormalizedFile &file) {
bool rMode = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT);
// Mach-O symbol table has three regions: locals, globals, undefs.
@@ -863,7 +965,7 @@ std::error_code Util::addSymbols(const lld::File &atomFile,
file.undefinedSymbols.push_back(sym);
}
- return std::error_code();
+ return llvm::Error();
}
const Atom *Util::targetOfLazyPointer(const DefinedAtom *lpAtom) {
@@ -1055,7 +1157,53 @@ void Util::addSectionRelocs(const lld::File &, NormalizedFile &file) {
}
}
+void Util::addFunctionStarts(const lld::File &, NormalizedFile &file) {
+ if (!_ctx.generateFunctionStartsLoadCommand())
+ return;
+ file.functionStarts.reserve(8192);
+ // Delta compress function starts, starting with the mach header symbol.
+ const uint64_t badAddress = ~0ULL;
+ uint64_t addr = badAddress;
+ for (SectionInfo *si : _sectionInfos) {
+ for (const AtomInfo &info : si->atomsAndOffsets) {
+ auto type = info.atom->contentType();
+ if (type == DefinedAtom::typeMachHeader) {
+ addr = _atomToAddress[info.atom];
+ continue;
+ }
+ if (type != DefinedAtom::typeCode)
+ continue;
+ assert(addr != badAddress && "Missing mach header symbol");
+ // Skip atoms which have 0 size. This is so that LC_FUNCTION_STARTS
+ // can't spill in to the next section.
+ if (!info.atom->size())
+ continue;
+ uint64_t nextAddr = _atomToAddress[info.atom];
+ if (_archHandler.isThumbFunction(*info.atom))
+ nextAddr |= 1;
+ uint64_t delta = nextAddr - addr;
+ if (delta) {
+ ByteBuffer buffer;
+ buffer.append_uleb128(delta);
+ file.functionStarts.insert(file.functionStarts.end(), buffer.bytes(),
+ buffer.bytes() + buffer.size());
+ }
+ addr = nextAddr;
+ }
+ }
+
+ // Null terminate, and pad to pointer size for this arch.
+ file.functionStarts.push_back(0);
+
+ auto size = file.functionStarts.size();
+ for (unsigned i = size, e = llvm::alignTo(size, _ctx.is64Bit() ? 8 : 4);
+ i != e; ++i)
+ file.functionStarts.push_back(0);
+}
+
void Util::buildDataInCodeArray(const lld::File &, NormalizedFile &file) {
+ if (!_ctx.generateDataInCodeLoadCommand())
+ return;
for (SectionInfo *si : _sectionInfos) {
for (const AtomInfo &info : si->atomsAndOffsets) {
// Atoms that contain data-in-code have "transition" references
@@ -1183,7 +1331,7 @@ void Util::addExportInfo(const lld::File &atomFile, NormalizedFile &nFile) {
uint32_t Util::fileFlags() {
// FIXME: these need to determined at runtime.
if (_ctx.outputMachOType() == MH_OBJECT) {
- return MH_SUBSECTIONS_VIA_SYMBOLS;
+ return _subsectionsViaSymbols ? MH_SUBSECTIONS_VIA_SYMBOLS : 0;
} else {
uint32_t flags = MH_DYLDLINK;
if (!_ctx.useFlatNamespace())
@@ -1203,12 +1351,12 @@ namespace mach_o {
namespace normalized {
/// Convert a set of Atoms into a normalized mach-o file.
-ErrorOr<std::unique_ptr<NormalizedFile>>
+llvm::Expected<std::unique_ptr<NormalizedFile>>
normalizedFromAtoms(const lld::File &atomFile,
const MachOLinkingContext &context) {
// The util object buffers info until the normalized file can be made.
Util util(context);
- util.assignAtomsToSections(atomFile);
+ util.processDefinedAtoms(atomFile);
util.organizeSections();
std::unique_ptr<NormalizedFile> f(new NormalizedFile());
@@ -1220,6 +1368,35 @@ normalizedFromAtoms(const lld::File &atomFile,
normFile.installName = context.installName();
normFile.currentVersion = context.currentVersion();
normFile.compatVersion = context.compatibilityVersion();
+ normFile.os = context.os();
+
+ // If we are emitting an object file, then the min version is the maximum
+ // of the min's of all the source files and the cmdline.
+ if (normFile.fileType == llvm::MachO::MH_OBJECT)
+ normFile.minOSverson = std::max(context.osMinVersion(), util.minVersion());
+ else
+ normFile.minOSverson = context.osMinVersion();
+
+ normFile.minOSVersionKind = util.minVersionCommandType();
+
+ normFile.sdkVersion = context.sdkVersion();
+ normFile.sourceVersion = context.sourceVersion();
+
+ if (context.generateVersionLoadCommand() &&
+ context.os() != MachOLinkingContext::OS::unknown)
+ normFile.hasMinVersionLoadCommand = true;
+ else if (normFile.fileType == llvm::MachO::MH_OBJECT &&
+ util.allSourceFilesHaveMinVersions() &&
+ ((normFile.os != MachOLinkingContext::OS::unknown) ||
+ util.minVersionCommandType())) {
+ // If we emit an object file, then it should contain a min version load
+ // command if all of the source files also contained min version commands.
+ // Also, we either need to have a platform, or found a platform from the
+ // source object files.
+ normFile.hasMinVersionLoadCommand = true;
+ }
+ normFile.generateDataInCodeLoadCommand =
+ context.generateDataInCodeLoadCommand();
normFile.pageSize = context.pageSize();
normFile.rpaths = context.rpaths();
util.addDependentDylibs(atomFile, normFile);
@@ -1230,12 +1407,13 @@ normalizedFromAtoms(const lld::File &atomFile,
util.updateSectionInfo(normFile);
util.copySectionContent(normFile);
if (auto ec = util.addSymbols(atomFile, normFile)) {
- return ec;
+ return std::move(ec);
}
util.addIndirectSymbols(atomFile, normFile);
util.addRebaseAndBindingInfo(atomFile, normFile);
util.addExportInfo(atomFile, normFile);
util.addSectionRelocs(atomFile, normFile);
+ util.addFunctionStarts(atomFile, normFile);
util.buildDataInCodeArray(atomFile, normFile);
util.copyEntryPointAddress(normFile);
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
index f9499b603214..fc760a3eddd0 100644
--- a/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
@@ -88,6 +88,8 @@ const MachORelocatableSectionToAtomType sectsToAtomType[] = {
ENTRY("__DATA", "__thread_data", S_THREAD_LOCAL_REGULAR, typeTLVInitialData),
ENTRY("__DATA", "__thread_bss", S_THREAD_LOCAL_ZEROFILL,
typeTLVInitialZeroFill),
+ ENTRY("__DATA", "__objc_imageinfo", S_REGULAR, typeObjCImageInfo),
+ ENTRY("__DATA", "__objc_catlist", S_REGULAR, typeObjC2CategoryList),
ENTRY("", "", S_INTERPOSING, typeInterposingTuples),
ENTRY("__LD", "__compact_unwind", S_REGULAR,
typeCompactUnwindInfo),
@@ -180,6 +182,8 @@ void sectionParseInfo(DefinedAtom::ContentType atomType,
atomizeCU),
ENTRY(typeGOT, 4, scopeLinkageUnit, mergeByContent,
atomizePointerSize),
+ ENTRY(typeObjC2CategoryList, 4, scopeTranslationUnit, mergeByContent,
+ atomizePointerSize),
ENTRY(typeUnknown, 1, scopeGlobal, mergeNo,
atomizeAtSymbols)
};
@@ -265,11 +269,11 @@ void atomFromSymbol(DefinedAtom::ContentType atomType, const Section &section,
}
}
-std::error_code processSymboledSection(DefinedAtom::ContentType atomType,
- const Section &section,
- const NormalizedFile &normalizedFile,
- MachOFile &file, bool scatterable,
- bool copyRefs) {
+llvm::Error processSymboledSection(DefinedAtom::ContentType atomType,
+ const Section &section,
+ const NormalizedFile &normalizedFile,
+ MachOFile &file, bool scatterable,
+ bool copyRefs) {
// Find section's index.
uint32_t sectIndex = 1;
for (auto &sect : normalizedFile.sections) {
@@ -316,7 +320,7 @@ std::error_code processSymboledSection(DefinedAtom::ContentType atomType,
// If section has no symbols and no content, there are no atoms.
if (symbols.empty() && section.content.empty())
- return std::error_code();
+ return llvm::Error();
if (symbols.empty()) {
// Section has no symbols, put all content in one anoymous atom.
@@ -360,22 +364,22 @@ std::error_code processSymboledSection(DefinedAtom::ContentType atomType,
file.eachAtomInSection(section,
[&](MachODefinedAtom *atom, uint64_t offset)->void {
if (prevAtom)
- prevAtom->addReference(0, Reference::kindLayoutAfter, atom, 0,
+ prevAtom->addReference(Reference::KindNamespace::all,
Reference::KindArch::all,
- Reference::KindNamespace::all);
+ Reference::kindLayoutAfter, 0, atom, 0);
prevAtom = atom;
});
}
- return std::error_code();
+ return llvm::Error();
}
-std::error_code processSection(DefinedAtom::ContentType atomType,
- const Section &section,
- bool customSectionName,
- const NormalizedFile &normalizedFile,
- MachOFile &file, bool scatterable,
- bool copyRefs) {
+llvm::Error processSection(DefinedAtom::ContentType atomType,
+ const Section &section,
+ bool customSectionName,
+ const NormalizedFile &normalizedFile,
+ MachOFile &file, bool scatterable,
+ bool copyRefs) {
const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
@@ -388,12 +392,13 @@ std::error_code processSection(DefinedAtom::ContentType atomType,
// Validate section size.
if ((section.content.size() % sizeMultiple) != 0)
- return make_dynamic_error_code(Twine("Section ") + section.segmentName
- + "/" + section.sectionName
- + " has size ("
- + Twine(section.content.size())
- + ") which is not a multiple of "
- + Twine(sizeMultiple) );
+ return llvm::make_error<GenericError>(Twine("Section ")
+ + section.segmentName
+ + "/" + section.sectionName
+ + " has size ("
+ + Twine(section.content.size())
+ + ") which is not a multiple of "
+ + Twine(sizeMultiple));
if (atomizeModel == atomizeAtSymbols) {
// Break section up into atoms each with a fixed size.
@@ -435,13 +440,13 @@ std::error_code processSection(DefinedAtom::ContentType atomType,
// Break section up into dwarf unwind CFIs (FDE or CIE).
size = read32(&section.content[offset], isBig) + 4;
if (offset+size > section.content.size()) {
- return make_dynamic_error_code(Twine(Twine("Section ")
- + section.segmentName
- + "/" + section.sectionName
- + " is malformed. Size of CFI "
- "starting at offset ("
- + Twine(offset)
- + ") is past end of section."));
+ return llvm::make_error<GenericError>(Twine("Section ")
+ + section.segmentName
+ + "/" + section.sectionName
+ + " is malformed. Size of CFI "
+ "starting at offset ("
+ + Twine(offset)
+ + ") is past end of section.");
}
break;
case atomizeCU:
@@ -456,10 +461,11 @@ std::error_code processSection(DefinedAtom::ContentType atomType,
break;
}
if (size == 0) {
- return make_dynamic_error_code(Twine("Section ") + section.segmentName
- + "/" + section.sectionName
- + " is malformed. The last atom is "
- "not zero terminated.");
+ return llvm::make_error<GenericError>(Twine("Section ")
+ + section.segmentName
+ + "/" + section.sectionName
+ + " is malformed. The last atom "
+ "is not zero terminated.");
}
if (customSectionName) {
// Mach-O needs a segment and section name. Concatentate those two
@@ -477,7 +483,7 @@ std::error_code processSection(DefinedAtom::ContentType atomType,
offset += size;
}
}
- return std::error_code();
+ return llvm::Error();
}
const Section* findSectionCoveringAddress(const NormalizedFile &normalizedFile,
@@ -509,23 +515,23 @@ findAtomCoveringAddress(const NormalizedFile &normalizedFile, MachOFile &file,
// Walks all relocations for a section in a normalized .o file and
// creates corresponding lld::Reference objects.
-std::error_code convertRelocs(const Section &section,
- const NormalizedFile &normalizedFile,
- bool scatterable,
- MachOFile &file,
- ArchHandler &handler) {
+llvm::Error convertRelocs(const Section &section,
+ const NormalizedFile &normalizedFile,
+ bool scatterable,
+ MachOFile &file,
+ ArchHandler &handler) {
// Utility function for ArchHandler to find atom by its address.
auto atomByAddr = [&] (uint32_t sectIndex, uint64_t addr,
const lld::Atom **atom, Reference::Addend *addend)
- -> std::error_code {
+ -> llvm::Error {
if (sectIndex > normalizedFile.sections.size())
- return make_dynamic_error_code(Twine("out of range section "
+ return llvm::make_error<GenericError>(Twine("out of range section "
"index (") + Twine(sectIndex) + ")");
const Section *sect = nullptr;
if (sectIndex == 0) {
sect = findSectionCoveringAddress(normalizedFile, addr);
if (!sect)
- return make_dynamic_error_code(Twine("address (" + Twine(addr)
+ return llvm::make_error<GenericError>(Twine("address (" + Twine(addr)
+ ") is not in any section"));
} else {
sect = &normalizedFile.sections[sectIndex-1];
@@ -534,12 +540,12 @@ std::error_code convertRelocs(const Section &section,
uint64_t offsetInSect = addr - sect->address;
*atom = file.findAtomCoveringAddress(*sect, offsetInSect, &offsetInTarget);
*addend = offsetInTarget;
- return std::error_code();
+ return llvm::Error();
};
// Utility function for ArchHandler to find atom by its symbol index.
auto atomBySymbol = [&] (uint32_t symbolIndex, const lld::Atom **result)
- -> std::error_code {
+ -> llvm::Error {
// Find symbol from index.
const Symbol *sym = nullptr;
uint32_t numLocal = normalizedFile.localSymbols.size();
@@ -552,13 +558,13 @@ std::error_code convertRelocs(const Section &section,
} else if (symbolIndex < numLocal+numGlobal+numUndef) {
sym = &normalizedFile.undefinedSymbols[symbolIndex-numLocal-numGlobal];
} else {
- return make_dynamic_error_code(Twine("symbol index (")
+ return llvm::make_error<GenericError>(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 (")
+ return llvm::make_error<GenericError>(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;
@@ -566,19 +572,19 @@ std::error_code convertRelocs(const Section &section,
targetOffsetInSect);
if (target) {
*result = target;
- return std::error_code();
+ return llvm::Error();
}
- return make_dynamic_error_code("no atom found for defined symbol");
+ return llvm::make_error<GenericError>("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 llvm::Error();
}
- return make_dynamic_error_code("no undefined atom found for sym");
+ return llvm::make_error<GenericError>("no undefined atom found for sym");
} else {
// Search undefs
- return make_dynamic_error_code("no atom found for symbol");
+ return llvm::make_error<GenericError>("no atom found for symbol");
}
};
@@ -589,7 +595,8 @@ std::error_code convertRelocs(const Section &section,
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)
+ return llvm::make_error<GenericError>(
+ Twine("r_address (") + Twine(reloc.offset)
+ ") is larger than section size ("
+ Twine(section.content.size()) + ")");
uint32_t offsetInAtom;
@@ -602,68 +609,74 @@ std::error_code convertRelocs(const Section &section,
const lld::Atom *target = nullptr;
Reference::Addend addend = 0;
Reference::KindValue kind;
- std::error_code relocErr;
if (handler.isPairedReloc(reloc)) {
// Handle paired relocations together.
const Relocation &reloc2 = *++it;
- relocErr = handler.getPairReferenceInfo(
+ auto relocErr = handler.getPairReferenceInfo(
reloc, reloc2, inAtom, offsetInAtom, fixupAddress, isBig, scatterable,
atomByAddr, atomBySymbol, &kind, &target, &addend);
if (relocErr) {
- return make_dynamic_error_code(
- Twine("bad relocation (") + relocErr.message()
- + ") in section "
- + section.segmentName + "/" + section.sectionName
- + " (r1_address=" + Twine::utohexstr(reloc.offset)
- + ", r1_type=" + Twine(reloc.type)
- + ", r1_extern=" + Twine(reloc.isExtern)
- + ", r1_length=" + Twine((int)reloc.length)
- + ", r1_pcrel=" + Twine(reloc.pcRel)
- + (!reloc.scattered ? (Twine(", r1_symbolnum=")
- + Twine(reloc.symbol))
- : (Twine(", r1_scattered=1, r1_value=")
- + Twine(reloc.value)))
- + ")"
- + ", (r2_address=" + Twine::utohexstr(reloc2.offset)
- + ", r2_type=" + Twine(reloc2.type)
- + ", r2_extern=" + Twine(reloc2.isExtern)
- + ", r2_length=" + Twine((int)reloc2.length)
- + ", r2_pcrel=" + Twine(reloc2.pcRel)
- + (!reloc2.scattered ? (Twine(", r2_symbolnum=")
- + Twine(reloc2.symbol))
- : (Twine(", r2_scattered=1, r2_value=")
- + Twine(reloc2.value)))
- + ")" );
+ return handleErrors(std::move(relocErr),
+ [&](std::unique_ptr<GenericError> GE) {
+ return llvm::make_error<GenericError>(
+ Twine("bad relocation (") + GE->getMessage()
+ + ") in section "
+ + section.segmentName + "/" + section.sectionName
+ + " (r1_address=" + Twine::utohexstr(reloc.offset)
+ + ", r1_type=" + Twine(reloc.type)
+ + ", r1_extern=" + Twine(reloc.isExtern)
+ + ", r1_length=" + Twine((int)reloc.length)
+ + ", r1_pcrel=" + Twine(reloc.pcRel)
+ + (!reloc.scattered ? (Twine(", r1_symbolnum=")
+ + Twine(reloc.symbol))
+ : (Twine(", r1_scattered=1, r1_value=")
+ + Twine(reloc.value)))
+ + ")"
+ + ", (r2_address=" + Twine::utohexstr(reloc2.offset)
+ + ", r2_type=" + Twine(reloc2.type)
+ + ", r2_extern=" + Twine(reloc2.isExtern)
+ + ", r2_length=" + Twine((int)reloc2.length)
+ + ", r2_pcrel=" + Twine(reloc2.pcRel)
+ + (!reloc2.scattered ? (Twine(", r2_symbolnum=")
+ + Twine(reloc2.symbol))
+ : (Twine(", r2_scattered=1, r2_value=")
+ + Twine(reloc2.value)))
+ + ")" );
+ });
}
}
else {
// Use ArchHandler to convert relocation record into information
// needed to instantiate an lld::Reference object.
- relocErr = handler.getReferenceInfo(
+ auto relocErr = handler.getReferenceInfo(
reloc, inAtom, offsetInAtom, fixupAddress, isBig, 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((int)reloc.length)
- + ", r_pcrel=" + Twine(reloc.pcRel)
- + (!reloc.scattered ? (Twine(", r_symbolnum=") + Twine(reloc.symbol))
- : (Twine(", r_scattered=1, r_value=")
- + Twine(reloc.value)))
- + ")" );
+ return handleErrors(std::move(relocErr),
+ [&](std::unique_ptr<GenericError> GE) {
+ return llvm::make_error<GenericError>(
+ Twine("bad relocation (") + GE->getMessage()
+ + ") 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((int)reloc.length)
+ + ", r_pcrel=" + Twine(reloc.pcRel)
+ + (!reloc.scattered ? (Twine(", r_symbolnum=") + Twine(reloc.symbol))
+ : (Twine(", r_scattered=1, r_value=")
+ + Twine(reloc.value)))
+ + ")" );
+ });
}
}
// Instantiate an lld::Reference object and add to its atom.
- inAtom->addReference(offsetInAtom, kind, target, addend,
- handler.kindArch());
+ inAtom->addReference(Reference::KindNamespace::mach_o,
+ handler.kindArch(),
+ kind, offsetInAtom, target, addend);
}
- return std::error_code();
+ return llvm::Error();
}
bool isDebugInfoSection(const Section &section) {
@@ -684,44 +697,81 @@ static int64_t readSPtr(bool is64, bool isBig, const uint8_t *addr) {
struct CIEInfo {
bool _augmentationDataPresent = false;
- bool _mayHaveLSDA = false;
+ bool _mayHaveEH = false;
+ uint32_t _offsetOfLSDA = ~0U;
+ uint32_t _offsetOfPersonality = ~0U;
+ uint32_t _offsetOfFDEPointerEncoding = ~0U;
+ uint32_t _augmentationDataLength = ~0U;
};
typedef llvm::DenseMap<const MachODefinedAtom*, CIEInfo> CIEInfoMap;
-static std::error_code processAugmentationString(const uint8_t *augStr,
- CIEInfo &cieInfo,
- unsigned *len = nullptr) {
+static llvm::Error processAugmentationString(const uint8_t *augStr,
+ CIEInfo &cieInfo,
+ unsigned &len) {
if (augStr[0] == '\0') {
- if (len)
- *len = 1;
- return std::error_code();
+ len = 1;
+ return llvm::Error();
}
if (augStr[0] != 'z')
- return make_dynamic_error_code("expected 'z' at start of augmentation "
- "string");
+ return llvm::make_error<GenericError>("expected 'z' at start of "
+ "augmentation string");
cieInfo._augmentationDataPresent = true;
uint64_t idx = 1;
+ uint32_t offsetInAugmentationData = 0;
while (augStr[idx] != '\0') {
if (augStr[idx] == 'L') {
- cieInfo._mayHaveLSDA = true;
+ cieInfo._offsetOfLSDA = offsetInAugmentationData;
+ // This adds a single byte to the augmentation data.
+ ++offsetInAugmentationData;
+ ++idx;
+ continue;
+ }
+ if (augStr[idx] == 'P') {
+ cieInfo._offsetOfPersonality = offsetInAugmentationData;
+ // This adds a single byte to the augmentation data for the encoding,
+ // then a number of bytes for the pointer data.
+ // FIXME: We are assuming 4 is correct here for the pointer size as we
+ // always currently use delta32ToGOT.
+ offsetInAugmentationData += 5;
++idx;
- } else
+ continue;
+ }
+ if (augStr[idx] == 'R') {
+ cieInfo._offsetOfFDEPointerEncoding = offsetInAugmentationData;
+ // This adds a single byte to the augmentation data.
+ ++offsetInAugmentationData;
++idx;
+ continue;
+ }
+ if (augStr[idx] == 'e') {
+ if (augStr[idx + 1] != 'h')
+ return llvm::make_error<GenericError>("expected 'eh' in "
+ "augmentation string");
+ cieInfo._mayHaveEH = true;
+ idx += 2;
+ continue;
+ }
+ ++idx;
}
- if (len)
- *len = idx + 1;
- return std::error_code();
+ cieInfo._augmentationDataLength = offsetInAugmentationData;
+
+ len = idx + 1;
+ return llvm::Error();
}
-static std::error_code processCIE(const NormalizedFile &normalizedFile,
- MachODefinedAtom *atom,
- CIEInfoMap &cieInfos) {
+static llvm::Error processCIE(const NormalizedFile &normalizedFile,
+ MachOFile &file,
+ mach_o::ArchHandler &handler,
+ const Section *ehFrameSection,
+ MachODefinedAtom *atom,
+ uint64_t offset,
+ CIEInfoMap &cieInfos) {
const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
const uint8_t *frameData = atom->rawContent().data();
@@ -734,31 +784,170 @@ static std::error_code processCIE(const NormalizedFile &normalizedFile,
uint64_t versionField = cieIDField + sizeof(uint32_t);
uint64_t augmentationStringField = versionField + sizeof(uint8_t);
+ unsigned augmentationStringLength = 0;
if (auto err = processAugmentationString(frameData + augmentationStringField,
- cieInfo))
+ cieInfo, augmentationStringLength))
return err;
+ if (cieInfo._offsetOfPersonality != ~0U) {
+ // If we have augmentation data for the personality function, then we may
+ // need to implicitly generate its relocation.
+
+ // Parse the EH Data field which is pointer sized.
+ uint64_t EHDataField = augmentationStringField + augmentationStringLength;
+ const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
+ unsigned EHDataFieldSize = (cieInfo._mayHaveEH ? (is64 ? 8 : 4) : 0);
+
+ // Parse Code Align Factor which is a ULEB128.
+ uint64_t CodeAlignField = EHDataField + EHDataFieldSize;
+ unsigned lengthFieldSize = 0;
+ llvm::decodeULEB128(frameData + CodeAlignField, &lengthFieldSize);
+
+ // Parse Data Align Factor which is a SLEB128.
+ uint64_t DataAlignField = CodeAlignField + lengthFieldSize;
+ llvm::decodeSLEB128(frameData + DataAlignField, &lengthFieldSize);
+
+ // Parse Return Address Register which is a byte.
+ uint64_t ReturnAddressField = DataAlignField + lengthFieldSize;
+
+ // Parse the augmentation length which is a ULEB128.
+ uint64_t AugmentationLengthField = ReturnAddressField + 1;
+ uint64_t AugmentationLength =
+ llvm::decodeULEB128(frameData + AugmentationLengthField,
+ &lengthFieldSize);
+
+ if (AugmentationLength != cieInfo._augmentationDataLength)
+ return llvm::make_error<GenericError>("CIE augmentation data length "
+ "mismatch");
+
+ // Get the start address of the augmentation data.
+ uint64_t AugmentationDataField = AugmentationLengthField + lengthFieldSize;
+
+ // Parse the personality function from the augmentation data.
+ uint64_t PersonalityField =
+ AugmentationDataField + cieInfo._offsetOfPersonality;
+
+ // Parse the personality encoding.
+ // FIXME: Verify that this is a 32-bit pcrel offset.
+ uint64_t PersonalityFunctionField = PersonalityField + 1;
+
+ if (atom->begin() != atom->end()) {
+ // If we have an explicit relocation, then make sure it matches this
+ // offset as this is where we'd expect it to be applied to.
+ DefinedAtom::reference_iterator CurrentRef = atom->begin();
+ if (CurrentRef->offsetInAtom() != PersonalityFunctionField)
+ return llvm::make_error<GenericError>("CIE personality reloc at "
+ "wrong offset");
+
+ if (++CurrentRef != atom->end())
+ return llvm::make_error<GenericError>("CIE contains too many relocs");
+ } else {
+ // Implicitly generate the personality function reloc. It's assumed to
+ // be a delta32 offset to a GOT entry.
+ // FIXME: Parse the encoding and check this.
+ int32_t funcDelta = read32(frameData + PersonalityFunctionField, isBig);
+ uint64_t funcAddress = ehFrameSection->address + offset +
+ PersonalityFunctionField;
+ funcAddress += funcDelta;
+
+ const MachODefinedAtom *func = nullptr;
+ Reference::Addend addend;
+ func = findAtomCoveringAddress(normalizedFile, file, funcAddress,
+ &addend);
+ atom->addReference(Reference::KindNamespace::mach_o, handler.kindArch(),
+ handler.unwindRefToPersonalityFunctionKind(),
+ PersonalityFunctionField, func, addend);
+ }
+ } else if (atom->begin() != atom->end()) {
+ // Otherwise, we expect there to be no relocations in this atom as the only
+ // relocation would have been to the personality function.
+ return llvm::make_error<GenericError>("unexpected relocation in CIE");
+ }
+
+
cieInfos[atom] = std::move(cieInfo);
- return std::error_code();
+ return llvm::Error();
}
-static std::error_code processFDE(const NormalizedFile &normalizedFile,
- MachOFile &file,
- mach_o::ArchHandler &handler,
- const Section *ehFrameSection,
- MachODefinedAtom *atom,
- uint64_t offset,
- const CIEInfoMap &cieInfos) {
+static llvm::Error processFDE(const NormalizedFile &normalizedFile,
+ MachOFile &file,
+ mach_o::ArchHandler &handler,
+ const Section *ehFrameSection,
+ MachODefinedAtom *atom,
+ uint64_t offset,
+ const CIEInfoMap &cieInfos) {
const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
// Compiler wasn't lazy and actually told us what it meant.
+ // Unfortunately, the compiler may not have generated references for all of
+ // [cie, func, lsda] and so we still need to parse the FDE and add references
+ // for any the compiler didn't generate.
if (atom->begin() != atom->end())
- return std::error_code();
+ atom->sortReferences();
+
+ DefinedAtom::reference_iterator CurrentRef = atom->begin();
+
+ // This helper returns the reference (if one exists) at the offset we are
+ // currently processing. It automatically increments the ref iterator if we
+ // do return a ref, and throws an error if we pass over a ref without
+ // comsuming it.
+ auto currentRefGetter = [&CurrentRef,
+ &atom](uint64_t Offset)->const Reference* {
+ // If there are no more refs found, then we are done.
+ if (CurrentRef == atom->end())
+ return nullptr;
+
+ const Reference *Ref = *CurrentRef;
+
+ // If we haven't reached the offset for this reference, then return that
+ // we don't yet have a reference to process.
+ if (Offset < Ref->offsetInAtom())
+ return nullptr;
+
+ // If the offset is equal, then we want to process this ref.
+ if (Offset == Ref->offsetInAtom()) {
+ ++CurrentRef;
+ return Ref;
+ }
+
+ // The current ref is at an offset which is earlier than the current
+ // offset, then we failed to consume it when we should have. In this case
+ // throw an error.
+ llvm::report_fatal_error("Skipped reference when processing FDE");
+ };
+
+ // Helper to either get the reference at this current location, and verify
+ // that it is of the expected type, or add a reference of that type.
+ // Returns the reference target.
+ auto verifyOrAddReference = [&](uint64_t targetAddress,
+ Reference::KindValue refKind,
+ uint64_t refAddress,
+ bool allowsAddend)->const Atom* {
+ if (auto *ref = currentRefGetter(refAddress)) {
+ // The compiler already emitted a relocation for the CIE ref. This should
+ // have been converted to the correct type of reference in
+ // get[Pair]ReferenceInfo().
+ assert(ref->kindValue() == refKind &&
+ "Incorrect EHFrame reference kind");
+ return ref->target();
+ }
+ Reference::Addend addend;
+ auto *target = findAtomCoveringAddress(normalizedFile, file,
+ targetAddress, &addend);
+ atom->addReference(Reference::KindNamespace::mach_o, handler.kindArch(),
+ refKind, refAddress, target, addend);
+
+ if (!allowsAddend)
+ assert(!addend && "EHFrame reference cannot have addend");
+ return target;
+ };
+
+ const uint8_t *startFrameData = atom->rawContent().data();
+ const uint8_t *frameData = startFrameData;
- const uint8_t *frameData = atom->rawContent().data();
uint32_t size = read32(frameData, isBig);
uint64_t cieFieldInFDE = size == 0xffffffffU
? sizeof(uint32_t) + sizeof(uint64_t)
@@ -770,13 +959,11 @@ static std::error_code processFDE(const NormalizedFile &normalizedFile,
uint64_t cieAddress = ehFrameSection->address + offset + cieFieldInFDE;
cieAddress -= cieDelta;
- Reference::Addend addend;
- const MachODefinedAtom *cie =
- findAtomCoveringAddress(normalizedFile, file, cieAddress, &addend);
- atom->addReference(cieFieldInFDE, handler.unwindRefToCIEKind(), cie,
- addend, handler.kindArch());
-
- assert(cie && cie->contentType() == DefinedAtom::typeCFI && !addend &&
+ auto *cieRefTarget = verifyOrAddReference(cieAddress,
+ handler.unwindRefToCIEKind(),
+ cieFieldInFDE, false);
+ const MachODefinedAtom *cie = dyn_cast<MachODefinedAtom>(cieRefTarget);
+ assert(cie && cie->contentType() == DefinedAtom::typeCFI &&
"FDE's CIE field does not point at the start of a CIE.");
const CIEInfo &cieInfo = cieInfos.find(cie)->second;
@@ -792,10 +979,9 @@ static std::error_code processFDE(const NormalizedFile &normalizedFile,
uint64_t rangeStart = ehFrameSection->address + offset + rangeFieldInFDE;
rangeStart += functionFromFDE;
- const Atom *func =
- findAtomCoveringAddress(normalizedFile, file, rangeStart, &addend);
- atom->addReference(rangeFieldInFDE, handler.unwindRefToFunctionKind(),
- func, addend, handler.kindArch());
+ verifyOrAddReference(rangeStart,
+ handler.unwindRefToFunctionKind(),
+ rangeFieldInFDE, true);
// Handle the augmentation data if there is any.
if (cieInfo._augmentationDataPresent) {
@@ -807,7 +993,7 @@ static std::error_code processFDE(const NormalizedFile &normalizedFile,
llvm::decodeULEB128(frameData + augmentationDataLengthFieldInFDE,
&lengthFieldSize);
- if (cieInfo._mayHaveLSDA && augmentationDataLength > 0) {
+ if (cieInfo._offsetOfLSDA != ~0U && augmentationDataLength > 0) {
// Look at the augmentation data field.
uint64_t augmentationDataFieldInFDE =
@@ -818,20 +1004,19 @@ static std::error_code processFDE(const NormalizedFile &normalizedFile,
uint64_t lsdaStart =
ehFrameSection->address + offset + augmentationDataFieldInFDE +
lsdaFromFDE;
- const Atom *lsda =
- findAtomCoveringAddress(normalizedFile, file, lsdaStart, &addend);
- atom->addReference(augmentationDataFieldInFDE,
- handler.unwindRefToFunctionKind(),
- lsda, addend, handler.kindArch());
+
+ verifyOrAddReference(lsdaStart,
+ handler.unwindRefToFunctionKind(),
+ augmentationDataFieldInFDE, true);
}
}
- return std::error_code();
+ return llvm::Error();
}
-std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile,
- MachOFile &file,
- mach_o::ArchHandler &handler) {
+llvm::Error addEHFrameReferences(const NormalizedFile &normalizedFile,
+ MachOFile &file,
+ mach_o::ArchHandler &handler) {
const Section *ehFrameSection = nullptr;
for (auto &section : normalizedFile.sections)
@@ -843,9 +1028,9 @@ std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile,
// No __eh_frame so nothing to do.
if (!ehFrameSection)
- return std::error_code();
+ return llvm::Error();
- std::error_code ehFrameErr;
+ llvm::Error ehFrameErr;
CIEInfoMap cieInfos;
file.eachAtomInSection(*ehFrameSection,
@@ -858,7 +1043,8 @@ std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile,
const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
if (ArchHandler::isDwarfCIE(isBig, atom))
- ehFrameErr = processCIE(normalizedFile, atom, cieInfos);
+ ehFrameErr = processCIE(normalizedFile, file, handler, ehFrameSection,
+ atom, offset, cieInfos);
else
ehFrameErr = processFDE(normalizedFile, file, handler, ehFrameSection,
atom, offset, cieInfos);
@@ -867,24 +1053,66 @@ std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile,
return ehFrameErr;
}
+llvm::Error parseObjCImageInfo(const Section &sect,
+ const NormalizedFile &normalizedFile,
+ MachOFile &file) {
+
+ // struct objc_image_info {
+ // uint32_t version; // initially 0
+ // uint32_t flags;
+ // };
+
+ ArrayRef<uint8_t> content = sect.content;
+ if (content.size() != 8)
+ return llvm::make_error<GenericError>(sect.segmentName + "/" +
+ sect.sectionName +
+ " in file " + file.path() +
+ " should be 8 bytes in size");
+
+ const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+ uint32_t version = read32(content.data(), isBig);
+ if (version)
+ return llvm::make_error<GenericError>(sect.segmentName + "/" +
+ sect.sectionName +
+ " in file " + file.path() +
+ " should have version=0");
+
+ uint32_t flags = read32(content.data() + 4, isBig);
+ if (flags & (MachOLinkingContext::objc_supports_gc |
+ MachOLinkingContext::objc_gc_only))
+ return llvm::make_error<GenericError>(sect.segmentName + "/" +
+ sect.sectionName +
+ " in file " + file.path() +
+ " uses GC. This is not supported");
+
+ if (flags & MachOLinkingContext::objc_retainReleaseForSimulator)
+ file.setObjcConstraint(MachOLinkingContext::objc_retainReleaseForSimulator);
+ else
+ file.setObjcConstraint(MachOLinkingContext::objc_retainRelease);
+
+ file.setSwiftVersion((flags >> 8) & 0xFF);
+
+ return llvm::Error();
+}
+
/// Converts normalized mach-o file into an lld::File and lld::Atoms.
-ErrorOr<std::unique_ptr<lld::File>>
+llvm::Expected<std::unique_ptr<lld::File>>
objectToAtoms(const NormalizedFile &normalizedFile, StringRef path,
bool copyRefs) {
std::unique_ptr<MachOFile> file(new MachOFile(path));
- if (std::error_code ec = normalizedObjectToAtoms(
- file.get(), normalizedFile, copyRefs))
- return ec;
+ if (auto ec = normalizedObjectToAtoms(file.get(), normalizedFile, copyRefs))
+ return std::move(ec);
return std::unique_ptr<File>(std::move(file));
}
-ErrorOr<std::unique_ptr<lld::File>>
+llvm::Expected<std::unique_ptr<lld::File>>
dylibToAtoms(const NormalizedFile &normalizedFile, StringRef path,
bool copyRefs) {
// Instantiate SharedLibraryFile object.
std::unique_ptr<MachODylibFile> file(new MachODylibFile(path));
- normalizedDylibToAtoms(file.get(), normalizedFile, copyRefs);
+ if (auto ec = normalizedDylibToAtoms(file.get(), normalizedFile, copyRefs))
+ return std::move(ec);
return std::unique_ptr<File>(std::move(file));
}
@@ -892,7 +1120,12 @@ dylibToAtoms(const NormalizedFile &normalizedFile, StringRef path,
namespace normalized {
-std::error_code
+static bool isObjCImageInfo(const Section &sect) {
+ return (sect.segmentName == "__OBJC" && sect.sectionName == "__image_info") ||
+ (sect.segmentName == "__DATA" && sect.sectionName == "__objc_imageinfo");
+}
+
+llvm::Error
normalizedObjectToAtoms(MachOFile *file,
const NormalizedFile &normalizedFile,
bool copyRefs) {
@@ -905,12 +1138,23 @@ normalizedObjectToAtoms(MachOFile *file,
DEBUG(llvm::dbgs() << "Creating atoms: "; sect.dump());
if (isDebugInfoSection(sect))
continue;
+
+
+ // If the file contains an objc_image_info struct, then we should parse the
+ // ObjC flags and Swift version.
+ if (isObjCImageInfo(sect)) {
+ if (auto ec = parseObjCImageInfo(sect, normalizedFile, *file))
+ return ec;
+ // We then skip adding atoms for this section as we use the ObjCPass to
+ // re-emit this data after it has been aggregated for all files.
+ continue;
+ }
+
bool customSectionName;
DefinedAtom::ContentType atomType = atomTypeFromSection(sect,
customSectionName);
- if (std::error_code ec =
- processSection(atomType, sect, customSectionName, normalizedFile,
- *file, scatterable, copyRefs))
+ if (auto ec = processSection(atomType, sect, customSectionName,
+ normalizedFile, *file, scatterable, copyRefs))
return ec;
}
// Create atoms from undefined symbols.
@@ -931,9 +1175,9 @@ normalizedObjectToAtoms(MachOFile *file,
for (auto &sect : normalizedFile.sections) {
if (isDebugInfoSection(sect))
continue;
- if (std::error_code ec = convertRelocs(sect, normalizedFile, scatterable,
- *file, *handler))
- return ec;
+ if (llvm::Error ec = convertRelocs(sect, normalizedFile, scatterable,
+ *file, *handler))
+ return ec;
}
// Add additional arch-specific References
@@ -945,7 +1189,7 @@ normalizedObjectToAtoms(MachOFile *file,
// providing unwind info for) and itself (FDE -> CIE). These aren't
// represented in the relocations on some architectures, so we have to add
// them back in manually there.
- if (std::error_code ec = addEHFrameReferences(normalizedFile, *file, *handler))
+ if (auto ec = addEHFrameReferences(normalizedFile, *file, *handler))
return ec;
// Process mach-o data-in-code regions array. That information is encoded in
@@ -955,25 +1199,26 @@ normalizedObjectToAtoms(MachOFile *file,
++nextIndex;
const Section* s = findSectionCoveringAddress(normalizedFile, entry.offset);
if (!s) {
- return make_dynamic_error_code(Twine("LC_DATA_IN_CODE address ("
- + Twine(entry.offset)
- + ") is not in any section"));
+ return llvm::make_error<GenericError>(Twine("LC_DATA_IN_CODE address ("
+ + Twine(entry.offset)
+ + ") is not in any section"));
}
uint64_t offsetInSect = entry.offset - s->address;
uint32_t offsetInAtom;
MachODefinedAtom *atom = file->findAtomCoveringAddress(*s, offsetInSect,
&offsetInAtom);
if (offsetInAtom + entry.length > atom->size()) {
- return make_dynamic_error_code(Twine("LC_DATA_IN_CODE entry (offset="
- + Twine(entry.offset)
- + ", length="
- + Twine(entry.length)
- + ") crosses atom boundary."));
+ return llvm::make_error<GenericError>(Twine("LC_DATA_IN_CODE entry "
+ "(offset="
+ + Twine(entry.offset)
+ + ", length="
+ + Twine(entry.length)
+ + ") crosses atom boundary."));
}
// Add reference that marks start of data-in-code.
- atom->addReference(offsetInAtom,
- handler->dataInCodeTransitionStart(*atom), atom,
- entry.kind, handler->kindArch());
+ atom->addReference(Reference::KindNamespace::mach_o, handler->kindArch(),
+ handler->dataInCodeTransitionStart(*atom),
+ offsetInAtom, atom, entry.kind);
// Peek at next entry, if it starts where this one ends, skip ending ref.
if (nextIndex < normalizedFile.dataInCode.size()) {
@@ -987,19 +1232,26 @@ normalizedObjectToAtoms(MachOFile *file,
continue;
// Add reference that marks end of data-in-code.
- atom->addReference(offsetInAtom+entry.length,
- handler->dataInCodeTransitionEnd(*atom), atom, 0,
- handler->kindArch());
+ atom->addReference(Reference::KindNamespace::mach_o, handler->kindArch(),
+ handler->dataInCodeTransitionEnd(*atom),
+ offsetInAtom+entry.length, atom, 0);
}
+ // Cache some attributes on the file for use later.
+ file->setFlags(normalizedFile.flags);
+ file->setArch(normalizedFile.arch);
+ file->setOS(normalizedFile.os);
+ file->setMinVersion(normalizedFile.minOSverson);
+ file->setMinVersionLoadCommandKind(normalizedFile.minOSVersionKind);
+
// Sort references in each atom to their canonical order.
for (const DefinedAtom* defAtom : file->defined()) {
reinterpret_cast<const SimpleDefinedAtom*>(defAtom)->sortReferences();
}
- return std::error_code();
+ return llvm::Error();
}
-std::error_code
+llvm::Error
normalizedDylibToAtoms(MachODylibFile *file,
const NormalizedFile &normalizedFile,
bool copyRefs) {
@@ -1027,7 +1279,7 @@ normalizedDylibToAtoms(MachODylibFile *file,
if (dep.kind == llvm::MachO::LC_REEXPORT_DYLIB)
file->addReExportedDylib(dep.path);
}
- return std::error_code();
+ return llvm::Error();
}
void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType,
@@ -1058,7 +1310,7 @@ void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType,
llvm_unreachable("content type not yet supported");
}
-ErrorOr<std::unique_ptr<lld::File>>
+llvm::Expected<std::unique_ptr<lld::File>>
normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path,
bool copyRefs) {
switch (normalizedFile.fileType) {
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
index 0b92a68eeae8..66be77173983 100644
--- a/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
@@ -237,6 +237,29 @@ struct ScalarBitSetTraits<SectionAttr> {
}
};
+/// This is a custom formatter for SectionAlignment. Values are
+/// the power to raise by, ie, the n in 2^n.
+template <> struct ScalarTraits<SectionAlignment> {
+ static void output(const SectionAlignment &value, void *ctxt,
+ raw_ostream &out) {
+ out << llvm::format("%d", (uint32_t)value);
+ }
+
+ static StringRef input(StringRef scalar, void *ctxt,
+ SectionAlignment &value) {
+ uint32_t alignment;
+ if (scalar.getAsInteger(0, alignment)) {
+ return "malformed alignment value";
+ }
+ if (!llvm::isPowerOf2_32(alignment))
+ return "alignment must be a power of 2";
+ value = alignment;
+ return StringRef(); // returning empty string means success
+ }
+
+ static bool mustQuote(StringRef) { return false; }
+};
+
template <>
struct ScalarEnumerationTraits<NListType> {
static void enumeration(IO &io, NListType &value) {
@@ -276,7 +299,7 @@ struct MappingTraits<Section> {
io.mapRequired("section", sect.sectionName);
io.mapRequired("type", sect.type);
io.mapOptional("attributes", sect.attributes);
- io.mapOptional("alignment", sect.alignment, (uint16_t)1);
+ io.mapOptional("alignment", sect.alignment, (SectionAlignment)1);
io.mapRequired("address", sect.address);
if (isZeroFillSection(sect.type)) {
// S_ZEROFILL sections use "size:" instead of "content:"
@@ -311,6 +334,8 @@ struct MappingTraits<Section> {
NormalizedFile *file = info->_normalizeMachOFile;
assert(file != nullptr);
size_t size = _normalizedContent.size();
+ if (!size)
+ return None;
uint8_t *bytes = file->ownedAllocations.Allocate<uint8_t>(size);
std::copy(_normalizedContent.begin(), _normalizedContent.end(), bytes);
return makeArrayRef(bytes, size);
@@ -504,10 +529,11 @@ struct ScalarTraits<VMProtect> {
template <>
struct MappingTraits<Segment> {
static void mapping(IO &io, Segment& seg) {
- io.mapRequired("name", seg.name);
- io.mapRequired("address", seg.address);
- io.mapRequired("size", seg.size);
- io.mapRequired("access", seg.access);
+ io.mapRequired("name", seg.name);
+ io.mapRequired("address", seg.address);
+ io.mapRequired("size", seg.size);
+ io.mapRequired("init-access", seg.init_access);
+ io.mapRequired("max-access", seg.max_access);
}
};
@@ -524,6 +550,14 @@ struct ScalarEnumerationTraits<LoadCommandType> {
llvm::MachO::LC_LOAD_UPWARD_DYLIB);
io.enumCase(value, "LC_LAZY_LOAD_DYLIB",
llvm::MachO::LC_LAZY_LOAD_DYLIB);
+ io.enumCase(value, "LC_VERSION_MIN_MACOSX",
+ llvm::MachO::LC_VERSION_MIN_MACOSX);
+ io.enumCase(value, "LC_VERSION_MIN_IPHONEOS",
+ llvm::MachO::LC_VERSION_MIN_IPHONEOS);
+ io.enumCase(value, "LC_VERSION_MIN_TVOS",
+ llvm::MachO::LC_VERSION_MIN_TVOS);
+ io.enumCase(value, "LC_VERSION_MIN_WATCHOS",
+ llvm::MachO::LC_VERSION_MIN_WATCHOS);
}
};
@@ -692,6 +726,7 @@ struct MappingTraits<NormalizedFile> {
io.mapOptional("source-version", file.sourceVersion, Hex64(0));
io.mapOptional("OS", file.os);
io.mapOptional("min-os-version", file.minOSverson, PackedVersion(0));
+ io.mapOptional("min-os-version-kind", file.minOSVersionKind, (LoadCommandType)0);
io.mapOptional("sdk-version", file.sdkVersion, PackedVersion(0));
io.mapOptional("segments", file.segments);
io.mapOptional("sections", file.sections);
@@ -731,8 +766,21 @@ bool MachOYamlIOTaggedDocumentHandler::handledDocTag(llvm::yaml::IO &io,
info->_normalizeMachOFile = &nf;
MappingTraits<NormalizedFile>::mapping(io, nf);
// Step 2: parse normalized mach-o struct into atoms.
- ErrorOr<std::unique_ptr<lld::File>> foe = normalizedToAtoms(nf, info->_path,
- true);
+ auto fileOrError = normalizedToAtoms(nf, info->_path, true);
+
+ // Check that we parsed successfully.
+ if (!fileOrError) {
+ std::string buffer;
+ llvm::raw_string_ostream stream(buffer);
+ handleAllErrors(fileOrError.takeError(),
+ [&](const llvm::ErrorInfoBase &EI) {
+ EI.log(stream);
+ stream << "\n";
+ });
+ io.setError(stream.str());
+ return false;
+ }
+
if (nf.arch != _arch) {
io.setError(Twine("file is wrong architecture. Expected ("
+ MachOLinkingContext::nameFromArch(_arch)
@@ -742,16 +790,8 @@ bool MachOYamlIOTaggedDocumentHandler::handledDocTag(llvm::yaml::IO &io,
return false;
}
info->_normalizeMachOFile = nullptr;
-
- if (foe) {
- // Transfer ownership to "out" File parameter.
- std::unique_ptr<lld::File> f = std::move(foe.get());
- file = f.release();
- return true;
- } else {
- io.setError(foe.getError().message());
- return false;
- }
+ file = fileOrError->release();
+ return true;
}
@@ -759,7 +799,7 @@ bool MachOYamlIOTaggedDocumentHandler::handledDocTag(llvm::yaml::IO &io,
namespace normalized {
/// Parses a yaml encoded mach-o file to produce an in-memory normalized view.
-ErrorOr<std::unique_ptr<NormalizedFile>>
+llvm::Expected<std::unique_ptr<NormalizedFile>>
readYaml(std::unique_ptr<MemoryBuffer> &mb) {
// Make empty NormalizedFile.
std::unique_ptr<NormalizedFile> f(new NormalizedFile());
@@ -773,8 +813,9 @@ readYaml(std::unique_ptr<MemoryBuffer> &mb) {
yin >> *f;
// Return error if there were parsing problems.
- if (yin.error())
- return make_error_code(lld::YamlReaderError::illegal_value);
+ if (auto ec = yin.error())
+ return llvm::make_error<GenericError>(Twine("YAML parsing error: ")
+ + ec.message());
// Hand ownership of instantiated NormalizedFile to caller.
return std::move(f);
diff --git a/lib/ReaderWriter/MachO/MachOPasses.h b/lib/ReaderWriter/MachO/MachOPasses.h
index a73785418d5f..cd01d4aa2c93 100644
--- a/lib/ReaderWriter/MachO/MachOPasses.h
+++ b/lib/ReaderWriter/MachO/MachOPasses.h
@@ -21,6 +21,7 @@ void addStubsPass(PassManager &pm, const MachOLinkingContext &ctx);
void addGOTPass(PassManager &pm, const MachOLinkingContext &ctx);
void addTLVPass(PassManager &pm, const MachOLinkingContext &ctx);
void addCompactUnwindPass(PassManager &pm, const MachOLinkingContext &ctx);
+void addObjCPass(PassManager &pm, const MachOLinkingContext &ctx);
void addShimPass(PassManager &pm, const MachOLinkingContext &ctx);
} // namespace mach_o
diff --git a/lib/ReaderWriter/MachO/ObjCPass.cpp b/lib/ReaderWriter/MachO/ObjCPass.cpp
new file mode 100644
index 000000000000..ba24b3fecdf4
--- /dev/null
+++ b/lib/ReaderWriter/MachO/ObjCPass.cpp
@@ -0,0 +1,128 @@
+//===- lib/ReaderWriter/MachO/ObjCPass.cpp -------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachOPasses.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+
+namespace lld {
+namespace mach_o {
+
+///
+/// ObjC Image Info Atom created by the ObjC pass.
+///
+class ObjCImageInfoAtom : public SimpleDefinedAtom {
+public:
+ ObjCImageInfoAtom(const File &file,
+ MachOLinkingContext::ObjCConstraint objCConstraint,
+ uint32_t swiftVersion)
+ : SimpleDefinedAtom(file) {
+
+ Data.info.version = 0;
+
+ switch (objCConstraint) {
+ case MachOLinkingContext::objc_unknown:
+ llvm_unreachable("Shouldn't run the objc pass without a constraint");
+ case MachOLinkingContext::objc_supports_gc:
+ case MachOLinkingContext::objc_gc_only:
+ llvm_unreachable("GC is not supported");
+ case MachOLinkingContext::objc_retainReleaseForSimulator:
+ // The retain/release for simulator flag is already the correct
+ // encoded value for the data so just set it here.
+ Data.info.flags = (uint32_t)objCConstraint;
+ break;
+ case MachOLinkingContext::objc_retainRelease:
+ // We don't need to encode this flag, so just leave the flags as 0.
+ Data.info.flags = 0;
+ break;
+ }
+
+ Data.info.flags |= (swiftVersion << 8);
+ }
+
+ ~ObjCImageInfoAtom() override = default;
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeObjCImageInfo;
+ }
+
+ Alignment alignment() const override {
+ return 4;
+ }
+
+ uint64_t size() const override {
+ return 8;
+ }
+
+ ContentPermissions permissions() const override {
+ return DefinedAtom::permR__;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(Data.bytes, size());
+ }
+
+private:
+
+ struct objc_image_info {
+ uint32_t version;
+ uint32_t flags;
+ };
+
+ union {
+ objc_image_info info;
+ uint8_t bytes[8];
+ } Data;
+};
+
+class ObjCPass : public Pass {
+public:
+ ObjCPass(const MachOLinkingContext &context)
+ : _ctx(context),
+ _file(*_ctx.make_file<MachOFile>("<mach-o objc pass>")) {
+ _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ }
+
+ llvm::Error perform(SimpleFile &mergedFile) override {
+ // Add the image info.
+ mergedFile.addAtom(*getImageInfo());
+
+ return llvm::Error();
+ }
+
+private:
+
+ const DefinedAtom* getImageInfo() {
+ return new (_file.allocator()) ObjCImageInfoAtom(_file,
+ _ctx.objcConstraint(),
+ _ctx.swiftVersion());
+ }
+
+ const MachOLinkingContext &_ctx;
+ MachOFile &_file;
+};
+
+
+
+void addObjCPass(PassManager &pm, const MachOLinkingContext &ctx) {
+ pm.add(llvm::make_unique<ObjCPass>(ctx));
+}
+
+} // end namespace mach_o
+} // end namespace lld
diff --git a/lib/ReaderWriter/MachO/SectCreateFile.h b/lib/ReaderWriter/MachO/SectCreateFile.h
index 2e6e97c5433f..49e65f63151d 100644
--- a/lib/ReaderWriter/MachO/SectCreateFile.h
+++ b/lib/ReaderWriter/MachO/SectCreateFile.h
@@ -31,6 +31,8 @@ public:
_combinedName((segName + "/" + sectName).str()),
_content(std::move(content)) {}
+ ~SectCreateAtom() override = default;
+
uint64_t size() const override { return _content->getBufferSize(); }
Scope scope() const override { return scopeGlobal; }
@@ -59,7 +61,7 @@ public:
std::unique_ptr<MemoryBuffer> _content;
};
- SectCreateFile() : File("sectcreate", kindObject) {}
+ SectCreateFile() : File("sectcreate", kindSectCreateObject) {}
void addSection(StringRef seg, StringRef sect,
std::unique_ptr<MemoryBuffer> content) {
@@ -67,22 +69,29 @@ public:
new (allocator()) SectCreateAtom(*this, seg, sect, std::move(content)));
}
- const AtomVector<DefinedAtom> &defined() const override {
+ const AtomRange<DefinedAtom> defined() const override {
return _definedAtoms;
}
- const AtomVector<UndefinedAtom> &undefined() const override {
+ const AtomRange<UndefinedAtom> undefined() const override {
return _noUndefinedAtoms;
}
- const AtomVector<SharedLibraryAtom> &sharedLibrary() const override {
+ const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
return _noSharedLibraryAtoms;
}
- const AtomVector<AbsoluteAtom> &absolute() const override {
+ const AtomRange<AbsoluteAtom> absolute() const override {
return _noAbsoluteAtoms;
}
+ void clearAtoms() override {
+ _definedAtoms.clear();
+ _noUndefinedAtoms.clear();
+ _noSharedLibraryAtoms.clear();
+ _noAbsoluteAtoms.clear();
+ }
+
private:
AtomVector<DefinedAtom> _definedAtoms;
};
diff --git a/lib/ReaderWriter/MachO/ShimPass.cpp b/lib/ReaderWriter/MachO/ShimPass.cpp
index df29e37c183b..cd5367146658 100644
--- a/lib/ReaderWriter/MachO/ShimPass.cpp
+++ b/lib/ReaderWriter/MachO/ShimPass.cpp
@@ -42,9 +42,12 @@ class ShimPass : public Pass {
public:
ShimPass(const MachOLinkingContext &context)
: _ctx(context), _archHandler(_ctx.archHandler()),
- _stubInfo(_archHandler.stubInfo()), _file("<mach-o shim pass>") {}
+ _stubInfo(_archHandler.stubInfo()),
+ _file(*_ctx.make_file<MachOFile>("<mach-o shim pass>")) {
+ _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ }
- std::error_code perform(SimpleFile &mergedFile) override {
+ llvm::Error perform(SimpleFile &mergedFile) override {
// Scan all references in all atoms.
for (const DefinedAtom *atom : mergedFile.defined()) {
for (const Reference *ref : *atom) {
@@ -63,7 +66,7 @@ public:
}
// Exit early if no shims needed.
if (_targetToShim.empty())
- return std::error_code();
+ return llvm::Error();
// Sort shim atoms so the layout order is stable.
std::vector<const DefinedAtom *> shims;
@@ -80,7 +83,7 @@ public:
for (const DefinedAtom *shim : shims)
mergedFile.addAtom(*shim);
- return std::error_code();
+ return llvm::Error();
}
private:
@@ -112,7 +115,7 @@ private:
const MachOLinkingContext &_ctx;
mach_o::ArchHandler &_archHandler;
const ArchHandler::StubInfo &_stubInfo;
- MachOFile _file;
+ MachOFile &_file;
llvm::DenseMap<const Atom*, const DefinedAtom*> _targetToShim;
};
diff --git a/lib/ReaderWriter/MachO/StubsPass.cpp b/lib/ReaderWriter/MachO/StubsPass.cpp
index 1f61256a5b79..d53b78b24d14 100644
--- a/lib/ReaderWriter/MachO/StubsPass.cpp
+++ b/lib/ReaderWriter/MachO/StubsPass.cpp
@@ -37,6 +37,8 @@ public:
LazyPointerAtom(const File &file, bool is64)
: SimpleDefinedAtom(file), _is64(is64) { }
+ ~LazyPointerAtom() override = default;
+
ContentType contentType() const override {
return DefinedAtom::typeLazyPointer;
}
@@ -68,11 +70,13 @@ private:
//
class NonLazyPointerAtom : public SimpleDefinedAtom {
public:
- NonLazyPointerAtom(const File &file, bool is64)
- : SimpleDefinedAtom(file), _is64(is64) { }
+ NonLazyPointerAtom(const File &file, bool is64, ContentType contentType)
+ : SimpleDefinedAtom(file), _is64(is64), _contentType(contentType) { }
+
+ ~NonLazyPointerAtom() override = default;
ContentType contentType() const override {
- return DefinedAtom::typeGOT;
+ return _contentType;
}
Alignment alignment() const override {
@@ -95,6 +99,7 @@ public:
private:
const bool _is64;
+ const ContentType _contentType;
};
//
@@ -105,6 +110,8 @@ public:
StubAtom(const File &file, const ArchHandler::StubInfo &stubInfo)
: SimpleDefinedAtom(file), _stubInfo(stubInfo){ }
+ ~StubAtom() override = default;
+
ContentType contentType() const override {
return DefinedAtom::typeStub;
}
@@ -137,6 +144,8 @@ public:
StubHelperAtom(const File &file, const ArchHandler::StubInfo &stubInfo)
: SimpleDefinedAtom(file), _stubInfo(stubInfo) { }
+ ~StubHelperAtom() override = default;
+
ContentType contentType() const override {
return DefinedAtom::typeStubHelper;
}
@@ -170,12 +179,14 @@ public:
StubHelperCommonAtom(const File &file, const ArchHandler::StubInfo &stubInfo)
: SimpleDefinedAtom(file), _stubInfo(stubInfo) { }
+ ~StubHelperCommonAtom() override = default;
+
ContentType contentType() const override {
return DefinedAtom::typeStubHelper;
}
Alignment alignment() const override {
- return 1 << _stubInfo.codeAlignment;
+ return 1 << _stubInfo.stubHelperCommonAlignment;
}
uint64_t size() const override {
@@ -199,12 +210,15 @@ class StubsPass : public Pass {
public:
StubsPass(const MachOLinkingContext &context)
: _ctx(context), _archHandler(_ctx.archHandler()),
- _stubInfo(_archHandler.stubInfo()), _file("<mach-o Stubs pass>") {}
+ _stubInfo(_archHandler.stubInfo()),
+ _file(*_ctx.make_file<MachOFile>("<mach-o Stubs pass>")) {
+ _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ }
- std::error_code perform(SimpleFile &mergedFile) override {
+ llvm::Error perform(SimpleFile &mergedFile) override {
// Skip this pass if output format uses text relocations instead of stubs.
if (!this->noTextRelocs())
- return std::error_code();
+ return llvm::Error();
// Scan all references in all atoms.
for (const DefinedAtom *atom : mergedFile.defined()) {
@@ -231,15 +245,17 @@ public:
// Exit early if no stubs needed.
if (_targetToUses.empty())
- return std::error_code();
+ return llvm::Error();
// First add help-common and GOT slots used by lazy binding.
SimpleDefinedAtom *helperCommonAtom =
new (_file.allocator()) StubHelperCommonAtom(_file, _stubInfo);
SimpleDefinedAtom *helperCacheNLPAtom =
- new (_file.allocator()) NonLazyPointerAtom(_file, _ctx.is64Bit());
+ new (_file.allocator()) NonLazyPointerAtom(_file, _ctx.is64Bit(),
+ _stubInfo.stubHelperImageCacheContentType);
SimpleDefinedAtom *helperBinderNLPAtom =
- new (_file.allocator()) NonLazyPointerAtom(_file, _ctx.is64Bit());
+ new (_file.allocator()) NonLazyPointerAtom(_file, _ctx.is64Bit(),
+ _stubInfo.stubHelperImageCacheContentType);
addReference(helperCommonAtom, _stubInfo.stubHelperCommonReferenceToCache,
helperCacheNLPAtom);
addOptReference(
@@ -307,7 +323,7 @@ public:
lazyOffset += target->name().size() + 12;
}
- return std::error_code();
+ return llvm::Error();
}
private:
@@ -351,7 +367,7 @@ private:
const MachOLinkingContext &_ctx;
mach_o::ArchHandler &_archHandler;
const ArchHandler::StubInfo &_stubInfo;
- MachOFile _file;
+ MachOFile &_file;
TargetToUses _targetToUses;
};
diff --git a/lib/ReaderWriter/MachO/TLVPass.cpp b/lib/ReaderWriter/MachO/TLVPass.cpp
index aba222edcd27..7a8496c20a4e 100644
--- a/lib/ReaderWriter/MachO/TLVPass.cpp
+++ b/lib/ReaderWriter/MachO/TLVPass.cpp
@@ -30,6 +30,8 @@ public:
TLVPEntryAtom(const File &file, bool is64, StringRef name)
: SimpleDefinedAtom(file), _is64(is64), _name(name) {}
+ ~TLVPEntryAtom() override = default;
+
ContentType contentType() const override {
return DefinedAtom::typeTLVInitializerPtr;
}
@@ -65,10 +67,12 @@ class TLVPass : public Pass {
public:
TLVPass(const MachOLinkingContext &context)
: _ctx(context), _archHandler(_ctx.archHandler()),
- _file("<mach-o TLV Pass>") {}
+ _file(*_ctx.make_file<MachOFile>("<mach-o TLV pass>")) {
+ _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ }
private:
- std::error_code perform(SimpleFile &mergedFile) override {
+ llvm::Error perform(SimpleFile &mergedFile) override {
bool allowTLV = _ctx.minOS("10.7", "1.0");
for (const DefinedAtom *atom : mergedFile.defined()) {
@@ -77,7 +81,7 @@ private:
continue;
if (!allowTLV)
- return make_dynamic_error_code(
+ return llvm::make_error<GenericError>(
"targeted OS version does not support use of thread local "
"variables in " + atom->name() + " for architecture " +
_ctx.archName());
@@ -103,7 +107,7 @@ private:
for (const TLVPEntryAtom *slot : entries)
mergedFile.addAtom(*slot);
- return std::error_code();
+ return llvm::Error();
}
const DefinedAtom *makeTLVPEntry(const Atom *target) {
@@ -124,7 +128,7 @@ private:
const MachOLinkingContext &_ctx;
mach_o::ArchHandler &_archHandler;
- MachOFile _file;
+ MachOFile &_file;
llvm::DenseMap<const Atom*, const TLVPEntryAtom*> _targetToTLVP;
};
diff --git a/lib/ReaderWriter/MachO/WriterMachO.cpp b/lib/ReaderWriter/MachO/WriterMachO.cpp
index cce0a179608c..f08487f21ac1 100644
--- a/lib/ReaderWriter/MachO/WriterMachO.cpp
+++ b/lib/ReaderWriter/MachO/WriterMachO.cpp
@@ -28,17 +28,18 @@ class MachOWriter : public Writer {
public:
MachOWriter(const MachOLinkingContext &ctxt) : _ctx(ctxt) {}
- std::error_code writeFile(const lld::File &file, StringRef path) override {
+ llvm::Error writeFile(const lld::File &file, StringRef path) override {
// Construct empty normalized file from atoms.
- ErrorOr<std::unique_ptr<NormalizedFile>> nFile =
+ llvm::Expected<std::unique_ptr<NormalizedFile>> nFile =
normalized::normalizedFromAtoms(file, _ctx);
- if (std::error_code ec = nFile.getError())
+ if (auto ec = nFile.takeError())
return ec;
// For testing, write out yaml form of normalized file.
if (_ctx.printAtoms()) {
std::unique_ptr<Writer> yamlWriter = createWriterYAML(_ctx);
- yamlWriter->writeFile(file, "-");
+ if (auto ec = yamlWriter->writeFile(file, "-"))
+ return ec;
}
// Write normalized file as mach-o binary.