10b57cec5SDimitry Andric //===- MIPS.cpp -----------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "InputFiles.h"
100b57cec5SDimitry Andric #include "OutputSections.h"
110b57cec5SDimitry Andric #include "Symbols.h"
120b57cec5SDimitry Andric #include "SyntheticSections.h"
130b57cec5SDimitry Andric #include "Target.h"
140b57cec5SDimitry Andric #include "lld/Common/ErrorHandler.h"
1581ad6265SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric using namespace llvm;
180b57cec5SDimitry Andric using namespace llvm::object;
190b57cec5SDimitry Andric using namespace llvm::ELF;
205ffd83dbSDimitry Andric using namespace lld;
215ffd83dbSDimitry Andric using namespace lld::elf;
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric namespace {
240b57cec5SDimitry Andric template <class ELFT> class MIPS final : public TargetInfo {
250b57cec5SDimitry Andric public:
260b57cec5SDimitry Andric   MIPS();
270b57cec5SDimitry Andric   uint32_t calcEFlags() const override;
280b57cec5SDimitry Andric   RelExpr getRelExpr(RelType type, const Symbol &s,
290b57cec5SDimitry Andric                      const uint8_t *loc) const override;
300b57cec5SDimitry Andric   int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override;
310b57cec5SDimitry Andric   RelType getDynRel(RelType type) const override;
320b57cec5SDimitry Andric   void writeGotPlt(uint8_t *buf, const Symbol &s) const override;
330b57cec5SDimitry Andric   void writePltHeader(uint8_t *buf) const override;
34480093f4SDimitry Andric   void writePlt(uint8_t *buf, const Symbol &sym,
35480093f4SDimitry Andric                 uint64_t pltEntryAddr) const override;
360b57cec5SDimitry Andric   bool needsThunk(RelExpr expr, RelType type, const InputFile *file,
37480093f4SDimitry Andric                   uint64_t branchAddr, const Symbol &s,
38480093f4SDimitry Andric                   int64_t a) const override;
395ffd83dbSDimitry Andric   void relocate(uint8_t *loc, const Relocation &rel,
405ffd83dbSDimitry Andric                 uint64_t val) const override;
410b57cec5SDimitry Andric   bool usesOnlyLowPageBits(RelType type) const override;
420b57cec5SDimitry Andric };
430b57cec5SDimitry Andric } // namespace
440b57cec5SDimitry Andric 
MIPS()450b57cec5SDimitry Andric template <class ELFT> MIPS<ELFT>::MIPS() {
460b57cec5SDimitry Andric   gotPltHeaderEntriesNum = 2;
470b57cec5SDimitry Andric   defaultMaxPageSize = 65536;
480b57cec5SDimitry Andric   pltEntrySize = 16;
490b57cec5SDimitry Andric   pltHeaderSize = 32;
500b57cec5SDimitry Andric   copyRel = R_MIPS_COPY;
510b57cec5SDimitry Andric   pltRel = R_MIPS_JUMP_SLOT;
520b57cec5SDimitry Andric   needsThunks = true;
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   // Set `sigrie 1` as a trap instruction.
550b57cec5SDimitry Andric   write32(trapInstr.data(), 0x04170001);
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric   if (ELFT::Is64Bits) {
580b57cec5SDimitry Andric     relativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32;
590b57cec5SDimitry Andric     symbolicRel = R_MIPS_64;
600b57cec5SDimitry Andric     tlsGotRel = R_MIPS_TLS_TPREL64;
610b57cec5SDimitry Andric     tlsModuleIndexRel = R_MIPS_TLS_DTPMOD64;
620b57cec5SDimitry Andric     tlsOffsetRel = R_MIPS_TLS_DTPREL64;
630b57cec5SDimitry Andric   } else {
640b57cec5SDimitry Andric     relativeRel = R_MIPS_REL32;
650b57cec5SDimitry Andric     symbolicRel = R_MIPS_32;
660b57cec5SDimitry Andric     tlsGotRel = R_MIPS_TLS_TPREL32;
670b57cec5SDimitry Andric     tlsModuleIndexRel = R_MIPS_TLS_DTPMOD32;
680b57cec5SDimitry Andric     tlsOffsetRel = R_MIPS_TLS_DTPREL32;
690b57cec5SDimitry Andric   }
700b57cec5SDimitry Andric }
710b57cec5SDimitry Andric 
calcEFlags() const720b57cec5SDimitry Andric template <class ELFT> uint32_t MIPS<ELFT>::calcEFlags() const {
730b57cec5SDimitry Andric   return calcMipsEFlags<ELFT>();
740b57cec5SDimitry Andric }
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric template <class ELFT>
getRelExpr(RelType type,const Symbol & s,const uint8_t * loc) const770b57cec5SDimitry Andric RelExpr MIPS<ELFT>::getRelExpr(RelType type, const Symbol &s,
780b57cec5SDimitry Andric                                const uint8_t *loc) const {
790b57cec5SDimitry Andric   // See comment in the calculateMipsRelChain.
800b57cec5SDimitry Andric   if (ELFT::Is64Bits || config->mipsN32Abi)
810b57cec5SDimitry Andric     type &= 0xff;
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric   switch (type) {
840b57cec5SDimitry Andric   case R_MIPS_JALR:
85480093f4SDimitry Andric     // Older versions of clang would erroneously emit this relocation not only
86480093f4SDimitry Andric     // against functions (loaded from the GOT) but also against data symbols
87480093f4SDimitry Andric     // (e.g. a table of function pointers). When we encounter this, ignore the
88480093f4SDimitry Andric     // relocation and emit a warning instead.
89480093f4SDimitry Andric     if (!s.isFunc() && s.type != STT_NOTYPE) {
90480093f4SDimitry Andric       warn(getErrorLocation(loc) +
91480093f4SDimitry Andric            "found R_MIPS_JALR relocation against non-function symbol " +
92480093f4SDimitry Andric            toString(s) + ". This is invalid and most likely a compiler bug.");
93480093f4SDimitry Andric       return R_NONE;
94480093f4SDimitry Andric     }
95480093f4SDimitry Andric 
9685868e8aSDimitry Andric     // If the target symbol is not preemptible and is not microMIPS,
9785868e8aSDimitry Andric     // it might be possible to replace jalr/jr instruction by bal/b.
9885868e8aSDimitry Andric     // It depends on the target symbol's offset.
9985868e8aSDimitry Andric     if (!s.isPreemptible && !(s.getVA() & 0x1))
10085868e8aSDimitry Andric       return R_PC;
10185868e8aSDimitry Andric     return R_NONE;
1020b57cec5SDimitry Andric   case R_MICROMIPS_JALR:
10385868e8aSDimitry Andric     return R_NONE;
1040b57cec5SDimitry Andric   case R_MIPS_GPREL16:
1050b57cec5SDimitry Andric   case R_MIPS_GPREL32:
1060b57cec5SDimitry Andric   case R_MICROMIPS_GPREL16:
1070b57cec5SDimitry Andric   case R_MICROMIPS_GPREL7_S2:
1080b57cec5SDimitry Andric     return R_MIPS_GOTREL;
1090b57cec5SDimitry Andric   case R_MIPS_26:
1100b57cec5SDimitry Andric   case R_MICROMIPS_26_S1:
1110b57cec5SDimitry Andric     return R_PLT;
1120b57cec5SDimitry Andric   case R_MICROMIPS_PC26_S1:
1130b57cec5SDimitry Andric     return R_PLT_PC;
1140b57cec5SDimitry Andric   case R_MIPS_HI16:
1150b57cec5SDimitry Andric   case R_MIPS_LO16:
1160b57cec5SDimitry Andric   case R_MIPS_HIGHER:
1170b57cec5SDimitry Andric   case R_MIPS_HIGHEST:
1180b57cec5SDimitry Andric   case R_MICROMIPS_HI16:
1190b57cec5SDimitry Andric   case R_MICROMIPS_LO16:
1200b57cec5SDimitry Andric     // R_MIPS_HI16/R_MIPS_LO16 relocations against _gp_disp calculate
1210b57cec5SDimitry Andric     // offset between start of function and 'gp' value which by default
1220b57cec5SDimitry Andric     // equal to the start of .got section. In that case we consider these
1230b57cec5SDimitry Andric     // relocations as relative.
1240b57cec5SDimitry Andric     if (&s == ElfSym::mipsGpDisp)
1250b57cec5SDimitry Andric       return R_MIPS_GOT_GP_PC;
1260b57cec5SDimitry Andric     if (&s == ElfSym::mipsLocalGp)
1270b57cec5SDimitry Andric       return R_MIPS_GOT_GP;
128bdd1243dSDimitry Andric     [[fallthrough]];
1290b57cec5SDimitry Andric   case R_MIPS_32:
1300b57cec5SDimitry Andric   case R_MIPS_64:
1310b57cec5SDimitry Andric   case R_MIPS_GOT_OFST:
1320b57cec5SDimitry Andric   case R_MIPS_SUB:
133349cc55cSDimitry Andric     return R_ABS;
1340b57cec5SDimitry Andric   case R_MIPS_TLS_DTPREL_HI16:
1350b57cec5SDimitry Andric   case R_MIPS_TLS_DTPREL_LO16:
1360b57cec5SDimitry Andric   case R_MIPS_TLS_DTPREL32:
1370b57cec5SDimitry Andric   case R_MIPS_TLS_DTPREL64:
13885868e8aSDimitry Andric   case R_MICROMIPS_TLS_DTPREL_HI16:
13985868e8aSDimitry Andric   case R_MICROMIPS_TLS_DTPREL_LO16:
140349cc55cSDimitry Andric     return R_DTPREL;
1410b57cec5SDimitry Andric   case R_MIPS_TLS_TPREL_HI16:
1420b57cec5SDimitry Andric   case R_MIPS_TLS_TPREL_LO16:
1430b57cec5SDimitry Andric   case R_MIPS_TLS_TPREL32:
1440b57cec5SDimitry Andric   case R_MIPS_TLS_TPREL64:
1450b57cec5SDimitry Andric   case R_MICROMIPS_TLS_TPREL_HI16:
1460b57cec5SDimitry Andric   case R_MICROMIPS_TLS_TPREL_LO16:
147e8d8bef9SDimitry Andric     return R_TPREL;
1480b57cec5SDimitry Andric   case R_MIPS_PC32:
1490b57cec5SDimitry Andric   case R_MIPS_PC16:
1500b57cec5SDimitry Andric   case R_MIPS_PC19_S2:
1510b57cec5SDimitry Andric   case R_MIPS_PC21_S2:
1520b57cec5SDimitry Andric   case R_MIPS_PC26_S2:
1530b57cec5SDimitry Andric   case R_MIPS_PCHI16:
1540b57cec5SDimitry Andric   case R_MIPS_PCLO16:
1550b57cec5SDimitry Andric   case R_MICROMIPS_PC7_S1:
1560b57cec5SDimitry Andric   case R_MICROMIPS_PC10_S1:
1570b57cec5SDimitry Andric   case R_MICROMIPS_PC16_S1:
1580b57cec5SDimitry Andric   case R_MICROMIPS_PC18_S3:
1590b57cec5SDimitry Andric   case R_MICROMIPS_PC19_S2:
1600b57cec5SDimitry Andric   case R_MICROMIPS_PC23_S2:
1610b57cec5SDimitry Andric   case R_MICROMIPS_PC21_S1:
1620b57cec5SDimitry Andric     return R_PC;
1630b57cec5SDimitry Andric   case R_MIPS_GOT16:
1640b57cec5SDimitry Andric   case R_MICROMIPS_GOT16:
1650b57cec5SDimitry Andric     if (s.isLocal())
1660b57cec5SDimitry Andric       return R_MIPS_GOT_LOCAL_PAGE;
167bdd1243dSDimitry Andric     [[fallthrough]];
1680b57cec5SDimitry Andric   case R_MIPS_CALL16:
1690b57cec5SDimitry Andric   case R_MIPS_GOT_DISP:
1700b57cec5SDimitry Andric   case R_MIPS_TLS_GOTTPREL:
1710b57cec5SDimitry Andric   case R_MICROMIPS_CALL16:
1720b57cec5SDimitry Andric   case R_MICROMIPS_TLS_GOTTPREL:
1730b57cec5SDimitry Andric     return R_MIPS_GOT_OFF;
1740b57cec5SDimitry Andric   case R_MIPS_CALL_HI16:
1750b57cec5SDimitry Andric   case R_MIPS_CALL_LO16:
1760b57cec5SDimitry Andric   case R_MIPS_GOT_HI16:
1770b57cec5SDimitry Andric   case R_MIPS_GOT_LO16:
1780b57cec5SDimitry Andric   case R_MICROMIPS_CALL_HI16:
1790b57cec5SDimitry Andric   case R_MICROMIPS_CALL_LO16:
1800b57cec5SDimitry Andric   case R_MICROMIPS_GOT_HI16:
1810b57cec5SDimitry Andric   case R_MICROMIPS_GOT_LO16:
1820b57cec5SDimitry Andric     return R_MIPS_GOT_OFF32;
1830b57cec5SDimitry Andric   case R_MIPS_GOT_PAGE:
1840b57cec5SDimitry Andric     return R_MIPS_GOT_LOCAL_PAGE;
1850b57cec5SDimitry Andric   case R_MIPS_TLS_GD:
1860b57cec5SDimitry Andric   case R_MICROMIPS_TLS_GD:
1870b57cec5SDimitry Andric     return R_MIPS_TLSGD;
1880b57cec5SDimitry Andric   case R_MIPS_TLS_LDM:
1890b57cec5SDimitry Andric   case R_MICROMIPS_TLS_LDM:
1900b57cec5SDimitry Andric     return R_MIPS_TLSLD;
1910b57cec5SDimitry Andric   case R_MIPS_NONE:
1920b57cec5SDimitry Andric     return R_NONE;
1930b57cec5SDimitry Andric   default:
1940b57cec5SDimitry Andric     error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
1950b57cec5SDimitry Andric           ") against symbol " + toString(s));
1960b57cec5SDimitry Andric     return R_NONE;
1970b57cec5SDimitry Andric   }
1980b57cec5SDimitry Andric }
1990b57cec5SDimitry Andric 
getDynRel(RelType type) const2000b57cec5SDimitry Andric template <class ELFT> RelType MIPS<ELFT>::getDynRel(RelType type) const {
2010b57cec5SDimitry Andric   if (type == symbolicRel)
2020b57cec5SDimitry Andric     return type;
2030b57cec5SDimitry Andric   return R_MIPS_NONE;
2040b57cec5SDimitry Andric }
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric template <class ELFT>
writeGotPlt(uint8_t * buf,const Symbol &) const2070b57cec5SDimitry Andric void MIPS<ELFT>::writeGotPlt(uint8_t *buf, const Symbol &) const {
2080b57cec5SDimitry Andric   uint64_t va = in.plt->getVA();
2090b57cec5SDimitry Andric   if (isMicroMips())
2100b57cec5SDimitry Andric     va |= 1;
21185868e8aSDimitry Andric   write32(buf, va);
2120b57cec5SDimitry Andric }
2130b57cec5SDimitry Andric 
readShuffle(const uint8_t * loc)2140b57cec5SDimitry Andric template <endianness E> static uint32_t readShuffle(const uint8_t *loc) {
2150b57cec5SDimitry Andric   // The major opcode of a microMIPS instruction needs to appear
2160b57cec5SDimitry Andric   // in the first 16-bit word (lowest address) for efficient hardware
2170b57cec5SDimitry Andric   // decode so that it knows if the instruction is 16-bit or 32-bit
2180b57cec5SDimitry Andric   // as early as possible. To do so, little-endian binaries keep 16-bit
2190b57cec5SDimitry Andric   // words in a big-endian order. That is why we have to swap these
2200b57cec5SDimitry Andric   // words to get a correct value.
22185868e8aSDimitry Andric   uint32_t v = read32(loc);
2225f757f3fSDimitry Andric   if (E == llvm::endianness::little)
2230b57cec5SDimitry Andric     return (v << 16) | (v >> 16);
2240b57cec5SDimitry Andric   return v;
2250b57cec5SDimitry Andric }
2260b57cec5SDimitry Andric 
writeValue(uint8_t * loc,uint64_t v,uint8_t bitsSize,uint8_t shift)2270b57cec5SDimitry Andric static void writeValue(uint8_t *loc, uint64_t v, uint8_t bitsSize,
2280b57cec5SDimitry Andric                        uint8_t shift) {
22985868e8aSDimitry Andric   uint32_t instr = read32(loc);
2300b57cec5SDimitry Andric   uint32_t mask = 0xffffffff >> (32 - bitsSize);
2310b57cec5SDimitry Andric   uint32_t data = (instr & ~mask) | ((v >> shift) & mask);
23285868e8aSDimitry Andric   write32(loc, data);
2330b57cec5SDimitry Andric }
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric template <endianness E>
writeShuffleValue(uint8_t * loc,uint64_t v,uint8_t bitsSize,uint8_t shift)2360b57cec5SDimitry Andric static void writeShuffleValue(uint8_t *loc, uint64_t v, uint8_t bitsSize,
2370b57cec5SDimitry Andric                               uint8_t shift) {
2380b57cec5SDimitry Andric   // See comments in readShuffle for purpose of this code.
2390b57cec5SDimitry Andric   uint16_t *words = (uint16_t *)loc;
2405f757f3fSDimitry Andric   if (E == llvm::endianness::little)
2410b57cec5SDimitry Andric     std::swap(words[0], words[1]);
2420b57cec5SDimitry Andric 
24385868e8aSDimitry Andric   writeValue(loc, v, bitsSize, shift);
2440b57cec5SDimitry Andric 
2455f757f3fSDimitry Andric   if (E == llvm::endianness::little)
2460b57cec5SDimitry Andric     std::swap(words[0], words[1]);
2470b57cec5SDimitry Andric }
2480b57cec5SDimitry Andric 
2490b57cec5SDimitry Andric template <endianness E>
writeMicroRelocation16(uint8_t * loc,uint64_t v,uint8_t bitsSize,uint8_t shift)2500b57cec5SDimitry Andric static void writeMicroRelocation16(uint8_t *loc, uint64_t v, uint8_t bitsSize,
2510b57cec5SDimitry Andric                                    uint8_t shift) {
25285868e8aSDimitry Andric   uint16_t instr = read16(loc);
2530b57cec5SDimitry Andric   uint16_t mask = 0xffff >> (16 - bitsSize);
2540b57cec5SDimitry Andric   uint16_t data = (instr & ~mask) | ((v >> shift) & mask);
25585868e8aSDimitry Andric   write16(loc, data);
2560b57cec5SDimitry Andric }
2570b57cec5SDimitry Andric 
writePltHeader(uint8_t * buf) const2580b57cec5SDimitry Andric template <class ELFT> void MIPS<ELFT>::writePltHeader(uint8_t *buf) const {
2590b57cec5SDimitry Andric   if (isMicroMips()) {
2600b57cec5SDimitry Andric     uint64_t gotPlt = in.gotPlt->getVA();
2610b57cec5SDimitry Andric     uint64_t plt = in.plt->getVA();
2620b57cec5SDimitry Andric     // Overwrite trap instructions written by Writer::writeTrapInstr.
2630b57cec5SDimitry Andric     memset(buf, 0, pltHeaderSize);
2640b57cec5SDimitry Andric 
26585868e8aSDimitry Andric     write16(buf, isMipsR6() ? 0x7860 : 0x7980);  // addiupc v1, (GOTPLT) - .
26685868e8aSDimitry Andric     write16(buf + 4, 0xff23);    // lw      $25, 0($3)
26785868e8aSDimitry Andric     write16(buf + 8, 0x0535);    // subu16  $2,  $2, $3
26885868e8aSDimitry Andric     write16(buf + 10, 0x2525);   // srl16   $2,  $2, 2
26985868e8aSDimitry Andric     write16(buf + 12, 0x3302);   // addiu   $24, $2, -2
27085868e8aSDimitry Andric     write16(buf + 14, 0xfffe);
27185868e8aSDimitry Andric     write16(buf + 16, 0x0dff);   // move    $15, $31
2720b57cec5SDimitry Andric     if (isMipsR6()) {
27385868e8aSDimitry Andric       write16(buf + 18, 0x0f83); // move    $28, $3
27485868e8aSDimitry Andric       write16(buf + 20, 0x472b); // jalrc   $25
27585868e8aSDimitry Andric       write16(buf + 22, 0x0c00); // nop
2765ffd83dbSDimitry Andric       relocateNoSym(buf, R_MICROMIPS_PC19_S2, gotPlt - plt);
2770b57cec5SDimitry Andric     } else {
27885868e8aSDimitry Andric       write16(buf + 18, 0x45f9); // jalrc   $25
27985868e8aSDimitry Andric       write16(buf + 20, 0x0f83); // move    $28, $3
28085868e8aSDimitry Andric       write16(buf + 22, 0x0c00); // nop
2815ffd83dbSDimitry Andric       relocateNoSym(buf, R_MICROMIPS_PC23_S2, gotPlt - plt);
2820b57cec5SDimitry Andric     }
2830b57cec5SDimitry Andric     return;
2840b57cec5SDimitry Andric   }
2850b57cec5SDimitry Andric 
2860b57cec5SDimitry Andric   if (config->mipsN32Abi) {
28785868e8aSDimitry Andric     write32(buf, 0x3c0e0000);      // lui   $14, %hi(&GOTPLT[0])
28885868e8aSDimitry Andric     write32(buf + 4, 0x8dd90000);  // lw    $25, %lo(&GOTPLT[0])($14)
28985868e8aSDimitry Andric     write32(buf + 8, 0x25ce0000);  // addiu $14, $14, %lo(&GOTPLT[0])
29085868e8aSDimitry Andric     write32(buf + 12, 0x030ec023); // subu  $24, $24, $14
29185868e8aSDimitry Andric     write32(buf + 16, 0x03e07825); // move  $15, $31
29285868e8aSDimitry Andric     write32(buf + 20, 0x0018c082); // srl   $24, $24, 2
2930b57cec5SDimitry Andric   } else if (ELFT::Is64Bits) {
29485868e8aSDimitry Andric     write32(buf, 0x3c0e0000);      // lui   $14, %hi(&GOTPLT[0])
29585868e8aSDimitry Andric     write32(buf + 4, 0xddd90000);  // ld    $25, %lo(&GOTPLT[0])($14)
29685868e8aSDimitry Andric     write32(buf + 8, 0x25ce0000);  // addiu $14, $14, %lo(&GOTPLT[0])
29785868e8aSDimitry Andric     write32(buf + 12, 0x030ec023); // subu  $24, $24, $14
29885868e8aSDimitry Andric     write32(buf + 16, 0x03e07825); // move  $15, $31
29985868e8aSDimitry Andric     write32(buf + 20, 0x0018c0c2); // srl   $24, $24, 3
3000b57cec5SDimitry Andric   } else {
30185868e8aSDimitry Andric     write32(buf, 0x3c1c0000);      // lui   $28, %hi(&GOTPLT[0])
30285868e8aSDimitry Andric     write32(buf + 4, 0x8f990000);  // lw    $25, %lo(&GOTPLT[0])($28)
30385868e8aSDimitry Andric     write32(buf + 8, 0x279c0000);  // addiu $28, $28, %lo(&GOTPLT[0])
30485868e8aSDimitry Andric     write32(buf + 12, 0x031cc023); // subu  $24, $24, $28
30585868e8aSDimitry Andric     write32(buf + 16, 0x03e07825); // move  $15, $31
30685868e8aSDimitry Andric     write32(buf + 20, 0x0018c082); // srl   $24, $24, 2
3070b57cec5SDimitry Andric   }
3080b57cec5SDimitry Andric 
3090b57cec5SDimitry Andric   uint32_t jalrInst = config->zHazardplt ? 0x0320fc09 : 0x0320f809;
31085868e8aSDimitry Andric   write32(buf + 24, jalrInst); // jalr.hb $25 or jalr $25
31185868e8aSDimitry Andric   write32(buf + 28, 0x2718fffe); // subu  $24, $24, 2
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric   uint64_t gotPlt = in.gotPlt->getVA();
31485868e8aSDimitry Andric   writeValue(buf, gotPlt + 0x8000, 16, 16);
31585868e8aSDimitry Andric   writeValue(buf + 4, gotPlt, 16, 0);
31685868e8aSDimitry Andric   writeValue(buf + 8, gotPlt, 16, 0);
3170b57cec5SDimitry Andric }
3180b57cec5SDimitry Andric 
3190b57cec5SDimitry Andric template <class ELFT>
writePlt(uint8_t * buf,const Symbol & sym,uint64_t pltEntryAddr) const320480093f4SDimitry Andric void MIPS<ELFT>::writePlt(uint8_t *buf, const Symbol &sym,
321480093f4SDimitry Andric                           uint64_t pltEntryAddr) const {
322480093f4SDimitry Andric   uint64_t gotPltEntryAddr = sym.getGotPltVA();
3230b57cec5SDimitry Andric   if (isMicroMips()) {
3240b57cec5SDimitry Andric     // Overwrite trap instructions written by Writer::writeTrapInstr.
3250b57cec5SDimitry Andric     memset(buf, 0, pltEntrySize);
3260b57cec5SDimitry Andric 
3270b57cec5SDimitry Andric     if (isMipsR6()) {
32885868e8aSDimitry Andric       write16(buf, 0x7840);      // addiupc $2, (GOTPLT) - .
32985868e8aSDimitry Andric       write16(buf + 4, 0xff22);  // lw $25, 0($2)
33085868e8aSDimitry Andric       write16(buf + 8, 0x0f02);  // move $24, $2
33185868e8aSDimitry Andric       write16(buf + 10, 0x4723); // jrc $25 / jr16 $25
3325ffd83dbSDimitry Andric       relocateNoSym(buf, R_MICROMIPS_PC19_S2, gotPltEntryAddr - pltEntryAddr);
3330b57cec5SDimitry Andric     } else {
33485868e8aSDimitry Andric       write16(buf, 0x7900);      // addiupc $2, (GOTPLT) - .
33585868e8aSDimitry Andric       write16(buf + 4, 0xff22);  // lw $25, 0($2)
33685868e8aSDimitry Andric       write16(buf + 8, 0x4599);  // jrc $25 / jr16 $25
33785868e8aSDimitry Andric       write16(buf + 10, 0x0f02); // move $24, $2
3385ffd83dbSDimitry Andric       relocateNoSym(buf, R_MICROMIPS_PC23_S2, gotPltEntryAddr - pltEntryAddr);
3390b57cec5SDimitry Andric     }
3400b57cec5SDimitry Andric     return;
3410b57cec5SDimitry Andric   }
3420b57cec5SDimitry Andric 
3430b57cec5SDimitry Andric   uint32_t loadInst = ELFT::Is64Bits ? 0xddf90000 : 0x8df90000;
3440b57cec5SDimitry Andric   uint32_t jrInst = isMipsR6() ? (config->zHazardplt ? 0x03200409 : 0x03200009)
3450b57cec5SDimitry Andric                                : (config->zHazardplt ? 0x03200408 : 0x03200008);
3460b57cec5SDimitry Andric   uint32_t addInst = ELFT::Is64Bits ? 0x65f80000 : 0x25f80000;
3470b57cec5SDimitry Andric 
34885868e8aSDimitry Andric   write32(buf, 0x3c0f0000);     // lui   $15, %hi(.got.plt entry)
34985868e8aSDimitry Andric   write32(buf + 4, loadInst);   // l[wd] $25, %lo(.got.plt entry)($15)
35085868e8aSDimitry Andric   write32(buf + 8, jrInst);     // jr  $25 / jr.hb $25
35185868e8aSDimitry Andric   write32(buf + 12, addInst);   // [d]addiu $24, $15, %lo(.got.plt entry)
35285868e8aSDimitry Andric   writeValue(buf, gotPltEntryAddr + 0x8000, 16, 16);
35385868e8aSDimitry Andric   writeValue(buf + 4, gotPltEntryAddr, 16, 0);
35485868e8aSDimitry Andric   writeValue(buf + 12, gotPltEntryAddr, 16, 0);
3550b57cec5SDimitry Andric }
3560b57cec5SDimitry Andric 
3570b57cec5SDimitry Andric template <class ELFT>
needsThunk(RelExpr expr,RelType type,const InputFile * file,uint64_t branchAddr,const Symbol & s,int64_t) const3580b57cec5SDimitry Andric bool MIPS<ELFT>::needsThunk(RelExpr expr, RelType type, const InputFile *file,
359480093f4SDimitry Andric                             uint64_t branchAddr, const Symbol &s,
360480093f4SDimitry Andric                             int64_t /*a*/) const {
3610b57cec5SDimitry Andric   // Any MIPS PIC code function is invoked with its address in register $t9.
3620b57cec5SDimitry Andric   // So if we have a branch instruction from non-PIC code to the PIC one
3630b57cec5SDimitry Andric   // we cannot make the jump directly and need to create a small stubs
3640b57cec5SDimitry Andric   // to save the target function address.
3650b57cec5SDimitry Andric   // See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
3660b57cec5SDimitry Andric   if (type != R_MIPS_26 && type != R_MIPS_PC26_S2 &&
3670b57cec5SDimitry Andric       type != R_MICROMIPS_26_S1 && type != R_MICROMIPS_PC26_S1)
3680b57cec5SDimitry Andric     return false;
3690b57cec5SDimitry Andric   auto *f = dyn_cast_or_null<ObjFile<ELFT>>(file);
3700b57cec5SDimitry Andric   if (!f)
3710b57cec5SDimitry Andric     return false;
3720b57cec5SDimitry Andric   // If current file has PIC code, LA25 stub is not required.
373e8d8bef9SDimitry Andric   if (f->getObj().getHeader().e_flags & EF_MIPS_PIC)
3740b57cec5SDimitry Andric     return false;
3750b57cec5SDimitry Andric   auto *d = dyn_cast<Defined>(&s);
3760b57cec5SDimitry Andric   // LA25 is required if target file has PIC code
3770b57cec5SDimitry Andric   // or target symbol is a PIC symbol.
3780b57cec5SDimitry Andric   return d && isMipsPIC<ELFT>(d);
3790b57cec5SDimitry Andric }
3800b57cec5SDimitry Andric 
3810b57cec5SDimitry Andric template <class ELFT>
getImplicitAddend(const uint8_t * buf,RelType type) const3820b57cec5SDimitry Andric int64_t MIPS<ELFT>::getImplicitAddend(const uint8_t *buf, RelType type) const {
3830b57cec5SDimitry Andric   const endianness e = ELFT::TargetEndianness;
3840b57cec5SDimitry Andric   switch (type) {
3850b57cec5SDimitry Andric   case R_MIPS_32:
386fe6060f1SDimitry Andric   case R_MIPS_REL32:
3870b57cec5SDimitry Andric   case R_MIPS_GPREL32:
3880b57cec5SDimitry Andric   case R_MIPS_TLS_DTPREL32:
389fe6060f1SDimitry Andric   case R_MIPS_TLS_DTPMOD32:
3900b57cec5SDimitry Andric   case R_MIPS_TLS_TPREL32:
39185868e8aSDimitry Andric     return SignExtend64<32>(read32(buf));
3920b57cec5SDimitry Andric   case R_MIPS_26:
3930b57cec5SDimitry Andric     // FIXME (simon): If the relocation target symbol is not a PLT entry
3940b57cec5SDimitry Andric     // we should use another expression for calculation:
3950b57cec5SDimitry Andric     // ((A << 2) | (P & 0xf0000000)) >> 2
39685868e8aSDimitry Andric     return SignExtend64<28>(read32(buf) << 2);
397fe6060f1SDimitry Andric   case R_MIPS_CALL_HI16:
3980b57cec5SDimitry Andric   case R_MIPS_GOT16:
399fe6060f1SDimitry Andric   case R_MIPS_GOT_HI16:
4000b57cec5SDimitry Andric   case R_MIPS_HI16:
4010b57cec5SDimitry Andric   case R_MIPS_PCHI16:
40285868e8aSDimitry Andric     return SignExtend64<16>(read32(buf)) << 16;
403fe6060f1SDimitry Andric   case R_MIPS_CALL16:
404fe6060f1SDimitry Andric   case R_MIPS_CALL_LO16:
405fe6060f1SDimitry Andric   case R_MIPS_GOT_LO16:
4060b57cec5SDimitry Andric   case R_MIPS_GPREL16:
4070b57cec5SDimitry Andric   case R_MIPS_LO16:
4080b57cec5SDimitry Andric   case R_MIPS_PCLO16:
4090b57cec5SDimitry Andric   case R_MIPS_TLS_DTPREL_HI16:
4100b57cec5SDimitry Andric   case R_MIPS_TLS_DTPREL_LO16:
411fe6060f1SDimitry Andric   case R_MIPS_TLS_GD:
412fe6060f1SDimitry Andric   case R_MIPS_TLS_GOTTPREL:
413fe6060f1SDimitry Andric   case R_MIPS_TLS_LDM:
4140b57cec5SDimitry Andric   case R_MIPS_TLS_TPREL_HI16:
4150b57cec5SDimitry Andric   case R_MIPS_TLS_TPREL_LO16:
41685868e8aSDimitry Andric     return SignExtend64<16>(read32(buf));
4170b57cec5SDimitry Andric   case R_MICROMIPS_GOT16:
4180b57cec5SDimitry Andric   case R_MICROMIPS_HI16:
4190b57cec5SDimitry Andric     return SignExtend64<16>(readShuffle<e>(buf)) << 16;
420fe6060f1SDimitry Andric   case R_MICROMIPS_CALL16:
4210b57cec5SDimitry Andric   case R_MICROMIPS_GPREL16:
4220b57cec5SDimitry Andric   case R_MICROMIPS_LO16:
4230b57cec5SDimitry Andric   case R_MICROMIPS_TLS_DTPREL_HI16:
4240b57cec5SDimitry Andric   case R_MICROMIPS_TLS_DTPREL_LO16:
425fe6060f1SDimitry Andric   case R_MICROMIPS_TLS_GD:
426fe6060f1SDimitry Andric   case R_MICROMIPS_TLS_GOTTPREL:
427fe6060f1SDimitry Andric   case R_MICROMIPS_TLS_LDM:
4280b57cec5SDimitry Andric   case R_MICROMIPS_TLS_TPREL_HI16:
4290b57cec5SDimitry Andric   case R_MICROMIPS_TLS_TPREL_LO16:
4300b57cec5SDimitry Andric     return SignExtend64<16>(readShuffle<e>(buf));
4310b57cec5SDimitry Andric   case R_MICROMIPS_GPREL7_S2:
4320b57cec5SDimitry Andric     return SignExtend64<9>(readShuffle<e>(buf) << 2);
4330b57cec5SDimitry Andric   case R_MIPS_PC16:
43485868e8aSDimitry Andric     return SignExtend64<18>(read32(buf) << 2);
4350b57cec5SDimitry Andric   case R_MIPS_PC19_S2:
43685868e8aSDimitry Andric     return SignExtend64<21>(read32(buf) << 2);
4370b57cec5SDimitry Andric   case R_MIPS_PC21_S2:
43885868e8aSDimitry Andric     return SignExtend64<23>(read32(buf) << 2);
4390b57cec5SDimitry Andric   case R_MIPS_PC26_S2:
44085868e8aSDimitry Andric     return SignExtend64<28>(read32(buf) << 2);
4410b57cec5SDimitry Andric   case R_MIPS_PC32:
44285868e8aSDimitry Andric     return SignExtend64<32>(read32(buf));
4430b57cec5SDimitry Andric   case R_MICROMIPS_26_S1:
4440b57cec5SDimitry Andric     return SignExtend64<27>(readShuffle<e>(buf) << 1);
4450b57cec5SDimitry Andric   case R_MICROMIPS_PC7_S1:
44685868e8aSDimitry Andric     return SignExtend64<8>(read16(buf) << 1);
4470b57cec5SDimitry Andric   case R_MICROMIPS_PC10_S1:
44885868e8aSDimitry Andric     return SignExtend64<11>(read16(buf) << 1);
4490b57cec5SDimitry Andric   case R_MICROMIPS_PC16_S1:
4500b57cec5SDimitry Andric     return SignExtend64<17>(readShuffle<e>(buf) << 1);
4510b57cec5SDimitry Andric   case R_MICROMIPS_PC18_S3:
4520b57cec5SDimitry Andric     return SignExtend64<21>(readShuffle<e>(buf) << 3);
4530b57cec5SDimitry Andric   case R_MICROMIPS_PC19_S2:
4540b57cec5SDimitry Andric     return SignExtend64<21>(readShuffle<e>(buf) << 2);
4550b57cec5SDimitry Andric   case R_MICROMIPS_PC21_S1:
4560b57cec5SDimitry Andric     return SignExtend64<22>(readShuffle<e>(buf) << 1);
4570b57cec5SDimitry Andric   case R_MICROMIPS_PC23_S2:
4580b57cec5SDimitry Andric     return SignExtend64<25>(readShuffle<e>(buf) << 2);
4590b57cec5SDimitry Andric   case R_MICROMIPS_PC26_S1:
4600b57cec5SDimitry Andric     return SignExtend64<27>(readShuffle<e>(buf) << 1);
461fe6060f1SDimitry Andric   case R_MIPS_64:
462fe6060f1SDimitry Andric   case R_MIPS_TLS_DTPMOD64:
463fe6060f1SDimitry Andric   case R_MIPS_TLS_DTPREL64:
464fe6060f1SDimitry Andric   case R_MIPS_TLS_TPREL64:
465fe6060f1SDimitry Andric   case (R_MIPS_64 << 8) | R_MIPS_REL32:
466fe6060f1SDimitry Andric     return read64(buf);
467fe6060f1SDimitry Andric   case R_MIPS_COPY:
468fe6060f1SDimitry Andric     return config->is64 ? read64(buf) : read32(buf);
469fe6060f1SDimitry Andric   case R_MIPS_NONE:
470fe6060f1SDimitry Andric   case R_MIPS_JUMP_SLOT:
471fe6060f1SDimitry Andric   case R_MIPS_JALR:
472fe6060f1SDimitry Andric     // These relocations are defined as not having an implicit addend.
473fe6060f1SDimitry Andric     return 0;
4740b57cec5SDimitry Andric   default:
475fe6060f1SDimitry Andric     internalLinkerError(getErrorLocation(buf),
476fe6060f1SDimitry Andric                         "cannot read addend for relocation " + toString(type));
4770b57cec5SDimitry Andric     return 0;
4780b57cec5SDimitry Andric   }
4790b57cec5SDimitry Andric }
4800b57cec5SDimitry Andric 
4810b57cec5SDimitry Andric static std::pair<uint32_t, uint64_t>
calculateMipsRelChain(uint8_t * loc,RelType type,uint64_t val)4820b57cec5SDimitry Andric calculateMipsRelChain(uint8_t *loc, RelType type, uint64_t val) {
4830b57cec5SDimitry Andric   // MIPS N64 ABI packs multiple relocations into the single relocation
4840b57cec5SDimitry Andric   // record. In general, all up to three relocations can have arbitrary
4850b57cec5SDimitry Andric   // types. In fact, Clang and GCC uses only a few combinations. For now,
4860b57cec5SDimitry Andric   // we support two of them. That is allow to pass at least all LLVM
4870b57cec5SDimitry Andric   // test suite cases.
4880b57cec5SDimitry Andric   // <any relocation> / R_MIPS_SUB / R_MIPS_HI16 | R_MIPS_LO16
4890b57cec5SDimitry Andric   // <any relocation> / R_MIPS_64 / R_MIPS_NONE
4900b57cec5SDimitry Andric   // The first relocation is a 'real' relocation which is calculated
4910b57cec5SDimitry Andric   // using the corresponding symbol's value. The second and the third
4920b57cec5SDimitry Andric   // relocations used to modify result of the first one: extend it to
4930b57cec5SDimitry Andric   // 64-bit, extract high or low part etc. For details, see part 2.9 Relocation
4940b57cec5SDimitry Andric   // at the https://dmz-portal.mips.com/mw/images/8/82/007-4658-001.pdf
4950b57cec5SDimitry Andric   RelType type2 = (type >> 8) & 0xff;
4960b57cec5SDimitry Andric   RelType type3 = (type >> 16) & 0xff;
4970b57cec5SDimitry Andric   if (type2 == R_MIPS_NONE && type3 == R_MIPS_NONE)
4980b57cec5SDimitry Andric     return std::make_pair(type, val);
4990b57cec5SDimitry Andric   if (type2 == R_MIPS_64 && type3 == R_MIPS_NONE)
5000b57cec5SDimitry Andric     return std::make_pair(type2, val);
5010b57cec5SDimitry Andric   if (type2 == R_MIPS_SUB && (type3 == R_MIPS_HI16 || type3 == R_MIPS_LO16))
5020b57cec5SDimitry Andric     return std::make_pair(type3, -val);
5030b57cec5SDimitry Andric   error(getErrorLocation(loc) + "unsupported relocations combination " +
5040b57cec5SDimitry Andric         Twine(type));
5050b57cec5SDimitry Andric   return std::make_pair(type & 0xff, val);
5060b57cec5SDimitry Andric }
5070b57cec5SDimitry Andric 
isBranchReloc(RelType type)5080b57cec5SDimitry Andric static bool isBranchReloc(RelType type) {
5090b57cec5SDimitry Andric   return type == R_MIPS_26 || type == R_MIPS_PC26_S2 ||
5100b57cec5SDimitry Andric          type == R_MIPS_PC21_S2 || type == R_MIPS_PC16;
5110b57cec5SDimitry Andric }
5120b57cec5SDimitry Andric 
isMicroBranchReloc(RelType type)5130b57cec5SDimitry Andric static bool isMicroBranchReloc(RelType type) {
5140b57cec5SDimitry Andric   return type == R_MICROMIPS_26_S1 || type == R_MICROMIPS_PC16_S1 ||
5150b57cec5SDimitry Andric          type == R_MICROMIPS_PC10_S1 || type == R_MICROMIPS_PC7_S1;
5160b57cec5SDimitry Andric }
5170b57cec5SDimitry Andric 
5180b57cec5SDimitry Andric template <class ELFT>
fixupCrossModeJump(uint8_t * loc,RelType type,uint64_t val)5190b57cec5SDimitry Andric static uint64_t fixupCrossModeJump(uint8_t *loc, RelType type, uint64_t val) {
5200b57cec5SDimitry Andric   // Here we need to detect jump/branch from regular MIPS code
5210b57cec5SDimitry Andric   // to a microMIPS target and vice versa. In that cases jump
5220b57cec5SDimitry Andric   // instructions need to be replaced by their "cross-mode"
5230b57cec5SDimitry Andric   // equivalents.
5240b57cec5SDimitry Andric   const endianness e = ELFT::TargetEndianness;
5250b57cec5SDimitry Andric   bool isMicroTgt = val & 0x1;
5260b57cec5SDimitry Andric   bool isCrossJump = (isMicroTgt && isBranchReloc(type)) ||
5270b57cec5SDimitry Andric                      (!isMicroTgt && isMicroBranchReloc(type));
5280b57cec5SDimitry Andric   if (!isCrossJump)
5290b57cec5SDimitry Andric     return val;
5300b57cec5SDimitry Andric 
5310b57cec5SDimitry Andric   switch (type) {
5320b57cec5SDimitry Andric   case R_MIPS_26: {
53385868e8aSDimitry Andric     uint32_t inst = read32(loc) >> 26;
5340b57cec5SDimitry Andric     if (inst == 0x3 || inst == 0x1d) { // JAL or JALX
53585868e8aSDimitry Andric       writeValue(loc, 0x1d << 26, 32, 0);
5360b57cec5SDimitry Andric       return val;
5370b57cec5SDimitry Andric     }
5380b57cec5SDimitry Andric     break;
5390b57cec5SDimitry Andric   }
5400b57cec5SDimitry Andric   case R_MICROMIPS_26_S1: {
5410b57cec5SDimitry Andric     uint32_t inst = readShuffle<e>(loc) >> 26;
5420b57cec5SDimitry Andric     if (inst == 0x3d || inst == 0x3c) { // JAL32 or JALX32
5430b57cec5SDimitry Andric       val >>= 1;
5440b57cec5SDimitry Andric       writeShuffleValue<e>(loc, 0x3c << 26, 32, 0);
5450b57cec5SDimitry Andric       return val;
5460b57cec5SDimitry Andric     }
5470b57cec5SDimitry Andric     break;
5480b57cec5SDimitry Andric   }
5490b57cec5SDimitry Andric   case R_MIPS_PC26_S2:
5500b57cec5SDimitry Andric   case R_MIPS_PC21_S2:
5510b57cec5SDimitry Andric   case R_MIPS_PC16:
5520b57cec5SDimitry Andric   case R_MICROMIPS_PC16_S1:
5530b57cec5SDimitry Andric   case R_MICROMIPS_PC10_S1:
5540b57cec5SDimitry Andric   case R_MICROMIPS_PC7_S1:
5550b57cec5SDimitry Andric     // FIXME (simon): Support valid branch relocations.
5560b57cec5SDimitry Andric     break;
5570b57cec5SDimitry Andric   default:
5580b57cec5SDimitry Andric     llvm_unreachable("unexpected jump/branch relocation");
5590b57cec5SDimitry Andric   }
5600b57cec5SDimitry Andric 
5610b57cec5SDimitry Andric   error(getErrorLocation(loc) +
5620b57cec5SDimitry Andric         "unsupported jump/branch instruction between ISA modes referenced by " +
5630b57cec5SDimitry Andric         toString(type) + " relocation");
5640b57cec5SDimitry Andric   return val;
5650b57cec5SDimitry Andric }
5660b57cec5SDimitry Andric 
5670b57cec5SDimitry Andric template <class ELFT>
relocate(uint8_t * loc,const Relocation & rel,uint64_t val) const5685ffd83dbSDimitry Andric void MIPS<ELFT>::relocate(uint8_t *loc, const Relocation &rel,
5695ffd83dbSDimitry Andric                           uint64_t val) const {
5700b57cec5SDimitry Andric   const endianness e = ELFT::TargetEndianness;
5715ffd83dbSDimitry Andric   RelType type = rel.type;
5720b57cec5SDimitry Andric 
5730b57cec5SDimitry Andric   if (ELFT::Is64Bits || config->mipsN32Abi)
5740b57cec5SDimitry Andric     std::tie(type, val) = calculateMipsRelChain(loc, type, val);
5750b57cec5SDimitry Andric 
5760b57cec5SDimitry Andric   // Detect cross-mode jump/branch and fix instruction.
5770b57cec5SDimitry Andric   val = fixupCrossModeJump<ELFT>(loc, type, val);
5780b57cec5SDimitry Andric 
5790b57cec5SDimitry Andric   // Thread pointer and DRP offsets from the start of TLS data area.
5800b57cec5SDimitry Andric   // https://www.linux-mips.org/wiki/NPTL
5810b57cec5SDimitry Andric   if (type == R_MIPS_TLS_DTPREL_HI16 || type == R_MIPS_TLS_DTPREL_LO16 ||
5820b57cec5SDimitry Andric       type == R_MIPS_TLS_DTPREL32 || type == R_MIPS_TLS_DTPREL64 ||
5830b57cec5SDimitry Andric       type == R_MICROMIPS_TLS_DTPREL_HI16 ||
5840b57cec5SDimitry Andric       type == R_MICROMIPS_TLS_DTPREL_LO16) {
5850b57cec5SDimitry Andric     val -= 0x8000;
5860b57cec5SDimitry Andric   }
5870b57cec5SDimitry Andric 
5880b57cec5SDimitry Andric   switch (type) {
5890b57cec5SDimitry Andric   case R_MIPS_32:
5900b57cec5SDimitry Andric   case R_MIPS_GPREL32:
5910b57cec5SDimitry Andric   case R_MIPS_TLS_DTPREL32:
5920b57cec5SDimitry Andric   case R_MIPS_TLS_TPREL32:
59385868e8aSDimitry Andric     write32(loc, val);
5940b57cec5SDimitry Andric     break;
5950b57cec5SDimitry Andric   case R_MIPS_64:
5960b57cec5SDimitry Andric   case R_MIPS_TLS_DTPREL64:
5970b57cec5SDimitry Andric   case R_MIPS_TLS_TPREL64:
59885868e8aSDimitry Andric     write64(loc, val);
5990b57cec5SDimitry Andric     break;
6000b57cec5SDimitry Andric   case R_MIPS_26:
60185868e8aSDimitry Andric     writeValue(loc, val, 26, 2);
6020b57cec5SDimitry Andric     break;
6030b57cec5SDimitry Andric   case R_MIPS_GOT16:
6040b57cec5SDimitry Andric     // The R_MIPS_GOT16 relocation's value in "relocatable" linking mode
6050b57cec5SDimitry Andric     // is updated addend (not a GOT index). In that case write high 16 bits
6060b57cec5SDimitry Andric     // to store a correct addend value.
6070b57cec5SDimitry Andric     if (config->relocatable) {
60885868e8aSDimitry Andric       writeValue(loc, val + 0x8000, 16, 16);
6090b57cec5SDimitry Andric     } else {
6105ffd83dbSDimitry Andric       checkInt(loc, val, 16, rel);
61185868e8aSDimitry Andric       writeValue(loc, val, 16, 0);
6120b57cec5SDimitry Andric     }
6130b57cec5SDimitry Andric     break;
6140b57cec5SDimitry Andric   case R_MICROMIPS_GOT16:
6150b57cec5SDimitry Andric     if (config->relocatable) {
6160b57cec5SDimitry Andric       writeShuffleValue<e>(loc, val + 0x8000, 16, 16);
6170b57cec5SDimitry Andric     } else {
6185ffd83dbSDimitry Andric       checkInt(loc, val, 16, rel);
6190b57cec5SDimitry Andric       writeShuffleValue<e>(loc, val, 16, 0);
6200b57cec5SDimitry Andric     }
6210b57cec5SDimitry Andric     break;
6220b57cec5SDimitry Andric   case R_MIPS_CALL16:
6230b57cec5SDimitry Andric   case R_MIPS_GOT_DISP:
6240b57cec5SDimitry Andric   case R_MIPS_GOT_PAGE:
6250b57cec5SDimitry Andric   case R_MIPS_GPREL16:
6260b57cec5SDimitry Andric   case R_MIPS_TLS_GD:
6270b57cec5SDimitry Andric   case R_MIPS_TLS_GOTTPREL:
6280b57cec5SDimitry Andric   case R_MIPS_TLS_LDM:
6295ffd83dbSDimitry Andric     checkInt(loc, val, 16, rel);
630bdd1243dSDimitry Andric     [[fallthrough]];
6310b57cec5SDimitry Andric   case R_MIPS_CALL_LO16:
6320b57cec5SDimitry Andric   case R_MIPS_GOT_LO16:
6330b57cec5SDimitry Andric   case R_MIPS_GOT_OFST:
6340b57cec5SDimitry Andric   case R_MIPS_LO16:
6350b57cec5SDimitry Andric   case R_MIPS_PCLO16:
6360b57cec5SDimitry Andric   case R_MIPS_TLS_DTPREL_LO16:
6370b57cec5SDimitry Andric   case R_MIPS_TLS_TPREL_LO16:
63885868e8aSDimitry Andric     writeValue(loc, val, 16, 0);
6390b57cec5SDimitry Andric     break;
6400b57cec5SDimitry Andric   case R_MICROMIPS_GPREL16:
6410b57cec5SDimitry Andric   case R_MICROMIPS_TLS_GD:
6420b57cec5SDimitry Andric   case R_MICROMIPS_TLS_LDM:
6435ffd83dbSDimitry Andric     checkInt(loc, val, 16, rel);
6440b57cec5SDimitry Andric     writeShuffleValue<e>(loc, val, 16, 0);
6450b57cec5SDimitry Andric     break;
6460b57cec5SDimitry Andric   case R_MICROMIPS_CALL16:
6470b57cec5SDimitry Andric   case R_MICROMIPS_CALL_LO16:
6480b57cec5SDimitry Andric   case R_MICROMIPS_LO16:
6490b57cec5SDimitry Andric   case R_MICROMIPS_TLS_DTPREL_LO16:
6500b57cec5SDimitry Andric   case R_MICROMIPS_TLS_GOTTPREL:
6510b57cec5SDimitry Andric   case R_MICROMIPS_TLS_TPREL_LO16:
6520b57cec5SDimitry Andric     writeShuffleValue<e>(loc, val, 16, 0);
6530b57cec5SDimitry Andric     break;
6540b57cec5SDimitry Andric   case R_MICROMIPS_GPREL7_S2:
6555ffd83dbSDimitry Andric     checkInt(loc, val, 7, rel);
6560b57cec5SDimitry Andric     writeShuffleValue<e>(loc, val, 7, 2);
6570b57cec5SDimitry Andric     break;
6580b57cec5SDimitry Andric   case R_MIPS_CALL_HI16:
6590b57cec5SDimitry Andric   case R_MIPS_GOT_HI16:
6600b57cec5SDimitry Andric   case R_MIPS_HI16:
6610b57cec5SDimitry Andric   case R_MIPS_PCHI16:
6620b57cec5SDimitry Andric   case R_MIPS_TLS_DTPREL_HI16:
6630b57cec5SDimitry Andric   case R_MIPS_TLS_TPREL_HI16:
66485868e8aSDimitry Andric     writeValue(loc, val + 0x8000, 16, 16);
6650b57cec5SDimitry Andric     break;
6660b57cec5SDimitry Andric   case R_MICROMIPS_CALL_HI16:
6670b57cec5SDimitry Andric   case R_MICROMIPS_GOT_HI16:
6680b57cec5SDimitry Andric   case R_MICROMIPS_HI16:
6690b57cec5SDimitry Andric   case R_MICROMIPS_TLS_DTPREL_HI16:
6700b57cec5SDimitry Andric   case R_MICROMIPS_TLS_TPREL_HI16:
6710b57cec5SDimitry Andric     writeShuffleValue<e>(loc, val + 0x8000, 16, 16);
6720b57cec5SDimitry Andric     break;
6730b57cec5SDimitry Andric   case R_MIPS_HIGHER:
67485868e8aSDimitry Andric     writeValue(loc, val + 0x80008000, 16, 32);
6750b57cec5SDimitry Andric     break;
6760b57cec5SDimitry Andric   case R_MIPS_HIGHEST:
67785868e8aSDimitry Andric     writeValue(loc, val + 0x800080008000, 16, 48);
6780b57cec5SDimitry Andric     break;
6790b57cec5SDimitry Andric   case R_MIPS_JALR:
68085868e8aSDimitry Andric     val -= 4;
68185868e8aSDimitry Andric     // Replace jalr/jr instructions by bal/b if the target
68285868e8aSDimitry Andric     // offset fits into the 18-bit range.
68385868e8aSDimitry Andric     if (isInt<18>(val)) {
68485868e8aSDimitry Andric       switch (read32(loc)) {
68585868e8aSDimitry Andric       case 0x0320f809:  // jalr $25 => bal sym
68685868e8aSDimitry Andric         write32(loc, 0x04110000 | ((val >> 2) & 0xffff));
68785868e8aSDimitry Andric         break;
68885868e8aSDimitry Andric       case 0x03200008:  // jr $25 => b sym
68985868e8aSDimitry Andric         write32(loc, 0x10000000 | ((val >> 2) & 0xffff));
69085868e8aSDimitry Andric         break;
69185868e8aSDimitry Andric       }
69285868e8aSDimitry Andric     }
69385868e8aSDimitry Andric     break;
6940b57cec5SDimitry Andric   case R_MICROMIPS_JALR:
6950b57cec5SDimitry Andric     // Ignore this optimization relocation for now
6960b57cec5SDimitry Andric     break;
6970b57cec5SDimitry Andric   case R_MIPS_PC16:
6985ffd83dbSDimitry Andric     checkAlignment(loc, val, 4, rel);
6995ffd83dbSDimitry Andric     checkInt(loc, val, 18, rel);
70085868e8aSDimitry Andric     writeValue(loc, val, 16, 2);
7010b57cec5SDimitry Andric     break;
7020b57cec5SDimitry Andric   case R_MIPS_PC19_S2:
7035ffd83dbSDimitry Andric     checkAlignment(loc, val, 4, rel);
7045ffd83dbSDimitry Andric     checkInt(loc, val, 21, rel);
70585868e8aSDimitry Andric     writeValue(loc, val, 19, 2);
7060b57cec5SDimitry Andric     break;
7070b57cec5SDimitry Andric   case R_MIPS_PC21_S2:
7085ffd83dbSDimitry Andric     checkAlignment(loc, val, 4, rel);
7095ffd83dbSDimitry Andric     checkInt(loc, val, 23, rel);
71085868e8aSDimitry Andric     writeValue(loc, val, 21, 2);
7110b57cec5SDimitry Andric     break;
7120b57cec5SDimitry Andric   case R_MIPS_PC26_S2:
7135ffd83dbSDimitry Andric     checkAlignment(loc, val, 4, rel);
7145ffd83dbSDimitry Andric     checkInt(loc, val, 28, rel);
71585868e8aSDimitry Andric     writeValue(loc, val, 26, 2);
7160b57cec5SDimitry Andric     break;
7170b57cec5SDimitry Andric   case R_MIPS_PC32:
71885868e8aSDimitry Andric     writeValue(loc, val, 32, 0);
7190b57cec5SDimitry Andric     break;
7200b57cec5SDimitry Andric   case R_MICROMIPS_26_S1:
7210b57cec5SDimitry Andric   case R_MICROMIPS_PC26_S1:
7225ffd83dbSDimitry Andric     checkInt(loc, val, 27, rel);
7230b57cec5SDimitry Andric     writeShuffleValue<e>(loc, val, 26, 1);
7240b57cec5SDimitry Andric     break;
7250b57cec5SDimitry Andric   case R_MICROMIPS_PC7_S1:
7265ffd83dbSDimitry Andric     checkInt(loc, val, 8, rel);
7270b57cec5SDimitry Andric     writeMicroRelocation16<e>(loc, val, 7, 1);
7280b57cec5SDimitry Andric     break;
7290b57cec5SDimitry Andric   case R_MICROMIPS_PC10_S1:
7305ffd83dbSDimitry Andric     checkInt(loc, val, 11, rel);
7310b57cec5SDimitry Andric     writeMicroRelocation16<e>(loc, val, 10, 1);
7320b57cec5SDimitry Andric     break;
7330b57cec5SDimitry Andric   case R_MICROMIPS_PC16_S1:
7345ffd83dbSDimitry Andric     checkInt(loc, val, 17, rel);
7350b57cec5SDimitry Andric     writeShuffleValue<e>(loc, val, 16, 1);
7360b57cec5SDimitry Andric     break;
7370b57cec5SDimitry Andric   case R_MICROMIPS_PC18_S3:
7385ffd83dbSDimitry Andric     checkInt(loc, val, 21, rel);
7390b57cec5SDimitry Andric     writeShuffleValue<e>(loc, val, 18, 3);
7400b57cec5SDimitry Andric     break;
7410b57cec5SDimitry Andric   case R_MICROMIPS_PC19_S2:
7425ffd83dbSDimitry Andric     checkInt(loc, val, 21, rel);
7430b57cec5SDimitry Andric     writeShuffleValue<e>(loc, val, 19, 2);
7440b57cec5SDimitry Andric     break;
7450b57cec5SDimitry Andric   case R_MICROMIPS_PC21_S1:
7465ffd83dbSDimitry Andric     checkInt(loc, val, 22, rel);
7470b57cec5SDimitry Andric     writeShuffleValue<e>(loc, val, 21, 1);
7480b57cec5SDimitry Andric     break;
7490b57cec5SDimitry Andric   case R_MICROMIPS_PC23_S2:
7505ffd83dbSDimitry Andric     checkInt(loc, val, 25, rel);
7510b57cec5SDimitry Andric     writeShuffleValue<e>(loc, val, 23, 2);
7520b57cec5SDimitry Andric     break;
7530b57cec5SDimitry Andric   default:
7540b57cec5SDimitry Andric     llvm_unreachable("unknown relocation");
7550b57cec5SDimitry Andric   }
7560b57cec5SDimitry Andric }
7570b57cec5SDimitry Andric 
usesOnlyLowPageBits(RelType type) const7580b57cec5SDimitry Andric template <class ELFT> bool MIPS<ELFT>::usesOnlyLowPageBits(RelType type) const {
7590b57cec5SDimitry Andric   return type == R_MIPS_LO16 || type == R_MIPS_GOT_OFST ||
7600b57cec5SDimitry Andric          type == R_MICROMIPS_LO16;
7610b57cec5SDimitry Andric }
7620b57cec5SDimitry Andric 
7630b57cec5SDimitry Andric // Return true if the symbol is a PIC function.
isMipsPIC(const Defined * sym)7645ffd83dbSDimitry Andric template <class ELFT> bool elf::isMipsPIC(const Defined *sym) {
7650b57cec5SDimitry Andric   if (!sym->isFunc())
7660b57cec5SDimitry Andric     return false;
7670b57cec5SDimitry Andric 
7680b57cec5SDimitry Andric   if (sym->stOther & STO_MIPS_PIC)
7690b57cec5SDimitry Andric     return true;
7700b57cec5SDimitry Andric 
7710b57cec5SDimitry Andric   if (!sym->section)
7720b57cec5SDimitry Andric     return false;
7730b57cec5SDimitry Andric 
7747a6dacacSDimitry Andric   InputFile *file = cast<InputSectionBase>(sym->section)->file;
7757a6dacacSDimitry Andric   if (!file || file->isInternal())
7760b57cec5SDimitry Andric     return false;
7770b57cec5SDimitry Andric 
7787a6dacacSDimitry Andric   return cast<ObjFile<ELFT>>(file)->getObj().getHeader().e_flags & EF_MIPS_PIC;
7790b57cec5SDimitry Andric }
7800b57cec5SDimitry Andric 
getMipsTargetInfo()7815ffd83dbSDimitry Andric template <class ELFT> TargetInfo *elf::getMipsTargetInfo() {
7820b57cec5SDimitry Andric   static MIPS<ELFT> target;
7830b57cec5SDimitry Andric   return &target;
7840b57cec5SDimitry Andric }
7850b57cec5SDimitry Andric 
7865ffd83dbSDimitry Andric template TargetInfo *elf::getMipsTargetInfo<ELF32LE>();
7875ffd83dbSDimitry Andric template TargetInfo *elf::getMipsTargetInfo<ELF32BE>();
7885ffd83dbSDimitry Andric template TargetInfo *elf::getMipsTargetInfo<ELF64LE>();
7895ffd83dbSDimitry Andric template TargetInfo *elf::getMipsTargetInfo<ELF64BE>();
7900b57cec5SDimitry Andric 
7915ffd83dbSDimitry Andric template bool elf::isMipsPIC<ELF32LE>(const Defined *);
7925ffd83dbSDimitry Andric template bool elf::isMipsPIC<ELF32BE>(const Defined *);
7935ffd83dbSDimitry Andric template bool elf::isMipsPIC<ELF64LE>(const Defined *);
7945ffd83dbSDimitry Andric template bool elf::isMipsPIC<ELF64BE>(const Defined *);
795