Skip to content

Conversation

ylzsx
Copy link
Contributor

@ylzsx ylzsx commented Jul 30, 2025

Linker relaxation to R_LARCH_GOT_PC_{HI20,LO12} is only possible when the addend of the relocation is zero.

Note: For ld.bfd, GOT references with non-zero addends will trigger an assert in LoongArch, but lld handles these cases without any errors.

ld.bfd: BFD (GNU Binutils) 2.44.0 assertion fail
/usr/src/debug/binutils/binutils-gdb/bfd/elfnn-loongarch.c:4248

We could relax codes when the addends of both relocations are zero.

Note: For `ld.bfd`, GOT references with non-zero addends will trigger
an assert in LoongArch, but `lld` handles these cases without any
errors.
```
ld.bfd: BFD (GNU Binutils) 2.44.0 assertion fail
/usr/src/debug/binutils/binutils-gdb/bfd/elfnn-loongarch.c:4248
```
@llvmbot
Copy link
Member

llvmbot commented Jul 30, 2025

@llvm/pr-subscribers-backend-loongarch

@llvm/pr-subscribers-lld-elf

Author: Zhaoxin Yang (ylzsx)

Changes

We could relax codes when the addends of both relocations are zero for R_LARCH_GOT_PC_{HI20,LO12}.

Note: For ld.bfd, GOT references with non-zero addends will trigger an assert in LoongArch, but lld handles these cases without any errors.

ld.bfd: BFD (GNU Binutils) 2.44.0 assertion fail
/usr/src/debug/binutils/binutils-gdb/bfd/elfnn-loongarch.c:4248

Full diff: https://github.com/llvm/llvm-project/pull/151264.diff

2 Files Affected:

  • (modified) lld/ELF/Arch/LoongArch.cpp (+6-3)
  • (modified) lld/test/ELF/loongarch-relax-pc-hi20-lo12.s (+25-3)
diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index 15dcddb13baf7..a14553018fc36 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -809,10 +809,13 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
   // address.
   // Meanwhile skip undefined, preemptible and STT_GNU_IFUNC symbols, because
   // these symbols may be resolve in runtime.
+  // Moreover, relaxation can only occur if the addends of both relocations are
+  // zero for GOT references.
   if (rHi20.type == R_LARCH_GOT_PC_HI20 &&
-      (!rHi20.sym->isDefined() || rHi20.sym->isPreemptible ||
-       rHi20.sym->isGnuIFunc() ||
-       (ctx.arg.isPic && !cast<Defined>(*rHi20.sym).section)))
+      (!rHi20.sym || rHi20.sym != rLo12.sym || !rHi20.sym->isDefined() ||
+       rHi20.sym->isPreemptible || rHi20.sym->isGnuIFunc() ||
+       (ctx.arg.isPic && !cast<Defined>(*rHi20.sym).section) ||
+       rHi20.addend != 0 || rLo12.addend != 0))
     return;
 
   uint64_t dest = 0;
diff --git a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
index a417d89e9fa2e..d5bec595bbfd7 100644
--- a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
+++ b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
@@ -1,12 +1,12 @@
 # REQUIRES: loongarch
 
-# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax %s -o %t.32.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax --defsym ELF32=1 %s -o %t.32.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax %s -o %t.64.o
 
 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.32.o -o %t.32
 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.64.o -o %t.64
-# RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX %s
-# RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck --check-prefixes=RELAX %s
+# RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX,RELAX32 %s
+# RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck --check-prefixes=RELAX,RELAX64 %s
 
 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.32.o -shared -o %t.32s
 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.64.o -shared -o %t.64s
@@ -25,6 +25,11 @@
 # RELAX-NEXT:              pcaddi $a0, 4094
 # RELAX-NEXT:              pcaddi $a0, 4093
 
+# RELAX32-NEXT:            pcalau12i $a0, 4
+# RELAX32-NEXT:            ld.w      $a0, $a0, 8
+# RELAX64-NEXT:            pcalau12i $a0, 4
+# RELAX64-NEXT:            ld.d      $a0, $a0, 12
+
 # NORELAX32-LABEL: <_start>:
 ## offset exceed range of pcaddi
 ## offset = 0x410000 - 0x10000: 0x400 pages, page offset 0
@@ -36,6 +41,8 @@
 # NORELAX32-NEXT:          addi.w        $a0, $a0, 0
 # NORELAX32-NEXT:          pcalau12i     $a0, 1024
 # NORELAX32-NEXT:          ld.w          $a0, $a0, 4
+# NORELAX32-NEXT:          pcalau12i     $a0, 1024
+# NORELAX32-NEXT:          ld.w          $a0, $a0, 8
 
 # NORELAX64-LABEL: <_start>:
 ## offset exceed range of pcaddi
@@ -48,6 +55,16 @@
 # NORELAX64-NEXT:          addi.d        $a0, $a0, 0
 # NORELAX64-NEXT:          pcalau12i     $a0, 1024
 # NORELAX64-NEXT:          ld.d          $a0, $a0, 8
+# NORELAX64-NEXT:          pcalau12i     $a0, 1024
+# NORELAX64-NEXT:          ld.d          $a0, $a0, 12
+
+.macro ld dst, src1, src2
+.ifdef ELF32
+ld.w \dst, \src1, \src2
+.else
+ld.d \dst, \src1, \src2
+.endif
+.endm
 
 .section .text
 .global _start
@@ -57,6 +74,11 @@ _start:
   la.pcrel  $a0, sym
   la.got    $a0, sym
 
+  pcalau12i $a0, %got_pc_hi20(sym+4)
+    .reloc .-4, R_LARCH_RELAX, 0
+  ld        $a0, $a0, %got_pc_lo12(sym+4)
+    .reloc .-4, R_LARCH_RELAX, 0
+
 .section .data
 sym:
   .zero 4

@llvmbot
Copy link
Member

llvmbot commented Jul 30, 2025

@llvm/pr-subscribers-lld

Author: Zhaoxin Yang (ylzsx)

Changes

We could relax codes when the addends of both relocations are zero for R_LARCH_GOT_PC_{HI20,LO12}.

Note: For ld.bfd, GOT references with non-zero addends will trigger an assert in LoongArch, but lld handles these cases without any errors.

ld.bfd: BFD (GNU Binutils) 2.44.0 assertion fail
/usr/src/debug/binutils/binutils-gdb/bfd/elfnn-loongarch.c:4248

Full diff: https://github.com/llvm/llvm-project/pull/151264.diff

2 Files Affected:

  • (modified) lld/ELF/Arch/LoongArch.cpp (+6-3)
  • (modified) lld/test/ELF/loongarch-relax-pc-hi20-lo12.s (+25-3)
diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index 15dcddb13baf7..a14553018fc36 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -809,10 +809,13 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
   // address.
   // Meanwhile skip undefined, preemptible and STT_GNU_IFUNC symbols, because
   // these symbols may be resolve in runtime.
+  // Moreover, relaxation can only occur if the addends of both relocations are
+  // zero for GOT references.
   if (rHi20.type == R_LARCH_GOT_PC_HI20 &&
-      (!rHi20.sym->isDefined() || rHi20.sym->isPreemptible ||
-       rHi20.sym->isGnuIFunc() ||
-       (ctx.arg.isPic && !cast<Defined>(*rHi20.sym).section)))
+      (!rHi20.sym || rHi20.sym != rLo12.sym || !rHi20.sym->isDefined() ||
+       rHi20.sym->isPreemptible || rHi20.sym->isGnuIFunc() ||
+       (ctx.arg.isPic && !cast<Defined>(*rHi20.sym).section) ||
+       rHi20.addend != 0 || rLo12.addend != 0))
     return;
 
   uint64_t dest = 0;
diff --git a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
index a417d89e9fa2e..d5bec595bbfd7 100644
--- a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
+++ b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
@@ -1,12 +1,12 @@
 # REQUIRES: loongarch
 
-# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax %s -o %t.32.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax --defsym ELF32=1 %s -o %t.32.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax %s -o %t.64.o
 
 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.32.o -o %t.32
 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.64.o -o %t.64
-# RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX %s
-# RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck --check-prefixes=RELAX %s
+# RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX,RELAX32 %s
+# RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck --check-prefixes=RELAX,RELAX64 %s
 
 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.32.o -shared -o %t.32s
 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.64.o -shared -o %t.64s
@@ -25,6 +25,11 @@
 # RELAX-NEXT:              pcaddi $a0, 4094
 # RELAX-NEXT:              pcaddi $a0, 4093
 
+# RELAX32-NEXT:            pcalau12i $a0, 4
+# RELAX32-NEXT:            ld.w      $a0, $a0, 8
+# RELAX64-NEXT:            pcalau12i $a0, 4
+# RELAX64-NEXT:            ld.d      $a0, $a0, 12
+
 # NORELAX32-LABEL: <_start>:
 ## offset exceed range of pcaddi
 ## offset = 0x410000 - 0x10000: 0x400 pages, page offset 0
@@ -36,6 +41,8 @@
 # NORELAX32-NEXT:          addi.w        $a0, $a0, 0
 # NORELAX32-NEXT:          pcalau12i     $a0, 1024
 # NORELAX32-NEXT:          ld.w          $a0, $a0, 4
+# NORELAX32-NEXT:          pcalau12i     $a0, 1024
+# NORELAX32-NEXT:          ld.w          $a0, $a0, 8
 
 # NORELAX64-LABEL: <_start>:
 ## offset exceed range of pcaddi
@@ -48,6 +55,16 @@
 # NORELAX64-NEXT:          addi.d        $a0, $a0, 0
 # NORELAX64-NEXT:          pcalau12i     $a0, 1024
 # NORELAX64-NEXT:          ld.d          $a0, $a0, 8
+# NORELAX64-NEXT:          pcalau12i     $a0, 1024
+# NORELAX64-NEXT:          ld.d          $a0, $a0, 12
+
+.macro ld dst, src1, src2
+.ifdef ELF32
+ld.w \dst, \src1, \src2
+.else
+ld.d \dst, \src1, \src2
+.endif
+.endm
 
 .section .text
 .global _start
@@ -57,6 +74,11 @@ _start:
   la.pcrel  $a0, sym
   la.got    $a0, sym
 
+  pcalau12i $a0, %got_pc_hi20(sym+4)
+    .reloc .-4, R_LARCH_RELAX, 0
+  ld        $a0, $a0, %got_pc_lo12(sym+4)
+    .reloc .-4, R_LARCH_RELAX, 0
+
 .section .data
 sym:
   .zero 4

@SixWeining SixWeining changed the title [lld][LoongArch] Fix relaxation for R_LARCH_GOT_PC_{HI20,LO12} [lld][LoongArch] Check that the relocation addend is zero before applying linker relaxation to R_LARCH_GOT_PC_{HI20,LO12} Jul 30, 2025
@SixWeining SixWeining changed the title [lld][LoongArch] Check that the relocation addend is zero before applying linker relaxation to R_LARCH_GOT_PC_{HI20,LO12} [lld][LoongArch] Check that the relocation addend is zero before applying relaxation to R_LARCH_GOT_PC_{HI20,LO12} Jul 30, 2025
@ylzsx ylzsx merged commit 4ec8503 into llvm:main Jul 30, 2025
9 checks passed
@ylzsx
Copy link
Contributor Author

ylzsx commented Jul 31, 2025

/cherry-pick 4ec8503

@ylzsx ylzsx deleted the fix-got-addend branch July 31, 2025 07:53
@llvmbot
Copy link
Member

llvmbot commented Jul 31, 2025

/cherry-pick 4ec8503

Error: Command failed due to missing milestone.

@ylzsx
Copy link
Contributor Author

ylzsx commented Jul 31, 2025

/cherry-pick 4ec8503

@llvmbot
Copy link
Member

llvmbot commented Jul 31, 2025

/pull-request #151470

@llvmbot llvmbot moved this from Needs Triage to Done in LLVM Release Status Jul 31, 2025
tru pushed a commit to llvmbot/llvm-project that referenced this pull request Aug 1, 2025
…ying relaxation to R_LARCH_GOT_PC_{HI20,LO12} (llvm#151264)

Linker relaxation to R_LARCH_GOT_PC_{HI20,LO12} is only possible when
the addend of the relocation is zero.

Note: For `ld.bfd`, GOT references with non-zero addends will trigger an
assert in LoongArch, but `lld` handles these cases without any errors.
```
ld.bfd: BFD (GNU Binutils) 2.44.0 assertion fail
/usr/src/debug/binutils/binutils-gdb/bfd/elfnn-loongarch.c:4248
```

(cherry picked from commit 4ec8503)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Development

Successfully merging this pull request may close these issues.

3 participants