[llvm] [BOLT][RISCV] Implement TLS le/ie relocations (PR #67112)
Job Noorman via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 22 03:26:08 PDT 2023
https://github.com/mtvec created https://github.com/llvm/llvm-project/pull/67112
Handle the following relocations related to TLS local-exec and initial-exec:
- R_RISCV_TLS_GOT_HI20
- R_RISCV_TPREL_HI20
- R_RISCV_TPREL_ADD
- R_RISCV_TPREL_LO12_I
- R_RISCV_TPREL_LO12_S
In addition, GNU ld has a quirk where after TLS le relaxation, two unofficial relocation types may be emitted:
- R_RISCV_TPREL_I
- R_RISCV_TPREL_S
Since they are unofficial (defined in the reserved range of relocation types), LLVM does not define them. Hence, I've defined them locally in BOLT in a private namespace.
>From 05fff7eef84e941f85e88fd342954405e63d7584 Mon Sep 17 00:00:00 2001
From: Job Noorman <jnoorman at igalia.com>
Date: Fri, 22 Sep 2023 12:15:36 +0200
Subject: [PATCH] [BOLT][RISCV] Implement TLS le/ie relocations
Handle the following relocations related to TLS local-exec and
initial-exec:
- R_RISCV_TLS_GOT_HI20
- R_RISCV_TPREL_HI20
- R_RISCV_TPREL_ADD
- R_RISCV_TPREL_LO12_I
- R_RISCV_TPREL_LO12_S
In addition, GNU ld has a quirk where after TLS le relaxation, two
unofficial relocation types may be emitted:
- R_RISCV_TPREL_I
- R_RISCV_TPREL_S
Since they are unofficial (defined in the reserved range of relocation
types), LLVM does not define them. Hence, I've defined them locally in
BOLT in a private namespace.
---
bolt/lib/Core/Relocation.cpp | 26 ++++++
bolt/lib/Rewrite/RewriteInstance.cpp | 3 +-
bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp | 2 +
bolt/test/RISCV/Inputs/tls-le-gnu-ld.yaml | 92 ++++++++++++++++++++
bolt/test/RISCV/reloc-tls.s | 44 ++++++++++
bolt/test/RISCV/tls-le-gnu-ld.test | 11 +++
6 files changed, 177 insertions(+), 1 deletion(-)
create mode 100644 bolt/test/RISCV/Inputs/tls-le-gnu-ld.yaml
create mode 100644 bolt/test/RISCV/reloc-tls.s
create mode 100644 bolt/test/RISCV/tls-le-gnu-ld.test
diff --git a/bolt/lib/Core/Relocation.cpp b/bolt/lib/Core/Relocation.cpp
index 208a8c4d35576c1..4b697311e7acba3 100644
--- a/bolt/lib/Core/Relocation.cpp
+++ b/bolt/lib/Core/Relocation.cpp
@@ -20,6 +20,13 @@
using namespace llvm;
using namespace bolt;
+namespace ELFReserved {
+enum {
+ R_RISCV_TPREL_I = 49,
+ R_RISCV_TPREL_S = 50,
+};
+} // namespace ELFReserved
+
Triple::ArchType Relocation::Arch;
static bool isSupportedX86(uint64_t Type) {
@@ -106,6 +113,13 @@ static bool isSupportedRISCV(uint64_t Type) {
case ELF::R_RISCV_RVC_BRANCH:
case ELF::R_RISCV_ADD32:
case ELF::R_RISCV_SUB32:
+ case ELF::R_RISCV_TLS_GOT_HI20:
+ case ELF::R_RISCV_TPREL_HI20:
+ case ELF::R_RISCV_TPREL_ADD:
+ case ELF::R_RISCV_TPREL_LO12_I:
+ case ELF::R_RISCV_TPREL_LO12_S:
+ case ELFReserved::R_RISCV_TPREL_I:
+ case ELFReserved::R_RISCV_TPREL_S:
return true;
}
}
@@ -204,6 +218,7 @@ static size_t getSizeForTypeRISCV(uint64_t Type) {
case ELF::R_RISCV_SUB32:
return 4;
case ELF::R_RISCV_GOT_HI20:
+ case ELF::R_RISCV_TLS_GOT_HI20:
// See extractValueRISCV for why this is necessary.
return 8;
}
@@ -512,6 +527,7 @@ static uint64_t extractValueRISCV(uint64_t Type, uint64_t Contents,
case ELF::R_RISCV_BRANCH:
return extractBImmRISCV(Contents);
case ELF::R_RISCV_GOT_HI20:
+ case ELF::R_RISCV_TLS_GOT_HI20:
// We need to know the exact address of the GOT entry so we extract the
// value from both the AUIPC and L[D|W]. We cannot rely on the symbol in the
// relocation for this since it simply refers to the object that is stored
@@ -576,6 +592,7 @@ static bool isGOTRISCV(uint64_t Type) {
default:
return false;
case ELF::R_RISCV_GOT_HI20:
+ case ELF::R_RISCV_TLS_GOT_HI20:
return true;
}
}
@@ -612,6 +629,14 @@ static bool isTLSRISCV(uint64_t Type) {
switch (Type) {
default:
return false;
+ case ELF::R_RISCV_TLS_GOT_HI20:
+ case ELF::R_RISCV_TPREL_HI20:
+ case ELF::R_RISCV_TPREL_ADD:
+ case ELF::R_RISCV_TPREL_LO12_I:
+ case ELF::R_RISCV_TPREL_LO12_S:
+ case ELFReserved::R_RISCV_TPREL_I:
+ case ELFReserved::R_RISCV_TPREL_S:
+ return true;
}
}
@@ -704,6 +729,7 @@ static bool isPCRelativeRISCV(uint64_t Type) {
case ELF::R_RISCV_RVC_JUMP:
case ELF::R_RISCV_RVC_BRANCH:
case ELF::R_RISCV_32_PCREL:
+ case ELF::R_RISCV_TLS_GOT_HI20:
return true;
}
}
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 85c0092b505f73b..3110f8408faa65c 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -2332,7 +2332,8 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection,
if (BC->isX86())
return;
- // The non-got related TLS relocations on AArch64 also could be skipped.
+ // The non-got related TLS relocations on AArch64 and RISC-V also could be
+ // skipped.
if (!Relocation::isGOT(RType))
return;
}
diff --git a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp
index 0acfedabd08bd51..76ddae06af69b12 100644
--- a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp
+++ b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp
@@ -43,6 +43,7 @@ class RISCVMCPlusBuilder : public MCPlusBuilder {
case ELF::R_RISCV_PCREL_HI20:
case ELF::R_RISCV_PCREL_LO12_I:
case ELF::R_RISCV_PCREL_LO12_S:
+ case ELF::R_RISCV_TLS_GOT_HI20:
return true;
default:
llvm_unreachable("Unexpected RISCV relocation type in code");
@@ -393,6 +394,7 @@ class RISCVMCPlusBuilder : public MCPlusBuilder {
default:
return Expr;
case ELF::R_RISCV_GOT_HI20:
+ case ELF::R_RISCV_TLS_GOT_HI20:
// The GOT is reused so no need to create GOT relocations
case ELF::R_RISCV_PCREL_HI20:
return RISCVMCExpr::create(Expr, RISCVMCExpr::VK_RISCV_PCREL_HI, Ctx);
diff --git a/bolt/test/RISCV/Inputs/tls-le-gnu-ld.yaml b/bolt/test/RISCV/Inputs/tls-le-gnu-ld.yaml
new file mode 100644
index 000000000000000..feec407ffdfdaf3
--- /dev/null
+++ b/bolt/test/RISCV/Inputs/tls-le-gnu-ld.yaml
@@ -0,0 +1,92 @@
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_RISCV
+ Entry: 0x100B0
+ProgramHeaders:
+ - Type: PT_LOAD
+ Flags: [ PF_X, PF_R ]
+ FirstSec: .text
+ LastSec: .text
+ VAddr: 0x10000
+ Align: 0x1000
+ Offset: 0x0
+ - Type: PT_TLS
+ Flags: [ PF_R ]
+ FirstSec: .tbss
+ LastSec: .tbss
+ VAddr: 0x110C0
+ Align: 0x8
+ Offset: 0xc0
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ Address: 0x100B0
+ AddressAlign: 0x4
+ Content: '13000000832202002320520067800000'
+ - Name: .tbss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ Address: 0x110C0
+ AddressAlign: 0x8
+ Size: 0x8
+ - Name: .rela.text
+ Type: SHT_RELA
+ Flags: [ SHF_INFO_LINK ]
+ Link: .symtab
+ AddressAlign: 0x8
+ Info: .text
+ Relocations:
+ - Offset: 0x100B4
+ Type: R_RISCV_NONE
+ - Offset: 0x100B4
+ Type: R_RISCV_RELAX
+ - Offset: 0x100B4
+ Type: R_RISCV_NONE
+ - Offset: 0x100B4
+ Type: R_RISCV_RELAX
+ - Offset: 0x100B4
+ Symbol: i
+ Type: 0x31
+ - Offset: 0x100B4
+ Type: R_RISCV_RELAX
+ - Offset: 0x100B8
+ Symbol: i
+ Type: 0x32
+ - Offset: 0x100B8
+ Type: R_RISCV_RELAX
+ - Type: SectionHeaderTable
+ Sections:
+ - Name: .text
+ - Name: .rela.text
+ - Name: .tbss
+ - Name: .symtab
+ - Name: .strtab
+ - Name: .shstrtab
+Symbols:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ Value: 0x100B0
+ - Name: .tbss
+ Type: STT_SECTION
+ Section: .tbss
+ Value: 0x110C0
+ - Name: '__global_pointer$'
+ Index: SHN_ABS
+ Binding: STB_GLOBAL
+ Value: 0x118C0
+ - Name: i
+ Type: STT_TLS
+ Section: .tbss
+ Binding: STB_GLOBAL
+ Size: 0x8
+ - Name: _start
+ Section: .text
+ Binding: STB_GLOBAL
+ Value: 0x100B0
+ Size: 0x10
+...
diff --git a/bolt/test/RISCV/reloc-tls.s b/bolt/test/RISCV/reloc-tls.s
new file mode 100644
index 000000000000000..6ced25b8e630a56
--- /dev/null
+++ b/bolt/test/RISCV/reloc-tls.s
@@ -0,0 +1,44 @@
+// RUN: llvm-mc -triple riscv64 -filetype obj -o %t.o %s
+// RUN: ld.lld --emit-relocs -o %t %t.o
+// RUN: llvm-bolt --print-cfg --print-only=tls_le,tls_ie -o /dev/null %t \
+// RUN: | FileCheck %s
+
+// CHECK-LABEL: Binary Function "tls_le{{.*}}" after building cfg {
+// CHECK: lui a5, 0
+// CHECK-NEXT: add a5, a5, tp
+// CHECK-NEXT: lw t0, 0(a5)
+// CHECK-NEXT: sw t0, 0(a5)
+
+// CHECK-LABEL: Binary Function "tls_ie" after building cfg {
+// CHECK-LABEL: .Ltmp0
+// CHECK: auipc a0, %pcrel_hi(__BOLT_got_zero+{{[0-9]+}})
+// CHECK-NEXT: ld a0, %pcrel_lo(.Ltmp0)(a0)
+ .text
+ .globl tls_le, _start
+ .p2align 2
+tls_le:
+_start:
+ nop
+ lui a5, %tprel_hi(i)
+ add a5, a5, tp, %tprel_add(i)
+ lw t0, %tprel_lo(i)(a5)
+ sw t0, %tprel_lo(i)(a5)
+ ret
+ .size _start, .-_start
+
+ .globl tls_ie
+ .p2align 2
+tls_ie:
+ nop
+ la.tls.ie a0, i
+ ret
+ .size tls_ie, .-tls_ie
+
+ .section .tbss,"awT", at nobits
+ .type i, at object
+ .globl i
+ .p2align 3
+i:
+ .quad 0
+ .size i, .-i
+
diff --git a/bolt/test/RISCV/tls-le-gnu-ld.test b/bolt/test/RISCV/tls-le-gnu-ld.test
new file mode 100644
index 000000000000000..c3ff08b30ee60dd
--- /dev/null
+++ b/bolt/test/RISCV/tls-le-gnu-ld.test
@@ -0,0 +1,11 @@
+// This test checks that the binaries produces with GNU ld TLS le relaxation are
+// properly processed by BOLT. GNU ld currently emits two non-standard
+// relocations (R_RISCV_TPREL_I and R_RISCV_TPREL_S) in this case.
+
+// RUN: yaml2obj %p/Inputs/tls-le-gnu-ld.yaml &> %t.exe
+// RUN: llvm-bolt %t.exe -o %t.bolt.exe --print-cfg --print-only=_start \
+// RUN: | FileCheck %s
+
+// CHECK: Binary Function "_start" after building cfg {
+// CHECK: lw t0, 0(tp)
+// CHECK-NEXT: sw t0, 0(tp)
More information about the llvm-commits
mailing list