Skip to content

[lld][LoongArch] Support the R_LARCH_CALL36 relocation type #73346

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 4 commits into from
Dec 25, 2023

Conversation

SixWeining
Copy link
Contributor

R_LARCH_CALL36 was designed for function call on medium code model where the 2 instructions (pcaddu18i + jirl) must be adjacent. This is expected to replace current medium code model implementation, i.e. R_LARCH_PCALA_{HI20,LO12} on pcalau12i + jirl.

See loongson/la-abi-specs#3 for more details.

@llvmbot
Copy link
Member

llvmbot commented Nov 24, 2023

@llvm/pr-subscribers-lld

@llvm/pr-subscribers-lld-elf

Author: Lu Weining (SixWeining)

Changes

R_LARCH_CALL36 was designed for function call on medium code model where the 2 instructions (pcaddu18i + jirl) must be adjacent. This is expected to replace current medium code model implementation, i.e. R_LARCH_PCALA_{HI20,LO12} on pcalau12i + jirl.

See loongson/la-abi-specs#3 for more details.


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

3 Files Affected:

  • (modified) lld/ELF/Arch/LoongArch.cpp (+15)
  • (added) lld/test/ELF/loongarch-call36-shared.s (+41)
  • (added) lld/test/ELF/loongarch-call36.s (+40)
diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index d3a538577a59a5d..85debb925754532 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -464,6 +464,7 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
   case R_LARCH_B16:
   case R_LARCH_B21:
   case R_LARCH_B26:
+  case R_LARCH_CALL36:
     return R_PLT_PC;
   case R_LARCH_GOT_PC_HI20:
   case R_LARCH_GOT64_PC_LO20:
@@ -591,6 +592,20 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
     write32le(loc, setD10k16(read32le(loc), val >> 2));
     return;
 
+  case R_LARCH_CALL36: {
+    // This relocation type is designed for the adjancent pcaddu18i+jirl pair,
+    // so patch these 2 instructions in one time.
+    checkInt(loc, val, 38, rel);
+    checkAlignment(loc, val, 4, rel);
+    // Since jirl performs sign extension on the offset immediate, adds (1<<17)
+    // to original val to get the correct hi20.
+    uint32_t hi20 = extractBits(val + (1 << 17), 37, 18);
+    uint32_t lo18 = val & (1 << 18) - 1;
+    write32le(loc, setJ20(read32le(loc), hi20));
+    write32le(loc + 4, setK16(read32le(loc + 4), lo18 >> 2));
+    return;
+  }
+
   // Relocs intended for `addi`, `ld` or `st`.
   case R_LARCH_PCALA_LO12:
     // We have to again inspect the insn word to handle the R_LARCH_PCALA_LO12
diff --git a/lld/test/ELF/loongarch-call36-shared.s b/lld/test/ELF/loongarch-call36-shared.s
new file mode 100644
index 000000000000000..937f79bbb179946
--- /dev/null
+++ b/lld/test/ELF/loongarch-call36-shared.s
@@ -0,0 +1,41 @@
+# REQUIRES: loongarch
+# RUN: rm -rf %t && split-file %s %t
+# RUN: llvm-mc --filetype=obj --triple=loongarch64-unknown-elf %t/a.s -o %t/a.o
+# 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 %s
+
+## PLT should be present in this case.
+# CHECK:       Disassembly of section .plt:
+# CHECK:       <.plt>:
+##             bar@plt:
+# CHECK:       1234520:  pcaddu12i $t3, 64{{$}}
+# CHECK-NEXT:            ld.d $t3, $t3, 536{{$}}
+# CHECK-NEXT:            jirl $t1, $t3, 0
+# CHECK-NEXT:            nop
+
+# CHECK:      Disassembly of section .text:
+# CHECK:      <foo>:
+## hi20 = bar@plt - pc + (1 << 17) >> 18 = 0x1234520 - 0x1274670 + 0x20000 >> 18 = -1
+## lo18 = bar@plt - pc & (1 << 18) - 1 = 0x1234520 - 0x1274670 & 0x3ffff = -336
+# CHECK-NEXT: pcaddu18i $t0, -1{{$}}
+# CHECK-NEXT: jirl $zero, $t0, -336{{$}}
+
+# GOTPLT:      section '.got.plt':
+# GOTPLT-NEXT: 0x01274728 00000000 00000000 00000000 00000000
+# GOTPLT-NEXT: 0x01274738 00452301 00000000
+
+#--- a.t
+SECTIONS {
+ .plt   0x1234500: { *(.plt) }
+ .text  0x1274670: { *(.text) }
+}
+
+#--- a.s
+.text
+.global foo
+.global bar
+foo:
+    pcaddu18i $t0, 0
+    jirl      $zero, $t0, 0
+    .reloc foo, R_LARCH_CALL36, bar
diff --git a/lld/test/ELF/loongarch-call36.s b/lld/test/ELF/loongarch-call36.s
new file mode 100644
index 000000000000000..f32da0a123fe09d
--- /dev/null
+++ b/lld/test/ELF/loongarch-call36.s
@@ -0,0 +1,40 @@
+# REQUIRES: loongarch
+
+# RUN: llvm-mc --filetype=obj --triple=loongarch64-unknown-elf %s -o %t.o
+
+# RUN: ld.lld %t.o --section-start=.text=0x20010 --section-start=.sec.foo=0x60020 -o %t1
+# RUN: llvm-objdump --no-show-raw-insn -d %t1 | FileCheck --match-full-lines %s --check-prefix=CASE1
+## hi20 = target - pc + (1 << 17) >> 18 = 0x60020 - 0x20010 + 0x20000 >> 18 = 1
+## lo18 = target - pc & (1 << 18) - 1 = 0x60020 - 0x20010 & 0x3ffff = 16
+# CASE1:      20010: pcaddu18i $ra, 1
+# CASE1-NEXT: 20014: jirl $zero, $ra, 16
+
+# RUN: ld.lld %t.o --section-start=.text=0x20010 --section-start=.sec.foo=0x40020 -o %t2
+# RUN: llvm-objdump --no-show-raw-insn -d %t2 | FileCheck --match-full-lines %s --check-prefix=CASE2
+## hi20 = target - pc + (1 << 17) >> 18 = 0x40020 - 0x20010 + 0x20000 >> 18 = 1
+## lo18 = target - pc & (1 << 18) - 1 = 0x40020 - 0x20010 & 0x3ffff = -131056
+# CASE2:      20010: pcaddu18i $ra, 1
+# CASE2-NEXT: 20014: jirl $zero, $ra, -131056
+
+# RUN: not ld.lld %t.o --section-start=.text=0x20000 --section-start=.sec.foo=0x2000020000 -o /dev/null 2>&1 | \
+# RUN:   FileCheck -DFILE=%t.o --check-prefix=ERROR-RANGE %s
+# ERROR-RANGE: error: [[FILE]]:(.text+0x0): relocation R_LARCH_CALL36 out of range: 137438953472 is not in [-137438953472, 137438953471]; references 'foo'
+
+## Impossible case in reality becasue all LoongArch instructions are fixed 4-bytes long.
+# RUN: not ld.lld %t.o --section-start=.text=0x20000 --section-start=.sec.foo=0x40001 -o /dev/null 2>&1 | \
+# RUN:   FileCheck -DFILE=%t.o --check-prefix=ERROR-ALIGN %s
+# ERROR-ALIGN: error: [[FILE]]:(.text+0x0): improper alignment for relocation R_LARCH_CALL36: 0x20001 is not aligned to 4 bytes
+
+.text
+.global _start
+_start:
+1:
+  pcaddu18i $ra, 0
+  jirl $zero, $ra, 0
+  .reloc 1b, R_LARCH_CALL36, foo
+
+.section .sec.foo,"ax"
+.global foo
+foo:
+  nop
+  ret

@SixWeining
Copy link
Contributor Author

Depends on #73345

cc @MQ-mengqing @xen0n @xry111

R_LARCH_CALL36 was designed for function call on medium code model
where the 2 instructions (pcaddu18i + jirl) must be adjacent. This is
expected to replace current medium code model implementation, i.e.
R_LARCH_PCALA_{HI20,LO12} on pcalau12i + jirl.

See loongson/la-abi-specs#3 for more details.
Copy link
Contributor

@xen0n xen0n left a comment

Choose a reason for hiding this comment

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

Thanks for the patch!

@SixWeining SixWeining merged commit 88548df into llvm:main Dec 25, 2023
@MaskRay
Copy link
Member

MaskRay commented Dec 25, 2023

LGTM, though I'd wish that you gave more time before merging as many people are unavailable during the Christmas season.

@SixWeining SixWeining deleted the lld-call36 branch December 26, 2023 01:18
leecheechen pushed a commit to leecheechen/llvm-project that referenced this pull request Jun 9, 2025
R_LARCH_CALL36 was designed for function call on medium code model where
the 2 instructions (pcaddu18i + jirl) must be adjacent. This is expected
to replace current medium code model implementation, i.e.
R_LARCH_PCALA_{HI20,LO12} on pcalau12i + jirl.

See loongson/la-abi-specs#3 for more details.

(cherry picked from commit 88548df)
Change-Id: Ib2271319acf0eb9313e2150e0bc4e5b30dddc96a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants