aboutsummaryrefslogtreecommitdiff
path: root/lld/MachO
diff options
context:
space:
mode:
Diffstat (limited to 'lld/MachO')
-rw-r--r--lld/MachO/Arch/ARM.cpp36
-rw-r--r--lld/MachO/Arch/ARM64.cpp208
-rw-r--r--lld/MachO/Arch/ARM64Common.cpp18
-rw-r--r--lld/MachO/Arch/ARM64Common.h3
-rw-r--r--lld/MachO/Arch/X86_64.cpp23
-rw-r--r--lld/MachO/Config.h3
-rw-r--r--lld/MachO/Driver.cpp1
-rw-r--r--lld/MachO/InputFiles.cpp75
-rw-r--r--lld/MachO/InputFiles.h1
-rw-r--r--lld/MachO/InputSection.cpp6
-rw-r--r--lld/MachO/SymbolTable.cpp4
-rw-r--r--lld/MachO/Target.h9
-rw-r--r--lld/MachO/UnwindInfoSection.cpp2
13 files changed, 323 insertions, 66 deletions
diff --git a/lld/MachO/Arch/ARM.cpp b/lld/MachO/Arch/ARM.cpp
index 7de0837fcf38..fd215ed99b59 100644
--- a/lld/MachO/Arch/ARM.cpp
+++ b/lld/MachO/Arch/ARM.cpp
@@ -40,6 +40,9 @@ struct ARM : TargetInfo {
void relaxGotLoad(uint8_t *loc, uint8_t type) const override;
const RelocAttrs &getRelocAttrs(uint8_t type) const override;
uint64_t getPageSize() const override { return 4 * 1024; }
+
+ void handleDtraceReloc(const Symbol *sym, const Reloc &r,
+ uint8_t *loc) const override;
};
} // namespace
@@ -170,3 +173,36 @@ TargetInfo *macho::createARMTargetInfo(uint32_t cpuSubtype) {
static ARM t(cpuSubtype);
return &t;
}
+
+void ARM::handleDtraceReloc(const Symbol *sym, const Reloc &r,
+ uint8_t *loc) const {
+ if (config->outputType == MH_OBJECT)
+ return;
+
+ switch (r.type) {
+ case ARM_RELOC_BR24:
+ if (sym->getName().startswith("___dtrace_probe")) {
+ // change call site to a NOP
+ write32le(loc, 0xE1A00000);
+ } else if (sym->getName().startswith("___dtrace_isenabled")) {
+ // change call site to 'eor r0, r0, r0'
+ write32le(loc, 0xE0200000);
+ } else {
+ error("Unrecognized dtrace symbol prefix: " + toString(*sym));
+ }
+ break;
+ case ARM_THUMB_RELOC_BR22:
+ if (sym->getName().startswith("___dtrace_probe")) {
+ // change 32-bit blx call site to two thumb NOPs
+ write32le(loc, 0x46C046C0);
+ } else if (sym->getName().startswith("___dtrace_isenabled")) {
+ // change 32-bit blx call site to 'nop', 'eor r0, r0'
+ write32le(loc, 0x46C04040);
+ } else {
+ error("Unrecognized dtrace symbol prefix: " + toString(*sym));
+ }
+ break;
+ default:
+ llvm_unreachable("Unsupported dtrace relocation type for ARM");
+ }
+}
diff --git a/lld/MachO/Arch/ARM64.cpp b/lld/MachO/Arch/ARM64.cpp
index 7064df5793aa..5901a9e09b35 100644
--- a/lld/MachO/Arch/ARM64.cpp
+++ b/lld/MachO/Arch/ARM64.cpp
@@ -168,10 +168,10 @@ enum ExtendType { ZeroExtend = 1, Sign64 = 2, Sign32 = 3 };
struct Ldr {
uint8_t destRegister;
uint8_t baseRegister;
- uint8_t size;
+ uint8_t p2Size;
bool isFloat;
ExtendType extendType;
- uint64_t offset;
+ int64_t offset;
};
struct PerformedReloc {
@@ -189,6 +189,8 @@ public:
void applyAdrpAdd(const OptimizationHint &);
void applyAdrpAdrp(const OptimizationHint &);
void applyAdrpLdr(const OptimizationHint &);
+ void applyAdrpLdrGot(const OptimizationHint &);
+ void applyAdrpLdrGotLdr(const OptimizationHint &);
private:
uint8_t *buf;
@@ -227,34 +229,35 @@ static bool parseLdr(uint32_t insn, Ldr &ldr) {
if ((insn & 0x3fc00000) == 0x39400000) {
// LDR (immediate), LDRB (immediate), LDRH (immediate)
- ldr.size = 1 << size;
+ ldr.p2Size = size;
ldr.extendType = ZeroExtend;
ldr.isFloat = false;
} else if ((insn & 0x3f800000) == 0x39800000) {
// LDRSB (immediate), LDRSH (immediate), LDRSW (immediate)
- ldr.size = 1 << size;
+ ldr.p2Size = size;
ldr.extendType = static_cast<ExtendType>(opc);
ldr.isFloat = false;
} else if ((insn & 0x3f400000) == 0x3d400000) {
// LDR (immediate, SIMD&FP)
ldr.extendType = ZeroExtend;
ldr.isFloat = true;
- if (size == 2 && opc == 1)
- ldr.size = 4;
- else if (size == 3 && opc == 1)
- ldr.size = 8;
+ if (opc == 1)
+ ldr.p2Size = size;
else if (size == 0 && opc == 3)
- ldr.size = 16;
+ ldr.p2Size = 4;
else
return false;
} else {
return false;
}
- ldr.offset = ((insn >> 10) & 0xfff) * ldr.size;
+ ldr.offset = ((insn >> 10) & 0xfff) << ldr.p2Size;
return true;
}
+static bool isValidAdrOffset(int32_t delta) { return isInt<21>(delta); }
+
static void writeAdr(void *loc, uint32_t dest, int32_t delta) {
+ assert(isValidAdrOffset(delta));
uint32_t opcode = 0x10000000;
uint32_t immHi = (delta & 0x001ffffc) << 3;
uint32_t immLo = (delta & 0x00000003) << 29;
@@ -263,26 +266,63 @@ static void writeAdr(void *loc, uint32_t dest, int32_t delta) {
static void writeNop(void *loc) { write32le(loc, 0xd503201f); }
-static void writeLiteralLdr(void *loc, Ldr original, int32_t delta) {
- uint32_t imm19 = (delta & 0x001ffffc) << 3;
- uint32_t opcode = 0;
- switch (original.size) {
- case 4:
- if (original.isFloat)
+static bool isLiteralLdrEligible(const Ldr &ldr) {
+ return ldr.p2Size > 1 && isShiftedInt<19, 2>(ldr.offset);
+}
+
+static void writeLiteralLdr(void *loc, const Ldr &ldr) {
+ assert(isLiteralLdrEligible(ldr));
+ uint32_t imm19 = (ldr.offset / 4 & maskTrailingOnes<uint32_t>(19)) << 5;
+ uint32_t opcode;
+ switch (ldr.p2Size) {
+ case 2:
+ if (ldr.isFloat)
opcode = 0x1c000000;
else
- opcode = original.extendType == Sign64 ? 0x98000000 : 0x18000000;
+ opcode = ldr.extendType == Sign64 ? 0x98000000 : 0x18000000;
break;
- case 8:
- opcode = original.isFloat ? 0x5c000000 : 0x58000000;
+ case 3:
+ opcode = ldr.isFloat ? 0x5c000000 : 0x58000000;
break;
- case 16:
+ case 4:
opcode = 0x9c000000;
break;
default:
- assert(false && "Invalid size for literal ldr");
+ llvm_unreachable("Invalid literal ldr size");
+ }
+ write32le(loc, opcode | imm19 | ldr.destRegister);
+}
+
+static bool isImmediateLdrEligible(const Ldr &ldr) {
+ // Note: We deviate from ld64's behavior, which converts to immediate loads
+ // only if ldr.offset < 4096, even though the offset is divided by the load's
+ // size in the 12-bit immediate operand. Only the unsigned offset variant is
+ // supported.
+
+ uint32_t size = 1 << ldr.p2Size;
+ return ldr.offset >= 0 && (ldr.offset % size) == 0 &&
+ isUInt<12>(ldr.offset >> ldr.p2Size);
+}
+
+static void writeImmediateLdr(void *loc, const Ldr &ldr) {
+ assert(isImmediateLdrEligible(ldr));
+ uint32_t opcode = 0x39000000;
+ if (ldr.isFloat) {
+ opcode |= 0x04000000;
+ assert(ldr.extendType == ZeroExtend);
}
- write32le(loc, opcode | imm19 | original.destRegister);
+ opcode |= ldr.destRegister;
+ opcode |= ldr.baseRegister << 5;
+ uint8_t size, opc;
+ if (ldr.p2Size == 4) {
+ size = 0;
+ opc = 3;
+ } else {
+ opc = ldr.extendType;
+ size = ldr.p2Size;
+ }
+ uint32_t immBits = ldr.offset >> ldr.p2Size;
+ write32le(loc, opcode | (immBits << 10) | (opc << 22) | (size << 30));
}
uint64_t OptimizationHintContext::getRelocTarget(const Reloc &reloc) {
@@ -351,7 +391,7 @@ void OptimizationHintContext::applyAdrpAdd(const OptimizationHint &hint) {
if (rel1->referentVA != rel2->referentVA)
return;
int64_t delta = rel1->referentVA - rel1->rel.offset - isec->getVA();
- if (delta >= (1 << 20) || delta < -(1 << 20))
+ if (!isValidAdrOffset(delta))
return;
writeAdr(buf + hint.offset0, add.destRegister, delta);
@@ -412,16 +452,120 @@ void OptimizationHintContext::applyAdrpLdr(const OptimizationHint &hint) {
return;
if (ldr.offset != (rel1->referentVA & 0xfff))
return;
- if ((rel1->referentVA & 3) != 0)
+ ldr.offset = rel1->referentVA - rel2->rel.offset - isec->getVA();
+ if (!isLiteralLdrEligible(ldr))
+ return;
+
+ writeNop(buf + hint.offset0);
+ writeLiteralLdr(buf + hint.offset0 + hint.delta[0], ldr);
+}
+
+// GOT loads are emitted by the compiler as a pair of adrp and ldr instructions,
+// but they may be changed to adrp+add by relaxGotLoad(). This hint performs
+// the AdrpLdr or AdrpAdd transformation depending on whether it was relaxed.
+void OptimizationHintContext::applyAdrpLdrGot(const OptimizationHint &hint) {
+ uint32_t ins2 = read32le(buf + hint.offset0 + hint.delta[0]);
+ Add add;
+ Ldr ldr;
+ if (parseAdd(ins2, add))
+ applyAdrpAdd(hint);
+ else if (parseLdr(ins2, ldr))
+ applyAdrpLdr(hint);
+}
+
+// Relaxes a GOT-indirect load.
+// If the referenced symbol is external and its GOT entry is within +/- 1 MiB,
+// the GOT entry can be loaded with a single literal ldr instruction.
+// If the referenced symbol is local, its address may be loaded directly if it's
+// close enough, or with an adr(p) + ldr pair if it's not.
+void OptimizationHintContext::applyAdrpLdrGotLdr(const OptimizationHint &hint) {
+ uint32_t ins1 = read32le(buf + hint.offset0);
+ Adrp adrp;
+ if (!parseAdrp(ins1, adrp))
return;
- if (ldr.size == 1 || ldr.size == 2)
+ uint32_t ins3 = read32le(buf + hint.offset0 + hint.delta[1]);
+ Ldr ldr3;
+ if (!parseLdr(ins3, ldr3))
return;
- int64_t delta = rel1->referentVA - rel2->rel.offset - isec->getVA();
- if (delta >= (1 << 20) || delta < -(1 << 20))
+ uint32_t ins2 = read32le(buf + hint.offset0 + hint.delta[0]);
+ Ldr ldr2;
+ Add add2;
+
+ Optional<PerformedReloc> rel1 = findPrimaryReloc(hint.offset0);
+ Optional<PerformedReloc> rel2 = findReloc(hint.offset0 + hint.delta[0]);
+ if (!rel1 || !rel2)
return;
- writeNop(buf + hint.offset0);
- writeLiteralLdr(buf + hint.offset0 + hint.delta[0], ldr, delta);
+ if (parseAdd(ins2, add2)) {
+ // adrp x0, _foo@PAGE
+ // add x1, x0, _foo@PAGEOFF
+ // ldr x2, [x1, #off]
+
+ if (adrp.destRegister != add2.srcRegister)
+ return;
+ if (add2.destRegister != ldr3.baseRegister)
+ return;
+
+ // Load from the target address directly.
+ // nop
+ // nop
+ // ldr x2, [_foo + #off]
+ uint64_t rel3VA = hint.offset0 + hint.delta[1] + isec->getVA();
+ Ldr literalLdr = ldr3;
+ literalLdr.offset += rel1->referentVA - rel3VA;
+ if (isLiteralLdrEligible(literalLdr)) {
+ writeNop(buf + hint.offset0);
+ writeNop(buf + hint.offset0 + hint.delta[0]);
+ writeLiteralLdr(buf + hint.offset0 + hint.delta[1], literalLdr);
+ return;
+ }
+
+ // Load the target address into a register and load from there indirectly.
+ // adr x1, _foo
+ // nop
+ // ldr x2, [x1, #off]
+ int64_t adrOffset = rel1->referentVA - rel1->rel.offset - isec->getVA();
+ if (isValidAdrOffset(adrOffset)) {
+ writeAdr(buf + hint.offset0, ldr3.baseRegister, adrOffset);
+ writeNop(buf + hint.offset0 + hint.delta[0]);
+ return;
+ }
+
+ // Move the target's page offset into the ldr's immediate offset.
+ // adrp x0, _foo@PAGE
+ // nop
+ // ldr x2, [x0, _foo@PAGEOFF + #off]
+ Ldr immediateLdr = ldr3;
+ immediateLdr.baseRegister = adrp.destRegister;
+ immediateLdr.offset += add2.addend;
+ if (isImmediateLdrEligible(immediateLdr)) {
+ writeNop(buf + hint.offset0 + hint.delta[0]);
+ writeImmediateLdr(buf + hint.offset0 + hint.delta[1], immediateLdr);
+ return;
+ }
+ } else if (parseLdr(ins2, ldr2)) {
+ // adrp x1, _foo@GOTPAGE
+ // ldr x2, [x1, _foo@GOTPAGEOFF]
+ // ldr x3, [x2, #off]
+ if (ldr2.baseRegister != adrp.destRegister)
+ return;
+ if (ldr3.baseRegister != ldr2.destRegister)
+ return;
+ // Loads from the GOT must be pointer sized.
+ if (ldr2.p2Size != 3 || ldr2.isFloat)
+ return;
+
+ // Load the GOT entry's address directly.
+ // nop
+ // ldr x2, _foo@GOTPAGE + _foo@GOTPAGEOFF
+ // ldr x3, [x2, #off]
+ Ldr literalLdr = ldr2;
+ literalLdr.offset = rel1->referentVA - rel2->rel.offset - isec->getVA();
+ if (isLiteralLdrEligible(literalLdr)) {
+ writeNop(buf + hint.offset0);
+ writeLiteralLdr(buf + hint.offset0 + hint.delta[0], literalLdr);
+ }
+ }
}
void ARM64::applyOptimizationHints(uint8_t *buf, const ConcatInputSection *isec,
@@ -443,7 +587,11 @@ void ARM64::applyOptimizationHints(uint8_t *buf, const ConcatInputSection *isec,
ctx1.applyAdrpLdr(hint);
break;
case LOH_ARM64_ADRP_ADD_LDR:
+ // TODO: Implement this
+ break;
case LOH_ARM64_ADRP_LDR_GOT_LDR:
+ ctx1.applyAdrpLdrGotLdr(hint);
+ break;
case LOH_ARM64_ADRP_ADD_STR:
case LOH_ARM64_ADRP_LDR_GOT_STR:
// TODO: Implement these
@@ -452,7 +600,7 @@ void ARM64::applyOptimizationHints(uint8_t *buf, const ConcatInputSection *isec,
ctx1.applyAdrpAdd(hint);
break;
case LOH_ARM64_ADRP_LDR_GOT:
- // TODO: Implement this as well
+ ctx1.applyAdrpLdrGot(hint);
break;
}
}
diff --git a/lld/MachO/Arch/ARM64Common.cpp b/lld/MachO/Arch/ARM64Common.cpp
index f55258ce8ec9..27fdf4ba14d9 100644
--- a/lld/MachO/Arch/ARM64Common.cpp
+++ b/lld/MachO/Arch/ARM64Common.cpp
@@ -109,3 +109,21 @@ void ARM64Common::relaxGotLoad(uint8_t *loc, uint8_t type) const {
instruction = ((instruction & 0x001fffff) | 0x91000000);
write32le(loc, instruction);
}
+
+void ARM64Common::handleDtraceReloc(const Symbol *sym, const Reloc &r,
+ uint8_t *loc) const {
+ assert(r.type == ARM64_RELOC_BRANCH26);
+
+ if (config->outputType == MH_OBJECT)
+ return;
+
+ if (sym->getName().startswith("___dtrace_probe")) {
+ // change call site to a NOP
+ write32le(loc, 0xD503201F);
+ } else if (sym->getName().startswith("___dtrace_isenabled")) {
+ // change call site to 'MOVZ X0,0'
+ write32le(loc, 0xD2800000);
+ } else {
+ error("Unrecognized dtrace symbol prefix: " + toString(*sym));
+ }
+}
diff --git a/lld/MachO/Arch/ARM64Common.h b/lld/MachO/Arch/ARM64Common.h
index 54f94ee76c06..1bd85066b35a 100644
--- a/lld/MachO/Arch/ARM64Common.h
+++ b/lld/MachO/Arch/ARM64Common.h
@@ -29,6 +29,9 @@ struct ARM64Common : TargetInfo {
void relaxGotLoad(uint8_t *loc, uint8_t type) const override;
uint64_t getPageSize() const override { return 16 * 1024; }
+
+ void handleDtraceReloc(const Symbol *sym, const Reloc &r,
+ uint8_t *loc) const override;
};
inline uint64_t bitField(uint64_t value, int right, int width, int left) {
diff --git a/lld/MachO/Arch/X86_64.cpp b/lld/MachO/Arch/X86_64.cpp
index d675356b9ffb..d2efa5bb3451 100644
--- a/lld/MachO/Arch/X86_64.cpp
+++ b/lld/MachO/Arch/X86_64.cpp
@@ -39,6 +39,9 @@ struct X86_64 : TargetInfo {
void relaxGotLoad(uint8_t *loc, uint8_t type) const override;
const RelocAttrs &getRelocAttrs(uint8_t type) const override;
uint64_t getPageSize() const override { return 4 * 1024; }
+
+ void handleDtraceReloc(const Symbol *sym, const Reloc &r,
+ uint8_t *loc) const override;
};
} // namespace
@@ -199,3 +202,23 @@ TargetInfo *macho::createX86_64TargetInfo() {
static X86_64 t;
return &t;
}
+
+void X86_64::handleDtraceReloc(const Symbol *sym, const Reloc &r,
+ uint8_t *loc) const {
+ assert(r.type == X86_64_RELOC_BRANCH);
+
+ if (config->outputType == MH_OBJECT)
+ return;
+
+ if (sym->getName().startswith("___dtrace_probe")) {
+ // change call site to a NOP
+ loc[-1] = 0x90;
+ write32le(loc, 0x00401F0F);
+ } else if (sym->getName().startswith("___dtrace_isenabled")) {
+ // change call site to a clear eax
+ loc[-1] = 0x33;
+ write32le(loc, 0x909090C0);
+ } else {
+ error("Unrecognized dtrace symbol prefix: " + toString(*sym));
+ }
+}
diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h
index b6c6abb44c65..ccf71b6535ea 100644
--- a/lld/MachO/Config.h
+++ b/lld/MachO/Config.h
@@ -131,9 +131,6 @@ struct Configuration {
bool omitDebugInfo = false;
bool warnDylibInstallName = false;
bool ignoreOptimizationHints = false;
- // Temporary config flag that will be removed once we have fully implemented
- // support for __eh_frame.
- bool parseEhFrames = false;
uint32_t headerPad;
uint32_t dylibCompatibilityVersion = 0;
uint32_t dylibCurrentVersion = 0;
diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index 708facd180ba..abfe381f41e0 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -1305,7 +1305,6 @@ bool macho::link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
config->callGraphProfileSort = args.hasFlag(
OPT_call_graph_profile_sort, OPT_no_call_graph_profile_sort, true);
config->printSymbolOrder = args.getLastArgValue(OPT_print_symbol_order);
- config->parseEhFrames = static_cast<bool>(getenv("LLD_IN_TEST"));
// FIXME: Add a commandline flag for this too.
config->zeroModTime = getenv("ZERO_AR_DATE");
diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp
index c53874133a78..fda6900edabe 100644
--- a/lld/MachO/InputFiles.cpp
+++ b/lld/MachO/InputFiles.cpp
@@ -347,7 +347,7 @@ void ObjFile::parseSections(ArrayRef<SectionHeader> sectionHeaders) {
section.subsections.push_back({0, isec});
} else if (auto recordSize = getRecordSize(segname, name)) {
splitRecords(*recordSize);
- } else if (config->parseEhFrames && name == section_names::ehFrame &&
+ } else if (name == section_names::ehFrame &&
segname == segment_names::text) {
splitEhFrames(data, *sections.back());
} else if (segname == segment_names::llvm) {
@@ -1117,7 +1117,7 @@ template <class LP> void ObjFile::parse() {
}
if (compactUnwindSection)
registerCompactUnwind(*compactUnwindSection);
- if (config->parseEhFrames && ehFrameSection)
+ if (ehFrameSection)
registerEhFrames(*ehFrameSection);
}
@@ -1687,7 +1687,6 @@ DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella,
umbrella = this;
this->umbrella = umbrella;
- auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
auto *hdr = reinterpret_cast<const mach_header *>(mb.getBufferStart());
// Initialize installName.
@@ -1722,39 +1721,53 @@ DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella,
// Initialize symbols.
exportingFile = isImplicitlyLinked(installName) ? this : this->umbrella;
- if (const load_command *cmd = findCommand(hdr, LC_DYLD_INFO_ONLY)) {
- auto *c = reinterpret_cast<const dyld_info_command *>(cmd);
- struct TrieEntry {
- StringRef name;
- uint64_t flags;
- };
- std::vector<TrieEntry> entries;
- // Find all the $ld$* symbols to process first.
- parseTrie(buf + c->export_off, c->export_size,
- [&](const Twine &name, uint64_t flags) {
- StringRef savedName = saver().save(name);
- if (handleLDSymbol(savedName))
- return;
- entries.push_back({savedName, flags});
- });
+ const auto *dyldInfo = findCommand<dyld_info_command>(hdr, LC_DYLD_INFO_ONLY);
+ const auto *exportsTrie =
+ findCommand<linkedit_data_command>(hdr, LC_DYLD_EXPORTS_TRIE);
+ if (dyldInfo && exportsTrie) {
+ // It's unclear what should happen in this case. Maybe we should only error
+ // out if the two load commands refer to different data?
+ error("dylib " + toString(this) +
+ " has both LC_DYLD_INFO_ONLY and LC_DYLD_EXPORTS_TRIE");
+ return;
+ } else if (dyldInfo) {
+ parseExportedSymbols(dyldInfo->export_off, dyldInfo->export_size);
+ } else if (exportsTrie) {
+ parseExportedSymbols(exportsTrie->dataoff, exportsTrie->datasize);
+ } else {
+ error("No LC_DYLD_INFO_ONLY or LC_DYLD_EXPORTS_TRIE found in " +
+ toString(this));
+ return;
+ }
+}
- // Process the "normal" symbols.
- for (TrieEntry &entry : entries) {
- if (exportingFile->hiddenSymbols.contains(
- CachedHashStringRef(entry.name)))
- continue;
+void DylibFile::parseExportedSymbols(uint32_t offset, uint32_t size) {
+ struct TrieEntry {
+ StringRef name;
+ uint64_t flags;
+ };
- bool isWeakDef = entry.flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
- bool isTlv = entry.flags & EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL;
+ auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
+ std::vector<TrieEntry> entries;
+ // Find all the $ld$* symbols to process first.
+ parseTrie(buf + offset, size, [&](const Twine &name, uint64_t flags) {
+ StringRef savedName = saver().save(name);
+ if (handleLDSymbol(savedName))
+ return;
+ entries.push_back({savedName, flags});
+ });
- symbols.push_back(
- symtab->addDylib(entry.name, exportingFile, isWeakDef, isTlv));
- }
+ // Process the "normal" symbols.
+ for (TrieEntry &entry : entries) {
+ if (exportingFile->hiddenSymbols.contains(CachedHashStringRef(entry.name)))
+ continue;
- } else {
- error("LC_DYLD_INFO_ONLY not found in " + toString(this));
- return;
+ bool isWeakDef = entry.flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
+ bool isTlv = entry.flags & EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL;
+
+ symbols.push_back(
+ symtab->addDylib(entry.name, exportingFile, isWeakDef, isTlv));
}
}
diff --git a/lld/MachO/InputFiles.h b/lld/MachO/InputFiles.h
index 524418b91ee1..efddc1c46782 100644
--- a/lld/MachO/InputFiles.h
+++ b/lld/MachO/InputFiles.h
@@ -250,6 +250,7 @@ private:
void handleLDInstallNameSymbol(StringRef name, StringRef originalName);
void handleLDHideSymbol(StringRef name, StringRef originalName);
void checkAppExtensionSafety(bool dylibIsAppExtensionSafe) const;
+ void parseExportedSymbols(uint32_t offset, uint32_t size);
llvm::DenseSet<llvm::CachedHashStringRef> hiddenSymbols;
};
diff --git a/lld/MachO/InputSection.cpp b/lld/MachO/InputSection.cpp
index 25eb878736d9..df312525df61 100644
--- a/lld/MachO/InputSection.cpp
+++ b/lld/MachO/InputSection.cpp
@@ -201,6 +201,12 @@ void ConcatInputSection::writeTo(uint8_t *buf) {
if (target->hasAttr(r.type, RelocAttrBits::LOAD) &&
!referentSym->isInGot())
target->relaxGotLoad(loc, r.type);
+ // For dtrace symbols, do not handle them as normal undefined symbols
+ if (referentSym->getName().startswith("___dtrace_")) {
+ // Change dtrace call site to pre-defined instructions
+ target->handleDtraceReloc(referentSym, r, loc);
+ continue;
+ }
referentVA = resolveSymbolVA(referentSym, r.type) + r.addend;
if (isThreadLocalVariables(getFlags())) {
diff --git a/lld/MachO/SymbolTable.cpp b/lld/MachO/SymbolTable.cpp
index d309f66c119f..7bda1d13069f 100644
--- a/lld/MachO/SymbolTable.cpp
+++ b/lld/MachO/SymbolTable.cpp
@@ -332,6 +332,10 @@ static bool recoverFromUndefinedSymbol(const Undefined &sym) {
return true;
}
+ // Leave dtrace symbols, since we will handle them when we do the relocation
+ if (name.startswith("___dtrace_"))
+ return true;
+
// Handle -U.
if (config->explicitDynamicLookups.count(sym.getName())) {
symtab->addDynamicLookup(sym.getName());
diff --git a/lld/MachO/Target.h b/lld/MachO/Target.h
index 09ff3c5639ea..597502275dee 100644
--- a/lld/MachO/Target.h
+++ b/lld/MachO/Target.h
@@ -79,6 +79,15 @@ public:
bool usesThunks() const { return thunkSize > 0; }
+ // For now, handleDtraceReloc only implements -no_dtrace_dof, and ensures
+ // that the linking would not fail even when there are user-provided dtrace
+ // symbols. However, unlike ld64, lld currently does not emit __dof sections.
+ virtual void handleDtraceReloc(const Symbol *sym, const Reloc &r,
+ uint8_t *loc) const {
+ llvm_unreachable("Unsupported architecture for dtrace symbols");
+ }
+
+
virtual void applyOptimizationHints(uint8_t *buf, const ConcatInputSection *,
llvm::ArrayRef<uint64_t>) const {};
diff --git a/lld/MachO/UnwindInfoSection.cpp b/lld/MachO/UnwindInfoSection.cpp
index 2c4a469578de..8c3425a17459 100644
--- a/lld/MachO/UnwindInfoSection.cpp
+++ b/lld/MachO/UnwindInfoSection.cpp
@@ -506,7 +506,7 @@ void UnwindInfoSectionImpl::finalize() {
secondLevelPages.emplace_back();
SecondLevelPage &page = secondLevelPages.back();
page.entryIndex = i;
- uintptr_t functionAddressMax =
+ uint64_t functionAddressMax =
cuEntries[idx].functionAddress + COMPRESSED_ENTRY_FUNC_OFFSET_MASK;
size_t n = commonEncodings.size();
size_t wordsRemaining =