Skip to content

[X86][LLD] Handle R_X86_64_CODE_4_GOTPC32_TLSDESC relocation type #116909

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 27 additions & 12 deletions lld/ELF/Arch/X86_64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,11 @@ X86_64::X86_64(Ctx &ctx) : TargetInfo(ctx) {

int X86_64::getTlsGdRelaxSkip(RelType type) const {
// TLSDESC relocations are processed separately. See relaxTlsGdToLe below.
return type == R_X86_64_GOTPC32_TLSDESC || type == R_X86_64_TLSDESC_CALL ? 1
: 2;
return type == R_X86_64_GOTPC32_TLSDESC ||
type == R_X86_64_CODE_4_GOTPC32_TLSDESC ||
type == R_X86_64_TLSDESC_CALL
? 1
: 2;
}

// Opcodes for the different X86_64 jmp instructions.
Expand Down Expand Up @@ -390,6 +393,7 @@ RelExpr X86_64::getRelExpr(RelType type, const Symbol &s,
case R_X86_64_GOT64:
return R_GOTPLT;
case R_X86_64_GOTPC32_TLSDESC:
case R_X86_64_CODE_4_GOTPC32_TLSDESC:
return R_TLSDESC_PC;
case R_X86_64_GOTPCREL:
case R_X86_64_GOTPCRELX:
Expand Down Expand Up @@ -486,18 +490,26 @@ void X86_64::relaxTlsGdToLe(uint8_t *loc, const Relocation &rel,
// The original code used a pc relative relocation and so we have to
// compensate for the -4 in had in the addend.
write32le(loc + 8, val + 4);
} else if (rel.type == R_X86_64_GOTPC32_TLSDESC) {
} else if (rel.type == R_X86_64_GOTPC32_TLSDESC ||
rel.type == R_X86_64_CODE_4_GOTPC32_TLSDESC) {
// Convert leaq x@tlsdesc(%rip), %REG to movq $x@tpoff, %REG.
if ((loc[-3] & 0xfb) != 0x48 || loc[-2] != 0x8d ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems you're missing some tests. The (loc[-3] & 0xfb) != 0x48 is used to check the X and B bit for REX prefix, it would fail for REX2 prefix.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never mind. I got something wrong. It works for REX2 too if we don't support

{rex2} leaq x@tlsdesc(%rip), %r8 

for this relocation.

Currently, compiler won't emit such code.

(loc[-1] & 0xc7) != 0x05) {
Err(ctx) << getErrorLoc(ctx, loc - 3)
<< "R_X86_64_GOTPC32_TLSDESC must be used "
"in leaq x@tlsdesc(%rip), %REG";
Err(ctx) << getErrorLoc(ctx, (rel.type == R_X86_64_GOTPC32_TLSDESC)
? loc - 3
: loc - 4)
<< "R_X86_64_GOTPC32_TLSDESC/R_X86_64_CODE_4_GOTPC32_TLSDESC "
"must be used in leaq x@tlsdesc(%rip), %REG";
return;
}
loc[-3] = 0x48 | ((loc[-3] >> 2) & 1);
if (rel.type == R_X86_64_GOTPC32_TLSDESC) {
loc[-3] = 0x48 | ((loc[-3] >> 2) & 1);
} else {
loc[-3] = (loc[-3] & ~0x44) | ((loc[-3] & 0x44) >> 2);
}
loc[-2] = 0xc7;
loc[-1] = 0xc0 | ((loc[-1] >> 3) & 7);

write32le(loc, val + 4);
} else {
// Convert call *x@tlsdesc(%REG) to xchg ax, ax.
Expand Down Expand Up @@ -527,14 +539,16 @@ void X86_64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
// Both code sequences are PC relatives, but since we are moving the
// constant forward by 8 bytes we have to subtract the value by 8.
write32le(loc + 8, val - 8);
} else if (rel.type == R_X86_64_GOTPC32_TLSDESC) {
} else if (rel.type == R_X86_64_GOTPC32_TLSDESC ||
rel.type == R_X86_64_CODE_4_GOTPC32_TLSDESC) {
// Convert leaq x@tlsdesc(%rip), %REG to movq x@gottpoff(%rip), %REG.
assert(rel.type == R_X86_64_GOTPC32_TLSDESC);
if ((loc[-3] & 0xfb) != 0x48 || loc[-2] != 0x8d ||
(loc[-1] & 0xc7) != 0x05) {
Err(ctx) << getErrorLoc(ctx, loc - 3)
<< "R_X86_64_GOTPC32_TLSDESC must be used "
"in leaq x@tlsdesc(%rip), %REG";
Err(ctx) << getErrorLoc(ctx, (rel.type == R_X86_64_GOTPC32_TLSDESC)
? loc - 3
: loc - 4)
<< "R_X86_64_GOTPC32_TLSDESC/R_X86_64_CODE_4_GOTPC32_TLSDESC "
"must be used in leaq x@tlsdesc(%rip), %REG";
return;
}
loc[-2] = 0x8b;
Expand Down Expand Up @@ -830,6 +844,7 @@ void X86_64::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
}
break;
case R_X86_64_GOTPC32_TLSDESC:
case R_X86_64_CODE_4_GOTPC32_TLSDESC:
case R_X86_64_TLSDESC_CALL:
case R_X86_64_TLSGD:
if (rel.expr == R_RELAX_TLS_GD_TO_LE) {
Expand Down
7 changes: 6 additions & 1 deletion lld/test/ELF/invalid/x86-64-tlsdesc-gd.s
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@
## GD to IE relaxation.
# RUN: not ld.lld %t.o %t1.so -o /dev/null 2>&1 | FileCheck -DINPUT=%t.o %s

# CHECK: error: [[INPUT]]:(.text+0x0): R_X86_64_GOTPC32_TLSDESC must be used in leaq x@tlsdesc(%rip), %REG
# 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
# 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

leaq a@tlsdesc(%rbx), %rdx
call *a@tlscall(%rdx)
movl %fs:(%rax), %eax

leaq a@tlsdesc(%r16), %r20
call *a@tlscall(%r20)
movl %fs:(%rax), %eax
57 changes: 39 additions & 18 deletions lld/test/ELF/x86-64-tlsdesc-gd.s
Original file line number Diff line number Diff line change
Expand Up @@ -19,42 +19,48 @@
# RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn %t | FileCheck --check-prefix=IE %s

# GD-RELA: .rela.dyn {
# GD-RELA-NEXT: 0x23D0 R_X86_64_TLSDESC - 0xB
# GD-RELA-NEXT: 0x23B0 R_X86_64_TLSDESC a 0x0
# GD-RELA-NEXT: 0x23C0 R_X86_64_TLSDESC c 0x0
# GD-RELA-NEXT: 0x23E0 R_X86_64_TLSDESC - 0xB
# GD-RELA-NEXT: 0x23C0 R_X86_64_TLSDESC a 0x0
# GD-RELA-NEXT: 0x23D0 R_X86_64_TLSDESC c 0x0
# GD-RELA-NEXT: }
# GD-RELA: Hex dump of section '.got':
# GD-RELA-NEXT: 0x000023b0 00000000 00000000 00000000 00000000
# GD-RELA-NEXT: 0x000023c0 00000000 00000000 00000000 00000000
# GD-RELA-NEXT: 0x000023d0 00000000 00000000 00000000 00000000
# GD-RELA-NEXT: 0x000023e0 00000000 00000000 00000000 00000000

# GD-REL: .rel.dyn {
# GD-REL-NEXT: 0x23B8 R_X86_64_TLSDESC -
# GD-REL-NEXT: 0x2398 R_X86_64_TLSDESC a
# GD-REL-NEXT: 0x23A8 R_X86_64_TLSDESC c
# GD-REL-NEXT: 0x23C8 R_X86_64_TLSDESC -
# GD-REL-NEXT: 0x23A8 R_X86_64_TLSDESC a
# GD-REL-NEXT: 0x23B8 R_X86_64_TLSDESC c
# GD-REL-NEXT: }
# GD-REL: Hex dump of section '.got':
# GD-REL-NEXT: 0x00002398 00000000 00000000 00000000 00000000
# GD-REL-NEXT: 0x000023a8 00000000 00000000 00000000 00000000
# GD-REL-NEXT: 0x000023b8 00000000 00000000 0b000000 00000000
# GD-REL-NEXT: 0x000023b8 00000000 00000000 00000000 00000000
# GD-REL-NEXT: 0x000023c8 00000000 00000000 0b000000 00000000

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

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

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

## &.rela.dyn[c]-pc = 0x23D0-0x1312 = 4286
# GD-NEXT: leaq 4286(%rip), %r16
# GD-NEXT: 1312: movq %r16, %rax
# GD-NEXT: callq *(%rax)
# GD-NEXT: movl %fs:(%rax), %eax

# NOREL: no relocations

## tpoff(a) = st_value(a) - tls_size = -8
Expand All @@ -71,9 +77,14 @@
# LE-NEXT: movq %r15, %rax
# LE-NEXT: nop
# LE-NEXT: movl %fs:(%rax), %eax
## tpoff(c) = st_value(c) - tls_size = -4
# LE: movq $-4, %r16
# LE-NEXT: movq %r16, %rax
# LE-NEXT: nop
# LE-NEXT: movl %fs:(%rax), %eax

# IE-REL: .rela.dyn {
# IE-REL-NEXT: 0x202378 R_X86_64_TPOFF64 c 0x0
# IE-REL-NEXT: 0x202388 R_X86_64_TPOFF64 c 0x0
# IE-REL-NEXT: }

## a is relaxed to use LE.
Expand All @@ -84,11 +95,16 @@
# IE-NEXT: movq %rcx, %rax
# IE-NEXT: nop
# IE-NEXT: movl %fs:(%rax), %eax
## &.rela.dyn[c]-pc = 0x202378 - 0x2012aa = 4302
# IE-NEXT: movq 4302(%rip), %r15
## &.rela.dyn[c]-pc = 0x202388 - 0x2012aa = 4318
# IE-NEXT: movq 4318(%rip), %r15
# IE-NEXT: 2012aa: movq %r15, %rax
# IE-NEXT: nop
# IE-NEXT: movl %fs:(%rax), %eax
## &.rela.dyn[c]-pc = 0x202388 - 0x2012ba = 4302
# IE-NEXT: movq 4302(%rip), %r16
# IE-NEXT: 2012ba: movq %r16, %rax
# IE-NEXT: nop
# IE-NEXT: movl %fs:(%rax), %eax

leaq a@tlsdesc(%rip), %rax
call *a@tlscall(%rax)
Expand All @@ -106,6 +122,11 @@ movq %r15, %rax
call *c@tlscall(%rax)
movl %fs:(%rax), %eax

leaq c@tlsdesc(%rip), %r16
movq %r16, %rax
call *c@tlscall(%rax)
movl %fs:(%rax), %eax

.section .tbss
.globl a
.zero 8
Expand Down
Loading