Skip to content

Commit fad5ed6

Browse files
authored
[X86][LLD] Handle R_X86_64_CODE_4_GOTPC32_TLSDESC relocation type (#116909)
For lea name@tlsdesc(%rip), %reg add R_X86_64_CODE_4_GOTPC32_TLSDESC = 45 in #116908. Linker can treat R_X86_64_CODE_4_GOTPC32_TLSDESC as R_X86_64_GOTPC32_TLSDESC or convert the instruction above to mov $name@tpoff, %reg if the first byte of the instruction at the relocation offset - 4 is 0xd5 (namely, encoded w/REX2 prefix) when possible. Binutils patch: bminor/binutils-gdb@a533c8d Binutils mailthread: https://sourceware.org/pipermail/binutils/2023-December/131463.html ABI discussion: https://groups.google.com/g/x86-64-abi/c/ACwD-UQXVDs/m/vrgTenKyFwAJ Blog: https://kanrobert.github.io/rfc/All-about-APX-relocation
1 parent 73d1abb commit fad5ed6

File tree

3 files changed

+72
-31
lines changed

3 files changed

+72
-31
lines changed

lld/ELF/Arch/X86_64.cpp

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,11 @@ X86_64::X86_64(Ctx &ctx) : TargetInfo(ctx) {
9999

100100
int X86_64::getTlsGdRelaxSkip(RelType type) const {
101101
// TLSDESC relocations are processed separately. See relaxTlsGdToLe below.
102-
return type == R_X86_64_GOTPC32_TLSDESC || type == R_X86_64_TLSDESC_CALL ? 1
103-
: 2;
102+
return type == R_X86_64_GOTPC32_TLSDESC ||
103+
type == R_X86_64_CODE_4_GOTPC32_TLSDESC ||
104+
type == R_X86_64_TLSDESC_CALL
105+
? 1
106+
: 2;
104107
}
105108

106109
// Opcodes for the different X86_64 jmp instructions.
@@ -390,6 +393,7 @@ RelExpr X86_64::getRelExpr(RelType type, const Symbol &s,
390393
case R_X86_64_GOT64:
391394
return R_GOTPLT;
392395
case R_X86_64_GOTPC32_TLSDESC:
396+
case R_X86_64_CODE_4_GOTPC32_TLSDESC:
393397
return R_TLSDESC_PC;
394398
case R_X86_64_GOTPCREL:
395399
case R_X86_64_GOTPCRELX:
@@ -487,18 +491,26 @@ void X86_64::relaxTlsGdToLe(uint8_t *loc, const Relocation &rel,
487491
// The original code used a pc relative relocation and so we have to
488492
// compensate for the -4 in had in the addend.
489493
write32le(loc + 8, val + 4);
490-
} else if (rel.type == R_X86_64_GOTPC32_TLSDESC) {
494+
} else if (rel.type == R_X86_64_GOTPC32_TLSDESC ||
495+
rel.type == R_X86_64_CODE_4_GOTPC32_TLSDESC) {
491496
// Convert leaq x@tlsdesc(%rip), %REG to movq $x@tpoff, %REG.
492497
if ((loc[-3] & 0xfb) != 0x48 || loc[-2] != 0x8d ||
493498
(loc[-1] & 0xc7) != 0x05) {
494-
Err(ctx) << getErrorLoc(ctx, loc - 3)
495-
<< "R_X86_64_GOTPC32_TLSDESC must be used "
496-
"in leaq x@tlsdesc(%rip), %REG";
499+
Err(ctx) << getErrorLoc(ctx, (rel.type == R_X86_64_GOTPC32_TLSDESC)
500+
? loc - 3
501+
: loc - 4)
502+
<< "R_X86_64_GOTPC32_TLSDESC/R_X86_64_CODE_4_GOTPC32_TLSDESC "
503+
"must be used in leaq x@tlsdesc(%rip), %REG";
497504
return;
498505
}
499-
loc[-3] = 0x48 | ((loc[-3] >> 2) & 1);
506+
if (rel.type == R_X86_64_GOTPC32_TLSDESC) {
507+
loc[-3] = 0x48 | ((loc[-3] >> 2) & 1);
508+
} else {
509+
loc[-3] = (loc[-3] & ~0x44) | ((loc[-3] & 0x44) >> 2);
510+
}
500511
loc[-2] = 0xc7;
501512
loc[-1] = 0xc0 | ((loc[-1] >> 3) & 7);
513+
502514
write32le(loc, val + 4);
503515
} else {
504516
// Convert call *x@tlsdesc(%REG) to xchg ax, ax.
@@ -528,14 +540,16 @@ void X86_64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
528540
// Both code sequences are PC relatives, but since we are moving the
529541
// constant forward by 8 bytes we have to subtract the value by 8.
530542
write32le(loc + 8, val - 8);
531-
} else if (rel.type == R_X86_64_GOTPC32_TLSDESC) {
543+
} else if (rel.type == R_X86_64_GOTPC32_TLSDESC ||
544+
rel.type == R_X86_64_CODE_4_GOTPC32_TLSDESC) {
532545
// Convert leaq x@tlsdesc(%rip), %REG to movq x@gottpoff(%rip), %REG.
533-
assert(rel.type == R_X86_64_GOTPC32_TLSDESC);
534546
if ((loc[-3] & 0xfb) != 0x48 || loc[-2] != 0x8d ||
535547
(loc[-1] & 0xc7) != 0x05) {
536-
Err(ctx) << getErrorLoc(ctx, loc - 3)
537-
<< "R_X86_64_GOTPC32_TLSDESC must be used "
538-
"in leaq x@tlsdesc(%rip), %REG";
548+
Err(ctx) << getErrorLoc(ctx, (rel.type == R_X86_64_GOTPC32_TLSDESC)
549+
? loc - 3
550+
: loc - 4)
551+
<< "R_X86_64_GOTPC32_TLSDESC/R_X86_64_CODE_4_GOTPC32_TLSDESC "
552+
"must be used in leaq x@tlsdesc(%rip), %REG";
539553
return;
540554
}
541555
loc[-2] = 0x8b;
@@ -857,6 +871,7 @@ void X86_64::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
857871
}
858872
break;
859873
case R_X86_64_GOTPC32_TLSDESC:
874+
case R_X86_64_CODE_4_GOTPC32_TLSDESC:
860875
case R_X86_64_TLSDESC_CALL:
861876
case R_X86_64_TLSGD:
862877
if (rel.expr == R_RELAX_TLS_GD_TO_LE) {

lld/test/ELF/invalid/x86-64-tlsdesc-gd.s

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,13 @@
88
## GD to IE relaxation.
99
# RUN: not ld.lld %t.o %t1.so -o /dev/null 2>&1 | FileCheck -DINPUT=%t.o %s
1010

11-
# CHECK: error: [[INPUT]]:(.text+0x0): R_X86_64_GOTPC32_TLSDESC must be used in leaq x@tlsdesc(%rip), %REG
11+
# CHECK: error: [[INPUT]]:(.text+0x0): R_X86_64_GOTPC32_TLSDESC/R_X86_64_CODE_4_GOTPC32_TLSDESC must be used in leaq x@tlsdesc(%rip), %REG
12+
# CHECK-NEXT: error: [[INPUT]]:(.text+0xd): R_X86_64_GOTPC32_TLSDESC/R_X86_64_CODE_4_GOTPC32_TLSDESC must be used in leaq x@tlsdesc(%rip), %REG
1213

1314
leaq a@tlsdesc(%rbx), %rdx
1415
call *a@tlscall(%rdx)
1516
movl %fs:(%rax), %eax
17+
18+
leaq a@tlsdesc(%r16), %r20
19+
call *a@tlscall(%r20)
20+
movl %fs:(%rax), %eax

lld/test/ELF/x86-64-tlsdesc-gd.s

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,42 +19,48 @@
1919
# RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn %t | FileCheck --check-prefix=IE %s
2020

2121
# GD-RELA: .rela.dyn {
22-
# GD-RELA-NEXT: 0x23D0 R_X86_64_TLSDESC - 0xB
23-
# GD-RELA-NEXT: 0x23B0 R_X86_64_TLSDESC a 0x0
24-
# GD-RELA-NEXT: 0x23C0 R_X86_64_TLSDESC c 0x0
22+
# GD-RELA-NEXT: 0x23E0 R_X86_64_TLSDESC - 0xB
23+
# GD-RELA-NEXT: 0x23C0 R_X86_64_TLSDESC a 0x0
24+
# GD-RELA-NEXT: 0x23D0 R_X86_64_TLSDESC c 0x0
2525
# GD-RELA-NEXT: }
2626
# GD-RELA: Hex dump of section '.got':
27-
# GD-RELA-NEXT: 0x000023b0 00000000 00000000 00000000 00000000
2827
# GD-RELA-NEXT: 0x000023c0 00000000 00000000 00000000 00000000
2928
# GD-RELA-NEXT: 0x000023d0 00000000 00000000 00000000 00000000
29+
# GD-RELA-NEXT: 0x000023e0 00000000 00000000 00000000 00000000
3030

3131
# GD-REL: .rel.dyn {
32-
# GD-REL-NEXT: 0x23B8 R_X86_64_TLSDESC -
33-
# GD-REL-NEXT: 0x2398 R_X86_64_TLSDESC a
34-
# GD-REL-NEXT: 0x23A8 R_X86_64_TLSDESC c
32+
# GD-REL-NEXT: 0x23C8 R_X86_64_TLSDESC -
33+
# GD-REL-NEXT: 0x23A8 R_X86_64_TLSDESC a
34+
# GD-REL-NEXT: 0x23B8 R_X86_64_TLSDESC c
3535
# GD-REL-NEXT: }
3636
# GD-REL: Hex dump of section '.got':
37-
# GD-REL-NEXT: 0x00002398 00000000 00000000 00000000 00000000
3837
# GD-REL-NEXT: 0x000023a8 00000000 00000000 00000000 00000000
39-
# GD-REL-NEXT: 0x000023b8 00000000 00000000 0b000000 00000000
38+
# GD-REL-NEXT: 0x000023b8 00000000 00000000 00000000 00000000
39+
# GD-REL-NEXT: 0x000023c8 00000000 00000000 0b000000 00000000
4040

41-
## &.rela.dyn[a]-pc = 0x23B0-0x12e7 = 4297
42-
# GD: leaq 4297(%rip), %rax
41+
## &.rela.dyn[a]-pc = 0x23C0-0x12e7 = 4313
42+
# GD: leaq 4313(%rip), %rax
4343
# GD-NEXT: 12e7: callq *(%rax)
4444
# GD-NEXT: movl %fs:(%rax), %eax
4545

46-
## &.rela.dyn[b]-pc = 0x23D0-0x12f3 = 4317
47-
# GD-NEXT: leaq 4317(%rip), %rcx
46+
## &.rela.dyn[b]-pc = 0x23E0-0x12f3 = 4333
47+
# GD-NEXT: leaq 4333(%rip), %rcx
4848
# GD-NEXT: 12f3: movq %rcx, %rax
4949
# GD-NEXT: callq *(%rax)
5050
# GD-NEXT: movl %fs:(%rax), %eax
5151

52-
## &.rela.dyn[c]-pc = 0x23C0-0x1302 = 4286
53-
# GD-NEXT: leaq 4286(%rip), %r15
52+
## &.rela.dyn[c]-pc = 0x23D0-0x1302 = 4302
53+
# GD-NEXT: leaq 4302(%rip), %r15
5454
# GD-NEXT: 1302: movq %r15, %rax
5555
# GD-NEXT: callq *(%rax)
5656
# GD-NEXT: movl %fs:(%rax), %eax
5757

58+
## &.rela.dyn[c]-pc = 0x23D0-0x1312 = 4286
59+
# GD-NEXT: leaq 4286(%rip), %r16
60+
# GD-NEXT: 1312: movq %r16, %rax
61+
# GD-NEXT: callq *(%rax)
62+
# GD-NEXT: movl %fs:(%rax), %eax
63+
5864
# NOREL: no relocations
5965

6066
## tpoff(a) = st_value(a) - tls_size = -8
@@ -71,9 +77,14 @@
7177
# LE-NEXT: movq %r15, %rax
7278
# LE-NEXT: nop
7379
# LE-NEXT: movl %fs:(%rax), %eax
80+
## tpoff(c) = st_value(c) - tls_size = -4
81+
# LE: movq $-4, %r16
82+
# LE-NEXT: movq %r16, %rax
83+
# LE-NEXT: nop
84+
# LE-NEXT: movl %fs:(%rax), %eax
7485

7586
# IE-REL: .rela.dyn {
76-
# IE-REL-NEXT: 0x202378 R_X86_64_TPOFF64 c 0x0
87+
# IE-REL-NEXT: 0x202388 R_X86_64_TPOFF64 c 0x0
7788
# IE-REL-NEXT: }
7889

7990
## a is relaxed to use LE.
@@ -84,11 +95,16 @@
8495
# IE-NEXT: movq %rcx, %rax
8596
# IE-NEXT: nop
8697
# IE-NEXT: movl %fs:(%rax), %eax
87-
## &.rela.dyn[c]-pc = 0x202378 - 0x2012aa = 4302
88-
# IE-NEXT: movq 4302(%rip), %r15
98+
## &.rela.dyn[c]-pc = 0x202388 - 0x2012aa = 4318
99+
# IE-NEXT: movq 4318(%rip), %r15
89100
# IE-NEXT: 2012aa: movq %r15, %rax
90101
# IE-NEXT: nop
91102
# IE-NEXT: movl %fs:(%rax), %eax
103+
## &.rela.dyn[c]-pc = 0x202388 - 0x2012ba = 4302
104+
# IE-NEXT: movq 4302(%rip), %r16
105+
# IE-NEXT: 2012ba: movq %r16, %rax
106+
# IE-NEXT: nop
107+
# IE-NEXT: movl %fs:(%rax), %eax
92108

93109
leaq a@tlsdesc(%rip), %rax
94110
call *a@tlscall(%rax)
@@ -106,6 +122,11 @@ movq %r15, %rax
106122
call *c@tlscall(%rax)
107123
movl %fs:(%rax), %eax
108124

125+
leaq c@tlsdesc(%rip), %r16
126+
movq %r16, %rax
127+
call *c@tlscall(%rax)
128+
movl %fs:(%rax), %eax
129+
109130
.section .tbss
110131
.globl a
111132
.zero 8

0 commit comments

Comments
 (0)