[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