https://github.com/heiher created 
https://github.com/llvm/llvm-project/pull/172618

This patch adds support for processing the relocation types introduced in 
la-abi-specs v2.50.

Link: https://github.com/loongson/la-abi-specs/pull/16
Link: https://sourceware.org/pipermail/binutils/2025-December/146091.html

>From aa7aa53e7cc77eb153688605f511b1e94d7e7db3 Mon Sep 17 00:00:00 2001
From: WANG Rui <[email protected]>
Date: Thu, 4 Sep 2025 14:08:53 +0800
Subject: [PATCH] [lld][LoongArch] Add reloc types for LA32R/LA32S

This patch adds support for processing the relocation types introduced
in la-abi-specs v2.50.

Link: https://github.com/loongson/la-abi-specs/pull/16
Link: https://sourceware.org/pipermail/binutils/2025-December/146091.html
---
 lld/ELF/Arch/LoongArch.cpp                 |  67 +++++++++-
 lld/ELF/InputSection.cpp                   |  62 ++++++++++
 lld/ELF/Relocations.cpp                    |   2 +-
 lld/ELF/Relocations.h                      |   1 +
 lld/test/ELF/loongarch-call30.s            |  64 ++++++++++
 lld/test/ELF/loongarch-relax-call30-2.s    |  65 ++++++++++
 lld/test/ELF/loongarch-relax-call30.s      | 136 +++++++++++++++++++++
 lld/test/ELF/loongarch-relax-emit-relocs.s | 101 ++++++++++-----
 lld/test/ELF/loongarch-tls-gd-edge-case.s  |  10 +-
 lld/test/ELF/loongarch-tls-gd.s            |  10 +-
 lld/test/ELF/loongarch-tls-ie.s            |  21 ++--
 lld/test/ELF/loongarch-tls-ld.s            |  10 +-
 lld/test/ELF/loongarch-tlsdesc.s           |  30 ++++-
 13 files changed, 514 insertions(+), 65 deletions(-)
 create mode 100644 lld/test/ELF/loongarch-call30.s
 create mode 100644 lld/test/ELF/loongarch-relax-call30-2.s
 create mode 100644 lld/test/ELF/loongarch-relax-call30.s

diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index c6cdf05547d3f..1cea0d41bf74c 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -184,6 +184,10 @@ static uint32_t setJ5(uint32_t insn, uint32_t imm) {
   return (insn & 0xfffffc1f) | (extractBits(imm, 4, 0) << 5);
 }
 
+static uint32_t setK10(uint32_t insn, uint32_t imm) {
+  return (insn & 0xffc003ff) | (extractBits(imm, 9, 0) << 10);
+}
+
 static uint32_t setK12(uint32_t insn, uint32_t imm) {
   return (insn & 0xffc003ff) | (extractBits(imm, 11, 0) << 10);
 }
@@ -439,6 +443,13 @@ RelExpr LoongArch::getRelExpr(const RelType type, const 
Symbol &s,
     // [1]: 
https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=9f482b73f41a9a1bbfb173aad0733d1c824c788a
     // [2]: https://github.com/loongson/la-abi-specs/pull/3
     return isJirl(read32le(loc)) ? R_PLT : R_ABS;
+  case R_LARCH_PCADD_LO12:
+  case R_LARCH_GOT_PCADD_LO12:
+  case R_LARCH_TLS_IE_PCADD_LO12:
+  case R_LARCH_TLS_LD_PCADD_LO12:
+  case R_LARCH_TLS_GD_PCADD_LO12:
+  case R_LARCH_TLS_DESC_PCADD_LO12:
+    return RE_LOONGARCH_PC_INDIRECT;
   case R_LARCH_TLS_DTPREL32:
   case R_LARCH_TLS_DTPREL64:
     return R_DTPREL;
@@ -469,10 +480,12 @@ RelExpr LoongArch::getRelExpr(const RelType type, const 
Symbol &s,
   case R_LARCH_32_PCREL:
   case R_LARCH_64_PCREL:
   case R_LARCH_PCREL20_S2:
+  case R_LARCH_PCADD_HI20:
     return R_PC;
   case R_LARCH_B16:
   case R_LARCH_B21:
   case R_LARCH_B26:
+  case R_LARCH_CALL30:
   case R_LARCH_CALL36:
     return R_PLT_PC;
   case R_LARCH_GOT_PC_HI20:
@@ -482,6 +495,9 @@ RelExpr LoongArch::getRelExpr(const RelType type, const 
Symbol &s,
   case R_LARCH_TLS_IE64_PC_LO20:
   case R_LARCH_TLS_IE64_PC_HI12:
     return RE_LOONGARCH_GOT_PAGE_PC;
+  case R_LARCH_GOT_PCADD_HI20:
+  case R_LARCH_TLS_IE_PCADD_HI20:
+    return R_GOT_PC;
   case R_LARCH_GOT_PC_LO12:
   case R_LARCH_TLS_IE_PC_LO12:
     return RE_LOONGARCH_GOT;
@@ -545,12 +561,15 @@ RelExpr LoongArch::getRelExpr(const RelType type, const 
Symbol &s,
   case R_LARCH_TLS_DESC_LO12:
   case R_LARCH_TLS_DESC64_LO20:
   case R_LARCH_TLS_DESC64_HI12:
+  case R_LARCH_TLS_DESC_PCADD_HI20:
     return R_TLSDESC;
   case R_LARCH_TLS_DESC_CALL:
     return R_TLSDESC_CALL;
   case R_LARCH_TLS_LD_PCREL20_S2:
+  case R_LARCH_TLS_LD_PCADD_HI20:
     return R_TLSLD_PC;
   case R_LARCH_TLS_GD_PCREL20_S2:
+  case R_LARCH_TLS_GD_PCADD_HI20:
     return R_TLSGD_PC;
   case R_LARCH_TLS_DESC_PCREL20_S2:
     return R_TLSDESC_PC;
@@ -628,6 +647,22 @@ void LoongArch::relocate(uint8_t *loc, const Relocation 
&rel,
     write32le(loc, setD10k16(read32le(loc), val >> 2));
     return;
 
+  case R_LARCH_CALL30: {
+    // This relocation is designed for adjacent pcaddu12i+jirl pairs that
+    // are patched in one time.
+    // The relocation range is [-4G, +4G) (of course must be 4-byte aligned).
+    if ((int64_t)val != llvm::SignExtend64(val, 32))
+      reportRangeError(ctx, loc, rel, Twine(val), llvm::minIntN(32),
+                       llvm::maxIntN(32));
+    checkAlignment(ctx, loc, val, 4, rel);
+    uint32_t hi20 = extractBits(val, 31, 12);
+    // Despite the name, the lower part is actually 12 bits with 4-byte 
aligned.
+    uint32_t lo10 = extractBits(val, 11, 2);
+    write32le(loc, setJ20(read32le(loc), hi20));
+    write32le(loc + 4, setK10(read32le(loc + 4), lo10));
+    return;
+  }
+
   case R_LARCH_CALL36: {
     // This relocation is designed for adjacent pcaddu18i+jirl pairs that
     // are patched in one time. Because of sign extension of these insns'
@@ -671,6 +706,12 @@ void LoongArch::relocate(uint8_t *loc, const Relocation 
&rel,
   case R_LARCH_TLS_LE_LO12_R:
   case R_LARCH_TLS_DESC_PC_LO12:
   case R_LARCH_TLS_DESC_LO12:
+  case R_LARCH_PCADD_LO12:
+  case R_LARCH_GOT_PCADD_LO12:
+  case R_LARCH_TLS_IE_PCADD_LO12:
+  case R_LARCH_TLS_LD_PCADD_LO12:
+  case R_LARCH_TLS_GD_PCADD_LO12:
+  case R_LARCH_TLS_DESC_PCADD_LO12:
     write32le(loc, setK12(read32le(loc), extractBits(val, 11, 0)));
     return;
 
@@ -690,6 +731,17 @@ void LoongArch::relocate(uint8_t *loc, const Relocation 
&rel,
   case R_LARCH_TLS_DESC_HI20:
     write32le(loc, setJ20(read32le(loc), extractBits(val, 31, 12)));
     return;
+  case R_LARCH_PCADD_HI20:
+  case R_LARCH_GOT_PCADD_HI20:
+  case R_LARCH_TLS_IE_PCADD_HI20:
+  case R_LARCH_TLS_LD_PCADD_HI20:
+  case R_LARCH_TLS_GD_PCADD_HI20:
+  case R_LARCH_TLS_DESC_PCADD_HI20: {
+    uint64_t hi = val + 0x800;
+    checkInt(ctx, loc, SignExtend64(hi, 32) >> 12, 20, rel);
+    write32le(loc, setJ20(read32le(loc), extractBits(hi, 31, 12)));
+    return;
+  }
   case R_LARCH_TLS_LE_HI20_R:
     write32le(loc, setJ20(read32le(loc), extractBits(val + 0x800, 31, 12)));
     return;
@@ -998,12 +1050,16 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection 
&sec, size_t i,
 
 // Relax code sequence.
 // From:
-//   pcaddu18i $ra, %call36(foo)
-//   jirl $ra, $ra, 0
+//   la32r:
+//     pcaddu12i $ra, %call30(foo)
+//     jirl $ra, $ra, 0
+//   la32s/la64:
+//     pcaddu18i $ra, %call36(foo)
+//     jirl $ra, $ra, 0
 // To:
 //   b/bl foo
-static void relaxCall36(Ctx &ctx, const InputSection &sec, size_t i,
-                        uint64_t loc, Relocation &r, uint32_t &remove) {
+static void relaxMediumCall(Ctx &ctx, const InputSection &sec, size_t i,
+                            uint64_t loc, Relocation &r, uint32_t &remove) {
   const uint64_t dest =
       (r.expr == R_PLT_PC ? r.sym->getPltVA(ctx) : r.sym->getVA(ctx)) +
       r.addend;
@@ -1108,9 +1164,10 @@ static bool relax(Ctx &ctx, InputSection &sec) {
       } else if (isPairRelaxable(relocs, i))
         relaxPCHi20Lo12(ctx, sec, i, loc, r, relocs[i + 2], remove);
       break;
+    case R_LARCH_CALL30:
     case R_LARCH_CALL36:
       if (relaxable(relocs, i))
-        relaxCall36(ctx, sec, i, loc, r, remove);
+        relaxMediumCall(ctx, sec, i, loc, r, remove);
       break;
     case R_LARCH_TLS_LE_HI20_R:
     case R_LARCH_TLS_LE_ADD_R:
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index ff7ef2dce5c79..3b0fab23481c1 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -714,6 +714,63 @@ static Relocation *getRISCVPCRelHi20(Ctx &ctx, const 
InputSectionBase *loSec,
   return nullptr;
 }
 
+// For RE_LARCH_PC_INDIRECT (R_LARCH_*PCADD_LO12), the symbol actually points
+// the corresponding R_LARCH_*PCADD_HI20 relocation, and the target VA is
+// calculated using PCADD_HI20's symbol.
+//
+// This function returns the R_LARCH_*PCADD_HI20 relocation from the
+// R_LARCH_*PCADD_LO12 relocation.
+static Relocation *getLoongArchPCAddHi20(Ctx &ctx,
+                                         const InputSectionBase *loSec,
+                                         const Relocation &loReloc) {
+  int64_t addend = loReloc.addend;
+  Symbol *sym = loReloc.sym;
+
+  const Defined *d = cast<Defined>(sym);
+  if (!d->section) {
+    Err(ctx) << loSec->getLocation(loReloc.offset)
+             << ": R_LARCH_*PCADD_LO12 relocation points to an absolute 
symbol: "
+             << sym->getName();
+    return nullptr;
+  }
+  InputSection *hiSec = cast<InputSection>(d->section);
+
+  if (hiSec != loSec)
+    Err(ctx) << loSec->getLocation(loReloc.offset)
+             << ": R_LARCH_*PCADD_LO12 relocation points to a symbol '"
+             << sym->getName() << "' in a different section '" << hiSec->name
+             << "'";
+
+  if (addend != 0)
+    Warn(ctx) << loSec->getLocation(loReloc.offset)
+              << ": non-zero addend in R_LARCH_*PCADD_LO12 relocation to "
+              << hiSec->getObjMsg(d->value) << " is ignored";
+
+  // Relocations are sorted by offset, so we can use std::equal_range to do
+  // binary search.
+  Relocation hiReloc;
+  hiReloc.offset = d->value + addend;
+  auto range =
+      std::equal_range(hiSec->relocs().begin(), hiSec->relocs().end(), hiReloc,
+                       [](const Relocation &lhs, const Relocation &rhs) {
+                         return lhs.offset < rhs.offset;
+                       });
+
+  for (auto it = range.first; it != range.second; ++it)
+    if (it->type == R_LARCH_PCADD_HI20 || it->type == R_LARCH_GOT_PCADD_HI20 ||
+        it->type == R_LARCH_TLS_IE_PCADD_HI20 ||
+        it->type == R_LARCH_TLS_LD_PCADD_HI20 ||
+        it->type == R_LARCH_TLS_GD_PCADD_HI20 ||
+        it->type == R_LARCH_TLS_DESC_PCADD_HI20)
+      return &*it;
+
+  Err(ctx) << loSec->getLocation(loReloc.offset)
+           << ": R_LARCH_*PCADD_LO12 relocation points to "
+           << hiSec->getObjMsg(d->value)
+           << " without an associated R_LARCH_*PCADD_HI20 relocation";
+  return nullptr;
+}
+
 // A TLS symbol's virtual address is relative to the TLS segment. Add a
 // target-specific adjustment to produce a thread-pointer-relative offset.
 static int64_t getTlsTpOffset(Ctx &ctx, const Symbol &s) {
@@ -891,6 +948,11 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, 
const Relocation &r,
       return getRelocTargetVA(ctx, *hiRel, r.sym->getVA(ctx));
     return 0;
   }
+  case RE_LOONGARCH_PC_INDIRECT: {
+    if (const Relocation *hiRel = getLoongArchPCAddHi20(ctx, this, r))
+      return getRelocTargetVA(ctx, *hiRel, r.sym->getVA(ctx, a));
+    return 0;
+  }
   case RE_LOONGARCH_PAGE_PC:
     return getLoongArchPageDelta(r.sym->getVA(ctx, a), p, r.type);
   case R_PC:
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 59aa43036ce01..ae3578d8e7cb3 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -148,7 +148,7 @@ static bool isRelExpr(RelExpr expr) {
   return oneof<R_PC, R_GOTREL, R_GOTPLTREL, RE_ARM_PCA, RE_MIPS_GOTREL,
                RE_PPC64_CALL, RE_PPC64_RELAX_TOC, RE_AARCH64_PAGE_PC,
                R_RELAX_GOT_PC, RE_RISCV_PC_INDIRECT, RE_PPC64_RELAX_GOT_PC,
-               RE_LOONGARCH_PAGE_PC>(expr);
+               RE_LOONGARCH_PAGE_PC, RE_LOONGARCH_PC_INDIRECT>(expr);
 }
 
 static RelExpr toPlt(RelExpr expr) {
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index 86ca298cd7a56..bff899d5c4d0c 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -132,6 +132,7 @@ enum RelExpr {
   // also reused for TLS, making the semantics differ from other architectures.
   RE_LOONGARCH_GOT,
   RE_LOONGARCH_GOT_PAGE_PC,
+  RE_LOONGARCH_PC_INDIRECT,
   RE_LOONGARCH_TLSGD_PAGE_PC,
   RE_LOONGARCH_TLSDESC_PAGE_PC,
   RE_LOONGARCH_RELAX_TLS_GD_TO_IE_PAGE_PC,
diff --git a/lld/test/ELF/loongarch-call30.s b/lld/test/ELF/loongarch-call30.s
new file mode 100644
index 0000000000000..907e8704e908b
--- /dev/null
+++ b/lld/test/ELF/loongarch-call30.s
@@ -0,0 +1,64 @@
+# REQUIRES: loongarch
+
+# RUN: rm -rf %t && split-file %s %t
+# RUN: llvm-mc --filetype=obj --triple=loongarch32-unknown-elf %t/a.s -o %t/a.o
+
+# RUN: ld.lld %t/a.o --section-start=.text=0x20010 
--section-start=.sec.foo=0x21020 -o %t/exe1
+# RUN: llvm-objdump --no-show-raw-insn -d %t/exe1 | FileCheck 
--match-full-lines %s --check-prefix=EXE1
+## hi20 = target - pc >> 12 = 0x21020 - 0x20010 >> 12 = 1
+## lo12 = target - pc & (1 << 12) - 1 = 0x21020 - 0x20010 & 0xfff = 16
+# EXE1:      20010: pcaddu12i $t0, 1
+# EXE1-NEXT: 20014: jirl $zero, $t0, 16
+
+# RUN: ld.lld %t/a.o --section-start=.text=0x20010 
--section-start=.sec.foo=0x21820 -o %t/exe2
+# RUN: llvm-objdump --no-show-raw-insn -d %t/exe2 | FileCheck 
--match-full-lines %s --check-prefix=EXE2
+## hi20 = target - pc >> 12 = 0x21820 - 0x20010 >> 12 = 1
+## lo12 = target - pc & (1 << 12) - 1 = 0x21820 - 0x20010 & 0xfff = 2064
+# EXE2:      20010: pcaddu12i $t0, 1
+# EXE2-NEXT: 20014: jirl $zero, $t0, 2064
+
+# RUN: ld.lld %t/a.o -shared -T %t/a.t -o %t/a.so
+# RUN: llvm-readelf -x .got.plt %t/a.so | FileCheck --check-prefix=GOTPLT %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t/a.so | FileCheck 
--check-prefix=SO %s
+## PLT should be present in this case.
+# SO:    Disassembly of section .plt:
+# SO:    <.plt>:
+##       foo@plt:
+# SO:    1234520:  pcaddu12i $t3, 64{{$}}
+# SO-NEXT:         ld.w $t3, $t3, 444{{$}}
+# SO-NEXT:         jirl $t1, $t3, 0
+# SO-NEXT:         nop
+
+# SO:   Disassembly of section .text:
+# SO:   <_start>:
+## hi20 = foo@plt - pc >> 12 = 0x1234520 - 0x1274670 >> 12 = -65
+## lo18 = foo@plt - pc & (1 << 12) - 1 = 0x1234520 - 0x1274670 & 0xfff = 3760
+# SO-NEXT: pcaddu12i $t0, -65{{$}}
+# SO-NEXT: jirl $zero, $t0, 3760{{$}}
+
+# GOTPLT:      section '.got.plt':
+# GOTPLT-NEXT: 0x012746d4 00000000 00000000 00452301
+
+## Impossible case in reality becasue all LoongArch instructions are fixed 
4-bytes long.
+# RUN: not ld.lld %t/a.o --section-start=.text=0x20000 
--section-start=.sec.foo=0x40001 -o /dev/null 2>&1 | \
+# RUN:   FileCheck -DFILE=%t/a.o --check-prefix=ERROR-ALIGN %s
+# ERROR-ALIGN: error: [[FILE]]:(.text+0x0): improper alignment for relocation 
R_LARCH_CALL30: 0x20001 is not aligned to 4 bytes
+
+#--- a.t
+SECTIONS {
+ .plt   0x1234500: { *(.plt) }
+ .text  0x1274670: { *(.text) }
+}
+
+#--- a.s
+.text
+.global _start
+_start:
+  .reloc ., R_LARCH_CALL30, foo
+  pcaddu12i $t0, 0
+  jirl      $zero, $t0, 0
+
+.section .sec.foo,"awx"
+.global foo
+foo:
+  ret
diff --git a/lld/test/ELF/loongarch-relax-call30-2.s 
b/lld/test/ELF/loongarch-relax-call30-2.s
new file mode 100644
index 0000000000000..45584f4e14dc8
--- /dev/null
+++ b/lld/test/ELF/loongarch-relax-call30-2.s
@@ -0,0 +1,65 @@
+# REQUIRES: loongarch
+## Relax R_LARCH_CALL30. This test tests boundary cases and some special 
symbols.
+
+# RUN: rm -rf %t && split-file %s %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=loongarch32 -mattr=+relax a.s -o a.o
+
+# RUN: ld.lld -T lds a.o -o a
+# RUN: llvm-objdump -d --no-show-raw-insn a | FileCheck %s 
--check-prefixes=RELAX,RELAX-MID
+
+## Unsure whether this needs a diagnostic. GNU ld allows this.
+# RUN: ld.lld -T lds -pie a.o -o a.pie
+# RUN: llvm-objdump -d --no-show-raw-insn a.pie | FileCheck %s 
--check-prefixes=RELAX,RELAX-MID
+
+# RUN: ld.lld -T lds -pie -z notext -z ifunc-noplt a.o -o a.ifunc-noplt
+# RUN: llvm-objdump -d --no-show-raw-insn a.ifunc-noplt | FileCheck %s 
--check-prefixes=RELAX,NORELAX-MID
+
+# RELAX-LABEL:  <_start>:
+## offset = 0x10000000 - 0x8000000 = 0x8000000(134217728), hi=512, lo18=0
+# RELAX-NEXT:    8000000:  pcaddu12i $ra, 32768
+# RELAX-NEXT:              jirl   $ra, $ra, 0
+# RELAX-NEXT:              bl     134217720
+# RELAX-NEXT:              bl     -134217728
+## offset = 12 - 0x8000010 = -0x8000004(-134217732), hi=512, lo18=-4
+# RELAX-NEXT:    8000010:  pcaddu12i $ra, -32769
+# RELAX-NEXT:              jirl   $ra, $ra, 4092
+# RELAX-EMPTY:
+
+# RELAX-MID-LABEL:  <.mid>:
+## offset = 0x8010000 - 0x8008000 = 32768
+# RELAX-MID-NEXT:    8008000:  bl     32768
+# RELAX-MID-NEXT:              b      32764
+# RELAX-MID-EMPTY:
+
+# NORELAX-MID-LABEL: <.mid>:
+# NORELAX-MID-NEXT:  8008000:  pcaddu12i $ra, 0
+# NORELAX-MID-NEXT:            jirl   $ra, $ra, 0
+# NORELAX-MID-NEXT:            pcaddu12i $t0, 0
+# NORELAX-MID-NEXT:            jr     $t0
+# NORELAX-MID-EMPTY:
+
+#--- a.s
+.global _start, ifunc
+_start:
+  call30 pos       # exceed positive range (.text+0x7fffffc), not relaxed
+  call30 pos       # relaxed
+  call30 neg       # relaxed
+  call30 neg       # exceed negative range (.text+16-0x8000000), not relaxed
+
+.section .mid,"ax",@progbits
+.balign 16
+  call30 ifunc      # enable ifunc, not relaxed
+  tail30 $t0, ifunc # enable ifunc, not relaxed
+
+.type ifunc, @gnu_indirect_function
+ifunc:
+  ret
+
+#--- lds
+SECTIONS {
+  .text 0x8000000 : { *(.text) }
+  .mid  0x8008000 : { *(.mid) }
+  .iplt 0x8010000 : { *(.iplt) }
+}
+neg = 12;
+pos = 0x10000000;
diff --git a/lld/test/ELF/loongarch-relax-call30.s 
b/lld/test/ELF/loongarch-relax-call30.s
new file mode 100644
index 0000000000000..f3172897f47fb
--- /dev/null
+++ b/lld/test/ELF/loongarch-relax-call30.s
@@ -0,0 +1,136 @@
+# REQUIRES: loongarch
+## Relax R_LARCH_CALL30, which involves the macro instructions call30/tail30.
+
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+# RUN: llvm-mc -filetype=obj -triple=loongarch32 -mattr=+relax a.s -o a.32.o
+# RUN: llvm-mc -filetype=obj -triple=loongarch32 -mattr=+relax b.s -o b.32.o
+# RUN: ld.lld -shared -soname=b.so b.32.o -o b.32.so
+# RUN: ld.lld -T lds a.32.o b.32.so -o 32
+# RUN: llvm-objdump -td --no-show-raw-insn 32 | FileCheck %s 
--check-prefix=RELAX
+
+## --no-relax disables relaxation.
+# RUN: ld.lld -T lds a.32.o b.32.so --no-relax -o 32.norelax
+# RUN: llvm-objdump -td --no-show-raw-insn 32.norelax | FileCheck %s 
--check-prefix=NORELAX
+
+# RELAX:       {{0*}}00010000 g       .text  {{0*}}0000001c _start
+# RELAX:       {{0*}}0001001c g       .text  {{0*}}00000000 _start_end
+# RELAX:       {{0*}}00010808 g       .mid   {{0*}}00000000 mid_end
+# RELAX:       {{0*}}10010010 g       .high  {{0*}}00000000 high_end
+
+# RELAX-LABEL: <_start>:
+## offset = 0x10018 - 0x10000 = 24
+# RELAX-NEXT:      10000:  bl     24 <a>
+# RELAX-NEXT:              b      20 <a>
+# RELAX-NEXT:              nop
+# RELAX-NEXT:              nop
+## offset = .plt(0x10400)+32 - 0x10010 = 1040
+# RELAX-NEXT:      10010:  bl     1040 <bar+0x10420>
+# RELAX-NEXT:              b      1036 <bar+0x10420>
+# RELAX-EMPTY:
+# RELAX-NEXT: <a>:
+# RELAX-NEXT:      10018:  ret
+# RELAX-EMPTY:
+
+# RELAX-LABEL: <.mid>:
+## offset = 0x10000 - 0x10800 = -2048
+# RELAX-NEXT:      10800:  bl     -2048 <_start>
+# RELAX-NEXT:              b      -2052 <_start>
+# RELAX-EMPTY:
+
+# RELAX-LABEL: <.mid2>:
+## offset = 0x10000 - 0x1010000 = -16777216
+# RELAX-NEXT:    1010000:  bl     -16777216 <_start>
+# RELAX-NEXT:              b      -16777220 <_start>
+# RELAX-EMPTY:
+
+# RELAX-LABEL: <.high>:
+## offset = 0x10000 - 0x10010000 = -0x10000000, hi=-1024, lo18=0
+# RELAX-NEXT:   10010000:  pcaddu12i $ra, -65536
+# RELAX-NEXT:              jirl   $ra, $ra, 0
+# RELAX-NEXT:              pcaddu12i $t0, -65537
+# RELAX-NEXT:              jirl   $zero, $t0, 4088
+# RELAX-EMPTY:
+
+
+# NORELAX-LABEL: <_start>:
+## offset = 0x10020 - 0x10000 = 0x20, hi=0, lo18=32
+# NORELAX-NEXT:    10000:  pcaddu12i $ra, 0
+# NORELAX-NEXT:            jirl   $ra, $ra, 32
+## offset = 0x10020 - 0x10008 = 0x18, hi=0, lo18=24
+# NORELAX-NEXT:    10008:  pcaddu12i $t0, 0
+# NORELAX-NEXT:            jirl   $zero, $t0, 24
+## offset = .plt(0x10400)+32 - 0x10010 = 0x410, hi=0, lo18=1040
+# NORELAX-NEXT:    10010:  pcaddu12i $ra, 0
+# NORELAX-NEXT:            jirl   $ra, $ra, 1040
+## offset = .plt(0x10400)+32 - 0x10018 = 0x408, hi=0, lo18=1032
+# NORELAX-NEXT:    10018:  pcaddu12i $t0, 0
+# NORELAX-NEXT:            jirl   $zero, $t0, 1032
+# NORELAX-EMPTY:
+# NORELAX-NEXT: <a>:
+# NORELAX-NEXT:      10020:  ret
+# NORELAX-EMPTY:
+
+# NORELAX-LABEL: <.mid>:
+## offset = 0x10000 - 0x10800 = -0x800, hi=0, lo18=-2048
+# NORELAX-NEXT:    10800:  pcaddu12i $ra, -1
+# NORELAX-NEXT:            jirl   $ra, $ra, 2048
+# NORELAX-NEXT:            pcaddu12i $t0, -1
+# NORELAX-NEXT:            jirl   $zero, $t0, 2040
+# NORELAX-EMPTY:
+
+# NORELAX-LABEL: <.mid2>:
+## offset = 0x10000 - 0x1010000 = -0x1000000, hi=-64, lo18=0
+# NORELAX-NEXT:  1010000:  pcaddu12i $ra, -4096
+# NORELAX-NEXT:            jirl   $ra, $ra, 0
+# NORELAX-NEXT:            pcaddu12i $t0, -4097
+# NORELAX-NEXT:            jirl   $zero, $t0, 4088
+# NORELAX-EMPTY:
+
+# NORELAX-LABEL: <.high>:
+## offset = 0x10000 - 0x10010000 = -0x10000000, hi=-1024, lo18=0
+# NORELAX-NEXT: 10010000:  pcaddu12i $ra, -65536
+# NORELAX-NEXT:            jirl   $ra, $ra, 0
+# NORELAX-NEXT:            pcaddu12i $t0, -65537
+# NORELAX-NEXT:            jirl   $zero, $t0, 4088
+# NORELAX-EMPTY:
+
+#--- a.s
+.global _start, _start_end
+_start:
+  call30 a          # relaxed. la32: bl
+  tail30 $t0, a     # relaxed. la32: b
+.balign 16
+  call30 bar        # PLT call30 can be relaxed. la32: bl
+  tail30 $t0, bar   # PLT tail30 can be relaxed. la32: bl
+
+a:
+  ret
+.size _start, . - _start
+_start_end:
+
+.section .mid,"ax",@progbits
+  call30 _start         # relaxed. la32: bl
+  tail30 $t0, _start    # relaxed. la32: b
+
+.section .mid2,"ax",@progbits
+  call30 _start         # relaxed. la32: bl
+  tail30 $t0, _start    # relaxed. la32: b
+
+.section .high,"ax",@progbits
+  call30 _start         # exceed range, not relaxed
+  tail30 $t0, _start    # exceed range, not relaxed
+
+#--- b.s
+.globl bar
+bar:
+  ret
+
+#--- lds
+SECTIONS {
+  .text 0x10000 : { *(.text) }
+  .plt 0x10400 : { *(.plt) }
+  .mid 0x10800 : { *(.mid); mid_end = .; }
+  .mid2 0x1010000 : { *(.mid2) }
+  .high 0x10010000 : { *(.high); high_end = .; }
+}
diff --git a/lld/test/ELF/loongarch-relax-emit-relocs.s 
b/lld/test/ELF/loongarch-relax-emit-relocs.s
index 6e1e85c004439..f2d6edc97d27a 100644
--- a/lld/test/ELF/loongarch-relax-emit-relocs.s
+++ b/lld/test/ELF/loongarch-relax-emit-relocs.s
@@ -1,7 +1,7 @@
 # REQUIRES: loongarch
 ## Test that we can handle --emit-relocs while relaxing.
 
-# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+32s,+relax %s -o 
%t.32.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %s -o %t.32.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax --defsym 
ELF64=1 %s -o %t.64.o
 # RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs %t.32.o 
-o %t.32
 # RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs %t.64.o 
-o %t.64
@@ -16,17 +16,39 @@
 # RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs 
--no-relax %t.64.o -o %t.64.norelax
 # RUN: llvm-objdump -dr %t.64.norelax | FileCheck %s --check-prefix=NORELAX
 
-# RELAX:      00010000 <_start>:
-# RELAX-NEXT:   pcaddi $a0, 0
-# RELAX-NEXT:     R_LARCH_RELAX _start
-# RELAX-NEXT:     R_LARCH_RELAX *ABS*
-# RELAX-NEXT:     R_LARCH_PCREL20_S2 _start
-# RELAX-NEXT:     R_LARCH_RELAX *ABS*
-# RELAX-NEXT:   pcaddi $a0, -1
-# RELAX-NEXT:     R_LARCH_RELAX _start
-# RELAX-NEXT:     R_LARCH_RELAX *ABS*
-# RELAX-NEXT:     R_LARCH_PCREL20_S2 _start
-# RELAX-NEXT:     R_LARCH_RELAX *ABS*
+# RELAX32:     00010000 <_start>:
+# RELAX32-NEXT:  pcaddu12i $a0, 0
+# RELAX32-NEXT:    R_LARCH_PCADD_HI20 _start
+# RELAX32-NEXT:    R_LARCH_RELAX *ABS*
+# RELAX32-NEXT:  addi.w $a0, $a0, 0
+# RELAX32-NEXT:    R_LARCH_PCADD_LO12 .Lpcadd_hi0
+# RELAX32-NEXT:    R_LARCH_RELAX *ABS*
+# RELAX32:     00010008 <.Lpcadd_hi1>:
+# RELAX32-NEXT:  pcaddu12i $a0, 16
+# RELAX32-NEXT:    R_LARCH_GOT_PCADD_HI20 _start
+# RELAX32-NEXT:    R_LARCH_RELAX *ABS*
+# RELAX32-NEXT:  ld.w $a0, $a0, 0
+# RELAX32-NEXT:    R_LARCH_GOT_PCADD_LO12 .Lpcadd_hi1
+# RELAX32-NEXT:    R_LARCH_RELAX *ABS*
+
+# RELAX64:     00010000 <_start>:
+# RELAX64-NEXT:  pcaddi $a0, 0
+# RELAX64-NEXT:    R_LARCH_RELAX _start
+# RELAX64-NEXT:    R_LARCH_RELAX *ABS*
+# RELAX64-NEXT:    R_LARCH_PCREL20_S2 _start
+# RELAX64-NEXT:    R_LARCH_RELAX *ABS*
+# RELAX64-NEXT:  pcaddi $a0, -1
+# RELAX64-NEXT:    R_LARCH_RELAX _start
+# RELAX64-NEXT:    R_LARCH_RELAX *ABS*
+# RELAX64-NEXT:    R_LARCH_PCREL20_S2 _start
+# RELAX64-NEXT:    R_LARCH_RELAX *ABS*
+
+# RELAX32-NEXT:  bl  -16
+# RELAX32-NEXT:    R_LARCH_B26 _start
+# RELAX32-NEXT:    R_LARCH_RELAX *ABS*
+# RELAX32-NEXT:  b   -20
+# RELAX32-NEXT:    R_LARCH_B26 _start
+# RELAX32-NEXT:    R_LARCH_RELAX *ABS*
 
 # RELAX64-NEXT:  bl  -8
 # RELAX64-NEXT:    R_LARCH_B26 _start
@@ -39,16 +61,34 @@
 # RELAX-NEXT:     R_LARCH_TLS_LE_HI20 a
 # RELAX-NEXT:   ori       $a0, $a0, 0
 # RELAX-NEXT:     R_LARCH_TLS_LE_LO12 a
-# RELAX-NEXT:   pcaddi    $a0, [[#]]
-# RELAX-NEXT:     R_LARCH_RELAX a
-# RELAX-NEXT:     R_LARCH_RELAX *ABS*
-# RELAX-NEXT:     R_LARCH_TLS_GD_PCREL20_S2 a
-# RELAX-NEXT:     R_LARCH_RELAX *ABS*
-# RELAX-NEXT:   pcaddi    $a0, [[#]]
-# RELAX-NEXT:     R_LARCH_RELAX a
-# RELAX-NEXT:     R_LARCH_RELAX *ABS*
-# RELAX-NEXT:     R_LARCH_TLS_LD_PCREL20_S2 a
-# RELAX-NEXT:     R_LARCH_RELAX *ABS*
+
+# RELAX32:     00010020 <.Lpcadd_hi2>:
+# RELAX32-NEXT:   pcaddu12i    $a0, 16
+# RELAX32-NEXT:     R_LARCH_TLS_GD_PCADD_HI20 a
+# RELAX32-NEXT:     R_LARCH_RELAX *ABS*
+# RELAX32-NEXT:   addi.w $a0, $a0, -20
+# RELAX32-NEXT:     R_LARCH_TLS_GD_PCADD_LO12 .Lpcadd_hi2
+# RELAX32-NEXT:     R_LARCH_RELAX *ABS*
+
+# RELAX32:     00010028 <.Lpcadd_hi3>:
+# RELAX32-NEXT:   pcaddu12i    $a0, 16
+# RELAX32-NEXT:     R_LARCH_TLS_LD_PCADD_HI20 a
+# RELAX32-NEXT:     R_LARCH_RELAX *ABS*
+# RELAX32-NEXT:   addi.w $a0, $a0, -40
+# RELAX32-NEXT:     R_LARCH_TLS_LD_PCADD_LO12 .Lpcadd_hi3
+# RELAX32-NEXT:     R_LARCH_RELAX *ABS*
+
+# RELAX64-NEXT:   pcaddi    $a0, [[#]]
+# RELAX64-NEXT:     R_LARCH_RELAX a
+# RELAX64-NEXT:     R_LARCH_RELAX *ABS*
+# RELAX64-NEXT:     R_LARCH_TLS_GD_PCREL20_S2 a
+# RELAX64-NEXT:     R_LARCH_RELAX *ABS*
+# RELAX64-NEXT:   pcaddi    $a0, [[#]]
+# RELAX64-NEXT:     R_LARCH_RELAX a
+# RELAX64-NEXT:     R_LARCH_RELAX *ABS*
+# RELAX64-NEXT:     R_LARCH_TLS_LD_PCREL20_S2 a
+# RELAX64-NEXT:     R_LARCH_RELAX *ABS*
+
 # RELAX-NEXT:   addi.{{[dw]}} $a0, $tp, 0
 # RELAX-NEXT:     R_LARCH_RELAX a
 # RELAX-NEXT:     R_LARCH_RELAX *ABS*
@@ -57,15 +97,11 @@
 # RELAX-NEXT:     R_LARCH_TLS_LE_LO12_R a
 # RELAX-NEXT:     R_LARCH_RELAX *ABS*
 
-# RELAX32-NEXT:  nop
-# RELAX32-NEXT:    R_LARCH_ALIGN *ABS*+0xc
-# RELAX32-NEXT:  ret
-
-# RELAX64-NEXT:  nop
-# RELAX64-NEXT:    R_LARCH_ALIGN *ABS*+0xc
-# RELAX64-NEXT:  nop
-# RELAX64-NEXT:  nop
-# RELAX64-NEXT:  ret
+# RELAX-NEXT:  nop
+# RELAX-NEXT:    R_LARCH_ALIGN *ABS*+0xc
+# RELAX-NEXT:  nop
+# RELAX-NEXT:  nop
+# RELAX-NEXT:  ret
 
 # NORELAX:      <_start>:
 # NORELAX-NEXT:   pcalau12i $a0, 0
@@ -195,6 +231,9 @@ _start:
 .ifdef ELF64
   call36 _start
   tail36 $a0, _start
+.else
+  call30 _start
+  tail30 $a0, _start
 .endif
 
   la.tls.le $a0, a  # without R_LARCH_RELAX reloaction
diff --git a/lld/test/ELF/loongarch-tls-gd-edge-case.s 
b/lld/test/ELF/loongarch-tls-gd-edge-case.s
index dd87d3002b180..1ebc69990b403 100644
--- a/lld/test/ELF/loongarch-tls-gd-edge-case.s
+++ b/lld/test/ELF/loongarch-tls-gd-edge-case.s
@@ -3,7 +3,7 @@
 ## Edge case: when a TLS symbol is being accessed in both GD and IE manners,
 ## correct reloc behavior should be preserved for both kinds of accesses.
 
-# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+32s %s -o %t.la32.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=-32s %s -o %t.la32.o
 # RUN: ld.lld %t.la32.o -shared -o %t.la32
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 %s -o %t.la64.o
 # RUN: ld.lld %t.la64.o -shared -o %t.la64
@@ -24,10 +24,10 @@
 # LA64-REL-NEXT: 00000000000203a8  0000000200000009 R_LARCH_TLS_DTPREL64   
0000000000000000 y + 0
 # LA64-REL-NEXT: 00000000000203b0  000000020000000b R_LARCH_TLS_TPREL64    
0000000000000000 y + 0
 
-# LA32:      101d4: pcalau12i $a0, 16
-# LA32-NEXT:        ld.w $a0, $a0, 580
-# LA32-NEXT:        pcalau12i $a1, 16
-# LA32-NEXT:        addi.w $a1, $a1, 572
+# LA32:      101d4: pcaddu12i $a0, 16
+# LA32-NEXT:        ld.w $a0, $a0, 112
+# LA32:      101dc: pcaddu12i $a1, 16
+# LA32-NEXT:        addi.w $a1, $a1, 96
 
 # LA64:      102e0: pcalau12i $a0, 16
 # LA64-NEXT:        ld.d $a0, $a0, 944
diff --git a/lld/test/ELF/loongarch-tls-gd.s b/lld/test/ELF/loongarch-tls-gd.s
index 9a4ccfa2201a4..c52690e9a1297 100644
--- a/lld/test/ELF/loongarch-tls-gd.s
+++ b/lld/test/ELF/loongarch-tls-gd.s
@@ -5,7 +5,7 @@
 ## (a) code sequence can be converted from `pcalau12i+addi.[wd]` to `pcaddi`.
 ## (b) dynamic relocations can be omitted for GD->LE relaxation.
 
-# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+32s %t/a.s -o 
%t/a.32.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=-32s %t/a.s -o 
%t/a.32.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+32s,+relax %t/a.s 
-o %t/a.32.relax.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+32s %t/bc.s -o 
%t/bc.32.o
 # RUN: ld.lld -shared -soname=bc.so %t/bc.32.o -o %t/bc.32.so
@@ -66,13 +66,13 @@
 # GD32-REL-NEXT: }
 
 ## &DTPMOD(a) - . = 0x20310 - 0x10250: 0x10 pages, page offset 0x310
-# GD32:      10250: pcalau12i $a0, 16
-# GD32-NEXT:        addi.w $a0, $a0, 784
+# GD32:      10250: pcaddu12i $a0, 16
+# GD32-NEXT:        addi.w $a0, $a0, 192
 # GD32-NEXT:        bl 56
 
 ## &DTPMOD(b) - . = 0x20318 - 0x1025c: 0x10 pages, page offset 0x318
-# GD32:      1025c: pcalau12i $a0, 16
-# GD32-NEXT:        addi.w $a0, $a0, 792
+# GD32:      1025c: pcaddu12i $a0, 16
+# GD32-NEXT:        addi.w $a0, $a0, 188
 # GD32-NEXT:        bl 44
 
 # GD32-REL-RELAX:      .rela.dyn {
diff --git a/lld/test/ELF/loongarch-tls-ie.s b/lld/test/ELF/loongarch-tls-ie.s
index e7e9617dd3efc..3b3fd944712fe 100644
--- a/lld/test/ELF/loongarch-tls-ie.s
+++ b/lld/test/ELF/loongarch-tls-ie.s
@@ -1,7 +1,7 @@
 # REQUIRES: loongarch
 # RUN: rm -rf %t && split-file %s %t
 
-# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+32s %t/32.s -o 
%t/32.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=-32s %t/32.s -o 
%t/32.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/64.s -o %t/64.o
 
 ## LA32 IE
@@ -41,11 +41,11 @@
 ## LA32:
 ## &.got[0] - . = 0x20214 - 0x101a4: 0x10 pages, page offset 0x214
 ## &.got[1] - . = 0x20218 - 0x101b0: 0x10 pages, page offset 0x218
-# IE32:      101a4: pcalau12i $a4, 16
-# IE32-NEXT:        ld.w $a4, $a4, 532
+# IE32:      101a4: pcaddu12i $a4, 16
+# IE32-NEXT:        ld.w $a4, $a4, 112
 # IE32-NEXT:        add.w $a4, $a4, $tp
-# IE32-NEXT: 101b0: pcalau12i $a5, 16
-# IE32-NEXT:        ld.w $a5, $a5, 536
+# IE32:      101b0: pcaddu12i $a5, 16
+# IE32-NEXT:        ld.w $a5, $a5, 104
 # IE32-NEXT:        add.w $a5, $a5, $tp
 
 ## LA64:
@@ -62,15 +62,16 @@
 
 # a@tprel = st_value(a) = 0x8
 # b@tprel = st_value(a) = 0xc
-# LE32-GOT: could not find section '.got'
+# LE32-GOT: section '.got':
+# LE32-GOT-NEXT: 0x0003012c 08000000 0c000000
 # LE64-GOT: could not find section '.got'
 
 ## LA32:
-# LE32:      200d4: nop
-# LE32-NEXT:        ori $a4, $zero, 8
+# LE32:      20114: pcaddu12i $a4, 16
+# LE32-NEXT:        ld.w $a4, $a4, 24
 # LE32-NEXT:        add.w $a4, $a4, $tp
-# LE32-NEXT: 200e0: nop
-# LE32-NEXT:        ori $a5, $zero, 12
+# LE32:      20120: pcaddu12i $a5, 16
+# LE32-NEXT:        ld.w $a5, $a5, 16
 # LE32-NEXT:        add.w $a5, $a5, $tp
 
 ## LA64:
diff --git a/lld/test/ELF/loongarch-tls-ld.s b/lld/test/ELF/loongarch-tls-ld.s
index 65be2f8fd36e4..179bd50aa47be 100644
--- a/lld/test/ELF/loongarch-tls-ld.s
+++ b/lld/test/ELF/loongarch-tls-ld.s
@@ -5,7 +5,7 @@
 ## (a) code sequence can be converted from `pcalau12i+addi.[wd]` to `pcaddi`.
 ## (b) dynamic relocations can be omitted for LD->LE relaxation.
 
-# RUN: llvm-mc --filetype=obj --triple=loongarch32 --position-independent 
-mattr=+32s %t/a.s -o %t/a.32.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 --position-independent 
-mattr=-32s %t/a.s -o %t/a.32.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch32 --position-independent 
-mattr=+32s,+relax %t/a.s -o %t/a.32.relax.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+32s %t/tga.s -o 
%t/tga.32.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 --position-independent 
%t/a.s -o %t/a.64.o
@@ -60,8 +60,8 @@
 # LD64-GOT-NEXT: 0x00020400 00000000 00000000 00000000 00000000
 
 ## LA32: &DTPMOD(a) - . = 0x20280 - 0x101cc: 0x10 pages, page offset 0x280
-# LD32:      101cc: pcalau12i $a0, 16
-# LD32-NEXT:        addi.w $a0, $a0, 640
+# LD32:      101cc: pcaddu12i $a0, 16
+# LD32-NEXT:        addi.w $a0, $a0, 180
 # LD32-NEXT:        bl 44
 
 ## LA64: &DTPMOD(a) - . = 0x20400 - 0x102e0: 0x10 pages, page offset 0x400
@@ -94,8 +94,8 @@
 # LE64-GOT-RELAX-NEXT: 0x000301d0 01000000 00000000 00000000 00000000
 
 ## LA32: DTPMOD(.LANCHOR0) - . = 0x30120 - 0x20114: 0x10 pages, page offset 
0x120
-# LE32:      20114: pcalau12i $a0, 16
-# LE32-NEXT:        addi.w $a0, $a0, 288
+# LE32:      20114: pcaddu12i $a0, 16
+# LE32-NEXT:        addi.w $a0, $a0, 12
 # LE32-NEXT:        bl 4
 
 ## LA64: DTPMOD(.LANCHOR0) - . = 0x301d8 - 0x201c8: 0x10 pages, page offset 
0x1d8
diff --git a/lld/test/ELF/loongarch-tlsdesc.s b/lld/test/ELF/loongarch-tlsdesc.s
index 7d07c66606a87..835e98907516c 100644
--- a/lld/test/ELF/loongarch-tlsdesc.s
+++ b/lld/test/ELF/loongarch-tlsdesc.s
@@ -3,8 +3,8 @@
 # RUN: llvm-mc -filetype=obj -triple=loongarch64 a.s -o a.64.o
 # RUN: llvm-mc -filetype=obj -triple=loongarch64 c.s -o c.64.o
 # RUN: ld.lld -shared -soname=c.64.so c.64.o -o c.64.so
-# RUN: llvm-mc -filetype=obj -triple=loongarch32 --mattr=+32s --defsym ELF32=1 
a.s -o a.32.o
-# RUN: llvm-mc -filetype=obj -triple=loongarch32 --mattr=+32s --defsym ELF32=1 
c.s -o c.32.o
+# RUN: llvm-mc -filetype=obj -triple=loongarch32 --defsym ELF32=1 a.s -o a.32.o
+# RUN: llvm-mc -filetype=obj -triple=loongarch32 --defsym ELF32=1 c.s -o c.32.o
 # RUN: ld.lld -shared -soname=c.32.so c.32.o -o c.32.so
 
 # RUN: ld.lld -shared -z now a.64.o c.64.o -o a.64.so
@@ -27,6 +27,7 @@
 
 # RUN: ld.lld -shared -z now a.32.o c.32.o -o rel.32.so -z rel
 # RUN: llvm-readobj -r -x .got rel.32.so | FileCheck --check-prefix=GD32-REL %s
+# RUN: llvm-objdump --no-show-raw-insn -h -d rel.32.so | FileCheck %s 
--check-prefix=GD32
 
 # GD64-RELA:      .rela.dyn {
 # GD64-RELA-NEXT:   0x20400 R_LARCH_TLS_DESC64 - 0x7FF
@@ -64,7 +65,7 @@
 # GD64-NEXT:          jirl $ra, $ra, 0
 # GD64-NEXT:          add.d $a2, $a0, $tp
 
-## &.got[c]-. = 0x23e0+16 - 0x10308: 0x10 pages, page offset 0x3f0
+## &.got[c]-. = 0x203e0+16 - 0x10308: 0x10 pages, page offset 0x3f0
 # GD64:        10308: pcalau12i $a0, 16
 # GD64-NEXT:          addi.d $a0, $a0, 1008
 # GD64-NEXT:          ld.d $ra, $a0, 0
@@ -127,6 +128,29 @@
 # GD32-REL-NEXT: 0x00020260 00000000 00000000 00000000 00000000 .
 # GD32-REL-NEXT: 0x00020270 00000000 ff070000                   .
 
+# GD32:      .got     00000018 00020260
+
+## &.got[a]-. = 0x20260 - 0x101c4
+# GD32:        101c4: pcaddu12i $a0, 32
+# GD32-NEXT:          addi.w $a0, $a0, 608
+# GD32-NEXT:          ld.w $ra, $a0, 0
+# GD32-NEXT:          jirl $ra, $ra, 0
+# GD32-NEXT:          add.w $a1, $a0, $tp
+
+## &.got[b]-. = 0x20260+16 - 0x101d8
+# GD32:        101d8: pcaddu12i $a0, 32
+# GD32-NEXT:          addi.w $a0, $a0, 624
+# GD32-NEXT:          ld.w $ra, $a0, 0
+# GD32-NEXT:          jirl $ra, $ra, 0
+# GD32-NEXT:          add.w $a2, $a0, $tp
+
+## &.got[c]-. = 0x20260+8 - 0x101ec
+# GD32:        101ec: pcaddu12i $a0, 32
+# GD32-NEXT:          addi.w $a0, $a0, 616
+# GD32-NEXT:          ld.w $ra, $a0, 0
+# GD32-NEXT:          jirl $ra, $ra, 0
+# GD32-NEXT:          add.w $a3, $a0, $tp
+
 #--- a.s
 .macro add dst, src1, src2
 .ifdef ELF32

_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to