Skip to content

Commit 6c641d0

Browse files
PRESIDENT810int3
authored andcommitted
[lld-macho] Handle user-provided dtrace symbols to avoid linking failure
This fixes #56238. ld64.lld currently does not generate __dof section in Mach-O, and -no_dtrace_dof option is on by default. However when there are user-defined dtrace symbols, ld64.lld will treat them as undefined symbols, which causes the linking to fail because lld cannot find their definitions. This patch allows ld64.lld to rewrite the instructions calling dtrace symbols to instructions like nop as what ld64 does; therefore, when encountered with user-provided dtrace probes, the linking can still succeed. I'm not sure whether support for dtrace is expected in lld, so for now I didn't add codes to make lld emit __dof section like ld64, and only made it possible to link with dtrace symbols provided. If this feature is needed, I can add that part in Dtrace.cpp & Dtrace.h. Reviewed By: int3, #lld-macho Differential Revision: https://reviews.llvm.org/D129062
1 parent f18de76 commit 6c641d0

11 files changed

+217
-0
lines changed

lld/MachO/Arch/ARM.cpp

+36
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ struct ARM : TargetInfo {
4040
void relaxGotLoad(uint8_t *loc, uint8_t type) const override;
4141
const RelocAttrs &getRelocAttrs(uint8_t type) const override;
4242
uint64_t getPageSize() const override { return 4 * 1024; }
43+
44+
void handleDtraceReloc(const Symbol *sym, const Reloc &r,
45+
uint8_t *loc) const override;
4346
};
4447

4548
} // namespace
@@ -170,3 +173,36 @@ TargetInfo *macho::createARMTargetInfo(uint32_t cpuSubtype) {
170173
static ARM t(cpuSubtype);
171174
return &t;
172175
}
176+
177+
void ARM::handleDtraceReloc(const Symbol *sym, const Reloc &r,
178+
uint8_t *loc) const {
179+
if (config->outputType == MH_OBJECT)
180+
return;
181+
182+
switch (r.type) {
183+
case ARM_RELOC_BR24:
184+
if (sym->getName().startswith("___dtrace_probe")) {
185+
// change call site to a NOP
186+
write32le(loc, 0xE1A00000);
187+
} else if (sym->getName().startswith("___dtrace_isenabled")) {
188+
// change call site to 'eor r0, r0, r0'
189+
write32le(loc, 0xE0200000);
190+
} else {
191+
error("Unrecognized dtrace symbol prefix: " + toString(*sym));
192+
}
193+
break;
194+
case ARM_THUMB_RELOC_BR22:
195+
if (sym->getName().startswith("___dtrace_probe")) {
196+
// change 32-bit blx call site to two thumb NOPs
197+
write32le(loc, 0x46C046C0);
198+
} else if (sym->getName().startswith("___dtrace_isenabled")) {
199+
// change 32-bit blx call site to 'nop', 'eor r0, r0'
200+
write32le(loc, 0x46C04040);
201+
} else {
202+
error("Unrecognized dtrace symbol prefix: " + toString(*sym));
203+
}
204+
break;
205+
default:
206+
llvm_unreachable("Unsupported dtrace relocation type for ARM");
207+
}
208+
}

lld/MachO/Arch/ARM64Common.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,21 @@ void ARM64Common::relaxGotLoad(uint8_t *loc, uint8_t type) const {
109109
instruction = ((instruction & 0x001fffff) | 0x91000000);
110110
write32le(loc, instruction);
111111
}
112+
113+
void ARM64Common::handleDtraceReloc(const Symbol *sym, const Reloc &r,
114+
uint8_t *loc) const {
115+
assert(r.type == ARM64_RELOC_BRANCH26);
116+
117+
if (config->outputType == MH_OBJECT)
118+
return;
119+
120+
if (sym->getName().startswith("___dtrace_probe")) {
121+
// change call site to a NOP
122+
write32le(loc, 0xD503201F);
123+
} else if (sym->getName().startswith("___dtrace_isenabled")) {
124+
// change call site to 'MOVZ X0,0'
125+
write32le(loc, 0xD2800000);
126+
} else {
127+
error("Unrecognized dtrace symbol prefix: " + toString(*sym));
128+
}
129+
}

lld/MachO/Arch/ARM64Common.h

+3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ struct ARM64Common : TargetInfo {
2929

3030
void relaxGotLoad(uint8_t *loc, uint8_t type) const override;
3131
uint64_t getPageSize() const override { return 16 * 1024; }
32+
33+
void handleDtraceReloc(const Symbol *sym, const Reloc &r,
34+
uint8_t *loc) const override;
3235
};
3336

3437
inline uint64_t bitField(uint64_t value, int right, int width, int left) {

lld/MachO/Arch/X86_64.cpp

+23
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ struct X86_64 : TargetInfo {
3939
void relaxGotLoad(uint8_t *loc, uint8_t type) const override;
4040
const RelocAttrs &getRelocAttrs(uint8_t type) const override;
4141
uint64_t getPageSize() const override { return 4 * 1024; }
42+
43+
void handleDtraceReloc(const Symbol *sym, const Reloc &r,
44+
uint8_t *loc) const override;
4245
};
4346

4447
} // namespace
@@ -199,3 +202,23 @@ TargetInfo *macho::createX86_64TargetInfo() {
199202
static X86_64 t;
200203
return &t;
201204
}
205+
206+
void X86_64::handleDtraceReloc(const Symbol *sym, const Reloc &r,
207+
uint8_t *loc) const {
208+
assert(r.type == X86_64_RELOC_BRANCH);
209+
210+
if (config->outputType == MH_OBJECT)
211+
return;
212+
213+
if (sym->getName().startswith("___dtrace_probe")) {
214+
// change call site to a NOP
215+
loc[-1] = 0x90;
216+
write32le(loc, 0x00401F0F);
217+
} else if (sym->getName().startswith("___dtrace_isenabled")) {
218+
// change call site to a clear eax
219+
loc[-1] = 0x33;
220+
write32le(loc, 0x909090C0);
221+
} else {
222+
error("Unrecognized dtrace symbol prefix: " + toString(*sym));
223+
}
224+
}

lld/MachO/InputSection.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,12 @@ void ConcatInputSection::writeTo(uint8_t *buf) {
201201
if (target->hasAttr(r.type, RelocAttrBits::LOAD) &&
202202
!referentSym->isInGot())
203203
target->relaxGotLoad(loc, r.type);
204+
// For dtrace symbols, do not handle them as normal undefined symbols
205+
if (referentSym->getName().startswith("___dtrace_")) {
206+
// Change dtrace call site to pre-defined instructions
207+
target->handleDtraceReloc(referentSym, r, loc);
208+
continue;
209+
}
204210
referentVA = resolveSymbolVA(referentSym, r.type) + r.addend;
205211

206212
if (isThreadLocalVariables(getFlags())) {

lld/MachO/SymbolTable.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,10 @@ static bool recoverFromUndefinedSymbol(const Undefined &sym) {
332332
return true;
333333
}
334334

335+
// Leave dtrace symbols, since we will handle them when we do the relocation
336+
if (name.startswith("___dtrace_"))
337+
return true;
338+
335339
// Handle -U.
336340
if (config->explicitDynamicLookups.count(sym.getName())) {
337341
symtab->addDynamicLookup(sym.getName());

lld/MachO/Target.h

+9
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,15 @@ class TargetInfo {
7979

8080
bool usesThunks() const { return thunkSize > 0; }
8181

82+
// For now, handleDtraceReloc only implements -no_dtrace_dof, and ensures
83+
// that the linking would not fail even when there are user-provided dtrace
84+
// symbols. However, unlike ld64, lld currently does not emit __dof sections.
85+
virtual void handleDtraceReloc(const Symbol *sym, const Reloc &r,
86+
uint8_t *loc) const {
87+
llvm_unreachable("Unsupported architecture for dtrace symbols");
88+
}
89+
90+
8291
virtual void applyOptimizationHints(uint8_t *buf, const ConcatInputSection *,
8392
llvm::ArrayRef<uint64_t>) const {};
8493

lld/test/MachO/arm-dtrace.s

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# REQUIRES: arm
2+
# RUN: rm -rf %t; split-file %s %t
3+
4+
# RUN: llvm-mc -filetype=obj -triple=armv4t-apple-darwin %t/armv4t-dtrace.s -o %t/armv4t-dtrace.o
5+
# RUN: %lld -arch armv4t -o %t/armv4t-dtrace %t/armv4t-dtrace.o
6+
7+
## If references of dtrace symbols are handled by lld, their relocation should be replaced with the following instructions
8+
# RUN: llvm-objdump --macho -D %t/armv4t-dtrace | FileCheck %s --check-prefix=CHECK-armv4t
9+
10+
# CHECK-armv4t: 00 00 20 e0 eor r0, r0, r0
11+
12+
# CHECK-armv4t: 00 00 a0 e1 mov r0, r0
13+
14+
# RUN: llvm-mc -filetype=obj -triple=thumbv7-apple-darwin %t/armv7-dtrace.s -o %t/armv7-dtrace.o
15+
# RUN: %lld -arch armv7 -o %t/armv7-dtrace %t/armv7-dtrace.o
16+
17+
## If references of dtrace symbols are handled by lld, their relocation should be replaced with the following instructions
18+
# RUN: llvm-objdump --macho -D %t/armv7-dtrace | FileCheck %s --check-prefix=CHECK-armv7
19+
20+
# CHECK-armv7: 40 40 eors r0, r0
21+
# CHECK-armv7-NEXT: c0 46 mov r8, r8
22+
23+
# CHECK-armv7: c0 46 mov r8, r8
24+
# CHECK-armv7-NEXT: c0 46 mov r8, r8
25+
26+
;--- armv4t-dtrace.s
27+
.globl _main
28+
_main:
29+
bl ___dtrace_isenabled$Foo$added$v1
30+
.reference ___dtrace_typedefs$Foo$v2
31+
bl ___dtrace_probe$Foo$added$v1$696e74
32+
.reference ___dtrace_stability$Foo$v1$1_1_0_1_1_0_1_1_0_1_1_0_1_1_0
33+
34+
.subsections_via_symbols
35+
36+
;--- armv7-dtrace.s
37+
.globl _main
38+
.thumb_func _main
39+
_main:
40+
bl ___dtrace_isenabled$Foo$added$v1
41+
.reference ___dtrace_typedefs$Foo$v2
42+
bl ___dtrace_probe$Foo$added$v1$696e74
43+
.reference ___dtrace_stability$Foo$v1$1_1_0_1_1_0_1_1_0_1_1_0_1_1_0
44+
45+
.subsections_via_symbols

lld/test/MachO/arm64-32-dtrace.s

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# REQUIRES: aarch64
2+
# RUN: rm -rf %t; split-file %s %t
3+
4+
# RUN: llvm-mc -filetype=obj -triple=arm64_32-apple-darwin %t/arm64-32-dtrace.s -o %t/arm64-32-dtrace.o
5+
# RUN: %lld -arch arm64_32 -o %t/arm64-32-dtrace %t/arm64-32-dtrace.o
6+
7+
## If references of dtrace symbols are handled by lld, their relocation should be replaced with the following instructions
8+
# RUN: llvm-objdump --macho -D %t/arm64-32-dtrace | FileCheck %s --check-prefix=CHECK
9+
10+
# CHECK: 00 00 80 d2 mov x0, #0
11+
12+
# CHECK: 1f 20 03 d5 nop
13+
14+
#--- arm64-32-dtrace.s
15+
.globl _main
16+
_main:
17+
bl ___dtrace_isenabled$Foo$added$v1
18+
.reference ___dtrace_typedefs$Foo$v2
19+
bl ___dtrace_probe$Foo$added$v1$696e74
20+
.reference ___dtrace_stability$Foo$v1$1_1_0_1_1_0_1_1_0_1_1_0_1_1_0
21+
ret
22+
23+
.subsections_via_symbols

lld/test/MachO/arm64-dtrace.s

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# REQUIRES: aarch64
2+
# RUN: rm -rf %t; split-file %s %t
3+
4+
# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/arm64-dtrace.s -o %t/arm64-dtrace.o
5+
# RUN: %lld -arch arm64 -o %t/arm64-dtrace %t/arm64-dtrace.o
6+
7+
## If references of dtrace symbols are handled by lld, their relocation should be replaced with the following instructions
8+
# RUN: llvm-objdump --macho -D %t/arm64-dtrace | FileCheck %s --check-prefix=CHECK
9+
10+
# CHECK: 00 00 80 d2 mov x0, #0
11+
12+
# CHECK: 1f 20 03 d5 nop
13+
14+
#--- arm64-dtrace.s
15+
.globl _main
16+
_main:
17+
bl ___dtrace_isenabled$Foo$added$v1
18+
.reference ___dtrace_typedefs$Foo$v2
19+
bl ___dtrace_probe$Foo$added$v1$696e74
20+
.reference ___dtrace_stability$Foo$v1$1_1_0_1_1_0_1_1_0_1_1_0_1_1_0
21+
ret
22+
23+
.subsections_via_symbols

lld/test/MachO/x86_64-dtrace.s

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# REQUIRES: x86
2+
# RUN: rm -rf %t; split-file %s %t
3+
4+
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/x86_64-dtrace.s -o %t/x86_64-dtrace.o
5+
# RUN: %lld -arch x86_64 -o %t/x86_64-dtrace %t/x86_64-dtrace.o
6+
7+
## If references of dtrace symbols are handled by lld, their relocation should be replaced with the following instructions
8+
# RUN: llvm-objdump --macho -D %t/x86_64-dtrace | FileCheck %s --check-prefix=CHECK
9+
10+
# CHECK: 33 c0 xorl %eax, %eax
11+
# CHECK-NEXT: 90 nop
12+
# CHECK-NEXT: 90 nop
13+
# CHECK-NEXT: 90 nop
14+
15+
# CHECK: 90 nop
16+
# CHECK-NEXT: 0f 1f 40 00 nopl (%rax)
17+
18+
#--- x86_64-dtrace.s
19+
.globl _main
20+
_main:
21+
callq ___dtrace_isenabled$Foo$added$v1
22+
.reference ___dtrace_typedefs$Foo$v2
23+
callq ___dtrace_probe$Foo$added$v1$696e74
24+
.reference ___dtrace_stability$Foo$v1$1_1_0_1_1_0_1_1_0_1_1_0_1_1_0
25+
retq
26+
27+
.subsections_via_symbols

0 commit comments

Comments
 (0)