xref: /freebsd-src/contrib/llvm-project/lld/ELF/Arch/LoongArch.cpp (revision 8a4dda33d67586ca2624f2a38417baa03a533a7f)
106c3fb27SDimitry Andric //===- LoongArch.cpp ------------------------------------------------------===//
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
806c3fb27SDimitry Andric 
906c3fb27SDimitry Andric #include "InputFiles.h"
1006c3fb27SDimitry Andric #include "OutputSections.h"
1106c3fb27SDimitry Andric #include "Symbols.h"
1206c3fb27SDimitry Andric #include "SyntheticSections.h"
1306c3fb27SDimitry Andric #include "Target.h"
1406c3fb27SDimitry Andric 
1506c3fb27SDimitry Andric using namespace llvm;
1606c3fb27SDimitry Andric using namespace llvm::object;
1706c3fb27SDimitry Andric using namespace llvm::support::endian;
1806c3fb27SDimitry Andric using namespace llvm::ELF;
1906c3fb27SDimitry Andric using namespace lld;
2006c3fb27SDimitry Andric using namespace lld::elf;
2106c3fb27SDimitry Andric 
2206c3fb27SDimitry Andric namespace {
2306c3fb27SDimitry Andric class LoongArch final : public TargetInfo {
2406c3fb27SDimitry Andric public:
2506c3fb27SDimitry Andric   LoongArch();
2606c3fb27SDimitry Andric   uint32_t calcEFlags() const override;
2706c3fb27SDimitry Andric   int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override;
2806c3fb27SDimitry Andric   void writeGotPlt(uint8_t *buf, const Symbol &s) const override;
2906c3fb27SDimitry Andric   void writeIgotPlt(uint8_t *buf, const Symbol &s) const override;
3006c3fb27SDimitry Andric   void writePltHeader(uint8_t *buf) const override;
3106c3fb27SDimitry Andric   void writePlt(uint8_t *buf, const Symbol &sym,
3206c3fb27SDimitry Andric                 uint64_t pltEntryAddr) const override;
3306c3fb27SDimitry Andric   RelType getDynRel(RelType type) const override;
3406c3fb27SDimitry Andric   RelExpr getRelExpr(RelType type, const Symbol &s,
3506c3fb27SDimitry Andric                      const uint8_t *loc) const override;
3606c3fb27SDimitry Andric   bool usesOnlyLowPageBits(RelType type) const override;
3706c3fb27SDimitry Andric   void relocate(uint8_t *loc, const Relocation &rel,
3806c3fb27SDimitry Andric                 uint64_t val) const override;
3906c3fb27SDimitry Andric };
4006c3fb27SDimitry Andric } // end anonymous namespace
4106c3fb27SDimitry Andric 
4206c3fb27SDimitry Andric enum Op {
4306c3fb27SDimitry Andric   SUB_W = 0x00110000,
4406c3fb27SDimitry Andric   SUB_D = 0x00118000,
4506c3fb27SDimitry Andric   BREAK = 0x002a0000,
4606c3fb27SDimitry Andric   SRLI_W = 0x00448000,
4706c3fb27SDimitry Andric   SRLI_D = 0x00450000,
4806c3fb27SDimitry Andric   ADDI_W = 0x02800000,
4906c3fb27SDimitry Andric   ADDI_D = 0x02c00000,
5006c3fb27SDimitry Andric   ANDI = 0x03400000,
5106c3fb27SDimitry Andric   PCADDU12I = 0x1c000000,
5206c3fb27SDimitry Andric   LD_W = 0x28800000,
5306c3fb27SDimitry Andric   LD_D = 0x28c00000,
5406c3fb27SDimitry Andric   JIRL = 0x4c000000,
5506c3fb27SDimitry Andric };
5606c3fb27SDimitry Andric 
5706c3fb27SDimitry Andric enum Reg {
5806c3fb27SDimitry Andric   R_ZERO = 0,
5906c3fb27SDimitry Andric   R_RA = 1,
6006c3fb27SDimitry Andric   R_TP = 2,
6106c3fb27SDimitry Andric   R_T0 = 12,
6206c3fb27SDimitry Andric   R_T1 = 13,
6306c3fb27SDimitry Andric   R_T2 = 14,
6406c3fb27SDimitry Andric   R_T3 = 15,
6506c3fb27SDimitry Andric };
6606c3fb27SDimitry Andric 
6706c3fb27SDimitry Andric // Mask out the input's lowest 12 bits for use with `pcalau12i`, in sequences
6806c3fb27SDimitry Andric // like `pcalau12i + addi.[wd]` or `pcalau12i + {ld,st}.*` where the `pcalau12i`
6906c3fb27SDimitry Andric // produces a PC-relative intermediate value with the lowest 12 bits zeroed (the
7006c3fb27SDimitry Andric // "page") for the next instruction to add in the "page offset". (`pcalau12i`
7106c3fb27SDimitry Andric // stands for something like "PC ALigned Add Upper that starts from the 12th
7206c3fb27SDimitry Andric // bit, Immediate".)
7306c3fb27SDimitry Andric //
7406c3fb27SDimitry Andric // Here a "page" is in fact just another way to refer to the 12-bit range
7506c3fb27SDimitry Andric // allowed by the immediate field of the addi/ld/st instructions, and not
7606c3fb27SDimitry Andric // related to the system or the kernel's actual page size. The sematics happens
7706c3fb27SDimitry Andric // to match the AArch64 `adrp`, so the concept of "page" is borrowed here.
7806c3fb27SDimitry Andric static uint64_t getLoongArchPage(uint64_t p) {
7906c3fb27SDimitry Andric   return p & ~static_cast<uint64_t>(0xfff);
8006c3fb27SDimitry Andric }
8106c3fb27SDimitry Andric 
8206c3fb27SDimitry Andric static uint32_t lo12(uint32_t val) { return val & 0xfff; }
8306c3fb27SDimitry Andric 
8406c3fb27SDimitry Andric // Calculate the adjusted page delta between dest and PC.
8506c3fb27SDimitry Andric uint64_t elf::getLoongArchPageDelta(uint64_t dest, uint64_t pc) {
8606c3fb27SDimitry Andric   // Consider the large code model access pattern, of which the smaller code
8706c3fb27SDimitry Andric   // models' access patterns are a subset:
8806c3fb27SDimitry Andric   //
8906c3fb27SDimitry Andric   //     pcalau12i       U, %foo_hi20(sym)        ; b in [-0x80000, 0x7ffff]
9006c3fb27SDimitry Andric   //     addi.d          T, zero, %foo_lo12(sym)  ; a in [-0x800, 0x7ff]
9106c3fb27SDimitry Andric   //     lu32i.d         T, %foo64_lo20(sym)      ; c in [-0x80000, 0x7ffff]
9206c3fb27SDimitry Andric   //     lu52i.d         T, T, %foo64_hi12(sym)   ; d in [-0x800, 0x7ff]
9306c3fb27SDimitry Andric   //     {ldx,stx,add}.* dest, U, T
9406c3fb27SDimitry Andric   //
9506c3fb27SDimitry Andric   // Let page(pc) = 0xRRR'QQQQQ'PPPPP'000 and dest = 0xZZZ'YYYYY'XXXXX'AAA,
9606c3fb27SDimitry Andric   // with RQ, P, ZY, X and A representing the respective bitfields as unsigned
9706c3fb27SDimitry Andric   // integers. We have:
9806c3fb27SDimitry Andric   //
9906c3fb27SDimitry Andric   //     page(dest) = 0xZZZ'YYYYY'XXXXX'000
10006c3fb27SDimitry Andric   //     - page(pc) = 0xRRR'QQQQQ'PPPPP'000
10106c3fb27SDimitry Andric   //     ----------------------------------
10206c3fb27SDimitry Andric   //                  0xddd'ccccc'bbbbb'000
10306c3fb27SDimitry Andric   //
10406c3fb27SDimitry Andric   // Now consider the above pattern's actual effects:
10506c3fb27SDimitry Andric   //
10606c3fb27SDimitry Andric   //     page(pc)                     0xRRR'QQQQQ'PPPPP'000
10706c3fb27SDimitry Andric   //     pcalau12i                  + 0xiii'iiiii'bbbbb'000
10806c3fb27SDimitry Andric   //     addi                       + 0xjjj'jjjjj'kkkkk'AAA
10906c3fb27SDimitry Andric   //     lu32i.d & lu52i.d          + 0xddd'ccccc'00000'000
11006c3fb27SDimitry Andric   //     --------------------------------------------------
11106c3fb27SDimitry Andric   //     dest = U + T
11206c3fb27SDimitry Andric   //          = ((RQ<<32) + (P<<12) + i + (b<<12)) + (j + k + A + (cd<<32))
11306c3fb27SDimitry Andric   //          = (((RQ+cd)<<32) + i + j) + (((P+b)<<12) + k) + A
11406c3fb27SDimitry Andric   //          = (ZY<<32)                + (X<<12)           + A
11506c3fb27SDimitry Andric   //
11606c3fb27SDimitry Andric   //     ZY<<32 = (RQ<<32)+(cd<<32)+i+j, X<<12 = (P<<12)+(b<<12)+k
11706c3fb27SDimitry Andric   //     cd<<32 = (ZY<<32)-(RQ<<32)-i-j, b<<12 = (X<<12)-(P<<12)-k
11806c3fb27SDimitry Andric   //
11906c3fb27SDimitry Andric   // where i and k are terms representing the effect of b's and A's sign
12006c3fb27SDimitry Andric   // extension respectively.
12106c3fb27SDimitry Andric   //
12206c3fb27SDimitry Andric   //     i = signed b < 0 ? -0x10000'0000 : 0
12306c3fb27SDimitry Andric   //     k = signed A < 0 ? -0x1000 : 0
12406c3fb27SDimitry Andric   //
12506c3fb27SDimitry Andric   // The j term is a bit complex: it represents the higher half of
12606c3fb27SDimitry Andric   // sign-extended bits from A that are effectively lost if i == 0 but k != 0,
12706c3fb27SDimitry Andric   // due to overwriting by lu32i.d & lu52i.d.
12806c3fb27SDimitry Andric   //
12906c3fb27SDimitry Andric   //     j = signed A < 0 && signed b >= 0 ? 0x10000'0000 : 0
13006c3fb27SDimitry Andric   //
13106c3fb27SDimitry Andric   // The actual effect of the instruction sequence before the final addition,
13206c3fb27SDimitry Andric   // i.e. our desired result value, is thus:
13306c3fb27SDimitry Andric   //
13406c3fb27SDimitry Andric   //     result = (cd<<32) + (b<<12)
13506c3fb27SDimitry Andric   //            = (ZY<<32)-(RQ<<32)-i-j + (X<<12)-(P<<12)-k
13606c3fb27SDimitry Andric   //            = ((ZY<<32)+(X<<12)) - ((RQ<<32)+(P<<12)) - i - j - k
13706c3fb27SDimitry Andric   //            = page(dest) - page(pc) - i - j - k
13806c3fb27SDimitry Andric   //
13906c3fb27SDimitry Andric   // when signed A >= 0 && signed b >= 0:
14006c3fb27SDimitry Andric   //
14106c3fb27SDimitry Andric   //     i = j = k = 0
14206c3fb27SDimitry Andric   //     result = page(dest) - page(pc)
14306c3fb27SDimitry Andric   //
14406c3fb27SDimitry Andric   // when signed A >= 0 && signed b < 0:
14506c3fb27SDimitry Andric   //
14606c3fb27SDimitry Andric   //     i = -0x10000'0000, j = k = 0
14706c3fb27SDimitry Andric   //     result = page(dest) - page(pc) + 0x10000'0000
14806c3fb27SDimitry Andric   //
14906c3fb27SDimitry Andric   // when signed A < 0 && signed b >= 0:
15006c3fb27SDimitry Andric   //
15106c3fb27SDimitry Andric   //     i = 0, j = 0x10000'0000, k = -0x1000
15206c3fb27SDimitry Andric   //     result = page(dest) - page(pc) - 0x10000'0000 + 0x1000
15306c3fb27SDimitry Andric   //
15406c3fb27SDimitry Andric   // when signed A < 0 && signed b < 0:
15506c3fb27SDimitry Andric   //
15606c3fb27SDimitry Andric   //     i = -0x10000'0000, j = 0, k = -0x1000
15706c3fb27SDimitry Andric   //     result = page(dest) - page(pc) + 0x1000
15806c3fb27SDimitry Andric   uint64_t result = getLoongArchPage(dest) - getLoongArchPage(pc);
15906c3fb27SDimitry Andric   bool negativeA = lo12(dest) > 0x7ff;
16006c3fb27SDimitry Andric   bool negativeB = (result & 0x8000'0000) != 0;
16106c3fb27SDimitry Andric 
16206c3fb27SDimitry Andric   if (negativeA)
16306c3fb27SDimitry Andric     result += 0x1000;
16406c3fb27SDimitry Andric   if (negativeA && !negativeB)
16506c3fb27SDimitry Andric     result -= 0x10000'0000;
16606c3fb27SDimitry Andric   else if (!negativeA && negativeB)
16706c3fb27SDimitry Andric     result += 0x10000'0000;
16806c3fb27SDimitry Andric 
16906c3fb27SDimitry Andric   return result;
17006c3fb27SDimitry Andric }
17106c3fb27SDimitry Andric 
17206c3fb27SDimitry Andric static uint32_t hi20(uint32_t val) { return (val + 0x800) >> 12; }
17306c3fb27SDimitry Andric 
17406c3fb27SDimitry Andric static uint32_t insn(uint32_t op, uint32_t d, uint32_t j, uint32_t k) {
17506c3fb27SDimitry Andric   return op | d | (j << 5) | (k << 10);
17606c3fb27SDimitry Andric }
17706c3fb27SDimitry Andric 
17806c3fb27SDimitry Andric // Extract bits v[begin:end], where range is inclusive.
17906c3fb27SDimitry Andric static uint32_t extractBits(uint64_t v, uint32_t begin, uint32_t end) {
18006c3fb27SDimitry Andric   return begin == 63 ? v >> end : (v & ((1ULL << (begin + 1)) - 1)) >> end;
18106c3fb27SDimitry Andric }
18206c3fb27SDimitry Andric 
18306c3fb27SDimitry Andric static uint32_t setD5k16(uint32_t insn, uint32_t imm) {
18406c3fb27SDimitry Andric   uint32_t immLo = extractBits(imm, 15, 0);
18506c3fb27SDimitry Andric   uint32_t immHi = extractBits(imm, 20, 16);
18606c3fb27SDimitry Andric   return (insn & 0xfc0003e0) | (immLo << 10) | immHi;
18706c3fb27SDimitry Andric }
18806c3fb27SDimitry Andric 
18906c3fb27SDimitry Andric static uint32_t setD10k16(uint32_t insn, uint32_t imm) {
19006c3fb27SDimitry Andric   uint32_t immLo = extractBits(imm, 15, 0);
19106c3fb27SDimitry Andric   uint32_t immHi = extractBits(imm, 25, 16);
19206c3fb27SDimitry Andric   return (insn & 0xfc000000) | (immLo << 10) | immHi;
19306c3fb27SDimitry Andric }
19406c3fb27SDimitry Andric 
19506c3fb27SDimitry Andric static uint32_t setJ20(uint32_t insn, uint32_t imm) {
19606c3fb27SDimitry Andric   return (insn & 0xfe00001f) | (extractBits(imm, 19, 0) << 5);
19706c3fb27SDimitry Andric }
19806c3fb27SDimitry Andric 
19906c3fb27SDimitry Andric static uint32_t setK12(uint32_t insn, uint32_t imm) {
20006c3fb27SDimitry Andric   return (insn & 0xffc003ff) | (extractBits(imm, 11, 0) << 10);
20106c3fb27SDimitry Andric }
20206c3fb27SDimitry Andric 
20306c3fb27SDimitry Andric static uint32_t setK16(uint32_t insn, uint32_t imm) {
20406c3fb27SDimitry Andric   return (insn & 0xfc0003ff) | (extractBits(imm, 15, 0) << 10);
20506c3fb27SDimitry Andric }
20606c3fb27SDimitry Andric 
20706c3fb27SDimitry Andric static bool isJirl(uint32_t insn) {
20806c3fb27SDimitry Andric   return (insn & 0xfc000000) == JIRL;
20906c3fb27SDimitry Andric }
21006c3fb27SDimitry Andric 
21106c3fb27SDimitry Andric LoongArch::LoongArch() {
21206c3fb27SDimitry Andric   // The LoongArch ISA itself does not have a limit on page sizes. According to
21306c3fb27SDimitry Andric   // the ISA manual, the PS (page size) field in MTLB entries and CSR.STLBPS is
21406c3fb27SDimitry Andric   // 6 bits wide, meaning the maximum page size is 2^63 which is equivalent to
21506c3fb27SDimitry Andric   // "unlimited".
21606c3fb27SDimitry Andric   // However, practically the maximum usable page size is constrained by the
21706c3fb27SDimitry Andric   // kernel implementation, and 64KiB is the biggest non-huge page size
21806c3fb27SDimitry Andric   // supported by Linux as of v6.4. The most widespread page size in use,
21906c3fb27SDimitry Andric   // though, is 16KiB.
22006c3fb27SDimitry Andric   defaultCommonPageSize = 16384;
22106c3fb27SDimitry Andric   defaultMaxPageSize = 65536;
22206c3fb27SDimitry Andric   write32le(trapInstr.data(), BREAK); // break 0
22306c3fb27SDimitry Andric 
22406c3fb27SDimitry Andric   copyRel = R_LARCH_COPY;
22506c3fb27SDimitry Andric   pltRel = R_LARCH_JUMP_SLOT;
22606c3fb27SDimitry Andric   relativeRel = R_LARCH_RELATIVE;
22706c3fb27SDimitry Andric   iRelativeRel = R_LARCH_IRELATIVE;
22806c3fb27SDimitry Andric 
22906c3fb27SDimitry Andric   if (config->is64) {
23006c3fb27SDimitry Andric     symbolicRel = R_LARCH_64;
23106c3fb27SDimitry Andric     tlsModuleIndexRel = R_LARCH_TLS_DTPMOD64;
23206c3fb27SDimitry Andric     tlsOffsetRel = R_LARCH_TLS_DTPREL64;
23306c3fb27SDimitry Andric     tlsGotRel = R_LARCH_TLS_TPREL64;
23406c3fb27SDimitry Andric   } else {
23506c3fb27SDimitry Andric     symbolicRel = R_LARCH_32;
23606c3fb27SDimitry Andric     tlsModuleIndexRel = R_LARCH_TLS_DTPMOD32;
23706c3fb27SDimitry Andric     tlsOffsetRel = R_LARCH_TLS_DTPREL32;
23806c3fb27SDimitry Andric     tlsGotRel = R_LARCH_TLS_TPREL32;
23906c3fb27SDimitry Andric   }
24006c3fb27SDimitry Andric 
24106c3fb27SDimitry Andric   gotRel = symbolicRel;
24206c3fb27SDimitry Andric 
24306c3fb27SDimitry Andric   // .got.plt[0] = _dl_runtime_resolve, .got.plt[1] = link_map
24406c3fb27SDimitry Andric   gotPltHeaderEntriesNum = 2;
24506c3fb27SDimitry Andric 
24606c3fb27SDimitry Andric   pltHeaderSize = 32;
24706c3fb27SDimitry Andric   pltEntrySize = 16;
24806c3fb27SDimitry Andric   ipltEntrySize = 16;
24906c3fb27SDimitry Andric }
25006c3fb27SDimitry Andric 
25106c3fb27SDimitry Andric static uint32_t getEFlags(const InputFile *f) {
25206c3fb27SDimitry Andric   if (config->is64)
25306c3fb27SDimitry Andric     return cast<ObjFile<ELF64LE>>(f)->getObj().getHeader().e_flags;
25406c3fb27SDimitry Andric   return cast<ObjFile<ELF32LE>>(f)->getObj().getHeader().e_flags;
25506c3fb27SDimitry Andric }
25606c3fb27SDimitry Andric 
25706c3fb27SDimitry Andric static bool inputFileHasCode(const InputFile *f) {
25806c3fb27SDimitry Andric   for (const auto *sec : f->getSections())
25906c3fb27SDimitry Andric     if (sec && sec->flags & SHF_EXECINSTR)
26006c3fb27SDimitry Andric       return true;
26106c3fb27SDimitry Andric 
26206c3fb27SDimitry Andric   return false;
26306c3fb27SDimitry Andric }
26406c3fb27SDimitry Andric 
26506c3fb27SDimitry Andric uint32_t LoongArch::calcEFlags() const {
26606c3fb27SDimitry Andric   // If there are only binary input files (from -b binary), use a
26706c3fb27SDimitry Andric   // value of 0 for the ELF header flags.
26806c3fb27SDimitry Andric   if (ctx.objectFiles.empty())
26906c3fb27SDimitry Andric     return 0;
27006c3fb27SDimitry Andric 
27106c3fb27SDimitry Andric   uint32_t target = 0;
27206c3fb27SDimitry Andric   const InputFile *targetFile;
27306c3fb27SDimitry Andric   for (const InputFile *f : ctx.objectFiles) {
27406c3fb27SDimitry Andric     // Do not enforce ABI compatibility if the input file does not contain code.
27506c3fb27SDimitry Andric     // This is useful for allowing linkage with data-only object files produced
27606c3fb27SDimitry Andric     // with tools like objcopy, that have zero e_flags.
27706c3fb27SDimitry Andric     if (!inputFileHasCode(f))
27806c3fb27SDimitry Andric       continue;
27906c3fb27SDimitry Andric 
28006c3fb27SDimitry Andric     // Take the first non-zero e_flags as the reference.
28106c3fb27SDimitry Andric     uint32_t flags = getEFlags(f);
28206c3fb27SDimitry Andric     if (target == 0 && flags != 0) {
28306c3fb27SDimitry Andric       target = flags;
28406c3fb27SDimitry Andric       targetFile = f;
28506c3fb27SDimitry Andric     }
28606c3fb27SDimitry Andric 
28706c3fb27SDimitry Andric     if ((flags & EF_LOONGARCH_ABI_MODIFIER_MASK) !=
28806c3fb27SDimitry Andric         (target & EF_LOONGARCH_ABI_MODIFIER_MASK))
28906c3fb27SDimitry Andric       error(toString(f) +
29006c3fb27SDimitry Andric             ": cannot link object files with different ABI from " +
29106c3fb27SDimitry Andric             toString(targetFile));
29206c3fb27SDimitry Andric 
29306c3fb27SDimitry Andric     // We cannot process psABI v1.x / object ABI v0 files (containing stack
29406c3fb27SDimitry Andric     // relocations), unlike ld.bfd.
29506c3fb27SDimitry Andric     //
29606c3fb27SDimitry Andric     // Instead of blindly accepting every v0 object and only failing at
29706c3fb27SDimitry Andric     // relocation processing time, just disallow interlink altogether. We
29806c3fb27SDimitry Andric     // don't expect significant usage of object ABI v0 in the wild (the old
29906c3fb27SDimitry Andric     // world may continue using object ABI v0 for a while, but as it's not
30006c3fb27SDimitry Andric     // binary-compatible with the upstream i.e. new-world ecosystem, it's not
30106c3fb27SDimitry Andric     // being considered here).
30206c3fb27SDimitry Andric     //
30306c3fb27SDimitry Andric     // There are briefly some new-world systems with object ABI v0 binaries too.
30406c3fb27SDimitry Andric     // It is because these systems were built before the new ABI was finalized.
30506c3fb27SDimitry Andric     // These are not supported either due to the extremely small number of them,
30606c3fb27SDimitry Andric     // and the few impacted users are advised to simply rebuild world or
30706c3fb27SDimitry Andric     // reinstall a recent system.
30806c3fb27SDimitry Andric     if ((flags & EF_LOONGARCH_OBJABI_MASK) != EF_LOONGARCH_OBJABI_V1)
30906c3fb27SDimitry Andric       error(toString(f) + ": unsupported object file ABI version");
31006c3fb27SDimitry Andric   }
31106c3fb27SDimitry Andric 
31206c3fb27SDimitry Andric   return target;
31306c3fb27SDimitry Andric }
31406c3fb27SDimitry Andric 
31506c3fb27SDimitry Andric int64_t LoongArch::getImplicitAddend(const uint8_t *buf, RelType type) const {
31606c3fb27SDimitry Andric   switch (type) {
31706c3fb27SDimitry Andric   default:
31806c3fb27SDimitry Andric     internalLinkerError(getErrorLocation(buf),
31906c3fb27SDimitry Andric                         "cannot read addend for relocation " + toString(type));
32006c3fb27SDimitry Andric     return 0;
32106c3fb27SDimitry Andric   case R_LARCH_32:
32206c3fb27SDimitry Andric   case R_LARCH_TLS_DTPMOD32:
32306c3fb27SDimitry Andric   case R_LARCH_TLS_DTPREL32:
32406c3fb27SDimitry Andric   case R_LARCH_TLS_TPREL32:
32506c3fb27SDimitry Andric     return SignExtend64<32>(read32le(buf));
32606c3fb27SDimitry Andric   case R_LARCH_64:
32706c3fb27SDimitry Andric   case R_LARCH_TLS_DTPMOD64:
32806c3fb27SDimitry Andric   case R_LARCH_TLS_DTPREL64:
32906c3fb27SDimitry Andric   case R_LARCH_TLS_TPREL64:
33006c3fb27SDimitry Andric     return read64le(buf);
33106c3fb27SDimitry Andric   case R_LARCH_RELATIVE:
33206c3fb27SDimitry Andric   case R_LARCH_IRELATIVE:
33306c3fb27SDimitry Andric     return config->is64 ? read64le(buf) : read32le(buf);
33406c3fb27SDimitry Andric   case R_LARCH_NONE:
33506c3fb27SDimitry Andric   case R_LARCH_JUMP_SLOT:
33606c3fb27SDimitry Andric     // These relocations are defined as not having an implicit addend.
33706c3fb27SDimitry Andric     return 0;
33806c3fb27SDimitry Andric   }
33906c3fb27SDimitry Andric }
34006c3fb27SDimitry Andric 
34106c3fb27SDimitry Andric void LoongArch::writeGotPlt(uint8_t *buf, const Symbol &s) const {
34206c3fb27SDimitry Andric   if (config->is64)
34306c3fb27SDimitry Andric     write64le(buf, in.plt->getVA());
34406c3fb27SDimitry Andric   else
34506c3fb27SDimitry Andric     write32le(buf, in.plt->getVA());
34606c3fb27SDimitry Andric }
34706c3fb27SDimitry Andric 
34806c3fb27SDimitry Andric void LoongArch::writeIgotPlt(uint8_t *buf, const Symbol &s) const {
34906c3fb27SDimitry Andric   if (config->writeAddends) {
35006c3fb27SDimitry Andric     if (config->is64)
35106c3fb27SDimitry Andric       write64le(buf, s.getVA());
35206c3fb27SDimitry Andric     else
35306c3fb27SDimitry Andric       write32le(buf, s.getVA());
35406c3fb27SDimitry Andric   }
35506c3fb27SDimitry Andric }
35606c3fb27SDimitry Andric 
35706c3fb27SDimitry Andric void LoongArch::writePltHeader(uint8_t *buf) const {
35806c3fb27SDimitry Andric   // The LoongArch PLT is currently structured just like that of RISCV.
35906c3fb27SDimitry Andric   // Annoyingly, this means the PLT is still using `pcaddu12i` to perform
36006c3fb27SDimitry Andric   // PC-relative addressing (because `pcaddu12i` is the same as RISCV `auipc`),
36106c3fb27SDimitry Andric   // in contrast to the AArch64-like page-offset scheme with `pcalau12i` that
36206c3fb27SDimitry Andric   // is used everywhere else involving PC-relative operations in the LoongArch
36306c3fb27SDimitry Andric   // ELF psABI v2.00.
36406c3fb27SDimitry Andric   //
36506c3fb27SDimitry Andric   // The `pcrel_{hi20,lo12}` operators are illustrative only and not really
36606c3fb27SDimitry Andric   // supported by LoongArch assemblers.
36706c3fb27SDimitry Andric   //
36806c3fb27SDimitry Andric   //   pcaddu12i $t2, %pcrel_hi20(.got.plt)
36906c3fb27SDimitry Andric   //   sub.[wd]  $t1, $t1, $t3
37006c3fb27SDimitry Andric   //   ld.[wd]   $t3, $t2, %pcrel_lo12(.got.plt)  ; t3 = _dl_runtime_resolve
37106c3fb27SDimitry Andric   //   addi.[wd] $t1, $t1, -pltHeaderSize-12      ; t1 = &.plt[i] - &.plt[0]
37206c3fb27SDimitry Andric   //   addi.[wd] $t0, $t2, %pcrel_lo12(.got.plt)
37306c3fb27SDimitry Andric   //   srli.[wd] $t1, $t1, (is64?1:2)             ; t1 = &.got.plt[i] - &.got.plt[0]
37406c3fb27SDimitry Andric   //   ld.[wd]   $t0, $t0, Wordsize               ; t0 = link_map
37506c3fb27SDimitry Andric   //   jr        $t3
37606c3fb27SDimitry Andric   uint32_t offset = in.gotPlt->getVA() - in.plt->getVA();
37706c3fb27SDimitry Andric   uint32_t sub = config->is64 ? SUB_D : SUB_W;
37806c3fb27SDimitry Andric   uint32_t ld = config->is64 ? LD_D : LD_W;
37906c3fb27SDimitry Andric   uint32_t addi = config->is64 ? ADDI_D : ADDI_W;
38006c3fb27SDimitry Andric   uint32_t srli = config->is64 ? SRLI_D : SRLI_W;
38106c3fb27SDimitry Andric   write32le(buf + 0, insn(PCADDU12I, R_T2, hi20(offset), 0));
38206c3fb27SDimitry Andric   write32le(buf + 4, insn(sub, R_T1, R_T1, R_T3));
38306c3fb27SDimitry Andric   write32le(buf + 8, insn(ld, R_T3, R_T2, lo12(offset)));
38406c3fb27SDimitry Andric   write32le(buf + 12, insn(addi, R_T1, R_T1, lo12(-target->pltHeaderSize - 12)));
38506c3fb27SDimitry Andric   write32le(buf + 16, insn(addi, R_T0, R_T2, lo12(offset)));
38606c3fb27SDimitry Andric   write32le(buf + 20, insn(srli, R_T1, R_T1, config->is64 ? 1 : 2));
38706c3fb27SDimitry Andric   write32le(buf + 24, insn(ld, R_T0, R_T0, config->wordsize));
38806c3fb27SDimitry Andric   write32le(buf + 28, insn(JIRL, R_ZERO, R_T3, 0));
38906c3fb27SDimitry Andric }
39006c3fb27SDimitry Andric 
39106c3fb27SDimitry Andric void LoongArch::writePlt(uint8_t *buf, const Symbol &sym,
39206c3fb27SDimitry Andric                      uint64_t pltEntryAddr) const {
39306c3fb27SDimitry Andric   // See the comment in writePltHeader for reason why pcaddu12i is used instead
39406c3fb27SDimitry Andric   // of the pcalau12i that's more commonly seen in the ELF psABI v2.0 days.
39506c3fb27SDimitry Andric   //
39606c3fb27SDimitry Andric   //   pcaddu12i $t3, %pcrel_hi20(f@.got.plt)
39706c3fb27SDimitry Andric   //   ld.[wd]   $t3, $t3, %pcrel_lo12(f@.got.plt)
39806c3fb27SDimitry Andric   //   jirl      $t1, $t3, 0
39906c3fb27SDimitry Andric   //   nop
40006c3fb27SDimitry Andric   uint32_t offset = sym.getGotPltVA() - pltEntryAddr;
40106c3fb27SDimitry Andric   write32le(buf + 0, insn(PCADDU12I, R_T3, hi20(offset), 0));
40206c3fb27SDimitry Andric   write32le(buf + 4,
40306c3fb27SDimitry Andric             insn(config->is64 ? LD_D : LD_W, R_T3, R_T3, lo12(offset)));
40406c3fb27SDimitry Andric   write32le(buf + 8, insn(JIRL, R_T1, R_T3, 0));
40506c3fb27SDimitry Andric   write32le(buf + 12, insn(ANDI, R_ZERO, R_ZERO, 0));
40606c3fb27SDimitry Andric }
40706c3fb27SDimitry Andric 
40806c3fb27SDimitry Andric RelType LoongArch::getDynRel(RelType type) const {
40906c3fb27SDimitry Andric   return type == target->symbolicRel ? type
41006c3fb27SDimitry Andric                                      : static_cast<RelType>(R_LARCH_NONE);
41106c3fb27SDimitry Andric }
41206c3fb27SDimitry Andric 
41306c3fb27SDimitry Andric RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
41406c3fb27SDimitry Andric                               const uint8_t *loc) const {
41506c3fb27SDimitry Andric   switch (type) {
41606c3fb27SDimitry Andric   case R_LARCH_NONE:
41706c3fb27SDimitry Andric   case R_LARCH_MARK_LA:
41806c3fb27SDimitry Andric   case R_LARCH_MARK_PCREL:
41906c3fb27SDimitry Andric     return R_NONE;
42006c3fb27SDimitry Andric   case R_LARCH_32:
42106c3fb27SDimitry Andric   case R_LARCH_64:
42206c3fb27SDimitry Andric   case R_LARCH_ABS_HI20:
42306c3fb27SDimitry Andric   case R_LARCH_ABS_LO12:
42406c3fb27SDimitry Andric   case R_LARCH_ABS64_LO20:
42506c3fb27SDimitry Andric   case R_LARCH_ABS64_HI12:
42606c3fb27SDimitry Andric     return R_ABS;
42706c3fb27SDimitry Andric   case R_LARCH_PCALA_LO12:
42806c3fb27SDimitry Andric     // We could just R_ABS, but the JIRL instruction reuses the relocation type
42906c3fb27SDimitry Andric     // for a different purpose. The questionable usage is part of glibc 2.37
43006c3fb27SDimitry Andric     // libc_nonshared.a [1], which is linked into user programs, so we have to
43106c3fb27SDimitry Andric     // work around it for a while, even if a new relocation type may be
43206c3fb27SDimitry Andric     // introduced in the future [2].
43306c3fb27SDimitry Andric     //
43406c3fb27SDimitry Andric     // [1]: https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=9f482b73f41a9a1bbfb173aad0733d1c824c788a
43506c3fb27SDimitry Andric     // [2]: https://github.com/loongson/la-abi-specs/pull/3
43606c3fb27SDimitry Andric     return isJirl(read32le(loc)) ? R_PLT : R_ABS;
43706c3fb27SDimitry Andric   case R_LARCH_TLS_DTPREL32:
43806c3fb27SDimitry Andric   case R_LARCH_TLS_DTPREL64:
43906c3fb27SDimitry Andric     return R_DTPREL;
44006c3fb27SDimitry Andric   case R_LARCH_TLS_TPREL32:
44106c3fb27SDimitry Andric   case R_LARCH_TLS_TPREL64:
44206c3fb27SDimitry Andric   case R_LARCH_TLS_LE_HI20:
44306c3fb27SDimitry Andric   case R_LARCH_TLS_LE_LO12:
44406c3fb27SDimitry Andric   case R_LARCH_TLS_LE64_LO20:
44506c3fb27SDimitry Andric   case R_LARCH_TLS_LE64_HI12:
44606c3fb27SDimitry Andric     return R_TPREL;
44706c3fb27SDimitry Andric   case R_LARCH_ADD8:
44806c3fb27SDimitry Andric   case R_LARCH_ADD16:
44906c3fb27SDimitry Andric   case R_LARCH_ADD32:
45006c3fb27SDimitry Andric   case R_LARCH_ADD64:
45106c3fb27SDimitry Andric   case R_LARCH_SUB8:
45206c3fb27SDimitry Andric   case R_LARCH_SUB16:
45306c3fb27SDimitry Andric   case R_LARCH_SUB32:
45406c3fb27SDimitry Andric   case R_LARCH_SUB64:
45506c3fb27SDimitry Andric     // The LoongArch add/sub relocs behave like the RISCV counterparts; reuse
45606c3fb27SDimitry Andric     // the RelExpr to avoid code duplication.
45706c3fb27SDimitry Andric     return R_RISCV_ADD;
45806c3fb27SDimitry Andric   case R_LARCH_32_PCREL:
45906c3fb27SDimitry Andric   case R_LARCH_64_PCREL:
460*8a4dda33SDimitry Andric   case R_LARCH_PCREL20_S2:
46106c3fb27SDimitry Andric     return R_PC;
46206c3fb27SDimitry Andric   case R_LARCH_B16:
46306c3fb27SDimitry Andric   case R_LARCH_B21:
46406c3fb27SDimitry Andric   case R_LARCH_B26:
46506c3fb27SDimitry Andric     return R_PLT_PC;
46606c3fb27SDimitry Andric   case R_LARCH_GOT_PC_HI20:
46706c3fb27SDimitry Andric   case R_LARCH_GOT64_PC_LO20:
46806c3fb27SDimitry Andric   case R_LARCH_GOT64_PC_HI12:
46906c3fb27SDimitry Andric   case R_LARCH_TLS_IE_PC_HI20:
47006c3fb27SDimitry Andric   case R_LARCH_TLS_IE64_PC_LO20:
47106c3fb27SDimitry Andric   case R_LARCH_TLS_IE64_PC_HI12:
47206c3fb27SDimitry Andric     return R_LOONGARCH_GOT_PAGE_PC;
47306c3fb27SDimitry Andric   case R_LARCH_GOT_PC_LO12:
47406c3fb27SDimitry Andric   case R_LARCH_TLS_IE_PC_LO12:
47506c3fb27SDimitry Andric     return R_LOONGARCH_GOT;
47606c3fb27SDimitry Andric   case R_LARCH_TLS_LD_PC_HI20:
47706c3fb27SDimitry Andric   case R_LARCH_TLS_GD_PC_HI20:
47806c3fb27SDimitry Andric     return R_LOONGARCH_TLSGD_PAGE_PC;
47906c3fb27SDimitry Andric   case R_LARCH_PCALA_HI20:
48006c3fb27SDimitry Andric     // Why not R_LOONGARCH_PAGE_PC, majority of references don't go through PLT
48106c3fb27SDimitry Andric     // anyway so why waste time checking only to get everything relaxed back to
48206c3fb27SDimitry Andric     // it?
48306c3fb27SDimitry Andric     //
48406c3fb27SDimitry Andric     // This is again due to the R_LARCH_PCALA_LO12 on JIRL case, where we want
48506c3fb27SDimitry Andric     // both the HI20 and LO12 to potentially refer to the PLT. But in reality
48606c3fb27SDimitry Andric     // the HI20 reloc appears earlier, and the relocs don't contain enough
48706c3fb27SDimitry Andric     // information to let us properly resolve semantics per symbol.
48806c3fb27SDimitry Andric     // Unlike RISCV, our LO12 relocs *do not* point to their corresponding HI20
48906c3fb27SDimitry Andric     // relocs, hence it is nearly impossible to 100% accurately determine each
49006c3fb27SDimitry Andric     // HI20's "flavor" without taking big performance hits, in the presence of
49106c3fb27SDimitry Andric     // edge cases (e.g. HI20 without pairing LO12; paired LO12 placed so far
49206c3fb27SDimitry Andric     // apart that relationship is not certain anymore), and programmer mistakes
49306c3fb27SDimitry Andric     // (e.g. as outlined in https://github.com/loongson/la-abi-specs/pull/3).
49406c3fb27SDimitry Andric     //
49506c3fb27SDimitry Andric     // Ideally we would scan in an extra pass for all LO12s on JIRL, then mark
49606c3fb27SDimitry Andric     // every HI20 reloc referring to the same symbol differently; this is not
49706c3fb27SDimitry Andric     // feasible with the current function signature of getRelExpr that doesn't
49806c3fb27SDimitry Andric     // allow for such inter-pass state.
49906c3fb27SDimitry Andric     //
50006c3fb27SDimitry Andric     // So, unfortunately we have to again workaround this quirk the same way as
50106c3fb27SDimitry Andric     // BFD: assuming every R_LARCH_PCALA_HI20 is potentially PLT-needing, only
50206c3fb27SDimitry Andric     // relaxing back to R_LOONGARCH_PAGE_PC if it's known not so at a later
50306c3fb27SDimitry Andric     // stage.
50406c3fb27SDimitry Andric     return R_LOONGARCH_PLT_PAGE_PC;
50506c3fb27SDimitry Andric   case R_LARCH_PCALA64_LO20:
50606c3fb27SDimitry Andric   case R_LARCH_PCALA64_HI12:
50706c3fb27SDimitry Andric     return R_LOONGARCH_PAGE_PC;
50806c3fb27SDimitry Andric   case R_LARCH_GOT_HI20:
50906c3fb27SDimitry Andric   case R_LARCH_GOT_LO12:
51006c3fb27SDimitry Andric   case R_LARCH_GOT64_LO20:
51106c3fb27SDimitry Andric   case R_LARCH_GOT64_HI12:
51206c3fb27SDimitry Andric   case R_LARCH_TLS_IE_HI20:
51306c3fb27SDimitry Andric   case R_LARCH_TLS_IE_LO12:
51406c3fb27SDimitry Andric   case R_LARCH_TLS_IE64_LO20:
51506c3fb27SDimitry Andric   case R_LARCH_TLS_IE64_HI12:
51606c3fb27SDimitry Andric     return R_GOT;
51706c3fb27SDimitry Andric   case R_LARCH_TLS_LD_HI20:
51806c3fb27SDimitry Andric     return R_TLSLD_GOT;
51906c3fb27SDimitry Andric   case R_LARCH_TLS_GD_HI20:
52006c3fb27SDimitry Andric     return R_TLSGD_GOT;
52106c3fb27SDimitry Andric   case R_LARCH_RELAX:
52206c3fb27SDimitry Andric     // LoongArch linker relaxation is not implemented yet.
52306c3fb27SDimitry Andric     return R_NONE;
52406c3fb27SDimitry Andric 
52506c3fb27SDimitry Andric   // Other known relocs that are explicitly unimplemented:
52606c3fb27SDimitry Andric   //
52706c3fb27SDimitry Andric   // - psABI v1 relocs that need a stateful stack machine to work, and not
52806c3fb27SDimitry Andric   //   required when implementing psABI v2;
52906c3fb27SDimitry Andric   // - relocs that are not used anywhere (R_LARCH_{ADD,SUB}_24 [1], and the
53006c3fb27SDimitry Andric   //   two GNU vtable-related relocs).
53106c3fb27SDimitry Andric   //
53206c3fb27SDimitry Andric   // [1]: https://web.archive.org/web/20230709064026/https://github.com/loongson/LoongArch-Documentation/issues/51
53306c3fb27SDimitry Andric   default:
53406c3fb27SDimitry Andric     error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
53506c3fb27SDimitry Andric           ") against symbol " + toString(s));
53606c3fb27SDimitry Andric     return R_NONE;
53706c3fb27SDimitry Andric   }
53806c3fb27SDimitry Andric }
53906c3fb27SDimitry Andric 
54006c3fb27SDimitry Andric bool LoongArch::usesOnlyLowPageBits(RelType type) const {
54106c3fb27SDimitry Andric   switch (type) {
54206c3fb27SDimitry Andric   default:
54306c3fb27SDimitry Andric     return false;
54406c3fb27SDimitry Andric   case R_LARCH_PCALA_LO12:
54506c3fb27SDimitry Andric   case R_LARCH_GOT_LO12:
54606c3fb27SDimitry Andric   case R_LARCH_GOT_PC_LO12:
54706c3fb27SDimitry Andric   case R_LARCH_TLS_IE_PC_LO12:
54806c3fb27SDimitry Andric     return true;
54906c3fb27SDimitry Andric   }
55006c3fb27SDimitry Andric }
55106c3fb27SDimitry Andric 
55206c3fb27SDimitry Andric void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
55306c3fb27SDimitry Andric                          uint64_t val) const {
55406c3fb27SDimitry Andric   switch (rel.type) {
55506c3fb27SDimitry Andric   case R_LARCH_32_PCREL:
55606c3fb27SDimitry Andric     checkInt(loc, val, 32, rel);
55706c3fb27SDimitry Andric     [[fallthrough]];
55806c3fb27SDimitry Andric   case R_LARCH_32:
55906c3fb27SDimitry Andric   case R_LARCH_TLS_DTPREL32:
56006c3fb27SDimitry Andric     write32le(loc, val);
56106c3fb27SDimitry Andric     return;
56206c3fb27SDimitry Andric   case R_LARCH_64:
56306c3fb27SDimitry Andric   case R_LARCH_TLS_DTPREL64:
56406c3fb27SDimitry Andric   case R_LARCH_64_PCREL:
56506c3fb27SDimitry Andric     write64le(loc, val);
56606c3fb27SDimitry Andric     return;
56706c3fb27SDimitry Andric 
568*8a4dda33SDimitry Andric   case R_LARCH_PCREL20_S2:
569*8a4dda33SDimitry Andric     checkInt(loc, val, 22, rel);
570*8a4dda33SDimitry Andric     checkAlignment(loc, val, 4, rel);
571*8a4dda33SDimitry Andric     write32le(loc, setJ20(read32le(loc), val >> 2));
572*8a4dda33SDimitry Andric     return;
573*8a4dda33SDimitry Andric 
57406c3fb27SDimitry Andric   case R_LARCH_B16:
57506c3fb27SDimitry Andric     checkInt(loc, val, 18, rel);
57606c3fb27SDimitry Andric     checkAlignment(loc, val, 4, rel);
57706c3fb27SDimitry Andric     write32le(loc, setK16(read32le(loc), val >> 2));
57806c3fb27SDimitry Andric     return;
57906c3fb27SDimitry Andric 
58006c3fb27SDimitry Andric   case R_LARCH_B21:
58106c3fb27SDimitry Andric     checkInt(loc, val, 23, rel);
58206c3fb27SDimitry Andric     checkAlignment(loc, val, 4, rel);
58306c3fb27SDimitry Andric     write32le(loc, setD5k16(read32le(loc), val >> 2));
58406c3fb27SDimitry Andric     return;
58506c3fb27SDimitry Andric 
58606c3fb27SDimitry Andric   case R_LARCH_B26:
58706c3fb27SDimitry Andric     checkInt(loc, val, 28, rel);
58806c3fb27SDimitry Andric     checkAlignment(loc, val, 4, rel);
58906c3fb27SDimitry Andric     write32le(loc, setD10k16(read32le(loc), val >> 2));
59006c3fb27SDimitry Andric     return;
59106c3fb27SDimitry Andric 
59206c3fb27SDimitry Andric   // Relocs intended for `addi`, `ld` or `st`.
59306c3fb27SDimitry Andric   case R_LARCH_PCALA_LO12:
59406c3fb27SDimitry Andric     // We have to again inspect the insn word to handle the R_LARCH_PCALA_LO12
59506c3fb27SDimitry Andric     // on JIRL case: firstly JIRL wants its immediate's 2 lowest zeroes
59606c3fb27SDimitry Andric     // removed by us (in contrast to regular R_LARCH_PCALA_LO12), secondly
59706c3fb27SDimitry Andric     // its immediate slot width is different too (16, not 12).
59806c3fb27SDimitry Andric     // In this case, process like an R_LARCH_B16, but without overflow checking
59906c3fb27SDimitry Andric     // and only taking the value's lowest 12 bits.
60006c3fb27SDimitry Andric     if (isJirl(read32le(loc))) {
60106c3fb27SDimitry Andric       checkAlignment(loc, val, 4, rel);
60206c3fb27SDimitry Andric       val = SignExtend64<12>(val);
60306c3fb27SDimitry Andric       write32le(loc, setK16(read32le(loc), val >> 2));
60406c3fb27SDimitry Andric       return;
60506c3fb27SDimitry Andric     }
60606c3fb27SDimitry Andric     [[fallthrough]];
60706c3fb27SDimitry Andric   case R_LARCH_ABS_LO12:
60806c3fb27SDimitry Andric   case R_LARCH_GOT_PC_LO12:
60906c3fb27SDimitry Andric   case R_LARCH_GOT_LO12:
61006c3fb27SDimitry Andric   case R_LARCH_TLS_LE_LO12:
61106c3fb27SDimitry Andric   case R_LARCH_TLS_IE_PC_LO12:
61206c3fb27SDimitry Andric   case R_LARCH_TLS_IE_LO12:
61306c3fb27SDimitry Andric     write32le(loc, setK12(read32le(loc), extractBits(val, 11, 0)));
61406c3fb27SDimitry Andric     return;
61506c3fb27SDimitry Andric 
61606c3fb27SDimitry Andric   // Relocs intended for `lu12i.w` or `pcalau12i`.
61706c3fb27SDimitry Andric   case R_LARCH_ABS_HI20:
61806c3fb27SDimitry Andric   case R_LARCH_PCALA_HI20:
61906c3fb27SDimitry Andric   case R_LARCH_GOT_PC_HI20:
62006c3fb27SDimitry Andric   case R_LARCH_GOT_HI20:
62106c3fb27SDimitry Andric   case R_LARCH_TLS_LE_HI20:
62206c3fb27SDimitry Andric   case R_LARCH_TLS_IE_PC_HI20:
62306c3fb27SDimitry Andric   case R_LARCH_TLS_IE_HI20:
62406c3fb27SDimitry Andric   case R_LARCH_TLS_LD_PC_HI20:
62506c3fb27SDimitry Andric   case R_LARCH_TLS_LD_HI20:
62606c3fb27SDimitry Andric   case R_LARCH_TLS_GD_PC_HI20:
62706c3fb27SDimitry Andric   case R_LARCH_TLS_GD_HI20:
62806c3fb27SDimitry Andric     write32le(loc, setJ20(read32le(loc), extractBits(val, 31, 12)));
62906c3fb27SDimitry Andric     return;
63006c3fb27SDimitry Andric 
63106c3fb27SDimitry Andric   // Relocs intended for `lu32i.d`.
63206c3fb27SDimitry Andric   case R_LARCH_ABS64_LO20:
63306c3fb27SDimitry Andric   case R_LARCH_PCALA64_LO20:
63406c3fb27SDimitry Andric   case R_LARCH_GOT64_PC_LO20:
63506c3fb27SDimitry Andric   case R_LARCH_GOT64_LO20:
63606c3fb27SDimitry Andric   case R_LARCH_TLS_LE64_LO20:
63706c3fb27SDimitry Andric   case R_LARCH_TLS_IE64_PC_LO20:
63806c3fb27SDimitry Andric   case R_LARCH_TLS_IE64_LO20:
63906c3fb27SDimitry Andric     write32le(loc, setJ20(read32le(loc), extractBits(val, 51, 32)));
64006c3fb27SDimitry Andric     return;
64106c3fb27SDimitry Andric 
64206c3fb27SDimitry Andric   // Relocs intended for `lu52i.d`.
64306c3fb27SDimitry Andric   case R_LARCH_ABS64_HI12:
64406c3fb27SDimitry Andric   case R_LARCH_PCALA64_HI12:
64506c3fb27SDimitry Andric   case R_LARCH_GOT64_PC_HI12:
64606c3fb27SDimitry Andric   case R_LARCH_GOT64_HI12:
64706c3fb27SDimitry Andric   case R_LARCH_TLS_LE64_HI12:
64806c3fb27SDimitry Andric   case R_LARCH_TLS_IE64_PC_HI12:
64906c3fb27SDimitry Andric   case R_LARCH_TLS_IE64_HI12:
65006c3fb27SDimitry Andric     write32le(loc, setK12(read32le(loc), extractBits(val, 63, 52)));
65106c3fb27SDimitry Andric     return;
65206c3fb27SDimitry Andric 
65306c3fb27SDimitry Andric   case R_LARCH_ADD8:
65406c3fb27SDimitry Andric     *loc += val;
65506c3fb27SDimitry Andric     return;
65606c3fb27SDimitry Andric   case R_LARCH_ADD16:
65706c3fb27SDimitry Andric     write16le(loc, read16le(loc) + val);
65806c3fb27SDimitry Andric     return;
65906c3fb27SDimitry Andric   case R_LARCH_ADD32:
66006c3fb27SDimitry Andric     write32le(loc, read32le(loc) + val);
66106c3fb27SDimitry Andric     return;
66206c3fb27SDimitry Andric   case R_LARCH_ADD64:
66306c3fb27SDimitry Andric     write64le(loc, read64le(loc) + val);
66406c3fb27SDimitry Andric     return;
66506c3fb27SDimitry Andric   case R_LARCH_SUB8:
66606c3fb27SDimitry Andric     *loc -= val;
66706c3fb27SDimitry Andric     return;
66806c3fb27SDimitry Andric   case R_LARCH_SUB16:
66906c3fb27SDimitry Andric     write16le(loc, read16le(loc) - val);
67006c3fb27SDimitry Andric     return;
67106c3fb27SDimitry Andric   case R_LARCH_SUB32:
67206c3fb27SDimitry Andric     write32le(loc, read32le(loc) - val);
67306c3fb27SDimitry Andric     return;
67406c3fb27SDimitry Andric   case R_LARCH_SUB64:
67506c3fb27SDimitry Andric     write64le(loc, read64le(loc) - val);
67606c3fb27SDimitry Andric     return;
67706c3fb27SDimitry Andric 
67806c3fb27SDimitry Andric   case R_LARCH_MARK_LA:
67906c3fb27SDimitry Andric   case R_LARCH_MARK_PCREL:
68006c3fb27SDimitry Andric     // no-op
68106c3fb27SDimitry Andric     return;
68206c3fb27SDimitry Andric 
68306c3fb27SDimitry Andric   case R_LARCH_RELAX:
68406c3fb27SDimitry Andric     return; // Ignored (for now)
68506c3fb27SDimitry Andric 
68606c3fb27SDimitry Andric   default:
68706c3fb27SDimitry Andric     llvm_unreachable("unknown relocation");
68806c3fb27SDimitry Andric   }
68906c3fb27SDimitry Andric }
69006c3fb27SDimitry Andric 
69106c3fb27SDimitry Andric TargetInfo *elf::getLoongArchTargetInfo() {
69206c3fb27SDimitry Andric   static LoongArch target;
69306c3fb27SDimitry Andric   return &target;
69406c3fb27SDimitry Andric }
695