Skip to content

Commit 0a256be

Browse files
committed
1 parent 5c08aea commit 0a256be

File tree

55 files changed

+1816
-935
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1816
-935
lines changed

lld/ELF/Arch/LoongArch.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,10 @@ static uint32_t setJ5(uint32_t insn, uint32_t imm) {
161161
return (insn & 0xfffffc1f) | (extractBits(imm, 4, 0) << 5);
162162
}
163163

164+
static uint32_t setK10(uint32_t insn, uint32_t imm) {
165+
return (insn & 0xffc003ff) | (extractBits(imm, 9, 0) << 10);
166+
}
167+
164168
static uint32_t setK12(uint32_t insn, uint32_t imm) {
165169
return (insn & 0xffc003ff) | (extractBits(imm, 11, 0) << 10);
166170
}
@@ -416,6 +420,8 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
416420
// [1]: https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=9f482b73f41a9a1bbfb173aad0733d1c824c788a
417421
// [2]: https://github.com/loongson/la-abi-specs/pull/3
418422
return isJirl(read32le(loc)) ? R_PLT : R_ABS;
423+
case R_LARCH_PCADD_LO12_I:
424+
return RE_LOONGARCH_PC_INDIRECT;
419425
case R_LARCH_TLS_DTPREL32:
420426
case R_LARCH_TLS_DTPREL64:
421427
return R_DTPREL;
@@ -446,10 +452,12 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
446452
case R_LARCH_32_PCREL:
447453
case R_LARCH_64_PCREL:
448454
case R_LARCH_PCREL20_S2:
455+
case R_LARCH_PCADD_HI20:
449456
return R_PC;
450457
case R_LARCH_B16:
451458
case R_LARCH_B21:
452459
case R_LARCH_B26:
460+
case R_LARCH_CALL30:
453461
case R_LARCH_CALL36:
454462
return R_PLT_PC;
455463
case R_LARCH_GOT_PC_HI20:
@@ -459,6 +467,9 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
459467
case R_LARCH_TLS_IE64_PC_LO20:
460468
case R_LARCH_TLS_IE64_PC_HI12:
461469
return RE_LOONGARCH_GOT_PAGE_PC;
470+
case R_LARCH_PCADD_GOT_HI20:
471+
case R_LARCH_PCADD_TLS_IE_HI20:
472+
return R_GOT_PC;
462473
case R_LARCH_GOT_PC_LO12:
463474
case R_LARCH_TLS_IE_PC_LO12:
464475
return RE_LOONGARCH_GOT;
@@ -522,6 +533,7 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
522533
case R_LARCH_TLS_DESC_LO12:
523534
case R_LARCH_TLS_DESC64_LO20:
524535
case R_LARCH_TLS_DESC64_HI12:
536+
case R_LARCH_PCADD_TLS_DESC_HI20:
525537
return R_TLSDESC;
526538
case R_LARCH_TLS_DESC_CALL:
527539
return R_TLSDESC_CALL;
@@ -605,6 +617,22 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
605617
write32le(loc, setD10k16(read32le(loc), val >> 2));
606618
return;
607619

620+
case R_LARCH_CALL30: {
621+
// This relocation is designed for adjacent pcaddu12i+jirl pairs that
622+
// are patched in one time.
623+
// The relocation range is [-4G, +4G) (of course must be 4-byte aligned).
624+
if ((int64_t)val != llvm::SignExtend64(val, 32))
625+
reportRangeError(ctx, loc, rel, Twine(val), llvm::minIntN(32),
626+
llvm::maxIntN(32));
627+
checkAlignment(ctx, loc, val, 4, rel);
628+
uint32_t hi20 = extractBits(val, 31, 12);
629+
// Despite the name, the lower part is actually 12 bits with 4-byte aligned.
630+
uint32_t lo10 = extractBits(val, 11, 2);
631+
write32le(loc, setJ20(read32le(loc), hi20));
632+
write32le(loc + 4, setK10(read32le(loc + 4), lo10));
633+
return;
634+
}
635+
608636
case R_LARCH_CALL36: {
609637
// This relocation is designed for adjacent pcaddu18i+jirl pairs that
610638
// are patched in one time. Because of sign extension of these insns'
@@ -648,6 +676,7 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
648676
case R_LARCH_TLS_LE_LO12_R:
649677
case R_LARCH_TLS_DESC_PC_LO12:
650678
case R_LARCH_TLS_DESC_LO12:
679+
case R_LARCH_PCADD_LO12_I:
651680
write32le(loc, setK12(read32le(loc), extractBits(val, 11, 0)));
652681
return;
653682

@@ -667,6 +696,15 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
667696
case R_LARCH_TLS_DESC_HI20:
668697
write32le(loc, setJ20(read32le(loc), extractBits(val, 31, 12)));
669698
return;
699+
case R_LARCH_PCADD_HI20:
700+
case R_LARCH_PCADD_GOT_HI20:
701+
case R_LARCH_PCADD_TLS_IE_HI20:
702+
case R_LARCH_PCADD_TLS_DESC_HI20: {
703+
uint64_t hi = val + 0x800;
704+
checkInt(ctx, loc, SignExtend64(hi, 32) >> 12, 20, rel);
705+
write32le(loc, setJ20(read32le(loc), extractBits(hi, 31, 12)));
706+
return;
707+
}
670708
case R_LARCH_TLS_LE_HI20_R:
671709
write32le(loc, setJ20(read32le(loc), extractBits(val + 0x800, 31, 12)));
672710
return;

lld/ELF/InputSection.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,61 @@ static Relocation *getRISCVPCRelHi20(Ctx &ctx, const InputSectionBase *loSec,
713713
return nullptr;
714714
}
715715

716+
// For RE_LARCH_PC_INDIRECT (R_LARCH_PCADD_LO12_I), the symbol actually
717+
// points the corresponding R_LARCH_PCADD_*_HI20 relocation, and the target VA
718+
// is calculated using PCADD_HI20's symbol.
719+
//
720+
// This function returns the R_LARCH_PCADD_*_HI20 relocation from the
721+
// R_LARCH_PCADD_LO12 relocation.
722+
static Relocation *getLoongArchPCAddHi20(Ctx &ctx,
723+
const InputSectionBase *loSec,
724+
const Relocation &loReloc) {
725+
int64_t addend = loReloc.addend;
726+
Symbol *sym = loReloc.sym;
727+
728+
const Defined *d = cast<Defined>(sym);
729+
if (!d->section) {
730+
Err(ctx) << loSec->getLocation(loReloc.offset)
731+
<< ": R_LARCH_PCADD_LO12 relocation points to an absolute symbol: "
732+
<< sym->getName();
733+
return nullptr;
734+
}
735+
InputSection *hiSec = cast<InputSection>(d->section);
736+
737+
if (hiSec != loSec)
738+
Err(ctx) << loSec->getLocation(loReloc.offset)
739+
<< ": R_LARCH_PCADD_LO12 relocation points to a symbol '"
740+
<< sym->getName() << "' in a different section '" << hiSec->name
741+
<< "'";
742+
743+
if (addend != 0)
744+
Warn(ctx) << loSec->getLocation(loReloc.offset)
745+
<< ": non-zero addend in R_LARCH_PCADD_LO12 relocation to "
746+
<< hiSec->getObjMsg(d->value) << " is ignored";
747+
748+
// Relocations are sorted by offset, so we can use std::equal_range to do
749+
// binary search.
750+
Relocation hiReloc;
751+
hiReloc.offset = d->value + addend;
752+
auto range =
753+
std::equal_range(hiSec->relocs().begin(), hiSec->relocs().end(), hiReloc,
754+
[](const Relocation &lhs, const Relocation &rhs) {
755+
return lhs.offset < rhs.offset;
756+
});
757+
758+
for (auto it = range.first; it != range.second; ++it)
759+
if (it->type == R_LARCH_PCADD_HI20 || it->type == R_LARCH_PCADD_GOT_HI20 ||
760+
it->type == R_LARCH_PCADD_TLS_IE_HI20 ||
761+
it->type == R_LARCH_PCADD_TLS_DESC_HI20)
762+
return &*it;
763+
764+
Err(ctx) << loSec->getLocation(loReloc.offset)
765+
<< ": R_LARCH_PCADD_LO12 relocation points to "
766+
<< hiSec->getObjMsg(d->value)
767+
<< " without an associated R_LARCH_PCADD_HI20 relocation";
768+
return nullptr;
769+
}
770+
716771
// A TLS symbol's virtual address is relative to the TLS segment. Add a
717772
// target-specific adjustment to produce a thread-pointer-relative offset.
718773
static int64_t getTlsTpOffset(Ctx &ctx, const Symbol &s) {
@@ -884,6 +939,11 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
884939
return getRelocTargetVA(ctx, *hiRel, r.sym->getVA(ctx));
885940
return 0;
886941
}
942+
case RE_LOONGARCH_PC_INDIRECT: {
943+
if (const Relocation *hiRel = getLoongArchPCAddHi20(ctx, this, r))
944+
return getRelocTargetVA(ctx, *hiRel, r.sym->getVA(ctx, a));
945+
return 0;
946+
}
887947
case RE_LOONGARCH_PAGE_PC:
888948
return getLoongArchPageDelta(r.sym->getVA(ctx, a), p, r.type);
889949
case R_PC:

lld/ELF/Relocations.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ static bool isRelExpr(RelExpr expr) {
210210
return oneof<R_PC, R_GOTREL, R_GOTPLTREL, RE_ARM_PCA, RE_MIPS_GOTREL,
211211
RE_PPC64_CALL, RE_PPC64_RELAX_TOC, RE_AARCH64_PAGE_PC,
212212
R_RELAX_GOT_PC, RE_RISCV_PC_INDIRECT, RE_PPC64_RELAX_GOT_PC,
213-
RE_LOONGARCH_PAGE_PC>(expr);
213+
RE_LOONGARCH_PAGE_PC, RE_LOONGARCH_PC_INDIRECT>(expr);
214214
}
215215

216216
static RelExpr toPlt(RelExpr expr) {

lld/ELF/Relocations.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ enum RelExpr {
129129
// also reused for TLS, making the semantics differ from other architectures.
130130
RE_LOONGARCH_GOT,
131131
RE_LOONGARCH_GOT_PAGE_PC,
132+
RE_LOONGARCH_PC_INDIRECT,
132133
RE_LOONGARCH_TLSGD_PAGE_PC,
133134
RE_LOONGARCH_TLSDESC_PAGE_PC,
134135
};

lld/test/ELF/loongarch-call30.s

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# REQUIRES: loongarch
2+
3+
# RUN: rm -rf %t && split-file %s %t
4+
# RUN: llvm-mc --filetype=obj --triple=loongarch32-unknown-elf %t/a.s -o %t/a.o
5+
6+
# RUN: ld.lld %t/a.o --section-start=.text=0x20010 --section-start=.sec.foo=0x21020 -o %t/exe1
7+
# RUN: llvm-objdump --no-show-raw-insn -d %t/exe1 | FileCheck --match-full-lines %s --check-prefix=EXE1
8+
## hi20 = target - pc >> 12 = 0x21020 - 0x20010 >> 12 = 1
9+
## lo12 = target - pc & (1 << 12) - 1 = 0x21020 - 0x20010 & 0xfff = 16
10+
# EXE1: 20010: pcaddu12i $t0, 1
11+
# EXE1-NEXT: 20014: jirl $zero, $t0, 16
12+
13+
# RUN: ld.lld %t/a.o --section-start=.text=0x20010 --section-start=.sec.foo=0x21820 -o %t/exe2
14+
# RUN: llvm-objdump --no-show-raw-insn -d %t/exe2 | FileCheck --match-full-lines %s --check-prefix=EXE2
15+
## hi20 = target - pc >> 12 = 0x21820 - 0x20010 >> 12 = 1
16+
## lo12 = target - pc & (1 << 12) - 1 = 0x21820 - 0x20010 & 0xfff = 2064
17+
# EXE2: 20010: pcaddu12i $t0, 1
18+
# EXE2-NEXT: 20014: jirl $zero, $t0, 2064
19+
20+
# RUN: ld.lld %t/a.o -shared -T %t/a.t -o %t/a.so
21+
# RUN: llvm-readelf -x .got.plt %t/a.so | FileCheck --check-prefix=GOTPLT %s
22+
# RUN: llvm-objdump -d --no-show-raw-insn %t/a.so | FileCheck --check-prefix=SO %s
23+
## PLT should be present in this case.
24+
# SO: Disassembly of section .plt:
25+
# SO: <.plt>:
26+
## foo@plt:
27+
# SO: 1234520: pcaddu12i $t3, 64{{$}}
28+
# SO-NEXT: ld.w $t3, $t3, 444{{$}}
29+
# SO-NEXT: jirl $t1, $t3, 0
30+
# SO-NEXT: nop
31+
32+
# SO: Disassembly of section .text:
33+
# SO: <_start>:
34+
## hi20 = foo@plt - pc >> 12 = 0x1234520 - 0x1274670 >> 12 = -65
35+
## lo18 = foo@plt - pc & (1 << 12) - 1 = 0x1234520 - 0x1274670 & 0xfff = 3760
36+
# SO-NEXT: pcaddu12i $t0, -65{{$}}
37+
# SO-NEXT: jirl $zero, $t0, 3760{{$}}
38+
39+
# GOTPLT: section '.got.plt':
40+
# GOTPLT-NEXT: 0x012746d4 00000000 00000000 00452301
41+
42+
## Impossible case in reality becasue all LoongArch instructions are fixed 4-bytes long.
43+
# RUN: not ld.lld %t/a.o --section-start=.text=0x20000 --section-start=.sec.foo=0x40001 -o /dev/null 2>&1 | \
44+
# RUN: FileCheck -DFILE=%t/a.o --check-prefix=ERROR-ALIGN %s
45+
# ERROR-ALIGN: error: [[FILE]]:(.text+0x0): improper alignment for relocation R_LARCH_CALL30: 0x20001 is not aligned to 4 bytes
46+
47+
#--- a.t
48+
SECTIONS {
49+
.plt 0x1234500: { *(.plt) }
50+
.text 0x1274670: { *(.text) }
51+
}
52+
53+
#--- a.s
54+
.text
55+
.global _start
56+
_start:
57+
.reloc ., R_LARCH_CALL30, foo
58+
pcaddu12i $t0, 0
59+
jirl $zero, $t0, 0
60+
61+
.section .sec.foo,"awx"
62+
.global foo
63+
foo:
64+
ret

lld/test/ELF/loongarch-relax-align.s

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# REQUIRES: loongarch
22

3-
# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %s -o %t.32.o
4-
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o
3+
# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+32s,+relax %s -o %t.32.o
4+
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+32s,+relax %s -o %t.64.o
55
# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.32.o -o %t.32
66
# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.64.o -o %t.64
77
# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --no-relax %t.32.o -o %t.32n

lld/test/ELF/loongarch-relax-emit-relocs.s

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# REQUIRES: loongarch
22
## Test that we can handle --emit-relocs while relaxing.
33

4-
# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %s -o %t.32.o
4+
# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+32s,+relax %s -o %t.32.o
55
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax --defsym ELF64=1 %s -o %t.64.o
66
# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs %t.32.o -o %t.32
77
# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs %t.64.o -o %t.64

lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
# REQUIRES: loongarch
55
# RUN: rm -rf %t && split-file %s %t && cd %t
66

7-
# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax symbols.s -o symbols.32.o
7+
# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+32s,+relax symbols.s -o symbols.32.o
88
# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax symbols.s -o symbols.64.o
9-
# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax abs.s -o abs.32.o
9+
# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+32s,+relax abs.s -o abs.32.o
1010
# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax abs.s -o abs.64.o
1111

1212
# RUN: ld.lld --shared -Tlinker.t symbols.32.o abs.32.o -o symbols.32.so

lld/test/ELF/loongarch-relax-pc-hi20-lo12.s

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# REQUIRES: loongarch
22

3-
# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax %s -o %t.32.o
3+
# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+32s,+relax %s -o %t.32.o
44
# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax %s -o %t.64.o
55

66
# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.32.o -o %t.32

lld/test/ELF/loongarch-tls-gd-edge-case.s

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
# LA64-REL-NEXT: 00000000000203a8 0000000200000009 R_LARCH_TLS_DTPREL64 0000000000000000 y + 0
2525
# LA64-REL-NEXT: 00000000000203b0 000000020000000b R_LARCH_TLS_TPREL64 0000000000000000 y + 0
2626

27-
# LA32: 101d4: pcalau12i $a0, 16
28-
# LA32-NEXT: ld.w $a0, $a0, 580
27+
# LA32: 101d4: pcaddu12i $a0, 16
28+
# LA32-NEXT: ld.w $a0, $a0, 112
2929
# LA32-NEXT: pcalau12i $a1, 16
3030
# LA32-NEXT: addi.w $a1, $a1, 572
3131

0 commit comments

Comments
 (0)