Skip to content

Commit 29c590f

Browse files
committed
[x86] Implement R_X86_64_TLSGD GD→LE TLS relaxation
For non-preemptible symbols in executables (static, dynamic, or PIE), the 16-byte GD sequence: 66 48 8d 3d [rel32] leaq sym@tlsgd(%rip), %rdi 66 66 48 e8 [rel32] callq __tls_get_addr@PLT is rewritten in-place to the LE form: 64 48 8b 04 25 00 00 00 00 movq %fs:0x0, %rax 48 8d 80 [imm32] leaq tpoff(%rax), %rax This eliminates the 2-slot GD GOT pair, the R_X86_64_DTPMOD64 and R_X86_64_DTPOFF64 dynamic relocations, and the __tls_get_addr PLT call. Relaxation fires when: - The symbol is non-preemptible and the output is an executable (static, dynamic, or PIE) — LE requires the variable's TP-relative offset to be a link-time constant, which holds only for the executable's own block - The link is not partial (-r) GD→LE is mandatory and fires regardless of --relax, matching lld and bfd. The --relax flag governs optional relaxations (e.g. GOTPCRELX); without GD→LE, executables fail with "undefined reference to __tls_get_addr". Approach -------- - Scan: qualifying TLSGD relocations skip GOT-pair creation and are recorded as candidates. The companion call reloc at TLSGD_offset+8 (R_X86_64_PLT32 for standard sequences, R_X86_64_GOTPCRELX for -fno-plt) is tracked to suppress undefined-ref errors and skip GOT/PLT allocation for __tls_get_addr. - postProcessing: the TLSGD candidate loop always runs (mandatory). The 16-byte rewrite uses finalizeTLSSymbol() to get the TP-relative offset. - Apply: early-return OK for candidates and companions to skip the apply path, which has no GOT pair to reference. - --trace=relax emits trace_relax_tlsgd_le for each relaxed reference. Link modes ---------- Relaxation applies to static and dynamic executables and PIE, where the variable's TP-relative offset is a link-time constant. Tests: - TLSGDRelax_StaticHidden - TLSGDRelax_DynExeHidden - TLSGDRelax_PIE_Hidden - TLSGDRelax_SharedPreemptible_NoRelax - TLSGDRelax_SharedHidden_NoRelax - TLSGDRelax_PartialRelink - TLSGDRelax_Trace - TLSGDRelax_NoPLT Fixes #1490 Signed-off-by: bsaharsh <[email protected]>
1 parent 3ce233a commit 29c590f

15 files changed

Lines changed: 338 additions & 22 deletions

include/eld/Diagnostics/DiagVerbose.inc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ DIAG(relax_to_compress, DiagnosticEngine::Verbose,
3636
"%3 in section %4+0x%5 file %6")
3737
DIAG(trace_relax_gotpcrelx, DiagnosticEngine::Trace,
3838
"%0: relaxed GOTPCRELX (%1) for symbol '%2' to PC-relative access")
39+
DIAG(trace_relax_tlsgd_le, DiagnosticEngine::Trace,
40+
"relaxed TLSGD for symbol '%0' to LE access in section %1+0x%2 file %3")
3941
DIAG(verbose_ehframe_remove_fde, DiagnosticEngine::Verbose, "EhFrame %0")
4042
DIAG(verbose_ehframe_read_fde, DiagnosticEngine::Verbose, "EhFrame %0")
4143
DIAG(verbose_ehframe_read_cie, DiagnosticEngine::Verbose, "EhFrame %0")

lib/Target/X86/x86_64LDBackend.cpp

Lines changed: 76 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ bool x86_64LDBackend::isGOTPCRELXRelaxable(const Relocation *reloc) const {
152152
}
153153

154154
bool x86_64LDBackend::shouldIgnoreRelocSync(Relocation *reloc) const {
155-
return isGOTPCRELXRelaxCandidate(reloc);
155+
return isGOTPCRELXRelaxCandidate(reloc) || isTLSGDRelaxCandidate(reloc);
156156
}
157157

158158
eld::Expected<void>
@@ -161,29 +161,32 @@ x86_64LDBackend::postProcessing(llvm::FileOutputBuffer &pOutput) {
161161

162162
// Relaxation rewrites bytes in the laid-out output image; it is not
163163
// applicable to partial links, which have no final layout.
164-
if (config().options().getRelax() && !config().isLinkPartial())
164+
if (!config().isLinkPartial())
165165
ELDEXP_RETURN_DIAGENTRY_IF_ERROR(doRelax(pOutput));
166166

167167
return {};
168168
}
169169

170170
eld::Expected<void> x86_64LDBackend::doRelax(llvm::FileOutputBuffer &pOutput) {
171171
uint8_t *buf = pOutput.getBufferStart();
172-
// The scan phase already identified every relaxation candidate (skipping
173-
// debug relocations and internal files, which never carry a relaxable
174-
// relocation). Iterate that cached set instead of re-walking all
175-
// relocations, and dispatch on the relocation type. Future relaxable types
176-
// (e.g. R_X86_64_REX_GOTPCRELX, TLS relaxations) add a case here.
177-
for (Relocation *reloc : m_GOTPCRELXRelaxCandidates) {
178-
switch (reloc->type()) {
179-
case llvm::ELF::R_X86_64_GOTPCRELX:
180-
ELDEXP_RETURN_DIAGENTRY_IF_ERROR(relaxGOTPCRELXReloc(reloc, buf));
181-
break;
182-
default:
183-
// Only relaxable types are recorded as candidates; skip anything else.
184-
break;
172+
// The scan phase already identified every relaxation candidate
173+
// GOTPCRELX relaxation is optional (--relax); GD→LE is
174+
// mandatory (otherwise we get an undefined reference for __tls_get_addr in
175+
// static links).
176+
if (config().options().getRelax()) {
177+
for (Relocation *reloc : m_GOTPCRELXRelaxCandidates) {
178+
switch (reloc->type()) {
179+
case llvm::ELF::R_X86_64_GOTPCRELX:
180+
ELDEXP_RETURN_DIAGENTRY_IF_ERROR(relaxGOTPCRELXReloc(reloc, buf));
181+
break;
182+
default:
183+
// Only relaxable types are recorded as candidates; skip anything else.
184+
break;
185+
}
185186
}
186187
}
188+
for (Relocation *reloc : m_TLSGDLERelaxCandidates)
189+
ELDEXP_RETURN_DIAGENTRY_IF_ERROR(relaxTLSGDToLEReloc(reloc, buf));
187190
return {};
188191
}
189192

@@ -280,7 +283,64 @@ eld::Expected<void> x86_64LDBackend::relaxGOTPCRELXReloc(Relocation *reloc,
280283
assert(traceSect &&
281284
"RegionFragment in relax candidate must have an owning section");
282285
location = traceSect->getLocation(offset, config().options());
283-
config().raise(Diag::trace_relax_gotpcrelx) << location << kind << rsym->name();
286+
config().raise(Diag::trace_relax_gotpcrelx)
287+
<< location << kind << rsym->name();
288+
}
289+
290+
return {};
291+
}
292+
293+
eld::Expected<void> x86_64LDBackend::relaxTLSGDToLEReloc(Relocation *reloc,
294+
uint8_t *buf) {
295+
auto *RF = llvm::cast<RegionFragment>(reloc->targetRef()->frag());
296+
297+
uint32_t offset = reloc->targetRef()->offset();
298+
assert(offset >= 4 && "TLSGD relax candidate offset must be >= 4");
299+
300+
FragmentRef::Offset off = reloc->targetRef()->getOutputOffset(m_Module);
301+
if (off == (FragmentRef::Offset)-1)
302+
return {};
303+
size_t out_off = reloc->targetRef()->getOutputELFSection()->offset() + off;
304+
305+
uint64_t TLSTemplateSize = getTLSTemplateSize();
306+
if (TLSTemplateSize == 0) {
307+
config().raise(Diag::no_pt_tls_segment);
308+
return {};
309+
}
310+
// Use finalizeTLSSymbol to get the TLS-segment-relative offset (S).
311+
// Relocation::symValue() ASSERTs on TLS-type symbols; the correct path
312+
// for TLS is through finalizeTLSSymbol(), mirroring what
313+
// Relocator::getSymValue does for thread-local symbols.
314+
uint64_t S = finalizeTLSSymbol(reloc->symInfo()->outSymbol());
315+
int64_t A = static_cast<int64_t>(reloc->addend());
316+
int64_t tpoff =
317+
static_cast<int64_t>(S) + A - static_cast<int64_t>(TLSTemplateSize);
318+
319+
// Rewrite 16 bytes starting at out_off-4:
320+
// 9 bytes: movq %fs:0x0, %rax
321+
// 7 bytes: leaq tpoff(%rax), %rax
322+
static const uint8_t kMoveFS[] = {0x64, 0x48, 0x8b, 0x04, 0x25,
323+
0x00, 0x00, 0x00, 0x00};
324+
std::memcpy(buf + out_off - 4, kMoveFS, sizeof(kMoveFS));
325+
buf[out_off + 5] = 0x48; // REX.W
326+
buf[out_off + 6] = 0x8d; // LEA opcode
327+
buf[out_off + 7] = 0x80; // ModR/M: disp32(%rax) -> %rax
328+
// imm32 at out_off+8: the R_X86_64_TLSGD addend is -4 (PC-relative bias);
329+
// adding +4 cancels it, giving the raw tpoff = S_rel - templateSize.
330+
llvm::support::endian::write32le(buf + out_off + 8,
331+
static_cast<uint32_t>(tpoff + 4));
332+
333+
if (m_Module.getPrinter()->traceRelax()) {
334+
ELFSection *traceSect = RF->getOwningSection();
335+
assert(traceSect &&
336+
"RegionFragment in relax candidate must have an owning section");
337+
std::string fileName;
338+
if (InputFile *F = traceSect->getInputFile())
339+
if (auto *I = F->getInput())
340+
fileName = I->decoratedPath();
341+
config().raise(Diag::trace_relax_tlsgd_le)
342+
<< reloc->symInfo()->name() << traceSect->name()
343+
<< llvm::utohexstr(offset) << fileName;
284344
}
285345

286346
return {};

lib/Target/X86/x86_64LDBackend.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "eld/SymbolResolver/IRBuilder.h"
1414
#include "eld/Target/GNULDBackend.h"
1515
#include "x86_64PLT.h"
16+
#include "llvm/ADT/DenseSet.h"
1617
#include "llvm/BinaryFormat/ELF.h"
1718
#include <unordered_set>
1819

@@ -124,6 +125,38 @@ class x86_64LDBackend : public GNULDBackend {
124125
return m_GOTPCRELXRelaxCandidates.count(reloc) != 0;
125126
}
126127

128+
/// Records a TLSGD relocation for GD→LE relaxation during scan.
129+
/// Called under the relocator mutex; no GOT pair will be created.
130+
void recordTLSGDLERelaxCandidate(Relocation *reloc) {
131+
m_TLSGDLERelaxCandidates.insert(reloc);
132+
m_TLSGDLEFragOffsets.insert(
133+
{reloc->targetRef()->frag(),
134+
static_cast<uint32_t>(reloc->targetRef()->offset())});
135+
}
136+
137+
/// Returns true if this R_X86_64_TLSGD was marked for GD→LE relaxation.
138+
bool isTLSGDLERelaxCandidate(Relocation *reloc) const {
139+
return m_TLSGDLERelaxCandidates.count(reloc) != 0;
140+
}
141+
142+
/// Returns true if this relocation is the companion call in a GD→LE relaxed
143+
/// sequence. The companion sits exactly 8 bytes after the TLSGD displacement
144+
/// field and is R_X86_64_PLT32 (standard) or R_X86_64_GOTPCRELX (-fno-plt).
145+
bool isTLSGDCompanion(const Relocation *reloc) const {
146+
uint32_t offset = reloc->targetRef()->offset();
147+
if (offset < 8)
148+
return false;
149+
return m_TLSGDLEFragOffsets.count(
150+
{reloc->targetRef()->frag(), offset - 8}) != 0;
151+
}
152+
153+
/// Returns true if this relocation is part of a GD→LE relaxed sequence and
154+
/// will be rewritten by postProcessing. Used to skip apply and dynamic-reloc
155+
/// sync for both the TLSGD reloc itself and its companion call reloc.
156+
bool isTLSGDRelaxCandidate(Relocation *reloc) const {
157+
return isTLSGDLERelaxCandidate(reloc) || isTLSGDCompanion(reloc);
158+
}
159+
127160
DynRelocType getDynRelocType(const Relocation *X) const override {
128161
if (X->type() == llvm::ELF::R_X86_64_GLOB_DAT)
129162
return DynRelocType::GLOB_DAT;
@@ -182,6 +215,9 @@ class x86_64LDBackend : public GNULDBackend {
182215
/// Iterates the cached relaxation candidates and rewrites each one.
183216
eld::Expected<void> doRelax(llvm::FileOutputBuffer &pOutput);
184217

218+
/// Rewrites the 16-byte GD sequence to the LE form (movq %fs:0 + leaq).
219+
eld::Expected<void> relaxTLSGDToLEReloc(Relocation *reloc, uint8_t *buf);
220+
185221
private:
186222
Relocator *m_pRelocator;
187223

@@ -199,6 +235,16 @@ class x86_64LDBackend : public GNULDBackend {
199235
/// postProcessing. unordered_set for O(1) membership checks in
200236
/// shouldIgnoreRelocSync and the apply-path guard.
201237
std::unordered_set<Relocation *> m_GOTPCRELXRelaxCandidates;
238+
239+
/// TLSGD relocations selected for GD→LE relaxation during the scan phase.
240+
/// Non-preemptible symbols in executables (static or dynamic); no GOT pair
241+
/// is created for these. Consumed single-threaded in doRelax.
242+
std::unordered_set<Relocation *> m_TLSGDLERelaxCandidates;
243+
244+
/// Fragment + intra-fragment offset of each TLSGD candidate, stored as a
245+
/// (Fragment*, uint32_t) pair. Used for O(1) companion detection.
246+
/// LLVM provides DenseMapInfo for pointer+integer pairs.
247+
llvm::DenseSet<std::pair<const Fragment *, uint32_t>> m_TLSGDLEFragOffsets;
202248
};
203249
} // namespace eld
204250

lib/Target/X86/x86_64Relocator.cpp

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,17 @@ void x86_64Relocator::scanRelocation(Relocation &pReloc,
137137
// symbol
138138
if (rsym->isUndef() || rsym->isBitCode()) {
139139
std::lock_guard<std::mutex> relocGuard(m_RelocMutex);
140-
if (!m_Target.canProvideSymbol(rsym)) {
141-
if (m_Target.canIssueUndef(rsym)) {
142-
if (rsym->visibility() != ResolveInfo::Default)
143-
issueInvisibleRef(pReloc, pInputFile);
144-
issueUndefRef(pReloc, pInputFile, &pSection);
140+
// Suppress undefined-ref for the companion call in a GD→LE relaxed
141+
// sequence (R_X86_64_PLT32 with PLT, or R_X86_64_GOTPCRELX with -fno-plt):
142+
// __tls_get_addr is unavailable in a static link, but the bytes at this
143+
// offset are fully overwritten by postProcessing.
144+
if (!m_Target.isTLSGDCompanion(&pReloc)) {
145+
if (!m_Target.canProvideSymbol(rsym)) {
146+
if (m_Target.canIssueUndef(rsym)) {
147+
if (rsym->visibility() != ResolveInfo::Default)
148+
issueInvisibleRef(pReloc, pInputFile);
149+
issueUndefRef(pReloc, pInputFile, &pSection);
150+
}
145151
}
146152
}
147153
}
@@ -398,6 +404,12 @@ void x86_64Relocator::scanGlobalReloc(InputFile &pInputFile, Relocation &pReloc,
398404
if (rsym->reserved() & ReservePLT)
399405
return;
400406

407+
// Suppress the companion call in a GD→LE relaxed sequence: the
408+
// R_X86_64_PLT32 at TLSGD_offset+8 references __tls_get_addr, which does
409+
// not exist in a static link. The bytes are overwritten by postProcessing;
410+
if (m_Target.isTLSGDCompanion(&pReloc))
411+
return;
412+
401413
// create IRELATIVE for IFUNC symbol
402414
if (rsym->type() == ResolveInfo::IndirectFunc && config().isCodeStatic()) {
403415
m_Target.createPLT(Obj, rsym, true);
@@ -431,6 +443,11 @@ void x86_64Relocator::scanGlobalReloc(InputFile &pInputFile, Relocation &pReloc,
431443
m_Target.recordGOTPCRELXRelaxCandidate(&pReloc);
432444
return;
433445
}
446+
// The GOTPCRELX at TLSGD_offset+8 is the companion call in a -fno-plt
447+
// GD sequence being relaxed to LE. Suppress GOT creation; the bytes are
448+
// overwritten by postProcessing.
449+
if (m_Target.isTLSGDCompanion(&pReloc))
450+
return;
434451
if (rsym->reserved() & ReserveGOT)
435452
return;
436453
CreateGOT(Obj, pReloc, !config().isCodeStatic(), m_Target);
@@ -475,7 +492,32 @@ void x86_64Relocator::scanGlobalReloc(InputFile &pInputFile, Relocation &pReloc,
475492
if (rsym->reserved() & ReserveGOT)
476493
return;
477494

478-
// Create GD GOT pair (x86_64GDGOT creates both entries)
495+
// GD→LE: non-preemptible symbol in an executable (static, dynamic, or PIE)
496+
// that is not a partial link. LE requires the variable's offset from the
497+
// thread pointer to be a link-time constant. That holds only for the
498+
// executable's own TLS block, which is always placed at a fixed distance
499+
// below TP. A DSO's block is positioned by the loader at startup, so its
500+
// tpoff is not known at link time — even for a hidden (non-preemptible)
501+
// symbol; DSOs are therefore excluded. Partial links are excluded because
502+
// they have no final layout; the re-link will decide. Preemptible symbols
503+
// in a non-shared executable would go GD→IE.
504+
if (!m_Target.isSymbolPreemptible(*rsym) &&
505+
m_Target.config().isBuildingExecutable() && !config().isLinkPartial()) {
506+
// Guard against a corrupt or hand-crafted object: require a
507+
// RegionFragment with offset >= 4. The 16-byte GD sequence requires 4
508+
// bytes of prefix before the TLSGD displacement field (same rationale as
509+
// GOTPCRELX guarding !RF and offset < 2 in isGOTPCRELXRelaxable). Fall
510+
// through to GOT creation for the corrupt case, consistent with GOTPCRELX
511+
// behavior.
512+
auto *RF = llvm::dyn_cast<RegionFragment>(pReloc.targetRef()->frag());
513+
if (RF && pReloc.targetRef()->offset() >= 4) {
514+
m_Target.recordTLSGDLERelaxCandidate(&pReloc);
515+
// Do not create a GOT pair; postProcessing rewrites the sequence.
516+
return;
517+
}
518+
}
519+
520+
// Non-relaxable: keep the full GD sequence with dynamic relocations.
479521
x86_64GOT *G = m_Target.createGOT(GOT::TLS_GD, Obj, rsym);
480522

481523
// Always emit DTPMOD64 for first entry (module ID unknown for DSO)
@@ -694,6 +736,13 @@ Relocator::Result eld::relocPLT32(Relocation &pReloc, x86_64Relocator &pParent,
694736
RelocationDescription &pRelocDesc) {
695737
DiagnosticEngine *DiagEngine = pParent.config().getDiagEngine();
696738
ResolveInfo *symInfo = pReloc.symInfo();
739+
740+
// The companion PLT32 in a relaxed GD sequence has its bytes overwritten
741+
// by postProcessing. Skip apply to avoid an undefined-symbol lookup for
742+
// __tls_get_addr.
743+
if (pParent.getTarget().isTLSGDCompanion(&pReloc))
744+
return Relocator::OK;
745+
697746
Relocator::Address S;
698747
if (symInfo->reserved() & Relocator::ReservePLT) {
699748
// Symbol has PLT entry - redirect through PLT
@@ -734,6 +783,11 @@ Relocator::Result eld::relocGOTRelative(Relocation &pReloc,
734783
if (pParent.getTarget().isGOTPCRELXRelaxCandidate(&pReloc))
735784
return Relocator::OK;
736785

786+
// GD→LE candidates and their companion relocs (PLT32 or GOTPCRELX) have no
787+
// GOT pair; postProcessing rewrites the entire sequence.
788+
if (pParent.getTarget().isTLSGDRelaxCandidate(&pReloc))
789+
return Relocator::OK;
790+
737791
Relocator::DWord A = pReloc.addend();
738792
Relocator::DWord P = pReloc.place(pParent.module());
739793
x86_64GOT *gotEntry = pParent.getTarget().findEntryInGOT(symInfo);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.globl tls_extern_def
2+
.section .tbss,"awT",@nobits
3+
tls_extern_def:
4+
.zero 4
5+
6+
.text
7+
.globl get_tls_noplt
8+
get_tls_noplt:
9+
.byte 0x66
10+
leaq tls_extern_def@tlsgd(%rip), %rdi
11+
.byte 0x66, 0x48
12+
call *__tls_get_addr@GOTPCREL(%rip)
13+
retq
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
.globl tls_hidden
2+
.hidden tls_hidden
3+
.section .tbss,"awT",@nobits
4+
tls_hidden:
5+
.zero 4
6+
7+
.text
8+
.globl get_tls
9+
get_tls:
10+
.byte 0x66
11+
leaq tls_hidden@tlsgd(%rip), %rdi
12+
.byte 0x66, 0x66, 0x48
13+
call __tls_get_addr@PLT
14+
retq
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.globl tls_default
2+
.section .tbss,"awT",@nobits
3+
tls_default:
4+
.zero 4
5+
6+
.text
7+
.globl get_tls_preempt
8+
get_tls_preempt:
9+
.byte 0x66
10+
leaq tls_default@tlsgd(%rip), %rdi
11+
.byte 0x66, 0x66, 0x48
12+
call __tls_get_addr@PLT
13+
retq
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#--TLSGDRelax_DynExeHidden.test----------Dynamic Executable--------#
2+
# GD→LE relaxation for a non-preemptible hidden symbol in a dynamic executable.
3+
#START_TEST
4+
RUN: %clang %clangopts -c %p/Inputs/tls_gd_hidden.s -o %t.o
5+
RUN: %link %linkopts -e get_tls -o %t.eld %t.o
6+
RUN: %objdump -d %t.eld | %filecheck %s
7+
RUN: %readelf -r %t.eld | %filecheck %s --check-prefix=NORELOC
8+
#END_TEST
9+
10+
CHECK: <get_tls>:
11+
CHECK-NEXT: {{[0-9a-f]+}}: 64 48 8b 04 25 {{.*}} movq
12+
CHECK-NEXT: {{[0-9a-f]+}}: 48 8d 80 {{.*}} leaq
13+
14+
NORELOC-NOT: R_X86_64_DTPMOD64
15+
NORELOC-NOT: R_X86_64_DTPOFF64
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#--TLSGDRelax_NoPLT.test----------Static Executable--------#
2+
# GD→LE relaxation when the companion is R_X86_64_GOTPCRELX (-fno-plt).
3+
#START_TEST
4+
RUN: %clang %clangopts -c %p/Inputs/tls_gd_gotpcrelx_companion.s -o %t.o
5+
RUN: %link %linkopts -static -e get_tls_noplt -o %t.eld %t.o
6+
RUN: %objdump -d %t.eld | %filecheck %s
7+
RUN: %readelf -r %t.eld | %filecheck %s --check-prefix=NORELOC
8+
#END_TEST
9+
10+
CHECK: <get_tls_noplt>:
11+
CHECK-NEXT: {{[0-9a-f]+}}: 64 48 8b 04 25 {{.*}} movq
12+
CHECK-NEXT: {{[0-9a-f]+}}: 48 8d 80 {{.*}} leaq
13+
14+
NORELOC-NOT: R_X86_64_DTPMOD64
15+
NORELOC-NOT: R_X86_64_DTPOFF64

0 commit comments

Comments
 (0)