From ea9fea20110021eb5095564f5c4b46e07974deeb Mon Sep 17 00:00:00 2001 From: yangzhaoxin Date: Fri, 27 Dec 2024 15:32:34 +0800 Subject: [PATCH 01/21] Relax PCHi20Lo12. Support relaxation optimization for two types of code sequences. ``` From: pcalau12i $a0, %pc_hi20(sym) R_LARCH_PCALA_HI20, R_LARCH_RELAX addi.w/d $a0, $a0, %pc_lo12(sym) R_LARCH_PCALA_LO12, R_LARCH_RELAX To: pcaddi $a0, %pc_lo12(sym) R_LARCH_PCREL20_S2 From: pcalau12i $a0, %got_pc_hi20(sym_got) R_LARCH_GOT_PC_HI20, R_LARCH_RELAX ld.w/d $a0, $a0, %got_pc_lo12(sym_got) R_LARCH_GOT_PC_LO12, R_LARCH_RELAX To: pcaddi $a0, %got_pc_hi20(sym_got) R_LARCH_PCREL20_S2 ``` --- lld/ELF/Arch/LoongArch.cpp | 110 ++++++++++++++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 2 deletions(-) diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp index 3280c34cb6ed0..07ca66700f648 100644 --- a/lld/ELF/Arch/LoongArch.cpp +++ b/lld/ELF/Arch/LoongArch.cpp @@ -53,6 +53,7 @@ enum Op { ADDI_W = 0x02800000, ADDI_D = 0x02c00000, ANDI = 0x03400000, + PCADDI = 0x18000000, PCADDU12I = 0x1c000000, LD_W = 0x28800000, LD_D = 0x28c00000, @@ -131,6 +132,8 @@ static uint32_t extractBits(uint64_t v, uint32_t begin, uint32_t end) { return begin == 63 ? v >> end : (v & ((1ULL << (begin + 1)) - 1)) >> end; } +static uint32_t getD5(uint64_t v) { return extractBits(v, 4, 0); } + static uint32_t setD5k16(uint32_t insn, uint32_t imm) { uint32_t immLo = extractBits(imm, 15, 0); uint32_t immHi = extractBits(imm, 20, 16); @@ -743,6 +746,84 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel, } } +static bool relaxable(ArrayRef relocs, size_t i) { + return i + 1 < relocs.size() && relocs[i + 1].type == R_LARCH_RELAX; +} + +static bool isPairRelaxable(ArrayRef relocs, size_t i) { + return relaxable(relocs, i) && relaxable(relocs, i + 2) && + relocs[i].offset + 4 == relocs[i + 2].offset; +} + +// Relax code sequence. +// From: +// pcalau12i $a0, %pc_hi20(sym) +// addi.w/d $a0, $a0, %pc_lo12(sym) +// To: +// pcaddi $a0, %pc_lo12(sym) +// +// From: +// pcalau12i $a0, %got_pc_hi20(sym_got) +// ld.w/d $a0, $a0, %got_pc_lo12(sym_got) +// To: +// pcaddi $a0, %got_pc_hi20(sym_got) +static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i, + uint64_t loc, Relocation &rHi20, Relocation &rLo12, + uint32_t &remove) { + // check if the relocations are relaxable sequences. + if (!((rHi20.type == R_LARCH_PCALA_HI20 && + rLo12.type == R_LARCH_PCALA_LO12) || + (rHi20.type == R_LARCH_GOT_PC_HI20 && + rLo12.type == R_LARCH_GOT_PC_LO12))) + return; + + // GOT references to absolute symbols can't be relaxed to use pcaddi in + // position-independent code, because these instructions produce a relative + // address. + // Meanwhile skip undefined, preemptible and STT_GNU_IFUNC symbols, because + // these symbols may be resolve in runtime. + if (rHi20.type == R_LARCH_GOT_PC_HI20 && + (!rHi20.sym->isDefined() || rHi20.sym->isPreemptible || + rHi20.sym->isGnuIFunc() || + (ctx.arg.isPic && !cast(*rHi20.sym).section))) + return; + + uint64_t symBase = 0; + if (rHi20.expr == RE_LOONGARCH_PLT_PAGE_PC) + symBase = rHi20.sym->getPltVA(ctx); + else if (rHi20.expr == RE_LOONGARCH_PAGE_PC || + rHi20.expr == RE_LOONGARCH_GOT_PAGE_PC) + symBase = rHi20.sym->getVA(ctx); + else { + Err(ctx) << getErrorLoc(ctx, (const uint8_t *)loc) << "unknown expr (" + << rHi20.expr << ") against symbol " << rHi20.sym + << "in relaxPCHi20Lo12"; + return; + } + const uint64_t symLocal = symBase + rHi20.addend; + + const int64_t distance = symLocal - loc; + // Check if the distance aligns 4 bytes or exceeds the range of pcaddi. + if ((distance & 0x3) != 0 || !isInt<22>(distance)) + return; + + // Note: If we can ensure that the .o files generated by LLVM only contain + // relaxable instruction sequences with R_LARCH_RELAX, then we do not need to + // decode instructions. The relaxable instruction sequences imply the + // following constraints: + // * For relocation pairs related to got_pc, the opcodes of instructions + // must be pcalau12i + ld.w/d. In other cases, the opcodes must be pcalau12i + + // addi.w/d. + // * The destination register of pcalau12i is guaranteed to be used only by + // the immediately following instruction. + const uint32_t nextInsn = read32le(sec.content().data() + rLo12.offset); + + sec.relaxAux->relocTypes[i] = R_LARCH_RELAX; + sec.relaxAux->relocTypes[i + 2] = R_LARCH_PCREL20_S2; + sec.relaxAux->writes.push_back(insn(PCADDI, getD5(nextInsn), 0, 0)); + remove = 4; +} + static bool relax(Ctx &ctx, InputSection &sec) { const uint64_t secAddr = sec.getVA(); const MutableArrayRef relocs = sec.relocs(); @@ -781,6 +862,12 @@ static bool relax(Ctx &ctx, InputSection &sec) { } break; } + case R_LARCH_PCALA_HI20: + case R_LARCH_GOT_PC_HI20: + // The overflow check for i+2 will be carried out in isPairRelaxable. + if (isPairRelaxable(relocs, i)) + relaxPCHi20Lo12(ctx, sec, i, loc, r, relocs[i + 2], remove); + break; } // For all anchors whose offsets are <= r.offset, they are preceded by @@ -851,6 +938,7 @@ void LoongArch::finalizeRelax(int passes) const { MutableArrayRef rels = sec->relocs(); ArrayRef old = sec->content(); size_t newSize = old.size() - aux.relocDeltas[rels.size() - 1]; + size_t writesIdx = 0; uint8_t *p = ctx.bAlloc.Allocate(newSize); uint64_t offset = 0; int64_t delta = 0; @@ -867,11 +955,29 @@ void LoongArch::finalizeRelax(int passes) const { continue; // Copy from last location to the current relocated location. - const Relocation &r = rels[i]; + Relocation &r = rels[i]; uint64_t size = r.offset - offset; memcpy(p, old.data() + offset, size); p += size; - offset = r.offset + remove; + + int64_t skip = 0; + if (RelType newType = aux.relocTypes[i]) { + switch (newType) { + case R_LARCH_RELAX: + break; + case R_LARCH_PCREL20_S2: + skip = 4; + write32le(p, aux.writes[writesIdx++]); + // RelExpr is needed for relocating. + r.expr = r.sym->hasFlag(NEEDS_PLT) ? R_PLT_PC : R_PC; + break; + default: + llvm_unreachable("unsupported type"); + } + } + + p += skip; + offset = r.offset + skip + remove; } memcpy(p, old.data() + offset, old.size() - offset); From 95f454086ea7766adeef4ae1e65b7689824ec7df Mon Sep 17 00:00:00 2001 From: yangzhaoxin Date: Tue, 24 Dec 2024 08:57:29 +0800 Subject: [PATCH 02/21] la.pcrel relax test modify. --- lld/test/ELF/loongarch-relax-align.s | 115 ++++++++++++++------- lld/test/ELF/loongarch-relax-emit-relocs.s | 41 +++++--- 2 files changed, 101 insertions(+), 55 deletions(-) diff --git a/lld/test/ELF/loongarch-relax-align.s b/lld/test/ELF/loongarch-relax-align.s index ab61e15d5caca..9eaff9144d85e 100644 --- a/lld/test/ELF/loongarch-relax-align.s +++ b/lld/test/ELF/loongarch-relax-align.s @@ -6,56 +6,91 @@ # RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.64.o -o %t.64 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.32.o --no-relax -o %t.32n # RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.64.o --no-relax -o %t.64n -# RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck %s -# RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck %s -# RUN: llvm-objdump -td --no-show-raw-insn %t.32n | FileCheck %s -# RUN: llvm-objdump -td --no-show-raw-insn %t.64n | FileCheck %s +# RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX,NOOLD %s +# RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck --check-prefixes=RELAX,NOOLD %s +# RUN: llvm-objdump -td --no-show-raw-insn %t.32n | FileCheck --check-prefixes=NORELAX,NOOLD %s +# RUN: llvm-objdump -td --no-show-raw-insn %t.64n | FileCheck --check-prefixes=NORELAX,NOOLD %s ## Test the R_LARCH_ALIGN without symbol index. # RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.o64.o --defsym=old=1 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.o64.o -o %t.o64 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.o64.o --no-relax -o %t.o64n -# RUN: llvm-objdump -td --no-show-raw-insn %t.o64 | FileCheck %s -# RUN: llvm-objdump -td --no-show-raw-insn %t.o64n | FileCheck %s +# RUN: llvm-objdump -td --no-show-raw-insn %t.o64 | FileCheck --check-prefixes=RELAX,OLD %s +# RUN: llvm-objdump -td --no-show-raw-insn %t.o64n | FileCheck --check-prefixes=NORELAX,OLD %s ## -r keeps section contents unchanged. # RUN: ld.lld -r %t.64.o -o %t.64.r # RUN: llvm-objdump -dr --no-show-raw-insn %t.64.r | FileCheck %s --check-prefix=CHECKR -# CHECK-DAG: {{0*}}10000 l .text {{0*}}44 .Ltext_start -# CHECK-DAG: {{0*}}10038 l .text {{0*}}0c .L1 -# CHECK-DAG: {{0*}}10040 l .text {{0*}}04 .L2 -# CHECK-DAG: {{0*}}20000 l .text2 {{0*}}14 .Ltext2_start - -# CHECK: <.Ltext_start>: -# CHECK-NEXT: break 1 -# CHECK-NEXT: break 2 -# CHECK-NEXT: nop -# CHECK-NEXT: nop -# CHECK-NEXT: break 3 -# CHECK-NEXT: break 4 -# CHECK-NEXT: nop -# CHECK-NEXT: nop -# CHECK-NEXT: pcalau12i $a0, 0 -# CHECK-NEXT: addi.{{[dw]}} $a0, $a0, 0 -# CHECK-NEXT: pcalau12i $a0, 0 -# CHECK-NEXT: addi.{{[dw]}} $a0, $a0, 56 -# CHECK-NEXT: pcalau12i $a0, 0 -# CHECK-NEXT: addi.{{[dw]}} $a0, $a0, 64 -# CHECK-EMPTY: -# CHECK-NEXT: <.L1>: -# CHECK-NEXT: nop -# CHECK-NEXT: nop -# CHECK-EMPTY: -# CHECK-NEXT: <.L2>: -# CHECK-NEXT: break 5 - -# CHECK: <.Ltext2_start>: -# CHECK-NEXT: pcalau12i $a0, 0 -# CHECK-NEXT: addi.{{[dw]}} $a0, $a0, 0 -# CHECK-NEXT: nop -# CHECK-NEXT: nop -# CHECK-NEXT: break 6 +# NOOLD: {{0*}}10000 l .text {{0*}}00 .Lalign_symbol +# OLD: {{0*}}00001 l *ABS* {{0*}}00 old + +# NORELAX-DAG: {{0*}}10000 l .text {{0*}}44 .Ltext_start +# NORELAX-DAG: {{0*}}10038 l .text {{0*}}0c .L1 +# NORELAX-DAG: {{0*}}10040 l .text {{0*}}04 .L2 +# NORELAX-DAG: {{0*}}20000 l .text2 {{0*}}14 .Ltext2_start + +# NORELAX: <.Ltext_start>: +# NORELAX-NEXT: break 1 +# NORELAX-NEXT: break 2 +# NORELAX-NEXT: nop +# NORELAX-NEXT: nop +# NORELAX-NEXT: break 3 +# NORELAX-NEXT: break 4 +# NORELAX-NEXT: nop +# NORELAX-NEXT: nop +# NORELAX-NEXT: pcalau12i $a0, 0 +# NORELAX-NEXT: addi.{{[dw]}} $a0, $a0, 0 +# NORELAX-NEXT: pcalau12i $a0, 0 +# NORELAX-NEXT: addi.{{[dw]}} $a0, $a0, 56 +# NORELAX-NEXT: pcalau12i $a0, 0 +# NORELAX-NEXT: addi.{{[dw]}} $a0, $a0, 64 +# NORELAX-EMPTY: +# NORELAX-NEXT: <.L1>: +# NORELAX-NEXT: nop +# NORELAX-NEXT: nop +# NORELAX-EMPTY: +# NORELAX-NEXT: <.L2>: +# NORELAX-NEXT: break 5 + +# NORELAX: <.Ltext2_start>: +# NORELAX-NEXT: pcalau12i $a0, 0 +# NORELAX-NEXT: addi.{{[dw]}} $a0, $a0, 0 +# NORELAX-NEXT: nop +# NORELAX-NEXT: nop +# NORELAX-NEXT: break 6 + + +# RELAX-DAG: {{0*}}10000 l .text {{0*}}34 .Ltext_start +# RELAX-DAG: {{0*}}1002c l .text {{0*}}08 .L1 +# RELAX-DAG: {{0*}}10030 l .text {{0*}}04 .L2 +# RELAX-DAG: {{0*}}20000 l .text2 {{0*}}14 .Ltext2_start + +# RELAX: <.Ltext_start>: +# RELAX-NEXT: break 1 +# RELAX-NEXT: break 2 +# RELAX-NEXT: nop +# RELAX-NEXT: nop +# RELAX-NEXT: break 3 +# RELAX-NEXT: break 4 +# RELAX-NEXT: nop +# RELAX-NEXT: nop +# RELAX-NEXT: pcaddi $a0, -8 +# RELAX-NEXT: pcaddi $a0, 2 +# RELAX-NEXT: pcaddi $a0, 2 +# RELAX-EMPTY: +# RELAX-NEXT: <.L1>: +# RELAX-NEXT: nop +# RELAX-EMPTY: +# RELAX-NEXT: <.L2>: +# RELAX-NEXT: break 5 + +# RELAX: <.Ltext2_start>: +# RELAX-NEXT: pcaddi $a0, 0 +# RELAX-NEXT: nop +# RELAX-NEXT: nop +# RELAX-NEXT: nop +# RELAX-NEXT: break 6 # CHECKR: <.Ltext2_start>: # CHECKR-NEXT: pcalau12i $a0, 0 diff --git a/lld/test/ELF/loongarch-relax-emit-relocs.s b/lld/test/ELF/loongarch-relax-emit-relocs.s index ba414e8c93f0f..7bc1f2d29c319 100644 --- a/lld/test/ELF/loongarch-relax-emit-relocs.s +++ b/lld/test/ELF/loongarch-relax-emit-relocs.s @@ -5,29 +5,40 @@ # RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o # RUN: ld.lld -Ttext=0x10000 --emit-relocs %t.32.o -o %t.32 # RUN: ld.lld -Ttext=0x10000 --emit-relocs %t.64.o -o %t.64 -# RUN: llvm-objdump -dr %t.32 | FileCheck %s -# RUN: llvm-objdump -dr %t.64 | FileCheck %s +# RUN: llvm-objdump -dr %t.32 | FileCheck %s --check-prefix=RELAX +# RUN: llvm-objdump -dr %t.64 | FileCheck %s --check-prefix=RELAX ## -r should keep original relocations. # RUN: ld.lld -r %t.64.o -o %t.64.r # RUN: llvm-objdump -dr %t.64.r | FileCheck %s --check-prefix=CHECKR ## --no-relax should keep original relocations. -## TODO Due to R_LARCH_RELAX is not relaxed, it plays same as --relax now. # RUN: ld.lld -Ttext=0x10000 --emit-relocs --no-relax %t.64.o -o %t.64.norelax -# RUN: llvm-objdump -dr %t.64.norelax | FileCheck %s +# RUN: llvm-objdump -dr %t.64.norelax | FileCheck %s --check-prefix=NORELAX -# CHECK: 00010000 <_start>: -# CHECK-NEXT: pcalau12i $a0, 0 -# CHECK-NEXT: R_LARCH_PCALA_HI20 _start -# CHECK-NEXT: R_LARCH_RELAX *ABS* -# CHECK-NEXT: addi.{{[dw]}} $a0, $a0, 0 -# CHECK-NEXT: R_LARCH_PCALA_LO12 _start -# CHECK-NEXT: R_LARCH_RELAX *ABS* -# CHECK-NEXT: nop -# CHECK-NEXT: R_LARCH_ALIGN *ABS*+0xc -# CHECK-NEXT: nop -# CHECK-NEXT: ret +# 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: nop +# RELAX-NEXT: R_LARCH_ALIGN *ABS*+0xc +# RELAX-NEXT: nop +# RELAX-NEXT: nop +# RELAX-NEXT: ret + +# NORELAX: <_start>: +# NORELAX-NEXT: pcalau12i $a0, 0 +# NORELAX-NEXT: R_LARCH_PCALA_HI20 _start +# NORELAX-NEXT: R_LARCH_RELAX *ABS* +# NORELAX-NEXT: addi.d $a0, $a0, 0 +# NORELAX-NEXT: R_LARCH_PCALA_LO12 _start +# NORELAX-NEXT: R_LARCH_RELAX *ABS* +# NORELAX-NEXT: nop +# NORELAX-NEXT: R_LARCH_ALIGN *ABS*+0xc +# NORELAX-NEXT: nop +# NORELAX-NEXT: ret # CHECKR: <_start>: # CHECKR-NEXT: pcalau12i $a0, 0 From 7b133c25913598143b2975553cf119b6bee97af2 Mon Sep 17 00:00:00 2001 From: yangzhaoxin Date: Fri, 27 Dec 2024 17:33:47 +0800 Subject: [PATCH 03/21] Add test for PCHi20Lo12 --- lld/test/ELF/loongarch-relax-emit-relocs.s | 33 ++++++++--- lld/test/ELF/loongarch-relax-pc-hi20-lo12.s | 62 +++++++++++++++++++++ 2 files changed, 86 insertions(+), 9 deletions(-) create mode 100644 lld/test/ELF/loongarch-relax-pc-hi20-lo12.s diff --git a/lld/test/ELF/loongarch-relax-emit-relocs.s b/lld/test/ELF/loongarch-relax-emit-relocs.s index 7bc1f2d29c319..9f3206b7ce54c 100644 --- a/lld/test/ELF/loongarch-relax-emit-relocs.s +++ b/lld/test/ELF/loongarch-relax-emit-relocs.s @@ -3,8 +3,8 @@ # RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %s -o %t.32.o # RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o -# RUN: ld.lld -Ttext=0x10000 --emit-relocs %t.32.o -o %t.32 -# RUN: ld.lld -Ttext=0x10000 --emit-relocs %t.64.o -o %t.64 +# 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 # RUN: llvm-objdump -dr %t.32 | FileCheck %s --check-prefix=RELAX # RUN: llvm-objdump -dr %t.64 | FileCheck %s --check-prefix=RELAX @@ -13,7 +13,7 @@ # RUN: llvm-objdump -dr %t.64.r | FileCheck %s --check-prefix=CHECKR ## --no-relax should keep original relocations. -# RUN: ld.lld -Ttext=0x10000 --emit-relocs --no-relax %t.64.o -o %t.64.norelax +# 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>: @@ -22,31 +22,45 @@ # 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* # 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 # NORELAX-NEXT: R_LARCH_PCALA_HI20 _start # NORELAX-NEXT: R_LARCH_RELAX *ABS* -# NORELAX-NEXT: addi.d $a0, $a0, 0 +# NORELAX-NEXT: addi.d $a0, $a0, 0 # NORELAX-NEXT: R_LARCH_PCALA_LO12 _start # NORELAX-NEXT: R_LARCH_RELAX *ABS* -# NORELAX-NEXT: nop -# NORELAX-NEXT: R_LARCH_ALIGN *ABS*+0xc -# NORELAX-NEXT: nop +# NORELAX-NEXT: pcalau12i $a0, 16 +# NORELAX-NEXT: R_LARCH_GOT_PC_HI20 _start +# NORELAX-NEXT: R_LARCH_RELAX *ABS* +# NORELAX-NEXT: ld.d $a0, $a0, 0 +# NORELAX-NEXT: R_LARCH_GOT_PC_LO12 _start +# NORELAX-NEXT: R_LARCH_RELAX *ABS* # NORELAX-NEXT: ret +# NORELAX-NEXT: R_LARCH_ALIGN *ABS*+0xc # CHECKR: <_start>: # CHECKR-NEXT: pcalau12i $a0, 0 # CHECKR-NEXT: R_LARCH_PCALA_HI20 _start # CHECKR-NEXT: R_LARCH_RELAX *ABS* -# CHECKR-NEXT: addi.d $a0, $a0, 0 +# CHECKR-NEXT: addi.d $a0, $a0, 0 # CHECKR-NEXT: R_LARCH_PCALA_LO12 _start # CHECKR-NEXT: R_LARCH_RELAX *ABS* +# CHECKR-NEXT: pcalau12i $a0, 0 +# CHECKR-NEXT: R_LARCH_GOT_PC_HI20 _start +# CHECKR-NEXT: R_LARCH_RELAX *ABS* +# CHECKR-NEXT: ld.d $a0, $a0, 0 +# CHECKR-NEXT: R_LARCH_GOT_PC_LO12 _start +# CHECKR-NEXT: R_LARCH_RELAX *ABS* # CHECKR-NEXT: nop # CHECKR-NEXT: R_LARCH_ALIGN *ABS*+0xc # CHECKR-NEXT: nop @@ -56,5 +70,6 @@ .global _start _start: la.pcrel $a0, _start + la.got $a0, _start .p2align 4 ret diff --git a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s new file mode 100644 index 0000000000000..a417d89e9fa2e --- /dev/null +++ b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s @@ -0,0 +1,62 @@ +# REQUIRES: loongarch + +# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax %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: 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 +# RUN: llvm-objdump -td --no-show-raw-insn %t.32s | FileCheck --check-prefixes=RELAX %s +# RUN: llvm-objdump -td --no-show-raw-insn %t.64s | FileCheck --check-prefixes=RELAX %s + +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 %t.32.o -o %t.32o +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 %t.64.o -o %t.64o +# RUN: llvm-objdump -td --no-show-raw-insn %t.32o | FileCheck --check-prefixes=NORELAX32 %s +# RUN: llvm-objdump -td --no-show-raw-insn %t.64o | FileCheck --check-prefixes=NORELAX64 %s + +# RELAX-LABEL: <_start>: +## offset = 0x14000 - 0x10000 = 4096<<2 +# RELAX-NEXT: 10000: pcaddi $a0, 4096 +# RELAX-NEXT: pcaddi $a0, 4095 +# RELAX-NEXT: pcaddi $a0, 4094 +# RELAX-NEXT: pcaddi $a0, 4093 + +# NORELAX32-LABEL: <_start>: +## offset exceed range of pcaddi +## offset = 0x410000 - 0x10000: 0x400 pages, page offset 0 +# NORELAX32-NEXT: 10000: pcalau12i $a0, 1024 +# 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: addi.w $a0, $a0, 0 +# NORELAX32-NEXT: pcalau12i $a0, 1024 +# NORELAX32-NEXT: ld.w $a0, $a0, 4 + +# NORELAX64-LABEL: <_start>: +## offset exceed range of pcaddi +## offset = 0x410000 - 0x10000: 0x400 pages, page offset 0 +# NORELAX64-NEXT: 10000: pcalau12i $a0, 1024 +# 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: addi.d $a0, $a0, 0 +# NORELAX64-NEXT: pcalau12i $a0, 1024 +# NORELAX64-NEXT: ld.d $a0, $a0, 8 + +.section .text +.global _start +_start: + la.local $a0, sym + la.global $a0, sym + la.pcrel $a0, sym + la.got $a0, sym + +.section .data +sym: + .zero 4 From abc1a458c7edc2d44e4f9295aa6654b4cd6ac9d8 Mon Sep 17 00:00:00 2001 From: yangzhaoxin Date: Mon, 30 Dec 2024 19:29:43 +0800 Subject: [PATCH 04/21] Add test for got symbols relaxation. Similar to aarch64-adrp-ldr-got-symbols.s. --- ...loongarch-relax-pc-hi20-lo12-got-symbols.s | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s diff --git a/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s b/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s new file mode 100644 index 0000000000000..bafb631bccb91 --- /dev/null +++ b/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s @@ -0,0 +1,90 @@ +## This test verifies that the pair pcalau12i + ld.w/d is relaxed/not relaxed +## depending on the target symbol properties. + +# REQUIRES: loongarch +# RUN: rm -rf %t && split-file %s %t && cd %t + +# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax symbols.s -o symbols.32.o +# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax symbols.s -o symbols.64.o +# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax abs.s -o abs.32.o +# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax abs.s -o abs.64.o + +# RUN: ld.lld --shared -Tlinker.t symbols.32.o abs.32.o -o symbols.32.so +# RUN: ld.lld --shared -Tlinker.t symbols.64.o abs.64.o -o symbols.64.so +# RUN: llvm-objdump -d --no-show-raw-insn symbols.32.so | FileCheck --check-prefixes=LIB %s +# RUN: llvm-objdump -d --no-show-raw-insn symbols.64.so | FileCheck --check-prefixes=LIB %s + +# RUN: ld.lld -Tlinker.t -z undefs symbols.32.o abs.32.o -o symbols.32 +# RUN: ld.lld -Tlinker.t -z undefs symbols.64.o abs.64.o -o symbols.64 +# RUN: llvm-objdump -d --no-show-raw-insn symbols.32 | FileCheck --check-prefixes=EXE %s +# RUN: llvm-objdump -d --no-show-raw-insn symbols.64 | FileCheck --check-prefixes=EXE %s + + +## Symbol 'hidden_sym' is nonpreemptible, the relaxation should be applied. +LIB: pcaddi $a0, {{[0-9]+}} +## Symbol 'global_sym' is preemptible, no relaxations should be applied. +LIB-NEXT: pcalau12i $a1, 4 +LIB-NEXT: ld.{{[wd]}} $a1, $a1, {{[0-9]+}} +## Symbol 'undefined_sym' is undefined, no relaxations should be applied. +LIB-NEXT: pcalau12i $a2, 4 +LIB-NEXT: ld.{{[wd]}} $a2, $a2, {{[0-9]+}} +## Symbol 'ifunc_sym' is STT_GNU_IFUNC, no relaxations should be applied. +LIB-NEXT: pcalau12i $a3, 4 +LIB-NEXT: ld.{{[wd]}} $a3, $a3, {{[0-9]+}} +## Symbol 'abs_sym' is absolute, no relaxations should be applied. +LIB-NEXT: pcalau12i $a4, 4 +LIB-NEXT: ld.{{[wd]}} $a4, $a4, {{[0-9]+}} + + +## Symbol 'hidden_sym' is nonpreemptible, the relaxation should be applied. +EXE: pcaddi $a0, {{[0-9]+}} +## Symbol 'global_sym' is nonpreemptible, the relaxation should be applied. +EXE-NEXT: pcaddi $a1, {{[0-9]+}} +## Symbol 'undefined_sym' is undefined, no relaxations should be applied. +EXE-NEXT: pcalau12i $a2, 4 +EXE-NEXT: ld.{{[wd]}} $a2, $a2, {{[0-9]+}} +## Symbol 'ifunc_sym' is STT_GNU_IFUNC, no relaxations should be applied. +EXE-NEXT: pcalau12i $a3, 4 +EXE-NEXT: ld.{{[wd]}} $a3, $a3, {{[0-9]+}} +## Symbol 'abs_sym' is absolute, relaxations may be applied in -no-pie mode. +EXE-NEXT: pcaddi $a4, -{{[0-9]+}} + + +## The linker script ensures that .rodata and .text are near (>4M) so that +## the pcalau12i+ld.w/d pair can be relaxed to pcaddi. +#--- linker.t +SECTIONS { + .text 0x10000: { *(.text) } + .rodata 0x14000: { *(.rodata) } +} + +# This symbol is defined in a separate file to prevent the definition from +# being folded into the instructions that reference it. +#--- abs.s +.global abs_sym +.hidden abs_sym +abs_sym = 0x1000 + +#--- symbols.s +.rodata +.hidden hidden_sym +hidden_sym: +.word 10 + +.global global_sym +global_sym: +.word 10 + +.text +.type ifunc_sym STT_GNU_IFUNC +.hidden ifunc_sym +ifunc_sym: + nop + +.global _start +_start: + la.got $a0, hidden_sym + la.got $a1, global_sym + la.got $a2, undefined_sym + la.got $a3, ifunc_sym + la.got $a4, abs_sym From 1b1804e3e26970cdf92ff1998d33a3f6ec59581d Mon Sep 17 00:00:00 2001 From: yangzhaoxin Date: Wed, 15 Jan 2025 13:56:26 +0800 Subject: [PATCH 05/21] Modify test. NFC Dependency on https://github.com/llvm/llvm-project/pull/123017 --- lld/test/ELF/loongarch-relax-align.s | 14 +++++++------- lld/test/ELF/loongarch-relax-emit-relocs.s | 8 ++++---- .../ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s | 8 ++++---- lld/test/ELF/loongarch-relax-pc-hi20-lo12.s | 12 ++++++------ 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/lld/test/ELF/loongarch-relax-align.s b/lld/test/ELF/loongarch-relax-align.s index 9eaff9144d85e..66a8ed3abf71e 100644 --- a/lld/test/ELF/loongarch-relax-align.s +++ b/lld/test/ELF/loongarch-relax-align.s @@ -2,10 +2,10 @@ # RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %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=.text2=0x20000 -e 0 %t.32.o -o %t.32 -# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.64.o -o %t.64 -# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.32.o --no-relax -o %t.32n -# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.64.o --no-relax -o %t.64n +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --relax %t.32.o -o %t.32 +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --relax %t.64.o -o %t.64 +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --no-relax %t.32.o -o %t.32n +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --no-relax %t.64.o -o %t.64n # RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX,NOOLD %s # RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck --check-prefixes=RELAX,NOOLD %s # RUN: llvm-objdump -td --no-show-raw-insn %t.32n | FileCheck --check-prefixes=NORELAX,NOOLD %s @@ -13,13 +13,13 @@ ## Test the R_LARCH_ALIGN without symbol index. # RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.o64.o --defsym=old=1 -# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.o64.o -o %t.o64 -# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.o64.o --no-relax -o %t.o64n +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --relax %t.o64.o -o %t.o64 +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --no-relax %t.o64.o -o %t.o64n # RUN: llvm-objdump -td --no-show-raw-insn %t.o64 | FileCheck --check-prefixes=RELAX,OLD %s # RUN: llvm-objdump -td --no-show-raw-insn %t.o64n | FileCheck --check-prefixes=NORELAX,OLD %s ## -r keeps section contents unchanged. -# RUN: ld.lld -r %t.64.o -o %t.64.r +# RUN: ld.lld -r --relax %t.64.o -o %t.64.r # RUN: llvm-objdump -dr --no-show-raw-insn %t.64.r | FileCheck %s --check-prefix=CHECKR # NOOLD: {{0*}}10000 l .text {{0*}}00 .Lalign_symbol diff --git a/lld/test/ELF/loongarch-relax-emit-relocs.s b/lld/test/ELF/loongarch-relax-emit-relocs.s index 9f3206b7ce54c..a02cd272aba5b 100644 --- a/lld/test/ELF/loongarch-relax-emit-relocs.s +++ b/lld/test/ELF/loongarch-relax-emit-relocs.s @@ -3,13 +3,13 @@ # RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %s -o %t.32.o # RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %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 +# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs --relax %t.32.o -o %t.32 +# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs --relax %t.64.o -o %t.64 # RUN: llvm-objdump -dr %t.32 | FileCheck %s --check-prefix=RELAX # RUN: llvm-objdump -dr %t.64 | FileCheck %s --check-prefix=RELAX ## -r should keep original relocations. -# RUN: ld.lld -r %t.64.o -o %t.64.r +# RUN: ld.lld --relax -r %t.64.o -o %t.64.r # RUN: llvm-objdump -dr %t.64.r | FileCheck %s --check-prefix=CHECKR ## --no-relax should keep original relocations. @@ -58,7 +58,7 @@ # CHECKR-NEXT: pcalau12i $a0, 0 # CHECKR-NEXT: R_LARCH_GOT_PC_HI20 _start # CHECKR-NEXT: R_LARCH_RELAX *ABS* -# CHECKR-NEXT: ld.d $a0, $a0, 0 +# CHECKR-NEXT: ld.d $a0, $a0, 0 # CHECKR-NEXT: R_LARCH_GOT_PC_LO12 _start # CHECKR-NEXT: R_LARCH_RELAX *ABS* # CHECKR-NEXT: nop diff --git a/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s b/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s index bafb631bccb91..0a75d2289209c 100644 --- a/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s +++ b/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s @@ -9,13 +9,13 @@ # RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax abs.s -o abs.32.o # RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax abs.s -o abs.64.o -# RUN: ld.lld --shared -Tlinker.t symbols.32.o abs.32.o -o symbols.32.so -# RUN: ld.lld --shared -Tlinker.t symbols.64.o abs.64.o -o symbols.64.so +# RUN: ld.lld --shared --relax -Tlinker.t symbols.32.o abs.32.o -o symbols.32.so +# RUN: ld.lld --shared --relax -Tlinker.t symbols.64.o abs.64.o -o symbols.64.so # RUN: llvm-objdump -d --no-show-raw-insn symbols.32.so | FileCheck --check-prefixes=LIB %s # RUN: llvm-objdump -d --no-show-raw-insn symbols.64.so | FileCheck --check-prefixes=LIB %s -# RUN: ld.lld -Tlinker.t -z undefs symbols.32.o abs.32.o -o symbols.32 -# RUN: ld.lld -Tlinker.t -z undefs symbols.64.o abs.64.o -o symbols.64 +# RUN: ld.lld --relax -Tlinker.t -z undefs symbols.32.o abs.32.o -o symbols.32 +# RUN: ld.lld --relax -Tlinker.t -z undefs symbols.64.o abs.64.o -o symbols.64 # RUN: llvm-objdump -d --no-show-raw-insn symbols.32 | FileCheck --check-prefixes=EXE %s # RUN: llvm-objdump -d --no-show-raw-insn symbols.64 | FileCheck --check-prefixes=EXE %s diff --git a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s index a417d89e9fa2e..760fe77d774e3 100644 --- a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s +++ b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s @@ -3,18 +3,18 @@ # RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax %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: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 --relax %t.32.o -o %t.32 +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 --relax %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: 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 +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 --relax %t.32.o -shared -o %t.32s +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 --relax %t.64.o -shared -o %t.64s # RUN: llvm-objdump -td --no-show-raw-insn %t.32s | FileCheck --check-prefixes=RELAX %s # RUN: llvm-objdump -td --no-show-raw-insn %t.64s | FileCheck --check-prefixes=RELAX %s -# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 %t.32.o -o %t.32o -# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 %t.64.o -o %t.64o +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 --relax %t.32.o -o %t.32o +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 --relax %t.64.o -o %t.64o # RUN: llvm-objdump -td --no-show-raw-insn %t.32o | FileCheck --check-prefixes=NORELAX32 %s # RUN: llvm-objdump -td --no-show-raw-insn %t.64o | FileCheck --check-prefixes=NORELAX64 %s From 30cb3827458cf4fc585aa72f62f77971d8b47a36 Mon Sep 17 00:00:00 2001 From: yangzhaoxin Date: Mon, 20 Jan 2025 08:51:15 +0800 Subject: [PATCH 06/21] Add check for register. --- lld/ELF/Arch/LoongArch.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp index 07ca66700f648..b999e7fd27ae9 100644 --- a/lld/ELF/Arch/LoongArch.cpp +++ b/lld/ELF/Arch/LoongArch.cpp @@ -134,6 +134,8 @@ static uint32_t extractBits(uint64_t v, uint32_t begin, uint32_t end) { static uint32_t getD5(uint64_t v) { return extractBits(v, 4, 0); } +static uint32_t getJ5(uint64_t v) { return extractBits(v, 9, 5); } + static uint32_t setD5k16(uint32_t insn, uint32_t imm) { uint32_t immLo = extractBits(imm, 15, 0); uint32_t immHi = extractBits(imm, 20, 16); @@ -816,7 +818,11 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i, // addi.w/d. // * The destination register of pcalau12i is guaranteed to be used only by // the immediately following instruction. + const uint32_t currInsn = read32le(sec.content().data() + rHi20.offset); const uint32_t nextInsn = read32le(sec.content().data() + rLo12.offset); + // Check if use the same register. + if (getD5(currInsn) != getJ5(nextInsn) || getJ5(nextInsn) != getD5(nextInsn)) + return; sec.relaxAux->relocTypes[i] = R_LARCH_RELAX; sec.relaxAux->relocTypes[i + 2] = R_LARCH_PCREL20_S2; From f1f995b5fc8e90126b5825d52b9c75cd45d27cfc Mon Sep 17 00:00:00 2001 From: yangzhaoxin Date: Thu, 26 Dec 2024 11:32:33 +0800 Subject: [PATCH 07/21] Relax call36/tail36. Instructions with relocation `R_LARCH_CALL36` may be relax as follows: ``` From: pcaddu18i $dest, %call36(foo) R_LARCH_CALL36, R_LARCH_RELAX jirl $r, $dest, 0 To: b/bl foo # bl if r=$ra, b if r=$zero R_LARCH_B26 ``` --- lld/ELF/Arch/LoongArch.cpp | 41 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp index b999e7fd27ae9..0aa0cf5b657a0 100644 --- a/lld/ELF/Arch/LoongArch.cpp +++ b/lld/ELF/Arch/LoongArch.cpp @@ -58,6 +58,8 @@ enum Op { LD_W = 0x28800000, LD_D = 0x28c00000, JIRL = 0x4c000000, + B = 0x50000000, + BL = 0x54000000, }; enum Reg { @@ -830,6 +832,37 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i, remove = 4; } +// Relax code sequence. +// From: +// 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) { + const uint64_t symLocal = + (r.expr == R_PLT_PC ? r.sym->getPltVA(ctx) : r.sym->getVA(ctx)) + + r.addend; + + const int64_t distance = symLocal - loc; + // Check if the distance aligns 4 bytes or exceeds the range of b[l]. + if ((distance & 0x3) != 0 || !isInt<28>(distance)) + return; + + const uint32_t nextInsn = read32le(sec.content().data() + r.offset + 4); + if (getD5(nextInsn) == R_RA) { + // convert jirl to bl + sec.relaxAux->relocTypes[i] = R_LARCH_B26; + sec.relaxAux->writes.push_back(insn(BL, 0, 0, 0)); + remove = 4; + } else if (getD5(nextInsn) == R_ZERO) { + // convert jirl to b + sec.relaxAux->relocTypes[i] = R_LARCH_B26; + sec.relaxAux->writes.push_back(insn(B, 0, 0, 0)); + remove = 4; + } +} + static bool relax(Ctx &ctx, InputSection &sec) { const uint64_t secAddr = sec.getVA(); const MutableArrayRef relocs = sec.relocs(); @@ -874,6 +907,10 @@ static bool relax(Ctx &ctx, InputSection &sec) { if (isPairRelaxable(relocs, i)) relaxPCHi20Lo12(ctx, sec, i, loc, r, relocs[i + 2], remove); break; + case R_LARCH_CALL36: + if (relaxable(relocs, i)) + relaxCall36(ctx, sec, i, loc, r, remove); + break; } // For all anchors whose offsets are <= r.offset, they are preceded by @@ -977,6 +1014,10 @@ void LoongArch::finalizeRelax(int passes) const { // RelExpr is needed for relocating. r.expr = r.sym->hasFlag(NEEDS_PLT) ? R_PLT_PC : R_PC; break; + case R_LARCH_B26: + skip = 4; + write32le(p, aux.writes[writesIdx++]); + break; default: llvm_unreachable("unsupported type"); } From f227ae532236e20148a872c811721a8de4e16318 Mon Sep 17 00:00:00 2001 From: yangzhaoxin Date: Fri, 27 Dec 2024 14:37:40 +0800 Subject: [PATCH 08/21] modify test for call36/tail36. --- lld/test/ELF/loongarch-relax-call36-2.s | 63 +++++++++ lld/test/ELF/loongarch-relax-call36.s | 135 +++++++++++++++++++ lld/test/ELF/loongarch-relax-emit-relocs-2.s | 61 +++++++++ 3 files changed, 259 insertions(+) create mode 100644 lld/test/ELF/loongarch-relax-call36-2.s create mode 100644 lld/test/ELF/loongarch-relax-call36.s create mode 100644 lld/test/ELF/loongarch-relax-emit-relocs-2.s diff --git a/lld/test/ELF/loongarch-relax-call36-2.s b/lld/test/ELF/loongarch-relax-call36-2.s new file mode 100644 index 0000000000000..1c216a9bdc35e --- /dev/null +++ b/lld/test/ELF/loongarch-relax-call36-2.s @@ -0,0 +1,63 @@ +# REQUIRES: loongarch +# RUN: rm -rf %t && split-file %s %t && cd %t +# RUN: llvm-mc -filetype=obj -triple=loongarch64 -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: pcaddu18i $ra, 512 +# 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: pcaddu18i $ra, -512 +# RELAX-NEXT: jirl $ra, $ra, -4 +# 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: pcaddu18i $ra, 0 +# NORELAX-MID-NEXT: jirl $ra, $ra, 0 +# NORELAX-MID-NEXT: pcaddu18i $t0, 0 +# NORELAX-MID-NEXT: jr $t0 +# NORELAX-MID-EMPTY: + +#--- a.s +.global _start, ifunc +_start: + call36 pos # exceed positive range (.text+0x7fffffc), not relaxed + call36 pos # relaxed + call36 neg # relaxed + call36 neg # exceed negative range (.text+16-0x8000000), not relaxed + +.section .mid,"ax",@progbits +.balign 16 + call36 ifunc@plt # enable ifunc, not relaxed + tail36 $t0, ifunc@plt # 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-call36.s b/lld/test/ELF/loongarch-relax-call36.s new file mode 100644 index 0000000000000..57ed214c9eb2e --- /dev/null +++ b/lld/test/ELF/loongarch-relax-call36.s @@ -0,0 +1,135 @@ +# REQUIRES: loongarch + +# RUN: rm -rf %t && split-file %s %t && cd %t + +# RUN: llvm-mc -filetype=obj -triple=loongarch64 -mattr=+relax a.s -o a.64.o +# RUN: llvm-mc -filetype=obj -triple=loongarch64 -mattr=+relax b.s -o b.64.o +# RUN: ld.lld -shared -soname=b.so b.64.o -o b.64.so +# RUN: ld.lld -T lds a.64.o b.64.so -o 64 +# RUN: llvm-objdump -td --no-show-raw-insn 64 | FileCheck %s --check-prefix=RELAX + +## --no-relax disables relaxation. +# RUN: ld.lld -T lds a.64.o b.64.so --no-relax -o 64.norelax +# RUN: llvm-objdump -td --no-show-raw-insn 64.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 +# RELAX-NEXT: b 20 +# RELAX-NEXT: nop +# RELAX-NEXT: nop +## offset = .plt(0x10400)+32 - 0x10010 = 1040 +# RELAX-NEXT: 10010: bl 1040 +# RELAX-NEXT: b 1036 +# RELAX-EMPTY: +# RELAX-NEXT: : +# 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: pcaddu18i $ra, -1024 +# RELAX-NEXT: jirl $ra, $ra, 0 +# RELAX-NEXT: pcaddu18i $t0, -1024 +# RELAX-NEXT: jirl $zero, $t0, -8 +# RELAX-EMPTY: + + +# NORELAX-LABEL: <_start>: +## offset = 0x10020 - 0x10000 = 0x20, hi=0, lo18=32 +# NORELAX-NEXT: 10000: pcaddu18i $ra, 0 +# NORELAX-NEXT: jirl $ra, $ra, 32 +## offset = 0x10020 - 0x10008 = 0x18, hi=0, lo18=24 +# NORELAX-NEXT: 10008: pcaddu18i $t0, 0 +# NORELAX-NEXT: jirl $zero, $t0, 24 +## offset = .plt(0x10400)+32 - 0x10010 = 0x410, hi=0, lo18=1040 +# NORELAX-NEXT: 10010: pcaddu18i $ra, 0 +# NORELAX-NEXT: jirl $ra, $ra, 1040 +## offset = .plt(0x10400)+32 - 0x10018 = 0x408, hi=0, lo18=1032 +# NORELAX-NEXT: 10018: pcaddu18i $t0, 0 +# NORELAX-NEXT: jirl $zero, $t0, 1032 +# NORELAX-EMPTY: +# NORELAX-NEXT: : +# NORELAX-NEXT: 10020: ret +# NORELAX-EMPTY: + +# NORELAX-LABEL: <.mid>: +## offset = 0x10000 - 0x10800 = -0x800, hi=0, lo18=-2048 +# NORELAX-NEXT: 10800: pcaddu18i $ra, 0 +# NORELAX-NEXT: jirl $ra, $ra, -2048 +# NORELAX-NEXT: pcaddu18i $t0, 0 +# NORELAX-NEXT: jirl $zero, $t0, -2056 +# NORELAX-EMPTY: + +# NORELAX-LABEL: <.mid2>: +## offset = 0x10000 - 0x1010000 = -0x1000000, hi=-64, lo18=0 +# NORELAX-NEXT: 1010000: pcaddu18i $ra, -64 +# NORELAX-NEXT: jirl $ra, $ra, 0 +# NORELAX-NEXT: pcaddu18i $t0, -64 +# NORELAX-NEXT: jirl $zero, $t0, -8 +# NORELAX-EMPTY: + +# NORELAX-LABEL: <.high>: +## offset = 0x10000 - 0x10010000 = -0x10000000, hi=-1024, lo18=0 +# NORELAX-NEXT: 10010000: pcaddu18i $ra, -1024 +# NORELAX-NEXT: jirl $ra, $ra, 0 +# NORELAX-NEXT: pcaddu18i $t0, -1024 +# NORELAX-NEXT: jirl $zero, $t0, -8 +# NORELAX-EMPTY: + +#--- a.s +.global _start, _start_end +_start: + call36 a # relaxed. la64: bl + tail36 $t0, a@plt # relaxed. la64: b +.balign 16 + call36 bar # PLT call36 can be relaxed. la64: bl + tail36 $t0, bar # PLT tail36 can be relaxed. la64: bl + +a: + ret +.size _start, . - _start +_start_end: + +.section .mid,"ax",@progbits + call36 _start@plt # relaxed. la64: bl + tail36 $t0, _start@plt # relaxed. la64: b + +.section .mid2,"ax",@progbits + call36 _start@plt # relaxed. la64: bl + tail36 $t0, _start@plt # relaxed. la64: b + +.section .high,"ax",@progbits + call36 _start@plt # exceed range, not relaxed + tail36 $t0,_start@plt # 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-2.s b/lld/test/ELF/loongarch-relax-emit-relocs-2.s new file mode 100644 index 0000000000000..31cae939eca71 --- /dev/null +++ b/lld/test/ELF/loongarch-relax-emit-relocs-2.s @@ -0,0 +1,61 @@ +# REQUIRES: loongarch +## Test that we can handle --emit-relocs while relaxing. +## Call36 and tail36 need LA64 basic integer, so they donot have 32-bit version. + +# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o +# RUN: ld.lld -Ttext=0x10000 --emit-relocs %t.64.o -o %t.64 +# RUN: llvm-objdump -dr %t.64 | FileCheck %s --check-prefix=RELAX + +## -r should keep original relocations. +# RUN: ld.lld -r %t.64.o -o %t.64.r +# RUN: llvm-objdump -dr %t.64.r | FileCheck %s --check-prefix=CHECKR + +## --no-relax should keep original relocations. +# RUN: ld.lld -Ttext=0x10000 --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: bl 0 +# RELAX-NEXT: R_LARCH_B26 _start +# RELAX-NEXT: R_LARCH_RELAX *ABS* +# RELAX-NEXT: b -4 +# RELAX-NEXT: R_LARCH_B26 _start +# RELAX-NEXT: R_LARCH_RELAX *ABS* +# RELAX-NEXT: nop +# RELAX-NEXT: R_LARCH_ALIGN *ABS*+0xc +# RELAX-NEXT: nop +# RELAX-NEXT: ret + +# CHECKR: <_start>: +# CHECKR-NEXT: pcaddu18i $ra, 0 +# CHECKR-NEXT: R_LARCH_CALL36 _start +# CHECKR-NEXT: R_LARCH_RELAX *ABS* +# CHECKR-NEXT: jirl $ra, $ra, 0 +# CHECKR-NEXT: pcaddu18i $t0, 0 +# CHECKR-NEXT: R_LARCH_CALL36 _start +# CHECKR-NEXT: R_LARCH_RELAX *ABS* +# CHECKR-NEXT: jr $t0 +# CHECKR-NEXT: nop +# CHECKR-NEXT: R_LARCH_ALIGN *ABS*+0xc +# CHECKR-NEXT: nop +# CHECKR-NEXT: nop +# CHECKR-NEXT: ret + +# NORELAX: <_start>: +# NORELAX-NEXT: pcaddu18i $ra, 0 +# NORELAX-NEXT: R_LARCH_CALL36 _start +# NORELAX-NEXT: R_LARCH_RELAX *ABS* +# NORELAX-NEXT: jirl $ra, $ra, 0 +# NORELAX-NEXT: pcaddu18i $t0, 0 +# NORELAX-NEXT: R_LARCH_CALL36 _start +# NORELAX-NEXT: R_LARCH_RELAX *ABS* +# NORELAX-NEXT: jirl $zero, $t0, -8 +# NORELAX-NEXT: ret +# NORELAX-NEXT: R_LARCH_ALIGN *ABS*+0xc + +.global _start +_start: + call36 _start + tail36 $t0, _start + .p2align 4 + ret From f2aae15f701863d03edd32657824a97f66696e8d Mon Sep 17 00:00:00 2001 From: yangzhaoxin Date: Thu, 16 Jan 2025 21:50:14 +0800 Subject: [PATCH 09/21] Modify test. Add the option --relax. --- lld/test/ELF/loongarch-relax-call36-2.s | 6 +++--- lld/test/ELF/loongarch-relax-call36.s | 6 +++--- lld/test/ELF/loongarch-relax-emit-relocs-2.s | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lld/test/ELF/loongarch-relax-call36-2.s b/lld/test/ELF/loongarch-relax-call36-2.s index 1c216a9bdc35e..71650aefe9432 100644 --- a/lld/test/ELF/loongarch-relax-call36-2.s +++ b/lld/test/ELF/loongarch-relax-call36-2.s @@ -2,14 +2,14 @@ # RUN: rm -rf %t && split-file %s %t && cd %t # RUN: llvm-mc -filetype=obj -triple=loongarch64 -mattr=+relax a.s -o a.o -# RUN: ld.lld -T lds a.o -o a +# RUN: ld.lld --relax -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: ld.lld --relax -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: ld.lld --relax -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>: diff --git a/lld/test/ELF/loongarch-relax-call36.s b/lld/test/ELF/loongarch-relax-call36.s index 57ed214c9eb2e..bda0c4f05da91 100644 --- a/lld/test/ELF/loongarch-relax-call36.s +++ b/lld/test/ELF/loongarch-relax-call36.s @@ -4,12 +4,12 @@ # RUN: llvm-mc -filetype=obj -triple=loongarch64 -mattr=+relax a.s -o a.64.o # RUN: llvm-mc -filetype=obj -triple=loongarch64 -mattr=+relax b.s -o b.64.o -# RUN: ld.lld -shared -soname=b.so b.64.o -o b.64.so -# RUN: ld.lld -T lds a.64.o b.64.so -o 64 +# RUN: ld.lld --relax -shared -soname=b.so b.64.o -o b.64.so +# RUN: ld.lld --relax -T lds a.64.o b.64.so -o 64 # RUN: llvm-objdump -td --no-show-raw-insn 64 | FileCheck %s --check-prefix=RELAX ## --no-relax disables relaxation. -# RUN: ld.lld -T lds a.64.o b.64.so --no-relax -o 64.norelax +# RUN: ld.lld --no-relax -T lds a.64.o b.64.so -o 64.norelax # RUN: llvm-objdump -td --no-show-raw-insn 64.norelax | FileCheck %s --check-prefix=NORELAX # RELAX: {{0*}}00010000 g .text {{0*}}0000001c _start diff --git a/lld/test/ELF/loongarch-relax-emit-relocs-2.s b/lld/test/ELF/loongarch-relax-emit-relocs-2.s index 31cae939eca71..eddfc46b1ad08 100644 --- a/lld/test/ELF/loongarch-relax-emit-relocs-2.s +++ b/lld/test/ELF/loongarch-relax-emit-relocs-2.s @@ -3,15 +3,15 @@ ## Call36 and tail36 need LA64 basic integer, so they donot have 32-bit version. # RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o -# RUN: ld.lld -Ttext=0x10000 --emit-relocs %t.64.o -o %t.64 +# RUN: ld.lld --relax -Ttext=0x10000 --emit-relocs %t.64.o -o %t.64 # RUN: llvm-objdump -dr %t.64 | FileCheck %s --check-prefix=RELAX ## -r should keep original relocations. -# RUN: ld.lld -r %t.64.o -o %t.64.r +# RUN: ld.lld --relax -r %t.64.o -o %t.64.r # RUN: llvm-objdump -dr %t.64.r | FileCheck %s --check-prefix=CHECKR ## --no-relax should keep original relocations. -# RUN: ld.lld -Ttext=0x10000 --emit-relocs --no-relax %t.64.o -o %t.64.norelax +# RUN: ld.lld --no-relax -Ttext=0x10000 --emit-relocs %t.64.o -o %t.64.norelax # RUN: llvm-objdump -dr %t.64.norelax | FileCheck %s --check-prefix=NORELAX # RELAX: 00010000 <_start>: From 7993434e2973437b010034051003f8c03d8eff71 Mon Sep 17 00:00:00 2001 From: yangzhaoxin Date: Fri, 27 Dec 2024 19:29:32 +0800 Subject: [PATCH 10/21] Relax TLS LE/GD/LD. In local-exec form, the code sequence is converted as follows: ``` From: lu12i.w $rd, %le_hi20_r(sym) R_LARCH_TLS_LE_HI20_R, R_LARCH_RELAX add.w/d $rd, $rd, $tp, %le_add_r(sym) R_LARCH_TLS_LE_ADD_R, R_LARCH_RELAX addi/ld/st.w/d $rd, $rd, %le_lo12_r(sym) R_LARCH_TLS_LE_LO12_R, R_LARCH_RELAX To: addi/ld/st.w/d $rd, $tp, %le_lo12_r(sym) R_LARCH_TLS_LE_LO12_R ``` In global-dynamic or local-dynamic, the code sequence is converted as follows: ``` From: pcalau12i $a0, %ld_pc_hi20(sym) | %gd_pc_hi20(sym) R_LARCH_TLS_GD_PC_HI20 | R_LARCH_TLS_LD_PC_HI20, R_LARCH_RELAX addi.w/d $a0, $a0, %got_pc_lo12(sym) | %got_pc_lo12(sym) R_LARCH_GOT_PC_LO12, R_LARCH_RELAX To: pcaddi $a0, %got_pc_lo12(sym) | %got_pc_lo12(sym) R_LARCH_TLS_GD_PCREL20_S2 | R_LARCH_TLS_LD_PCREL20_S2 ``` Note: For initial-exec form, since it involves the conversion from IE to LE, we will implement it in a future patch. --- lld/ELF/Arch/LoongArch.cpp | 68 +++++++++++++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp index 0aa0cf5b657a0..2d6d86d2ca63b 100644 --- a/lld/ELF/Arch/LoongArch.cpp +++ b/lld/ELF/Arch/LoongArch.cpp @@ -761,10 +761,10 @@ static bool isPairRelaxable(ArrayRef relocs, size_t i) { // Relax code sequence. // From: -// pcalau12i $a0, %pc_hi20(sym) -// addi.w/d $a0, $a0, %pc_lo12(sym) +// pcalau12i $a0, %pc_hi20(sym) | %ld_pc_hi20(sym) | %gd_pc_hi20(sym) +// addi.w/d $a0, $a0, %pc_lo12(sym) | %got_pc_lo12(sym) | %got_pc_lo12(sym) // To: -// pcaddi $a0, %pc_lo12(sym) +// pcaddi $a0, %pc_lo12(sym) | %got_pc_lo12(sym) | %got_pc_lo12(sym) // // From: // pcalau12i $a0, %got_pc_hi20(sym_got) @@ -778,6 +778,10 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i, if (!((rHi20.type == R_LARCH_PCALA_HI20 && rLo12.type == R_LARCH_PCALA_LO12) || (rHi20.type == R_LARCH_GOT_PC_HI20 && + rLo12.type == R_LARCH_GOT_PC_LO12) || + (rHi20.type == R_LARCH_TLS_GD_PC_HI20 && + rLo12.type == R_LARCH_GOT_PC_LO12) || + (rHi20.type == R_LARCH_TLS_LD_PC_HI20 && rLo12.type == R_LARCH_GOT_PC_LO12))) return; @@ -798,6 +802,8 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i, else if (rHi20.expr == RE_LOONGARCH_PAGE_PC || rHi20.expr == RE_LOONGARCH_GOT_PAGE_PC) symBase = rHi20.sym->getVA(ctx); + else if (rHi20.expr == RE_LOONGARCH_TLSGD_PAGE_PC) + symBase = ctx.in.got->getGlobalDynAddr(*rHi20.sym); else { Err(ctx) << getErrorLoc(ctx, (const uint8_t *)loc) << "unknown expr (" << rHi20.expr << ") against symbol " << rHi20.sym @@ -827,7 +833,12 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i, return; sec.relaxAux->relocTypes[i] = R_LARCH_RELAX; - sec.relaxAux->relocTypes[i + 2] = R_LARCH_PCREL20_S2; + if (rHi20.type == R_LARCH_TLS_GD_PC_HI20) + sec.relaxAux->relocTypes[i + 2] = R_LARCH_TLS_GD_PCREL20_S2; + else if (rHi20.type == R_LARCH_TLS_LD_PC_HI20) + sec.relaxAux->relocTypes[i + 2] = R_LARCH_TLS_LD_PCREL20_S2; + else + sec.relaxAux->relocTypes[i + 2] = R_LARCH_PCREL20_S2; sec.relaxAux->writes.push_back(insn(PCADDI, getD5(nextInsn), 0, 0)); remove = 4; } @@ -863,6 +874,35 @@ static void relaxCall36(Ctx &ctx, const InputSection &sec, size_t i, } } +// Relax code sequence. +// From: +// lu12i.w $rd, %le_hi20_r(sym) +// add.w/d $rd, $rd, $tp, %le_add_r(sym) +// addi/ld/st.w/d $rd, $rd, %le_lo12_r(sym) +// To: +// addi/ld/st.w/d $rd, $tp, %le_lo12_r(sym) +static void relaxTlsLe(Ctx &ctx, const InputSection &sec, size_t i, + uint64_t loc, Relocation &r, uint32_t &remove) { + uint64_t val = r.sym->getVA(ctx, r.addend); + // Check if the val exceeds the range of addi/ld/st. + if (!isInt<12>(val)) + return; + uint32_t currInsn = read32le(sec.content().data() + r.offset); + switch (r.type) { + case R_LARCH_TLS_LE_HI20_R: + case R_LARCH_TLS_LE_ADD_R: + sec.relaxAux->relocTypes[i] = R_LARCH_RELAX; + remove = 4; + break; + case R_LARCH_TLS_LE_LO12_R: + currInsn = + insn(extractBits(currInsn, 31, 22) << 22, getD5(currInsn), R_TP, 0); + sec.relaxAux->writes.push_back(currInsn); + sec.relaxAux->relocTypes[i] = R_LARCH_TLS_LE_LO12_R; + break; + } +} + static bool relax(Ctx &ctx, InputSection &sec) { const uint64_t secAddr = sec.getVA(); const MutableArrayRef relocs = sec.relocs(); @@ -903,6 +943,8 @@ static bool relax(Ctx &ctx, InputSection &sec) { } case R_LARCH_PCALA_HI20: case R_LARCH_GOT_PC_HI20: + case R_LARCH_TLS_GD_PC_HI20: + case R_LARCH_TLS_LD_PC_HI20: // The overflow check for i+2 will be carried out in isPairRelaxable. if (isPairRelaxable(relocs, i)) relaxPCHi20Lo12(ctx, sec, i, loc, r, relocs[i + 2], remove); @@ -911,6 +953,12 @@ static bool relax(Ctx &ctx, InputSection &sec) { if (relaxable(relocs, i)) relaxCall36(ctx, sec, i, loc, r, remove); break; + case R_LARCH_TLS_LE_HI20_R: + case R_LARCH_TLS_LE_ADD_R: + case R_LARCH_TLS_LE_LO12_R: + if (relaxable(relocs, i)) + relaxTlsLe(ctx, sec, i, loc, r, remove); + break; } // For all anchors whose offsets are <= r.offset, they are preceded by @@ -1015,8 +1063,20 @@ void LoongArch::finalizeRelax(int passes) const { r.expr = r.sym->hasFlag(NEEDS_PLT) ? R_PLT_PC : R_PC; break; case R_LARCH_B26: + case R_LARCH_TLS_LE_LO12_R: + skip = 4; + write32le(p, aux.writes[writesIdx++]); + break; + case R_LARCH_TLS_GD_PCREL20_S2: + // Note: R_LARCH_TLS_LD_PCREL20_S2 must also use R_TLSGD_PC instead + // of R_TLSLD_PC because the processing of relocation + // R_LARCH_TLS_LD_PC_HI20 is the same as R_LARCH_TLS_GD_PC_HI20. If + // not, the value obtained from getRelocTargetVA will be unexpected + // and lead to error. + case R_LARCH_TLS_LD_PCREL20_S2: skip = 4; write32le(p, aux.writes[writesIdx++]); + r.expr = R_TLSGD_PC; break; default: llvm_unreachable("unsupported type"); From 1e9aa529f34dbe6d61295980593c894d3074a7b2 Mon Sep 17 00:00:00 2001 From: yangzhaoxin Date: Sun, 29 Dec 2024 17:02:09 +0800 Subject: [PATCH 11/21] Add test for TLSLD/TLSGD when relax enabled. --- lld/test/ELF/loongarch-tls-gd.s | 43 +++++++++++++++++++++++++++++++-- lld/test/ELF/loongarch-tls-ld.s | 40 ++++++++++++++++++++++++++++-- 2 files changed, 79 insertions(+), 4 deletions(-) diff --git a/lld/test/ELF/loongarch-tls-gd.s b/lld/test/ELF/loongarch-tls-gd.s index 2aecb44c17a34..27d9fdb7ee701 100644 --- a/lld/test/ELF/loongarch-tls-gd.s +++ b/lld/test/ELF/loongarch-tls-gd.s @@ -1,14 +1,17 @@ # REQUIRES: loongarch # RUN: rm -rf %t && split-file %s %t -## LoongArch psABI doesn't specify TLS relaxation. Though the code sequences are not -## relaxed, dynamic relocations can be omitted for GD->LE relaxation. +## LoongArch psABI doesn't specify TLS relaxation. It can be handled the same way as gcc: +## (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 %t/a.s -o %t/a.32.o +# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax %t/a.s -o %t/a.32.relax.o # RUN: llvm-mc --filetype=obj --triple=loongarch32 %t/bc.s -o %t/bc.32.o # RUN: ld.lld -shared -soname=bc.so %t/bc.32.o -o %t/bc.32.so # RUN: llvm-mc --filetype=obj --triple=loongarch32 %t/tga.s -o %t/tga.32.o # RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/a.s -o %t/a.64.o +# RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/a.s -mattr=+relax -o %t/a.64.relax.o # RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/bc.s -o %t/bc.64.o # RUN: ld.lld -shared -soname=bc.so %t/bc.64.o -o %t/bc.64.so # RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/tga.s -o %t/tga.64.o @@ -17,6 +20,9 @@ # RUN: ld.lld -shared %t/a.32.o %t/bc.32.o -o %t/gd.32.so # RUN: llvm-readobj -r %t/gd.32.so | FileCheck --check-prefix=GD32-REL %s # RUN: llvm-objdump -d --no-show-raw-insn %t/gd.32.so | FileCheck --check-prefix=GD32 %s +# RUN: ld.lld -shared %t/a.32.relax.o %t/bc.32.o -o %t/gd.32.relax.so +# RUN: llvm-readobj -r %t/gd.32.relax.so | FileCheck --check-prefix=GD32-REL-RELAX %s +# RUN: llvm-objdump -d --no-show-raw-insn %t/gd.32.relax.so | FileCheck --check-prefix=GD32-RELAX %s ## LA32 GD -> LE # RUN: ld.lld %t/a.32.o %t/bc.32.o %t/tga.32.o -o %t/le.32 @@ -35,6 +41,9 @@ # RUN: ld.lld -shared %t/a.64.o %t/bc.64.o -o %t/gd.64.so # RUN: llvm-readobj -r %t/gd.64.so | FileCheck --check-prefix=GD64-REL %s # RUN: llvm-objdump -d --no-show-raw-insn %t/gd.64.so | FileCheck --check-prefix=GD64 %s +# RUN: ld.lld -shared %t/a.64.relax.o %t/bc.64.o -o %t/gd.64.relax.so +# RUN: llvm-readobj -r %t/gd.64.relax.so | FileCheck --check-prefix=GD64-REL-RELAX %s +# RUN: llvm-objdump -d --no-show-raw-insn %t/gd.64.relax.so | FileCheck --check-prefix=GD64-RELAX %s ## LA64 GD -> LE # RUN: ld.lld %t/a.64.o %t/bc.64.o %t/tga.64.o -o %t/le.64 @@ -66,6 +75,21 @@ # GD32-NEXT: addi.w $a0, $a0, 792 # GD32-NEXT: bl 44 +# GD32-REL-RELAX: .rela.dyn { +# GD32-REL-RELAX-NEXT: 0x20300 R_LARCH_TLS_DTPMOD32 a 0x0 +# GD32-REL-RELAX-NEXT: 0x20304 R_LARCH_TLS_DTPREL32 a 0x0 +# GD32-REL-RELAX-NEXT: 0x20308 R_LARCH_TLS_DTPMOD32 b 0x0 +# GD32-REL-RELAX-NEXT: 0x2030C R_LARCH_TLS_DTPREL32 b 0x0 +# GD32-REL-RELAX-NEXT: } + +## &DTPMOD(a) - . = 0x20300 - 0x10250 = 16428<<2 +# GD32-RELAX: 10250: pcaddi $a0, 16428 +# GD32-RELAX-NEXT: bl 44 + +## &DTPMOD(b) - . = 0x20308 - 0x10258 = 16428<<2 +# GD32-RELAX: 10258: pcaddi $a0, 16428 +# GD32-RELAX-NEXT: bl 36 + # GD64-REL: .rela.dyn { # GD64-REL-NEXT: 0x204C0 R_LARCH_TLS_DTPMOD64 a 0x0 # GD64-REL-NEXT: 0x204C8 R_LARCH_TLS_DTPREL64 a 0x0 @@ -83,6 +107,21 @@ # GD64-NEXT: addi.d $a0, $a0, 1232 # GD64-NEXT: bl 36 +# GD64-REL-RELAX: .rela.dyn { +# GD64-REL-RELAX-NEXT: 0x204C0 R_LARCH_TLS_DTPMOD64 a 0x0 +# GD64-REL-RELAX-NEXT: 0x204C8 R_LARCH_TLS_DTPREL64 a 0x0 +# GD64-REL-RELAX-NEXT: 0x204D0 R_LARCH_TLS_DTPMOD64 b 0x0 +# GD64-REL-RELAX-NEXT: 0x204D8 R_LARCH_TLS_DTPREL64 b 0x0 +# GD64-REL-RELAX-NEXT: } + +## &DTPMOD(a) - . = 0x204c0 - 0x10398 = 16458<<2 +# GD64-RELAX: 10398: pcaddi $a0, 16458 +# GD64-RELAX-NEXT: bl 52 + +## &DTPMOD(b) - . = 0x204d0 - 0x103a0 = 16460<<2 +# GD64-RELAX: 103a0: pcaddi $a0, 16460 +# GD64-RELAX-NEXT: bl 44 + # NOREL: no relocations ## .got contains pre-populated values: [a@dtpmod, a@dtprel, b@dtpmod, b@dtprel] diff --git a/lld/test/ELF/loongarch-tls-ld.s b/lld/test/ELF/loongarch-tls-ld.s index a5be3ad905b76..27adb1e17702a 100644 --- a/lld/test/ELF/loongarch-tls-ld.s +++ b/lld/test/ELF/loongarch-tls-ld.s @@ -1,12 +1,15 @@ # REQUIRES: loongarch # RUN: rm -rf %t && split-file %s %t -## LoongArch psABI doesn't specify TLS relaxation. Though the code sequences are not -## relaxed, dynamic relocations can be omitted for LD->LE relaxation. +## LoongArch psABI doesn't specify TLS relaxation. It can be handled the same way as gcc: +## (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 %t/a.s -o %t/a.32.o +# RUN: llvm-mc --filetype=obj --triple=loongarch32 --position-independent -mattr=+relax %t/a.s -o %t/a.32.relax.o # RUN: llvm-mc --filetype=obj --triple=loongarch32 %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 +# RUN: llvm-mc --filetype=obj --triple=loongarch64 --position-independent -mattr=+relax %t/a.s -o %t/a.64.relax.o # RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/tga.s -o %t/tga.64.o ## LA32 LD @@ -14,24 +17,34 @@ # RUN: llvm-readobj -r %t/ld.32.so | FileCheck --check-prefix=LD32-REL %s # RUN: llvm-readelf -x .got %t/ld.32.so | FileCheck --check-prefix=LD32-GOT %s # RUN: llvm-objdump -d --no-show-raw-insn %t/ld.32.so | FileCheck --check-prefixes=LD32 %s +# RUN: ld.lld -shared %t/a.32.relax.o -o %t/ld.32.relax.so +# RUN: llvm-objdump -d --no-show-raw-insn %t/ld.32.relax.so | FileCheck --check-prefixes=LD32-RELAX %s ## LA32 LD -> LE # RUN: ld.lld %t/a.32.o %t/tga.32.o -o %t/le.32 # RUN: llvm-readelf -r %t/le.32 | FileCheck --check-prefix=NOREL %s # RUN: llvm-readelf -x .got %t/le.32 | FileCheck --check-prefix=LE32-GOT %s # RUN: llvm-objdump -d --no-show-raw-insn %t/le.32 | FileCheck --check-prefixes=LE32 %s +# RUN: ld.lld %t/a.32.relax.o %t/tga.32.o -o %t/le.32.relax +# RUN: llvm-readelf -x .got %t/le.32.relax | FileCheck --check-prefix=LE32-GOT-RELAX %s +# RUN: llvm-objdump -d --no-show-raw-insn %t/le.32.relax | FileCheck --check-prefixes=LE32-RELAX %s ## LA64 LD # RUN: ld.lld -shared %t/a.64.o -o %t/ld.64.so # RUN: llvm-readobj -r %t/ld.64.so | FileCheck --check-prefix=LD64-REL %s # RUN: llvm-readelf -x .got %t/ld.64.so | FileCheck --check-prefix=LD64-GOT %s # RUN: llvm-objdump -d --no-show-raw-insn %t/ld.64.so | FileCheck --check-prefixes=LD64 %s +# RUN: ld.lld -shared %t/a.64.relax.o -o %t/ld.64.relax.so +# RUN: llvm-objdump -d --no-show-raw-insn %t/ld.64.relax.so | FileCheck --check-prefixes=LD64-RELAX %s ## LA64 LD -> LE # RUN: ld.lld %t/a.64.o %t/tga.64.o -o %t/le.64 # RUN: llvm-readelf -r %t/le.64 | FileCheck --check-prefix=NOREL %s # RUN: llvm-readelf -x .got %t/le.64 | FileCheck --check-prefix=LE64-GOT %s # RUN: llvm-objdump -d --no-show-raw-insn %t/le.64 | FileCheck --check-prefixes=LE64 %s +# RUN: ld.lld %t/a.64.relax.o %t/tga.64.o -o %t/le.64.relax +# RUN: llvm-readelf -x .got %t/le.64.relax | FileCheck --check-prefix=LE64-GOT-RELAX %s +# RUN: llvm-objdump -d --no-show-raw-insn %t/le.64.relax | FileCheck --check-prefixes=LE64-RELAX %s ## a@dtprel = st_value(a) = 0 is a link-time constant. # LD32-REL: .rela.dyn { @@ -56,6 +69,14 @@ # LD64-NEXT: addi.d $a0, $a0, 1024 # LD64-NEXT: bl 40 +## LA32: &DTPMOD(a) - . = 0x20280 - 0x101cc = 16429<<2 +# LD32-RELAX: 101cc: pcaddi $a0, 16429 +# LD32-RELAX-NEXT: bl 48 + +## LA64: &DTPMOD(a) - . = 0x20400 - 0x102e0 = 16456<<2 +# LD64-RELAX: 102e0: pcaddi $a0, 16456 +# LD64-RELAX-NEXT: bl 44 + # NOREL: no relocations ## a is local - its DTPMOD/DTPREL slots are link-time constants. @@ -66,6 +87,12 @@ # LE64-GOT: section '.got': # LE64-GOT-NEXT: 0x000301d8 01000000 00000000 00000000 00000000 +# LE32-GOT-RELAX: section '.got': +# LE32-GOT-RELAX-NEXT: 0x0003011c 01000000 00000000 + +# LE64-GOT-RELAX: section '.got': +# 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 @@ -76,6 +103,15 @@ # LE64-NEXT: addi.d $a0, $a0, 472 # LE64-NEXT: bl 4 +## LA32: DTPMOD(.LANCHOR0) - . = 0x3011c - 0x20114 = 16386<<2 +# LE32-RELAX: 20114: pcaddi $a0, 16386 +# LE32-RELAX-NEXT: bl 4 + +## LA64: DTPMOD(.LANCHOR0) - . = 0x301d0 - 0x201c8 = 16386<<2 +# LE64-RELAX: 201c8: pcaddi $a0, 16386 +# LE64-RELAX-NEXT: bl 4 + + #--- a.s la.tls.ld $a0, .LANCHOR0 bl %plt(__tls_get_addr) From 91da25ea973556fc3a9f4dd2af06af0371cc4d36 Mon Sep 17 00:00:00 2001 From: yangzhaoxin Date: Tue, 31 Dec 2024 20:00:17 +0800 Subject: [PATCH 12/21] Modify test for TLSLE when relax enabled. --- lld/test/ELF/loongarch-tls-le.s | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lld/test/ELF/loongarch-tls-le.s b/lld/test/ELF/loongarch-tls-le.s index 394c60f67bce8..981baa6fd726f 100644 --- a/lld/test/ELF/loongarch-tls-le.s +++ b/lld/test/ELF/loongarch-tls-le.s @@ -1,14 +1,20 @@ # REQUIRES: loongarch # RUN: llvm-mc --filetype=obj --triple=loongarch32 --defsym ELF32=1 %s -o %t.32.o +# RUN: llvm-mc --filetype=obj --triple=loongarch32 --defsym ELF32=1 -mattr=+relax %s -o %t.32.relax.o # RUN: llvm-mc --filetype=obj --triple=loongarch64 %s -o %t.64.o +# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax %s -o %t.64.relax.o # RUN: ld.lld %t.32.o -o %t.32 # RUN: llvm-nm -p %t.32 | FileCheck --check-prefixes=NM %s # RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=LE,LE32 %s +# RUN: ld.lld %t.32.relax.o -o %t.32.relax +# RUN: llvm-objdump -d --no-show-raw-insn %t.32.relax | FileCheck --check-prefixes=LE,LE32-RELAX %s # RUN: ld.lld %t.64.o -o %t.64 # RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=LE,LE64 %s +# RUN: ld.lld %t.64.relax.o -o %t.64.relax +# RUN: llvm-objdump -d --no-show-raw-insn %t.64.relax | FileCheck --check-prefixes=LE,LE64-RELAX %s # RUN: not ld.lld -shared %t.32.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR --implicit-check-not=error: @@ -37,12 +43,22 @@ # LE32-NEXT: add.w $a0, $a0, $tp # LE32-NEXT: addi.w $a0, $a0, -2048 +# LE32-RELAX: addi.w $a0, $tp, 8 +# LE32-RELAX-NEXT: lu12i.w $a0, 1 +# LE32-RELAX-NEXT: add.w $a0, $a0, $tp +# LE32-RELAX-NEXT: addi.w $a0, $a0, -2048 + # LE64: add.d $a0, $a0, $tp # LE64-NEXT: addi.d $a0, $a0, 8 # LE64-NEXT: lu12i.w $a0, 1 # LE64-NEXT: add.d $a0, $a0, $tp # LE64-NEXT: addi.d $a0, $a0, -2048 +# LE64-RELAX: addi.d $a0, $tp, 8 +# LE64-RELAX-NEXT: lu12i.w $a0, 1 +# LE64-RELAX-NEXT: add.d $a0, $a0, $tp +# LE64-RELAX-NEXT: addi.d $a0, $a0, -2048 + # LE-EMPTY: .macro add dst, src1, src2, src3 From 2066c5f7cc3eecfdd76216378efbfb8376fa4262 Mon Sep 17 00:00:00 2001 From: yangzhaoxin Date: Tue, 31 Dec 2024 14:49:40 +0800 Subject: [PATCH 13/21] Add test for loongarch-relax-tls-le.s and modify loongarch-relax-emit-relocs.s --- lld/test/ELF/loongarch-relax-emit-relocs.s | 112 +++++++++++++++++++- lld/test/ELF/loongarch-relax-tls-le.s | 115 +++++++++++++++++++++ 2 files changed, 222 insertions(+), 5 deletions(-) create mode 100644 lld/test/ELF/loongarch-relax-tls-le.s diff --git a/lld/test/ELF/loongarch-relax-emit-relocs.s b/lld/test/ELF/loongarch-relax-emit-relocs.s index a02cd272aba5b..5bb445dcaff50 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=+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 -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs --relax %t.32.o -o %t.32 # RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs --relax %t.64.o -o %t.64 @@ -17,19 +17,39 @@ # RUN: llvm-objdump -dr %t.64.norelax | FileCheck %s --check-prefix=NORELAX # RELAX: 00010000 <_start>: -# RELAX-NEXT: pcaddi $a0, 0 +# 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: 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* +# RELAX-NEXT: lu12i.w $a0, 0 +# 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, {{[0-9]+}} +# 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, {{[0-9]+}} +# 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* +# RELAX-NEXT: addi.{{[dw]}} $a0, $tp, 0 +# RELAX-NEXT: R_LARCH_RELAX a +# RELAX-NEXT: R_LARCH_RELAX *ABS* +# RELAX-NEXT: R_LARCH_RELAX a +# RELAX-NEXT: R_LARCH_RELAX *ABS* +# RELAX-NEXT: R_LARCH_TLS_LE_LO12_R a +# RELAX-NEXT: R_LARCH_RELAX *ABS* # RELAX-NEXT: nop # RELAX-NEXT: R_LARCH_ALIGN *ABS*+0xc -# RELAX-NEXT: nop # RELAX-NEXT: ret # NORELAX: <_start>: @@ -45,8 +65,36 @@ # NORELAX-NEXT: ld.d $a0, $a0, 0 # NORELAX-NEXT: R_LARCH_GOT_PC_LO12 _start # NORELAX-NEXT: R_LARCH_RELAX *ABS* -# NORELAX-NEXT: ret +# NORELAX-NEXT: lu12i.w $a0, 0 +# NORELAX-NEXT: R_LARCH_TLS_LE_HI20 a +# NORELAX-NEXT: ori $a0, $a0, 0 +# NORELAX-NEXT: R_LARCH_TLS_LE_LO12 a +# NORELAX-NEXT: pcalau12i $a0, 16 +# NORELAX-NEXT: R_LARCH_TLS_GD_PC_HI20 a +# NORELAX-NEXT: R_LARCH_RELAX *ABS* +# NORELAX-NEXT: addi.d $a0, $a0, 8 +# NORELAX-NEXT: R_LARCH_GOT_PC_LO12 a +# NORELAX-NEXT: R_LARCH_RELAX *ABS* +# NORELAX-NEXT: pcalau12i $a0, 16 +# NORELAX-NEXT: R_LARCH_TLS_LD_PC_HI20 a +# NORELAX-NEXT: R_LARCH_RELAX *ABS* +# NORELAX-NEXT: addi.d $a0, $a0, 8 +# NORELAX-NEXT: R_LARCH_GOT_PC_LO12 a +# NORELAX-NEXT: R_LARCH_RELAX *ABS* +# NORELAX-NEXT: lu12i.w $a0, 0 +# NORELAX-NEXT: R_LARCH_TLS_LE_HI20_R a +# NORELAX-NEXT: R_LARCH_RELAX *ABS* +# NORELAX-NEXT: add.d $a0, $a0, $tp +# NORELAX-NEXT: R_LARCH_TLS_LE_ADD_R a +# NORELAX-NEXT: R_LARCH_RELAX *ABS* +# NORELAX-NEXT: addi.d $a0, $a0, 0 +# NORELAX-NEXT: R_LARCH_TLS_LE_LO12_R a +# NORELAX-NEXT: R_LARCH_RELAX *ABS* +# NORELAX-NEXT: nop # NORELAX-NEXT: R_LARCH_ALIGN *ABS*+0xc +# NORELAX-NEXT: nop +# NORELAX-NEXT: nop +# NORELAX-NEXT: ret # CHECKR: <_start>: # CHECKR-NEXT: pcalau12i $a0, 0 @@ -61,15 +109,69 @@ # CHECKR-NEXT: ld.d $a0, $a0, 0 # CHECKR-NEXT: R_LARCH_GOT_PC_LO12 _start # CHECKR-NEXT: R_LARCH_RELAX *ABS* +# CHECKR-NEXT: lu12i.w $a0, 0 +# CHECKR-NEXT: R_LARCH_TLS_LE_HI20 a +# CHECKR-NEXT: ori $a0, $a0, 0 +# CHECKR-NEXT: R_LARCH_TLS_LE_LO12 a +# CHECKR-NEXT: pcalau12i $a0, 0 +# CHECKR-NEXT: R_LARCH_TLS_GD_PC_HI20 a +# CHECKR-NEXT: R_LARCH_RELAX *ABS* +# CHECKR-NEXT: addi.d $a0, $a0, 0 +# CHECKR-NEXT: R_LARCH_GOT_PC_LO12 a +# CHECKR-NEXT: R_LARCH_RELAX *ABS* +# CHECKR-NEXT: pcalau12i $a0, 0 +# CHECKR-NEXT: R_LARCH_TLS_LD_PC_HI20 a +# CHECKR-NEXT: R_LARCH_RELAX *ABS* +# CHECKR-NEXT: addi.d $a0, $a0, 0 +# CHECKR-NEXT: R_LARCH_GOT_PC_LO12 a +# CHECKR-NEXT: R_LARCH_RELAX *ABS* +# CHECKR-NEXT: lu12i.w $a0, 0 +# CHECKR-NEXT: R_LARCH_TLS_LE_HI20_R a +# CHECKR-NEXT: R_LARCH_RELAX *ABS* +# CHECKR-NEXT: add.d $a0, $a0, $tp +# CHECKR-NEXT: R_LARCH_TLS_LE_ADD_R a +# CHECKR-NEXT: R_LARCH_RELAX *ABS* +# CHECKR-NEXT: addi.d $a0, $a0, 0 +# CHECKR-NEXT: R_LARCH_TLS_LE_LO12_R a +# CHECKR-NEXT: R_LARCH_RELAX *ABS* # CHECKR-NEXT: nop # CHECKR-NEXT: R_LARCH_ALIGN *ABS*+0xc # CHECKR-NEXT: nop # CHECKR-NEXT: nop # CHECKR-NEXT: ret +.macro add dst, src1, src2, src3 +.ifdef ELF32 +add.w \dst, \src1, \src2, \src3 +.else +add.d \dst, \src1, \src2, \src3 +.endif +.endm +.macro addi dst, src1, src2 +.ifdef ELF32 +addi.w \dst, \src1, \src2 +.else +addi.d \dst, \src1, \src2 +.endif +.endm + .global _start _start: la.pcrel $a0, _start la.got $a0, _start + + la.tls.le $a0, a # without R_LARCH_RELAX reloaction + la.tls.gd $a0, a + la.tls.ld $a0, a + + lu12i.w $a0, %le_hi20_r(a) + add $a0, $a0, $tp, %le_add_r(a) + addi $a0, $a0, %le_lo12_r(a) + .p2align 4 ret + +.section .tbss,"awT",@nobits +.globl a +a: +.zero 4 diff --git a/lld/test/ELF/loongarch-relax-tls-le.s b/lld/test/ELF/loongarch-relax-tls-le.s new file mode 100644 index 0000000000000..8f9b6e1092a62 --- /dev/null +++ b/lld/test/ELF/loongarch-relax-tls-le.s @@ -0,0 +1,115 @@ +# REQUIRES: loongarch + +# 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 %t.32.o -o %t.32 +# RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX32 %s + +# RUN: ld.lld %t.64.o -o %t.64 +# RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=RELAX64 %s + +# RELAX32-LABEL: <_start>: +## .LANCHOR0@tprel = 8 +# RELAX32-NEXT: addi.w $a0, $tp, 8 +# RELAX32-NEXT: ld.w $a1, $a0, 0 +# RELAX32-NEXT: ld.w $a2, $tp, 8 +## .a@tprel - 4 = 0x7fc +# RELAX32-NEXT: addi.w $a1, $zero, 1 +# RELAX32-NEXT: addi.w $a1, $a1, 2 +# RELAX32-NEXT: st.w $a1, $tp, 2044 +## .a@tprel = 0x800 +# RELAX32-NEXT: lu12i.w $a0, 1 +# RELAX32-NEXT: add.w $a0, $a0, $tp +# RELAX32-NEXT: addi.w $a0, $a0, -2048 + +# RELAX64-LABEL: <_start>: +## .LANCHOR0@tprel = 8 +# RELAX64-NEXT: addi.d $a0, $tp, 8 +# RELAX64-NEXT: ld.d $a1, $a0, 0 +# RELAX64-NEXT: ld.d $a2, $tp, 8 +## .a@tprel - 4 = 0x7fc +# RELAX64-NEXT: addi.d $a1, $zero, 1 +# RELAX64-NEXT: addi.d $a1, $a1, 2 +# RELAX64-NEXT: st.d $a1, $tp, 2044 +## .a@tprel = 0x800 +# RELAX64-NEXT: lu12i.w $a0, 1 +# RELAX64-NEXT: add.d $a0, $a0, $tp +# RELAX64-NEXT: addi.d $a0, $a0, -2048 + +.macro add dst, src1, src2, src3 +.ifdef ELF32 +add.w \dst, \src1, \src2, \src3 +.else +add.d \dst, \src1, \src2, \src3 +.endif +.endm +.macro inst op dst, src1, src2 +.ifdef ELF32 + .ifc \op, addi + addi.w \dst, \src1, \src2 + .else; .ifc \op, ld + ld.w \dst, \src1, \src2 + .else; .ifc \op, st + st.w \dst, \src1, \src2 + .else; .ifc \op, ldptr + ldptr.w \dst, \src1, \src2 + .else + .error "Unknown op in ELF32 mode" + .endif; .endif; .endif; .endif +.else + .ifc \op, addi + addi.d \dst, \src1, \src2 + .else; .ifc \op, ld + ld.d \dst, \src1, \src2 + .else; .ifc \op, st + st.d \dst, \src1, \src2 + .else; .ifc \op, ldptr + ldptr.d \dst, \src1, \src2 + .else + .error "Unknown op in ELF64 mode" + .endif; .endif; .endif; .endif +.endif +.endm + +.macro addi dst, src1, src2 +inst addi \dst, \src1, \src2 +.endm +.macro ld dst, src1, src2 +inst ld \dst, \src1, \src2 +.endm +.macro st dst, src1, src2 +inst st \dst, \src1, \src2 +.endm +.macro ldptr dst, src1, src2 +inst ldptr \dst, \src1, \src2 +.endm + +_start: +## Test instructions not in pairs. +lu12i.w $a0, %le_hi20_r(.LANCHOR0) +add $a0, $a0, $tp, %le_add_r(.LANCHOR0) +addi $a0, $a0, %le_lo12_r(.LANCHOR0) +ld $a1, $a0, 0 +ld $a2, $a0, %le_lo12_r(.LANCHOR0) + +## hi20(a-4) = hi20(0x7fc) = 0. relaxable +## Test non-adjacent instructions. +lu12i.w $a0, %le_hi20_r(a-4) +addi $a1, $zero, 0x1 +add $a0, $a0, $tp, %le_add_r(a-4) +addi $a1, $a1, 0x2 +st $a1, $a0, %le_lo12_r(a-4) + +## hi20(a) = hi20(0x800) = 1. not relaxable +lu12i.w $a0, %le_hi20_r(a) +add $a0, $a0, $tp, %le_add_r(a) +addi $a0, $a0, %le_lo12_r(a) + +.section .tbss,"awT",@nobits +.space 8 +.LANCHOR0: +.space 0x800-8 +.globl a +a: +.zero 4 From b57c40e275dc0977e002e68834c2b40fa030d9fc Mon Sep 17 00:00:00 2001 From: yangzhaoxin Date: Thu, 16 Jan 2025 22:08:02 +0800 Subject: [PATCH 14/21] Modify test. Add --relax option. --- lld/test/ELF/loongarch-relax-tls-le.s | 4 ++-- lld/test/ELF/loongarch-tls-gd.s | 4 ++-- lld/test/ELF/loongarch-tls-ld.s | 8 ++++---- lld/test/ELF/loongarch-tls-le.s | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lld/test/ELF/loongarch-relax-tls-le.s b/lld/test/ELF/loongarch-relax-tls-le.s index 8f9b6e1092a62..b55f284f32cb8 100644 --- a/lld/test/ELF/loongarch-relax-tls-le.s +++ b/lld/test/ELF/loongarch-relax-tls-le.s @@ -3,10 +3,10 @@ # 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 %t.32.o -o %t.32 +# RUN: ld.lld --relax %t.32.o -o %t.32 # RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX32 %s -# RUN: ld.lld %t.64.o -o %t.64 +# RUN: ld.lld --relax %t.64.o -o %t.64 # RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=RELAX64 %s # RELAX32-LABEL: <_start>: diff --git a/lld/test/ELF/loongarch-tls-gd.s b/lld/test/ELF/loongarch-tls-gd.s index 27d9fdb7ee701..4cfed41d70f38 100644 --- a/lld/test/ELF/loongarch-tls-gd.s +++ b/lld/test/ELF/loongarch-tls-gd.s @@ -20,7 +20,7 @@ # RUN: ld.lld -shared %t/a.32.o %t/bc.32.o -o %t/gd.32.so # RUN: llvm-readobj -r %t/gd.32.so | FileCheck --check-prefix=GD32-REL %s # RUN: llvm-objdump -d --no-show-raw-insn %t/gd.32.so | FileCheck --check-prefix=GD32 %s -# RUN: ld.lld -shared %t/a.32.relax.o %t/bc.32.o -o %t/gd.32.relax.so +# RUN: ld.lld --relax -shared %t/a.32.relax.o %t/bc.32.o -o %t/gd.32.relax.so # RUN: llvm-readobj -r %t/gd.32.relax.so | FileCheck --check-prefix=GD32-REL-RELAX %s # RUN: llvm-objdump -d --no-show-raw-insn %t/gd.32.relax.so | FileCheck --check-prefix=GD32-RELAX %s @@ -41,7 +41,7 @@ # RUN: ld.lld -shared %t/a.64.o %t/bc.64.o -o %t/gd.64.so # RUN: llvm-readobj -r %t/gd.64.so | FileCheck --check-prefix=GD64-REL %s # RUN: llvm-objdump -d --no-show-raw-insn %t/gd.64.so | FileCheck --check-prefix=GD64 %s -# RUN: ld.lld -shared %t/a.64.relax.o %t/bc.64.o -o %t/gd.64.relax.so +# RUN: ld.lld --relax -shared %t/a.64.relax.o %t/bc.64.o -o %t/gd.64.relax.so # RUN: llvm-readobj -r %t/gd.64.relax.so | FileCheck --check-prefix=GD64-REL-RELAX %s # RUN: llvm-objdump -d --no-show-raw-insn %t/gd.64.relax.so | FileCheck --check-prefix=GD64-RELAX %s diff --git a/lld/test/ELF/loongarch-tls-ld.s b/lld/test/ELF/loongarch-tls-ld.s index 27adb1e17702a..6cf6fa92939d5 100644 --- a/lld/test/ELF/loongarch-tls-ld.s +++ b/lld/test/ELF/loongarch-tls-ld.s @@ -17,7 +17,7 @@ # RUN: llvm-readobj -r %t/ld.32.so | FileCheck --check-prefix=LD32-REL %s # RUN: llvm-readelf -x .got %t/ld.32.so | FileCheck --check-prefix=LD32-GOT %s # RUN: llvm-objdump -d --no-show-raw-insn %t/ld.32.so | FileCheck --check-prefixes=LD32 %s -# RUN: ld.lld -shared %t/a.32.relax.o -o %t/ld.32.relax.so +# RUN: ld.lld --relax -shared %t/a.32.relax.o -o %t/ld.32.relax.so # RUN: llvm-objdump -d --no-show-raw-insn %t/ld.32.relax.so | FileCheck --check-prefixes=LD32-RELAX %s ## LA32 LD -> LE @@ -25,7 +25,7 @@ # RUN: llvm-readelf -r %t/le.32 | FileCheck --check-prefix=NOREL %s # RUN: llvm-readelf -x .got %t/le.32 | FileCheck --check-prefix=LE32-GOT %s # RUN: llvm-objdump -d --no-show-raw-insn %t/le.32 | FileCheck --check-prefixes=LE32 %s -# RUN: ld.lld %t/a.32.relax.o %t/tga.32.o -o %t/le.32.relax +# RUN: ld.lld --relax %t/a.32.relax.o %t/tga.32.o -o %t/le.32.relax # RUN: llvm-readelf -x .got %t/le.32.relax | FileCheck --check-prefix=LE32-GOT-RELAX %s # RUN: llvm-objdump -d --no-show-raw-insn %t/le.32.relax | FileCheck --check-prefixes=LE32-RELAX %s @@ -34,7 +34,7 @@ # RUN: llvm-readobj -r %t/ld.64.so | FileCheck --check-prefix=LD64-REL %s # RUN: llvm-readelf -x .got %t/ld.64.so | FileCheck --check-prefix=LD64-GOT %s # RUN: llvm-objdump -d --no-show-raw-insn %t/ld.64.so | FileCheck --check-prefixes=LD64 %s -# RUN: ld.lld -shared %t/a.64.relax.o -o %t/ld.64.relax.so +# RUN: ld.lld --relax -shared %t/a.64.relax.o -o %t/ld.64.relax.so # RUN: llvm-objdump -d --no-show-raw-insn %t/ld.64.relax.so | FileCheck --check-prefixes=LD64-RELAX %s ## LA64 LD -> LE @@ -42,7 +42,7 @@ # RUN: llvm-readelf -r %t/le.64 | FileCheck --check-prefix=NOREL %s # RUN: llvm-readelf -x .got %t/le.64 | FileCheck --check-prefix=LE64-GOT %s # RUN: llvm-objdump -d --no-show-raw-insn %t/le.64 | FileCheck --check-prefixes=LE64 %s -# RUN: ld.lld %t/a.64.relax.o %t/tga.64.o -o %t/le.64.relax +# RUN: ld.lld --relax %t/a.64.relax.o %t/tga.64.o -o %t/le.64.relax # RUN: llvm-readelf -x .got %t/le.64.relax | FileCheck --check-prefix=LE64-GOT-RELAX %s # RUN: llvm-objdump -d --no-show-raw-insn %t/le.64.relax | FileCheck --check-prefixes=LE64-RELAX %s diff --git a/lld/test/ELF/loongarch-tls-le.s b/lld/test/ELF/loongarch-tls-le.s index 981baa6fd726f..bc55e08591d28 100644 --- a/lld/test/ELF/loongarch-tls-le.s +++ b/lld/test/ELF/loongarch-tls-le.s @@ -8,12 +8,12 @@ # RUN: ld.lld %t.32.o -o %t.32 # RUN: llvm-nm -p %t.32 | FileCheck --check-prefixes=NM %s # RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=LE,LE32 %s -# RUN: ld.lld %t.32.relax.o -o %t.32.relax +# RUN: ld.lld --relax %t.32.relax.o -o %t.32.relax # RUN: llvm-objdump -d --no-show-raw-insn %t.32.relax | FileCheck --check-prefixes=LE,LE32-RELAX %s # RUN: ld.lld %t.64.o -o %t.64 # RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=LE,LE64 %s -# RUN: ld.lld %t.64.relax.o -o %t.64.relax +# RUN: ld.lld --relax %t.64.relax.o -o %t.64.relax # RUN: llvm-objdump -d --no-show-raw-insn %t.64.relax | FileCheck --check-prefixes=LE,LE64-RELAX %s # RUN: not ld.lld -shared %t.32.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR --implicit-check-not=error: From 924d511235d2a06edd816360b54eebc7599423c3 Mon Sep 17 00:00:00 2001 From: yangzhaoxin Date: Fri, 14 Feb 2025 09:31:10 +0800 Subject: [PATCH 15/21] Fixes for reviews. --- lld/ELF/Arch/LoongArch.cpp | 14 +++++----- lld/test/ELF/loongarch-relax-align.s | 8 +++--- lld/test/ELF/loongarch-relax-emit-relocs.s | 6 ++-- ...loongarch-relax-pc-hi20-lo12-got-symbols.s | 28 +++++++++---------- lld/test/ELF/loongarch-relax-pc-hi20-lo12.s | 12 ++++---- 5 files changed, 34 insertions(+), 34 deletions(-) diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp index b999e7fd27ae9..dbf024eadf100 100644 --- a/lld/ELF/Arch/LoongArch.cpp +++ b/lld/ELF/Arch/LoongArch.cpp @@ -790,23 +790,23 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i, (ctx.arg.isPic && !cast(*rHi20.sym).section))) return; - uint64_t symBase = 0; + uint64_t dest = 0; if (rHi20.expr == RE_LOONGARCH_PLT_PAGE_PC) - symBase = rHi20.sym->getPltVA(ctx); + dest = rHi20.sym->getPltVA(ctx); else if (rHi20.expr == RE_LOONGARCH_PAGE_PC || rHi20.expr == RE_LOONGARCH_GOT_PAGE_PC) - symBase = rHi20.sym->getVA(ctx); + dest = rHi20.sym->getVA(ctx); else { Err(ctx) << getErrorLoc(ctx, (const uint8_t *)loc) << "unknown expr (" << rHi20.expr << ") against symbol " << rHi20.sym << "in relaxPCHi20Lo12"; return; } - const uint64_t symLocal = symBase + rHi20.addend; + dest += rHi20.addend; - const int64_t distance = symLocal - loc; - // Check if the distance aligns 4 bytes or exceeds the range of pcaddi. - if ((distance & 0x3) != 0 || !isInt<22>(distance)) + const int64_t displace = dest - loc; + // Check if the displace aligns 4 bytes or exceeds the range of pcaddi. + if ((displace & 0x3) != 0 || !isInt<22>(displace)) return; // Note: If we can ensure that the .o files generated by LLVM only contain diff --git a/lld/test/ELF/loongarch-relax-align.s b/lld/test/ELF/loongarch-relax-align.s index 66a8ed3abf71e..79353f2a3be47 100644 --- a/lld/test/ELF/loongarch-relax-align.s +++ b/lld/test/ELF/loongarch-relax-align.s @@ -2,8 +2,8 @@ # RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %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=.text2=0x20000 -e 0 --relax %t.32.o -o %t.32 -# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --relax %t.64.o -o %t.64 +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.32.o -o %t.32 +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.64.o -o %t.64 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --no-relax %t.32.o -o %t.32n # RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --no-relax %t.64.o -o %t.64n # RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX,NOOLD %s @@ -13,13 +13,13 @@ ## Test the R_LARCH_ALIGN without symbol index. # RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.o64.o --defsym=old=1 -# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --relax %t.o64.o -o %t.o64 +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.o64.o -o %t.o64 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --no-relax %t.o64.o -o %t.o64n # RUN: llvm-objdump -td --no-show-raw-insn %t.o64 | FileCheck --check-prefixes=RELAX,OLD %s # RUN: llvm-objdump -td --no-show-raw-insn %t.o64n | FileCheck --check-prefixes=NORELAX,OLD %s ## -r keeps section contents unchanged. -# RUN: ld.lld -r --relax %t.64.o -o %t.64.r +# RUN: ld.lld -r %t.64.o -o %t.64.r # RUN: llvm-objdump -dr --no-show-raw-insn %t.64.r | FileCheck %s --check-prefix=CHECKR # NOOLD: {{0*}}10000 l .text {{0*}}00 .Lalign_symbol diff --git a/lld/test/ELF/loongarch-relax-emit-relocs.s b/lld/test/ELF/loongarch-relax-emit-relocs.s index a02cd272aba5b..7031ffd9f6686 100644 --- a/lld/test/ELF/loongarch-relax-emit-relocs.s +++ b/lld/test/ELF/loongarch-relax-emit-relocs.s @@ -3,13 +3,13 @@ # RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %s -o %t.32.o # RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o -# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs --relax %t.32.o -o %t.32 -# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs --relax %t.64.o -o %t.64 +# 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 # RUN: llvm-objdump -dr %t.32 | FileCheck %s --check-prefix=RELAX # RUN: llvm-objdump -dr %t.64 | FileCheck %s --check-prefix=RELAX ## -r should keep original relocations. -# RUN: ld.lld --relax -r %t.64.o -o %t.64.r +# RUN: ld.lld -r %t.64.o -o %t.64.r # RUN: llvm-objdump -dr %t.64.r | FileCheck %s --check-prefix=CHECKR ## --no-relax should keep original relocations. diff --git a/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s b/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s index 0a75d2289209c..f37de8e3b7c83 100644 --- a/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s +++ b/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s @@ -9,45 +9,45 @@ # RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax abs.s -o abs.32.o # RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax abs.s -o abs.64.o -# RUN: ld.lld --shared --relax -Tlinker.t symbols.32.o abs.32.o -o symbols.32.so -# RUN: ld.lld --shared --relax -Tlinker.t symbols.64.o abs.64.o -o symbols.64.so +# RUN: ld.lld --shared -Tlinker.t symbols.32.o abs.32.o -o symbols.32.so +# RUN: ld.lld --shared -Tlinker.t symbols.64.o abs.64.o -o symbols.64.so # RUN: llvm-objdump -d --no-show-raw-insn symbols.32.so | FileCheck --check-prefixes=LIB %s # RUN: llvm-objdump -d --no-show-raw-insn symbols.64.so | FileCheck --check-prefixes=LIB %s -# RUN: ld.lld --relax -Tlinker.t -z undefs symbols.32.o abs.32.o -o symbols.32 -# RUN: ld.lld --relax -Tlinker.t -z undefs symbols.64.o abs.64.o -o symbols.64 +# RUN: ld.lld -Tlinker.t -z undefs symbols.32.o abs.32.o -o symbols.32 +# RUN: ld.lld -Tlinker.t -z undefs symbols.64.o abs.64.o -o symbols.64 # RUN: llvm-objdump -d --no-show-raw-insn symbols.32 | FileCheck --check-prefixes=EXE %s # RUN: llvm-objdump -d --no-show-raw-insn symbols.64 | FileCheck --check-prefixes=EXE %s ## Symbol 'hidden_sym' is nonpreemptible, the relaxation should be applied. -LIB: pcaddi $a0, {{[0-9]+}} +LIB: pcaddi $a0, [[#]] ## Symbol 'global_sym' is preemptible, no relaxations should be applied. LIB-NEXT: pcalau12i $a1, 4 -LIB-NEXT: ld.{{[wd]}} $a1, $a1, {{[0-9]+}} +LIB-NEXT: ld.{{[wd]}} $a1, $a1, [[#]] ## Symbol 'undefined_sym' is undefined, no relaxations should be applied. LIB-NEXT: pcalau12i $a2, 4 -LIB-NEXT: ld.{{[wd]}} $a2, $a2, {{[0-9]+}} +LIB-NEXT: ld.{{[wd]}} $a2, $a2, [[#]] ## Symbol 'ifunc_sym' is STT_GNU_IFUNC, no relaxations should be applied. LIB-NEXT: pcalau12i $a3, 4 -LIB-NEXT: ld.{{[wd]}} $a3, $a3, {{[0-9]+}} +LIB-NEXT: ld.{{[wd]}} $a3, $a3, [[#]] ## Symbol 'abs_sym' is absolute, no relaxations should be applied. LIB-NEXT: pcalau12i $a4, 4 -LIB-NEXT: ld.{{[wd]}} $a4, $a4, {{[0-9]+}} +LIB-NEXT: ld.{{[wd]}} $a4, $a4, [[#]] ## Symbol 'hidden_sym' is nonpreemptible, the relaxation should be applied. -EXE: pcaddi $a0, {{[0-9]+}} +EXE: pcaddi $a0, [[#]] ## Symbol 'global_sym' is nonpreemptible, the relaxation should be applied. -EXE-NEXT: pcaddi $a1, {{[0-9]+}} +EXE-NEXT: pcaddi $a1, [[#]] ## Symbol 'undefined_sym' is undefined, no relaxations should be applied. EXE-NEXT: pcalau12i $a2, 4 -EXE-NEXT: ld.{{[wd]}} $a2, $a2, {{[0-9]+}} +EXE-NEXT: ld.{{[wd]}} $a2, $a2, [[#]] ## Symbol 'ifunc_sym' is STT_GNU_IFUNC, no relaxations should be applied. EXE-NEXT: pcalau12i $a3, 4 -EXE-NEXT: ld.{{[wd]}} $a3, $a3, {{[0-9]+}} +EXE-NEXT: ld.{{[wd]}} $a3, $a3, [[#]] ## Symbol 'abs_sym' is absolute, relaxations may be applied in -no-pie mode. -EXE-NEXT: pcaddi $a4, -{{[0-9]+}} +EXE-NEXT: pcaddi $a4, -[[#]] ## The linker script ensures that .rodata and .text are near (>4M) so that diff --git a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s index 760fe77d774e3..a417d89e9fa2e 100644 --- a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s +++ b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s @@ -3,18 +3,18 @@ # RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax %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 --relax %t.32.o -o %t.32 -# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 --relax %t.64.o -o %t.64 +# 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: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 --relax %t.32.o -shared -o %t.32s -# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 --relax %t.64.o -shared -o %t.64s +# 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 # RUN: llvm-objdump -td --no-show-raw-insn %t.32s | FileCheck --check-prefixes=RELAX %s # RUN: llvm-objdump -td --no-show-raw-insn %t.64s | FileCheck --check-prefixes=RELAX %s -# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 --relax %t.32.o -o %t.32o -# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 --relax %t.64.o -o %t.64o +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 %t.32.o -o %t.32o +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 %t.64.o -o %t.64o # RUN: llvm-objdump -td --no-show-raw-insn %t.32o | FileCheck --check-prefixes=NORELAX32 %s # RUN: llvm-objdump -td --no-show-raw-insn %t.64o | FileCheck --check-prefixes=NORELAX64 %s From b9c2ea1ad26ad6c81213ee9d563bd1448ed4a097 Mon Sep 17 00:00:00 2001 From: yangzhaoxin Date: Fri, 14 Feb 2025 09:43:07 +0800 Subject: [PATCH 16/21] Revert "Modify test. Add the option --relax." This reverts commit f2aae15f701863d03edd32657824a97f66696e8d. --- lld/test/ELF/loongarch-relax-call36-2.s | 6 +++--- lld/test/ELF/loongarch-relax-call36.s | 6 +++--- lld/test/ELF/loongarch-relax-emit-relocs-2.s | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lld/test/ELF/loongarch-relax-call36-2.s b/lld/test/ELF/loongarch-relax-call36-2.s index 71650aefe9432..1c216a9bdc35e 100644 --- a/lld/test/ELF/loongarch-relax-call36-2.s +++ b/lld/test/ELF/loongarch-relax-call36-2.s @@ -2,14 +2,14 @@ # RUN: rm -rf %t && split-file %s %t && cd %t # RUN: llvm-mc -filetype=obj -triple=loongarch64 -mattr=+relax a.s -o a.o -# RUN: ld.lld --relax -T lds a.o -o a +# 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 --relax -T lds -pie a.o -o a.pie +# 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 --relax -T lds -pie -z notext -z ifunc-noplt a.o -o a.ifunc-noplt +# 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>: diff --git a/lld/test/ELF/loongarch-relax-call36.s b/lld/test/ELF/loongarch-relax-call36.s index bda0c4f05da91..57ed214c9eb2e 100644 --- a/lld/test/ELF/loongarch-relax-call36.s +++ b/lld/test/ELF/loongarch-relax-call36.s @@ -4,12 +4,12 @@ # RUN: llvm-mc -filetype=obj -triple=loongarch64 -mattr=+relax a.s -o a.64.o # RUN: llvm-mc -filetype=obj -triple=loongarch64 -mattr=+relax b.s -o b.64.o -# RUN: ld.lld --relax -shared -soname=b.so b.64.o -o b.64.so -# RUN: ld.lld --relax -T lds a.64.o b.64.so -o 64 +# RUN: ld.lld -shared -soname=b.so b.64.o -o b.64.so +# RUN: ld.lld -T lds a.64.o b.64.so -o 64 # RUN: llvm-objdump -td --no-show-raw-insn 64 | FileCheck %s --check-prefix=RELAX ## --no-relax disables relaxation. -# RUN: ld.lld --no-relax -T lds a.64.o b.64.so -o 64.norelax +# RUN: ld.lld -T lds a.64.o b.64.so --no-relax -o 64.norelax # RUN: llvm-objdump -td --no-show-raw-insn 64.norelax | FileCheck %s --check-prefix=NORELAX # RELAX: {{0*}}00010000 g .text {{0*}}0000001c _start diff --git a/lld/test/ELF/loongarch-relax-emit-relocs-2.s b/lld/test/ELF/loongarch-relax-emit-relocs-2.s index eddfc46b1ad08..31cae939eca71 100644 --- a/lld/test/ELF/loongarch-relax-emit-relocs-2.s +++ b/lld/test/ELF/loongarch-relax-emit-relocs-2.s @@ -3,15 +3,15 @@ ## Call36 and tail36 need LA64 basic integer, so they donot have 32-bit version. # RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o -# RUN: ld.lld --relax -Ttext=0x10000 --emit-relocs %t.64.o -o %t.64 +# RUN: ld.lld -Ttext=0x10000 --emit-relocs %t.64.o -o %t.64 # RUN: llvm-objdump -dr %t.64 | FileCheck %s --check-prefix=RELAX ## -r should keep original relocations. -# RUN: ld.lld --relax -r %t.64.o -o %t.64.r +# RUN: ld.lld -r %t.64.o -o %t.64.r # RUN: llvm-objdump -dr %t.64.r | FileCheck %s --check-prefix=CHECKR ## --no-relax should keep original relocations. -# RUN: ld.lld --no-relax -Ttext=0x10000 --emit-relocs %t.64.o -o %t.64.norelax +# RUN: ld.lld -Ttext=0x10000 --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>: From 11018299e150c7c6f20fc47ff2673d8f963eb199 Mon Sep 17 00:00:00 2001 From: yangzhaoxin Date: Fri, 14 Feb 2025 11:23:30 +0800 Subject: [PATCH 17/21] Fixes for reviews. --- lld/ELF/Arch/LoongArch.cpp | 8 +-- lld/test/ELF/loongarch-relax-call36-2.s | 2 + lld/test/ELF/loongarch-relax-call36.s | 1 + lld/test/ELF/loongarch-relax-emit-relocs-2.s | 61 -------------------- lld/test/ELF/loongarch-relax-emit-relocs.s | 43 +++++++++++--- 5 files changed, 43 insertions(+), 72 deletions(-) delete mode 100644 lld/test/ELF/loongarch-relax-emit-relocs-2.s diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp index 0aa0cf5b657a0..c1e2229c3f9a7 100644 --- a/lld/ELF/Arch/LoongArch.cpp +++ b/lld/ELF/Arch/LoongArch.cpp @@ -840,13 +840,13 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i, // b/bl foo static void relaxCall36(Ctx &ctx, const InputSection &sec, size_t i, uint64_t loc, Relocation &r, uint32_t &remove) { - const uint64_t symLocal = + const uint64_t dest = (r.expr == R_PLT_PC ? r.sym->getPltVA(ctx) : r.sym->getVA(ctx)) + r.addend; - const int64_t distance = symLocal - loc; - // Check if the distance aligns 4 bytes or exceeds the range of b[l]. - if ((distance & 0x3) != 0 || !isInt<28>(distance)) + const int64_t displace = dest - loc; + // Check if the displace aligns 4 bytes or exceeds the range of b[l]. + if ((displace & 0x3) != 0 || !isInt<28>(displace)) return; const uint32_t nextInsn = read32le(sec.content().data() + r.offset + 4); diff --git a/lld/test/ELF/loongarch-relax-call36-2.s b/lld/test/ELF/loongarch-relax-call36-2.s index 1c216a9bdc35e..482eed2ebd111 100644 --- a/lld/test/ELF/loongarch-relax-call36-2.s +++ b/lld/test/ELF/loongarch-relax-call36-2.s @@ -1,4 +1,6 @@ # REQUIRES: loongarch +## Relax R_LARCH_CALL36. 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=loongarch64 -mattr=+relax a.s -o a.o diff --git a/lld/test/ELF/loongarch-relax-call36.s b/lld/test/ELF/loongarch-relax-call36.s index 57ed214c9eb2e..0f0ba26b15f30 100644 --- a/lld/test/ELF/loongarch-relax-call36.s +++ b/lld/test/ELF/loongarch-relax-call36.s @@ -1,4 +1,5 @@ # REQUIRES: loongarch +## Relax R_LARCH_CALL36, which involves the macro instructions call36/tail36. # RUN: rm -rf %t && split-file %s %t && cd %t diff --git a/lld/test/ELF/loongarch-relax-emit-relocs-2.s b/lld/test/ELF/loongarch-relax-emit-relocs-2.s deleted file mode 100644 index 31cae939eca71..0000000000000 --- a/lld/test/ELF/loongarch-relax-emit-relocs-2.s +++ /dev/null @@ -1,61 +0,0 @@ -# REQUIRES: loongarch -## Test that we can handle --emit-relocs while relaxing. -## Call36 and tail36 need LA64 basic integer, so they donot have 32-bit version. - -# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o -# RUN: ld.lld -Ttext=0x10000 --emit-relocs %t.64.o -o %t.64 -# RUN: llvm-objdump -dr %t.64 | FileCheck %s --check-prefix=RELAX - -## -r should keep original relocations. -# RUN: ld.lld -r %t.64.o -o %t.64.r -# RUN: llvm-objdump -dr %t.64.r | FileCheck %s --check-prefix=CHECKR - -## --no-relax should keep original relocations. -# RUN: ld.lld -Ttext=0x10000 --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: bl 0 -# RELAX-NEXT: R_LARCH_B26 _start -# RELAX-NEXT: R_LARCH_RELAX *ABS* -# RELAX-NEXT: b -4 -# RELAX-NEXT: R_LARCH_B26 _start -# RELAX-NEXT: R_LARCH_RELAX *ABS* -# RELAX-NEXT: nop -# RELAX-NEXT: R_LARCH_ALIGN *ABS*+0xc -# RELAX-NEXT: nop -# RELAX-NEXT: ret - -# CHECKR: <_start>: -# CHECKR-NEXT: pcaddu18i $ra, 0 -# CHECKR-NEXT: R_LARCH_CALL36 _start -# CHECKR-NEXT: R_LARCH_RELAX *ABS* -# CHECKR-NEXT: jirl $ra, $ra, 0 -# CHECKR-NEXT: pcaddu18i $t0, 0 -# CHECKR-NEXT: R_LARCH_CALL36 _start -# CHECKR-NEXT: R_LARCH_RELAX *ABS* -# CHECKR-NEXT: jr $t0 -# CHECKR-NEXT: nop -# CHECKR-NEXT: R_LARCH_ALIGN *ABS*+0xc -# CHECKR-NEXT: nop -# CHECKR-NEXT: nop -# CHECKR-NEXT: ret - -# NORELAX: <_start>: -# NORELAX-NEXT: pcaddu18i $ra, 0 -# NORELAX-NEXT: R_LARCH_CALL36 _start -# NORELAX-NEXT: R_LARCH_RELAX *ABS* -# NORELAX-NEXT: jirl $ra, $ra, 0 -# NORELAX-NEXT: pcaddu18i $t0, 0 -# NORELAX-NEXT: R_LARCH_CALL36 _start -# NORELAX-NEXT: R_LARCH_RELAX *ABS* -# NORELAX-NEXT: jirl $zero, $t0, -8 -# NORELAX-NEXT: ret -# NORELAX-NEXT: R_LARCH_ALIGN *ABS*+0xc - -.global _start -_start: - call36 _start - tail36 $t0, _start - .p2align 4 - ret diff --git a/lld/test/ELF/loongarch-relax-emit-relocs.s b/lld/test/ELF/loongarch-relax-emit-relocs.s index a02cd272aba5b..d7f444470f0f9 100644 --- a/lld/test/ELF/loongarch-relax-emit-relocs.s +++ b/lld/test/ELF/loongarch-relax-emit-relocs.s @@ -2,11 +2,11 @@ ## Test that we can handle --emit-relocs while relaxing. # RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %s -o %t.32.o -# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.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 --relax %t.32.o -o %t.32 # RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs --relax %t.64.o -o %t.64 -# RUN: llvm-objdump -dr %t.32 | FileCheck %s --check-prefix=RELAX -# RUN: llvm-objdump -dr %t.64 | FileCheck %s --check-prefix=RELAX +# RUN: llvm-objdump -dr %t.32 | FileCheck %s --check-prefixes=RELAX,RELAX32 +# RUN: llvm-objdump -dr %t.64 | FileCheck %s --check-prefixes=RELAX,RELAX64 ## -r should keep original relocations. # RUN: ld.lld --relax -r %t.64.o -o %t.64.r @@ -27,10 +27,19 @@ # RELAX-NEXT: R_LARCH_RELAX *ABS* # RELAX-NEXT: R_LARCH_PCREL20_S2 _start # RELAX-NEXT: R_LARCH_RELAX *ABS* -# RELAX-NEXT: nop -# RELAX-NEXT: R_LARCH_ALIGN *ABS*+0xc -# RELAX-NEXT: nop -# RELAX-NEXT: ret +# RELAX32-NEXT: nop +# RELAX32-NEXT: R_LARCH_ALIGN *ABS*+0xc +# RELAX32-NEXT: nop +# RELAX32-NEXT: ret + +# RELAX64-NEXT: bl -8 +# RELAX64-NEXT: R_LARCH_B26 _start +# RELAX64-NEXT: R_LARCH_RELAX *ABS* +# RELAX64-NEXT: b -12 +# RELAX64-NEXT: R_LARCH_B26 _start +# RELAX64-NEXT: R_LARCH_RELAX *ABS* +# RELAX64-NEXT: ret +# RELAX64-NEXT: R_LARCH_ALIGN *ABS*+0xc # NORELAX: <_start>: # NORELAX-NEXT: pcalau12i $a0, 0 @@ -45,6 +54,14 @@ # NORELAX-NEXT: ld.d $a0, $a0, 0 # NORELAX-NEXT: R_LARCH_GOT_PC_LO12 _start # NORELAX-NEXT: R_LARCH_RELAX *ABS* +# NORELAX-NEXT: pcaddu18i $ra, 0 +# NORELAX-NEXT: R_LARCH_CALL36 _start +# NORELAX-NEXT: R_LARCH_RELAX *ABS* +# NORELAX-NEXT: jirl $ra, $ra, -16 +# NORELAX-NEXT: pcaddu18i $a0, 0 +# NORELAX-NEXT: R_LARCH_CALL36 _start +# NORELAX-NEXT: R_LARCH_RELAX *ABS* +# NORELAX-NEXT: jirl $zero, $a0, -24 # NORELAX-NEXT: ret # NORELAX-NEXT: R_LARCH_ALIGN *ABS*+0xc @@ -61,6 +78,14 @@ # CHECKR-NEXT: ld.d $a0, $a0, 0 # CHECKR-NEXT: R_LARCH_GOT_PC_LO12 _start # CHECKR-NEXT: R_LARCH_RELAX *ABS* +# CHECKR-NEXT: pcaddu18i $ra, 0 +# CHECKR-NEXT: R_LARCH_CALL36 _start +# CHECKR-NEXT: R_LARCH_RELAX *ABS* +# CHECKR-NEXT: jirl $ra, $ra, 0 +# CHECKR-NEXT: pcaddu18i $a0, 0 +# CHECKR-NEXT: R_LARCH_CALL36 _start +# CHECKR-NEXT: R_LARCH_RELAX *ABS* +# CHECKR-NEXT: jr $a0 # CHECKR-NEXT: nop # CHECKR-NEXT: R_LARCH_ALIGN *ABS*+0xc # CHECKR-NEXT: nop @@ -71,5 +96,9 @@ _start: la.pcrel $a0, _start la.got $a0, _start +.ifdef ELF64 + call36 _start + tail36 $a0, _start +.endif .p2align 4 ret From 1192441fd76a2c3bd407fa720b1d0d56e6b3f498 Mon Sep 17 00:00:00 2001 From: yangzhaoxin Date: Fri, 14 Feb 2025 14:11:17 +0800 Subject: [PATCH 18/21] Revert "Modify test. Add --relax option." This reverts commit b57c40e275dc0977e002e68834c2b40fa030d9fc. --- lld/test/ELF/loongarch-relax-tls-le.s | 4 ++-- lld/test/ELF/loongarch-tls-gd.s | 4 ++-- lld/test/ELF/loongarch-tls-ld.s | 8 ++++---- lld/test/ELF/loongarch-tls-le.s | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lld/test/ELF/loongarch-relax-tls-le.s b/lld/test/ELF/loongarch-relax-tls-le.s index b55f284f32cb8..8f9b6e1092a62 100644 --- a/lld/test/ELF/loongarch-relax-tls-le.s +++ b/lld/test/ELF/loongarch-relax-tls-le.s @@ -3,10 +3,10 @@ # 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 --relax %t.32.o -o %t.32 +# RUN: ld.lld %t.32.o -o %t.32 # RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX32 %s -# RUN: ld.lld --relax %t.64.o -o %t.64 +# RUN: ld.lld %t.64.o -o %t.64 # RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=RELAX64 %s # RELAX32-LABEL: <_start>: diff --git a/lld/test/ELF/loongarch-tls-gd.s b/lld/test/ELF/loongarch-tls-gd.s index 4cfed41d70f38..27d9fdb7ee701 100644 --- a/lld/test/ELF/loongarch-tls-gd.s +++ b/lld/test/ELF/loongarch-tls-gd.s @@ -20,7 +20,7 @@ # RUN: ld.lld -shared %t/a.32.o %t/bc.32.o -o %t/gd.32.so # RUN: llvm-readobj -r %t/gd.32.so | FileCheck --check-prefix=GD32-REL %s # RUN: llvm-objdump -d --no-show-raw-insn %t/gd.32.so | FileCheck --check-prefix=GD32 %s -# RUN: ld.lld --relax -shared %t/a.32.relax.o %t/bc.32.o -o %t/gd.32.relax.so +# RUN: ld.lld -shared %t/a.32.relax.o %t/bc.32.o -o %t/gd.32.relax.so # RUN: llvm-readobj -r %t/gd.32.relax.so | FileCheck --check-prefix=GD32-REL-RELAX %s # RUN: llvm-objdump -d --no-show-raw-insn %t/gd.32.relax.so | FileCheck --check-prefix=GD32-RELAX %s @@ -41,7 +41,7 @@ # RUN: ld.lld -shared %t/a.64.o %t/bc.64.o -o %t/gd.64.so # RUN: llvm-readobj -r %t/gd.64.so | FileCheck --check-prefix=GD64-REL %s # RUN: llvm-objdump -d --no-show-raw-insn %t/gd.64.so | FileCheck --check-prefix=GD64 %s -# RUN: ld.lld --relax -shared %t/a.64.relax.o %t/bc.64.o -o %t/gd.64.relax.so +# RUN: ld.lld -shared %t/a.64.relax.o %t/bc.64.o -o %t/gd.64.relax.so # RUN: llvm-readobj -r %t/gd.64.relax.so | FileCheck --check-prefix=GD64-REL-RELAX %s # RUN: llvm-objdump -d --no-show-raw-insn %t/gd.64.relax.so | FileCheck --check-prefix=GD64-RELAX %s diff --git a/lld/test/ELF/loongarch-tls-ld.s b/lld/test/ELF/loongarch-tls-ld.s index 6cf6fa92939d5..27adb1e17702a 100644 --- a/lld/test/ELF/loongarch-tls-ld.s +++ b/lld/test/ELF/loongarch-tls-ld.s @@ -17,7 +17,7 @@ # RUN: llvm-readobj -r %t/ld.32.so | FileCheck --check-prefix=LD32-REL %s # RUN: llvm-readelf -x .got %t/ld.32.so | FileCheck --check-prefix=LD32-GOT %s # RUN: llvm-objdump -d --no-show-raw-insn %t/ld.32.so | FileCheck --check-prefixes=LD32 %s -# RUN: ld.lld --relax -shared %t/a.32.relax.o -o %t/ld.32.relax.so +# RUN: ld.lld -shared %t/a.32.relax.o -o %t/ld.32.relax.so # RUN: llvm-objdump -d --no-show-raw-insn %t/ld.32.relax.so | FileCheck --check-prefixes=LD32-RELAX %s ## LA32 LD -> LE @@ -25,7 +25,7 @@ # RUN: llvm-readelf -r %t/le.32 | FileCheck --check-prefix=NOREL %s # RUN: llvm-readelf -x .got %t/le.32 | FileCheck --check-prefix=LE32-GOT %s # RUN: llvm-objdump -d --no-show-raw-insn %t/le.32 | FileCheck --check-prefixes=LE32 %s -# RUN: ld.lld --relax %t/a.32.relax.o %t/tga.32.o -o %t/le.32.relax +# RUN: ld.lld %t/a.32.relax.o %t/tga.32.o -o %t/le.32.relax # RUN: llvm-readelf -x .got %t/le.32.relax | FileCheck --check-prefix=LE32-GOT-RELAX %s # RUN: llvm-objdump -d --no-show-raw-insn %t/le.32.relax | FileCheck --check-prefixes=LE32-RELAX %s @@ -34,7 +34,7 @@ # RUN: llvm-readobj -r %t/ld.64.so | FileCheck --check-prefix=LD64-REL %s # RUN: llvm-readelf -x .got %t/ld.64.so | FileCheck --check-prefix=LD64-GOT %s # RUN: llvm-objdump -d --no-show-raw-insn %t/ld.64.so | FileCheck --check-prefixes=LD64 %s -# RUN: ld.lld --relax -shared %t/a.64.relax.o -o %t/ld.64.relax.so +# RUN: ld.lld -shared %t/a.64.relax.o -o %t/ld.64.relax.so # RUN: llvm-objdump -d --no-show-raw-insn %t/ld.64.relax.so | FileCheck --check-prefixes=LD64-RELAX %s ## LA64 LD -> LE @@ -42,7 +42,7 @@ # RUN: llvm-readelf -r %t/le.64 | FileCheck --check-prefix=NOREL %s # RUN: llvm-readelf -x .got %t/le.64 | FileCheck --check-prefix=LE64-GOT %s # RUN: llvm-objdump -d --no-show-raw-insn %t/le.64 | FileCheck --check-prefixes=LE64 %s -# RUN: ld.lld --relax %t/a.64.relax.o %t/tga.64.o -o %t/le.64.relax +# RUN: ld.lld %t/a.64.relax.o %t/tga.64.o -o %t/le.64.relax # RUN: llvm-readelf -x .got %t/le.64.relax | FileCheck --check-prefix=LE64-GOT-RELAX %s # RUN: llvm-objdump -d --no-show-raw-insn %t/le.64.relax | FileCheck --check-prefixes=LE64-RELAX %s diff --git a/lld/test/ELF/loongarch-tls-le.s b/lld/test/ELF/loongarch-tls-le.s index bc55e08591d28..981baa6fd726f 100644 --- a/lld/test/ELF/loongarch-tls-le.s +++ b/lld/test/ELF/loongarch-tls-le.s @@ -8,12 +8,12 @@ # RUN: ld.lld %t.32.o -o %t.32 # RUN: llvm-nm -p %t.32 | FileCheck --check-prefixes=NM %s # RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=LE,LE32 %s -# RUN: ld.lld --relax %t.32.relax.o -o %t.32.relax +# RUN: ld.lld %t.32.relax.o -o %t.32.relax # RUN: llvm-objdump -d --no-show-raw-insn %t.32.relax | FileCheck --check-prefixes=LE,LE32-RELAX %s # RUN: ld.lld %t.64.o -o %t.64 # RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=LE,LE64 %s -# RUN: ld.lld --relax %t.64.relax.o -o %t.64.relax +# RUN: ld.lld %t.64.relax.o -o %t.64.relax # RUN: llvm-objdump -d --no-show-raw-insn %t.64.relax | FileCheck --check-prefixes=LE,LE64-RELAX %s # RUN: not ld.lld -shared %t.32.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR --implicit-check-not=error: From e627784a042eb02a4b26eca40af0b9f2d1bb4f56 Mon Sep 17 00:00:00 2001 From: yangzhaoxin Date: Fri, 14 Feb 2025 14:18:29 +0800 Subject: [PATCH 19/21] Remove unnecessary spaces. --- lld/test/ELF/loongarch-relax-emit-relocs.s | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lld/test/ELF/loongarch-relax-emit-relocs.s b/lld/test/ELF/loongarch-relax-emit-relocs.s index df2c713855a26..0f4ca2ce03657 100644 --- a/lld/test/ELF/loongarch-relax-emit-relocs.s +++ b/lld/test/ELF/loongarch-relax-emit-relocs.s @@ -17,12 +17,12 @@ # RUN: llvm-objdump -dr %t.64.norelax | FileCheck %s --check-prefix=NORELAX # RELAX: 00010000 <_start>: -# RELAX-NEXT: pcaddi $a0, 0 +# 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: pcaddi $a0, -1 # RELAX-NEXT: R_LARCH_RELAX _start # RELAX-NEXT: R_LARCH_RELAX *ABS* # RELAX-NEXT: R_LARCH_PCREL20_S2 _start @@ -191,7 +191,6 @@ addi.w \dst, \src1, \src2 _start: la.pcrel $a0, _start la.got $a0, _start - .ifdef ELF64 call36 _start tail36 $a0, _start From 26c1e0c29bd09e58d80a6d8ef8552cf1c817c0af Mon Sep 17 00:00:00 2001 From: yangzhaoxin Date: Mon, 17 Feb 2025 11:28:26 +0800 Subject: [PATCH 20/21] Fixes for reviews. --- lld/ELF/Arch/LoongArch.cpp | 17 ++++++---- lld/test/ELF/loongarch-relax-tls-le.s | 46 +++++++++++++-------------- 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp index 526d8061fec26..709b31ed4e01a 100644 --- a/lld/ELF/Arch/LoongArch.cpp +++ b/lld/ELF/Arch/LoongArch.cpp @@ -154,6 +154,10 @@ static uint32_t setJ20(uint32_t insn, uint32_t imm) { return (insn & 0xfe00001f) | (extractBits(imm, 19, 0) << 5); } +static uint32_t setJ5(uint32_t insn, uint32_t imm) { + return (insn & 0xfffffc1f) | (extractBits(imm, 4, 0) << 5); +} + static uint32_t setK12(uint32_t insn, uint32_t imm) { return (insn & 0xffc003ff) | (extractBits(imm, 11, 0) << 10); } @@ -895,9 +899,7 @@ static void relaxTlsLe(Ctx &ctx, const InputSection &sec, size_t i, remove = 4; break; case R_LARCH_TLS_LE_LO12_R: - currInsn = - insn(extractBits(currInsn, 31, 22) << 22, getD5(currInsn), R_TP, 0); - sec.relaxAux->writes.push_back(currInsn); + sec.relaxAux->writes.push_back(setJ5(currInsn, R_TP)); sec.relaxAux->relocTypes[i] = R_LARCH_TLS_LE_LO12_R; break; } @@ -1069,10 +1071,11 @@ void LoongArch::finalizeRelax(int passes) const { break; case R_LARCH_TLS_GD_PCREL20_S2: // Note: R_LARCH_TLS_LD_PCREL20_S2 must also use R_TLSGD_PC instead - // of R_TLSLD_PC because the processing of relocation - // R_LARCH_TLS_LD_PC_HI20 is the same as R_LARCH_TLS_GD_PC_HI20. If - // not, the value obtained from getRelocTargetVA will be unexpected - // and lead to error. + // of R_TLSLD_PC due to historical reasons. In fact, right now TLSLD + // behaves exactly like TLSGD on LoongArch. + // + // This reason has also been mentioned in mold commit: + // https://github.com/rui314/mold/commit/5dfa1cf07c03bd57cb3d493b652ef22441bcd71c case R_LARCH_TLS_LD_PCREL20_S2: skip = 4; write32le(p, aux.writes[writesIdx++]); diff --git a/lld/test/ELF/loongarch-relax-tls-le.s b/lld/test/ELF/loongarch-relax-tls-le.s index 8f9b6e1092a62..a91374b6e81a3 100644 --- a/lld/test/ELF/loongarch-relax-tls-le.s +++ b/lld/test/ELF/loongarch-relax-tls-le.s @@ -39,9 +39,9 @@ .macro add dst, src1, src2, src3 .ifdef ELF32 -add.w \dst, \src1, \src2, \src3 + add.w \dst, \src1, \src2, \src3 .else -add.d \dst, \src1, \src2, \src3 + add.d \dst, \src1, \src2, \src3 .endif .endm .macro inst op dst, src1, src2 @@ -73,38 +73,38 @@ add.d \dst, \src1, \src2, \src3 .endm .macro addi dst, src1, src2 -inst addi \dst, \src1, \src2 + inst addi \dst, \src1, \src2 .endm .macro ld dst, src1, src2 -inst ld \dst, \src1, \src2 + inst ld \dst, \src1, \src2 .endm .macro st dst, src1, src2 -inst st \dst, \src1, \src2 + inst st \dst, \src1, \src2 .endm .macro ldptr dst, src1, src2 -inst ldptr \dst, \src1, \src2 + inst ldptr \dst, \src1, \src2 .endm _start: -## Test instructions not in pairs. -lu12i.w $a0, %le_hi20_r(.LANCHOR0) -add $a0, $a0, $tp, %le_add_r(.LANCHOR0) -addi $a0, $a0, %le_lo12_r(.LANCHOR0) -ld $a1, $a0, 0 -ld $a2, $a0, %le_lo12_r(.LANCHOR0) + ## Test instructions not in pairs. + lu12i.w $a0, %le_hi20_r(.LANCHOR0) + add $a0, $a0, $tp, %le_add_r(.LANCHOR0) + addi $a0, $a0, %le_lo12_r(.LANCHOR0) + ld $a1, $a0, 0 + ld $a2, $a0, %le_lo12_r(.LANCHOR0) -## hi20(a-4) = hi20(0x7fc) = 0. relaxable -## Test non-adjacent instructions. -lu12i.w $a0, %le_hi20_r(a-4) -addi $a1, $zero, 0x1 -add $a0, $a0, $tp, %le_add_r(a-4) -addi $a1, $a1, 0x2 -st $a1, $a0, %le_lo12_r(a-4) + ## hi20(a-4) = hi20(0x7fc) = 0. relaxable + ## Test non-adjacent instructions. + lu12i.w $a0, %le_hi20_r(a-4) + addi $a1, $zero, 0x1 + add $a0, $a0, $tp, %le_add_r(a-4) + addi $a1, $a1, 0x2 + st $a1, $a0, %le_lo12_r(a-4) -## hi20(a) = hi20(0x800) = 1. not relaxable -lu12i.w $a0, %le_hi20_r(a) -add $a0, $a0, $tp, %le_add_r(a) -addi $a0, $a0, %le_lo12_r(a) + ## hi20(a) = hi20(0x800) = 1. not relaxable + lu12i.w $a0, %le_hi20_r(a) + add $a0, $a0, $tp, %le_add_r(a) + addi $a0, $a0, %le_lo12_r(a) .section .tbss,"awT",@nobits .space 8 From 1484f9417ba83f50334cccee5e2c7749e18cf8ee Mon Sep 17 00:00:00 2001 From: yangzhaoxin Date: Mon, 10 Mar 2025 12:04:29 +0800 Subject: [PATCH 21/21] revise indentation. --- lld/test/ELF/loongarch-relax-emit-relocs.s | 8 ++++---- lld/test/ELF/loongarch-tls-gd.s | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lld/test/ELF/loongarch-relax-emit-relocs.s b/lld/test/ELF/loongarch-relax-emit-relocs.s index 6c6b4dade404d..909b65075a695 100644 --- a/lld/test/ELF/loongarch-relax-emit-relocs.s +++ b/lld/test/ELF/loongarch-relax-emit-relocs.s @@ -173,17 +173,17 @@ .macro add dst, src1, src2, src3 .ifdef ELF64 -add.d \dst, \src1, \src2, \src3 + add.d \dst, \src1, \src2, \src3 .else -add.w \dst, \src1, \src2, \src3 + add.w \dst, \src1, \src2, \src3 .endif .endm .macro addi dst, src1, src2 .ifdef ELF64 -addi.d \dst, \src1, \src2 + addi.d \dst, \src1, \src2 .else -addi.w \dst, \src1, \src2 + addi.w \dst, \src1, \src2 .endif .endm diff --git a/lld/test/ELF/loongarch-tls-gd.s b/lld/test/ELF/loongarch-tls-gd.s index 27d9fdb7ee701..140aa4cea6bad 100644 --- a/lld/test/ELF/loongarch-tls-gd.s +++ b/lld/test/ELF/loongarch-tls-gd.s @@ -3,7 +3,7 @@ ## LoongArch psABI doesn't specify TLS relaxation. It can be handled the same way as gcc: ## (a) code sequence can be converted from `pcalau12i+addi.[wd]` to `pcaddi`. -## (b) dynamic relocations can be omitted for LD->LE relaxation. +## (b) dynamic relocations can be omitted for GD->LE relaxation. # RUN: llvm-mc --filetype=obj --triple=loongarch32 %t/a.s -o %t/a.32.o # RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax %t/a.s -o %t/a.32.relax.o