[lld] r313028 - [MIPS] Initial support of microMIPS code linking

Simon Atanasyan via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 12 06:08:25 PDT 2017


Author: atanasyan
Date: Tue Sep 12 06:08:24 2017
New Revision: 313028

URL: http://llvm.org/viewvc/llvm-project?rev=313028&view=rev
Log:
[MIPS] Initial support of microMIPS code linking

The patch implements initial support of microMIPS code linking:
  - Handle microMIPS specific relocations.
  - Emit both R1-R5 and R6 microMIPS PLT records.

For now linking mixed set of regular and microMIPS object files is not
supported. Also the patch does not handle (setup and clear) the
least-significant bit of an address which is utilized as the ISA mode
bit and allows to make jump between regular and microMIPS code without
any thunks.

Differential revision: https://reviews.llvm.org/D37335

Added:
    lld/trunk/test/ELF/Inputs/mips-micro.s
    lld/trunk/test/ELF/mips-micro-got.s
    lld/trunk/test/ELF/mips-micro-got64.s
    lld/trunk/test/ELF/mips-micro-jal.s
    lld/trunk/test/ELF/mips-micro-relocs.s
Modified:
    lld/trunk/ELF/Arch/Mips.cpp
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/Relocations.cpp

Modified: lld/trunk/ELF/Arch/Mips.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Arch/Mips.cpp?rev=313028&r1=313027&r2=313028&view=diff
==============================================================================
--- lld/trunk/ELF/Arch/Mips.cpp (original)
+++ lld/trunk/ELF/Arch/Mips.cpp Tue Sep 12 06:08:24 2017
@@ -80,14 +80,23 @@ RelExpr MIPS<ELFT>::getRelExpr(uint32_t
   default:
     return R_ABS;
   case R_MIPS_JALR:
+  case R_MICROMIPS_JALR:
     return R_HINT;
   case R_MIPS_GPREL16:
   case R_MIPS_GPREL32:
+  case R_MICROMIPS_GPREL16:
+  case R_MICROMIPS_GPREL7_S2:
     return R_MIPS_GOTREL;
   case R_MIPS_26:
     return R_PLT;
+  case R_MICROMIPS_26_S1:
+    return R_PLT;
+  case R_MICROMIPS_PC26_S1:
+    return R_PLT_PC;
   case R_MIPS_HI16:
   case R_MIPS_LO16:
+  case R_MICROMIPS_HI16:
+  case R_MICROMIPS_LO16:
     // R_MIPS_HI16/R_MIPS_LO16 relocations against _gp_disp calculate
     // offset between start of function and 'gp' value which by default
     // equal to the start of .got section. In that case we consider these
@@ -98,6 +107,7 @@ RelExpr MIPS<ELFT>::getRelExpr(uint32_t
       return R_MIPS_GOT_GP;
     LLVM_FALLTHROUGH;
   case R_MIPS_GOT_OFST:
+  case R_MICROMIPS_GOT_OFST:
     return R_ABS;
   case R_MIPS_PC32:
   case R_MIPS_PC16:
@@ -106,25 +116,43 @@ RelExpr MIPS<ELFT>::getRelExpr(uint32_t
   case R_MIPS_PC26_S2:
   case R_MIPS_PCHI16:
   case R_MIPS_PCLO16:
+  case R_MICROMIPS_PC7_S1:
+  case R_MICROMIPS_PC10_S1:
+  case R_MICROMIPS_PC16_S1:
+  case R_MICROMIPS_PC18_S3:
+  case R_MICROMIPS_PC19_S2:
+  case R_MICROMIPS_PC23_S2:
+  case R_MICROMIPS_PC21_S1:
     return R_PC;
   case R_MIPS_GOT16:
+  case R_MICROMIPS_GOT16:
     if (S.isLocal())
       return R_MIPS_GOT_LOCAL_PAGE;
     LLVM_FALLTHROUGH;
   case R_MIPS_CALL16:
   case R_MIPS_GOT_DISP:
   case R_MIPS_TLS_GOTTPREL:
+  case R_MICROMIPS_CALL16:
+  case R_MICROMIPS_GOT_DISP:
+  case R_MICROMIPS_TLS_GOTTPREL:
     return R_MIPS_GOT_OFF;
   case R_MIPS_CALL_HI16:
   case R_MIPS_CALL_LO16:
   case R_MIPS_GOT_HI16:
   case R_MIPS_GOT_LO16:
+  case R_MICROMIPS_CALL_HI16:
+  case R_MICROMIPS_CALL_LO16:
+  case R_MICROMIPS_GOT_HI16:
+  case R_MICROMIPS_GOT_LO16:
     return R_MIPS_GOT_OFF32;
   case R_MIPS_GOT_PAGE:
+  case R_MICROMIPS_GOT_PAGE:
     return R_MIPS_GOT_LOCAL_PAGE;
   case R_MIPS_TLS_GD:
+  case R_MICROMIPS_TLS_GD:
     return R_MIPS_TLSGD;
   case R_MIPS_TLS_LDM:
+  case R_MICROMIPS_TLS_LDM:
     return R_MIPS_TLSLD;
   }
 }
@@ -142,6 +170,19 @@ void MIPS<ELFT>::writeGotPlt(uint8_t *Bu
   write32<ELFT::TargetEndianness>(Buf, InX::Plt->getVA());
 }
 
+template <endianness E> static uint32_t readShuffle(const uint8_t *Loc) {
+  // The major opcode of a microMIPS instruction needs to appear
+  // in the first 16-bit word (lowest address) for efficient hardware
+  // decode so that it knows if the instruction is 16-bit or 32-bit
+  // as early as possible. To do so, little-endian binaries keep 16-bit
+  // words in a big-endian order. That is why we have to swap these
+  // words to get a correct value.
+  uint32_t V = read32<E>(Loc);
+  if (E == support::little)
+    return (V << 16) | (V >> 16);
+  return V;
+}
+
 template <endianness E>
 static void writeRelocation(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
                             uint8_t Shift) {
@@ -151,6 +192,37 @@ static void writeRelocation(uint8_t *Loc
   write32<E>(Loc, Data);
 }
 
+template <endianness E>
+static void writeMicroRelocation32(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
+                                   uint8_t Shift) {
+  // See comments in readShuffle for purpose of this code.
+  uint16_t *Words = (uint16_t *)Loc;
+  if (E == support::little)
+    std::swap(Words[0], Words[1]);
+
+  writeRelocation<E>(Loc, V, BitsSize, Shift);
+
+  if (E == support::little)
+    std::swap(Words[0], Words[1]);
+}
+
+template <endianness E>
+static void writeMicroRelocation16(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
+                                   uint8_t Shift) {
+  uint16_t Instr = read16<E>(Loc);
+  uint16_t Mask = 0xffff >> (16 - BitsSize);
+  uint16_t Data = (Instr & ~Mask) | ((V >> Shift) & Mask);
+  write16<E>(Loc, Data);
+}
+
+template <class ELFT> static bool isMicroMips() {
+  // FIXME (simon): This code does not support the case when both
+  // microMIPS and MIPS object files are linked together.
+  const auto &FirstObj = cast<ELFFileBase<ELFT>>(*Config->FirstElf);
+  uint32_t Arch = FirstObj.getObj().getHeader()->e_flags & EF_MIPS_ARCH_ASE;
+  return Arch == EF_MIPS_MICROMIPS;
+}
+
 template <class ELFT> static bool isMipsR6() {
   const auto &FirstObj = cast<ELFFileBase<ELFT>>(*Config->FirstElf);
   uint32_t Arch = FirstObj.getObj().getHeader()->e_flags & EF_MIPS_ARCH;
@@ -159,6 +231,34 @@ template <class ELFT> static bool isMips
 
 template <class ELFT> void MIPS<ELFT>::writePltHeader(uint8_t *Buf) const {
   const endianness E = ELFT::TargetEndianness;
+  if (isMicroMips<ELFT>()) {
+    uint64_t GotPlt = In<ELFT>::GotPlt->getVA();
+    uint64_t Plt = In<ELFT>::Plt->getVA();
+    // Overwrite trap instructions written by Writer::writeTrapInstr.
+    memset(Buf, 0, PltHeaderSize);
+
+    write16<E>(Buf, isMipsR6<ELFT>() ? 0x7860 : 0x7980);
+                                    // addiupc v1, (GOTPLT) - .
+    write16<E>(Buf + 4, 0xff23);    // lw      $25, 0($3)
+    write16<E>(Buf + 8, 0x0535);    // subu16  $2,  $2, $3
+    write16<E>(Buf + 10, 0x2525);   // srl16   $2,  $2, 2
+    write16<E>(Buf + 12, 0x3302);   // addiu   $24, $2, -2
+    write16<E>(Buf + 14, 0xfffe);
+    write16<E>(Buf + 16, 0x0dff);   // move    $15, $31
+    if (isMipsR6<ELFT>()) {
+      write16<E>(Buf + 18, 0x0f83); // move    $28, $3
+      write16<E>(Buf + 20, 0x472b); // jalrc   $25
+      write16<E>(Buf + 22, 0x0c00); // nop
+      relocateOne(Buf, R_MICROMIPS_PC19_S2, GotPlt - Plt);
+    } else {
+      write16<E>(Buf + 18, 0x45f9); // jalrc   $25
+      write16<E>(Buf + 20, 0x0f83); // move    $28, $3
+      write16<E>(Buf + 22, 0x0c00); // nop
+      relocateOne(Buf, R_MICROMIPS_PC23_S2, GotPlt - Plt);
+    }
+    return;
+  }
+
   if (Config->MipsN32Abi) {
     write32<E>(Buf, 0x3c0e0000);      // lui   $14, %hi(&GOTPLT[0])
     write32<E>(Buf + 4, 0x8dd90000);  // lw    $25, %lo(&GOTPLT[0])($14)
@@ -187,6 +287,26 @@ void MIPS<ELFT>::writePlt(uint8_t *Buf,
                           uint64_t PltEntryAddr, int32_t Index,
                           unsigned RelOff) const {
   const endianness E = ELFT::TargetEndianness;
+  if (isMicroMips<ELFT>()) {
+    // Overwrite trap instructions written by Writer::writeTrapInstr.
+    memset(Buf, 0, PltEntrySize);
+
+    if (isMipsR6<ELFT>()) {
+      write16<E>(Buf, 0x7840);      // addiupc $2, (GOTPLT) - .
+      write16<E>(Buf + 4, 0xff22);  // lw $25, 0($2)
+      write16<E>(Buf + 8, 0x0f02);  // move $24, $2
+      write16<E>(Buf + 10, 0x4723); // jrc $25 / jr16 $25
+      relocateOne(Buf, R_MICROMIPS_PC19_S2, GotPltEntryAddr - PltEntryAddr);
+    } else {
+      write16<E>(Buf, 0x7900);      // addiupc $2, (GOTPLT) - .
+      write16<E>(Buf + 4, 0xff22);  // lw $25, 0($2)
+      write16<E>(Buf + 8, 0x4599);  // jrc $25 / jr16 $25
+      write16<E>(Buf + 10, 0x0f02); // move $24, $2
+      relocateOne(Buf, R_MICROMIPS_PC23_S2, GotPltEntryAddr - PltEntryAddr);
+    }
+    return;
+  }
+
   write32<E>(Buf, 0x3c0f0000);     // lui   $15, %hi(.got.plt entry)
   write32<E>(Buf + 4, 0x8df90000); // l[wd] $25, %lo(.got.plt entry)($15)
                                    // jr    $25
@@ -205,7 +325,8 @@ bool MIPS<ELFT>::needsThunk(RelExpr Expr
   // we cannot make the jump directly and need to create a small stubs
   // to save the target function address.
   // See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
-  if (Type != R_MIPS_26)
+  if (Type != R_MIPS_26 && Type != R_MICROMIPS_26_S1 &&
+      Type != R_MICROMIPS_PC26_S1)
     return false;
   auto *F = dyn_cast_or_null<ELFFileBase<ELFT>>(File);
   if (!F)
@@ -247,6 +368,18 @@ int64_t MIPS<ELFT>::getImplicitAddend(co
   case R_MIPS_TLS_TPREL_HI16:
   case R_MIPS_TLS_TPREL_LO16:
     return SignExtend64<16>(read32<E>(Buf));
+  case R_MICROMIPS_GOT16:
+  case R_MICROMIPS_HI16:
+    return SignExtend64<16>(readShuffle<E>(Buf)) << 16;
+  case R_MICROMIPS_GPREL16:
+  case R_MICROMIPS_LO16:
+  case R_MICROMIPS_TLS_DTPREL_HI16:
+  case R_MICROMIPS_TLS_DTPREL_LO16:
+  case R_MICROMIPS_TLS_TPREL_HI16:
+  case R_MICROMIPS_TLS_TPREL_LO16:
+    return SignExtend64<16>(readShuffle<E>(Buf));
+  case R_MICROMIPS_GPREL7_S2:
+    return SignExtend64<9>(readShuffle<E>(Buf) << 2);
   case R_MIPS_PC16:
     return SignExtend64<18>(read32<E>(Buf) << 2);
   case R_MIPS_PC19_S2:
@@ -257,6 +390,24 @@ int64_t MIPS<ELFT>::getImplicitAddend(co
     return SignExtend64<28>(read32<E>(Buf) << 2);
   case R_MIPS_PC32:
     return SignExtend64<32>(read32<E>(Buf));
+  case R_MICROMIPS_26_S1:
+    return SignExtend64<27>(readShuffle<E>(Buf) << 1);
+  case R_MICROMIPS_PC7_S1:
+    return SignExtend64<8>(read16<E>(Buf) << 1);
+  case R_MICROMIPS_PC10_S1:
+    return SignExtend64<11>(read16<E>(Buf) << 1);
+  case R_MICROMIPS_PC16_S1:
+    return SignExtend64<17>(readShuffle<E>(Buf) << 1);
+  case R_MICROMIPS_PC18_S3:
+    return SignExtend64<21>(readShuffle<E>(Buf) << 3);
+  case R_MICROMIPS_PC19_S2:
+    return SignExtend64<21>(readShuffle<E>(Buf) << 2);
+  case R_MICROMIPS_PC21_S1:
+    return SignExtend64<22>(readShuffle<E>(Buf) << 1);
+  case R_MICROMIPS_PC23_S2:
+    return SignExtend64<25>(readShuffle<E>(Buf) << 2);
+  case R_MICROMIPS_PC26_S1:
+    return SignExtend64<27>(readShuffle<E>(Buf) << 1);
   }
 }
 
@@ -282,6 +433,9 @@ calculateMipsRelChain(uint8_t *Loc, uint
     return std::make_pair(Type2, Val);
   if (Type2 == R_MIPS_SUB && (Type3 == R_MIPS_HI16 || Type3 == R_MIPS_LO16))
     return std::make_pair(Type3, -Val);
+  if (Type2 == R_MICROMIPS_SUB &&
+      (Type3 == R_MICROMIPS_HI16 || Type3 == R_MICROMIPS_LO16))
+    return std::make_pair(Type3, -Val);
   error(getErrorLocation(Loc) + "unsupported relocations combination " +
         Twine(Type));
   return std::make_pair(Type & 0xff, Val);
@@ -293,10 +447,14 @@ void MIPS<ELFT>::relocateOne(uint8_t *Lo
   // Thread pointer and DRP offsets from the start of TLS data area.
   // https://www.linux-mips.org/wiki/NPTL
   if (Type == R_MIPS_TLS_DTPREL_HI16 || Type == R_MIPS_TLS_DTPREL_LO16 ||
-      Type == R_MIPS_TLS_DTPREL32 || Type == R_MIPS_TLS_DTPREL64)
+      Type == R_MIPS_TLS_DTPREL32 || Type == R_MIPS_TLS_DTPREL64 ||
+      Type == R_MICROMIPS_TLS_DTPREL_HI16 ||
+      Type == R_MICROMIPS_TLS_DTPREL_LO16)
     Val -= 0x8000;
   else if (Type == R_MIPS_TLS_TPREL_HI16 || Type == R_MIPS_TLS_TPREL_LO16 ||
-           Type == R_MIPS_TLS_TPREL32 || Type == R_MIPS_TLS_TPREL64)
+           Type == R_MIPS_TLS_TPREL32 || Type == R_MIPS_TLS_TPREL64 ||
+           Type == R_MICROMIPS_TLS_TPREL_HI16 ||
+           Type == R_MICROMIPS_TLS_TPREL_LO16)
     Val -= 0x7000;
   if (ELFT::Is64Bits || Config->MipsN32Abi)
     std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val);
@@ -326,6 +484,14 @@ void MIPS<ELFT>::relocateOne(uint8_t *Lo
       writeRelocation<E>(Loc, Val, 16, 0);
     }
     break;
+  case R_MICROMIPS_GOT16:
+    if (Config->Relocatable) {
+      writeMicroRelocation32<E>(Loc, Val + 0x8000, 16, 16);
+    } else {
+      checkInt<16>(Loc, Val, Type);
+      writeMicroRelocation32<E>(Loc, Val, 16, 0);
+    }
+    break;
   case R_MIPS_GOT_DISP:
   case R_MIPS_GOT_PAGE:
   case R_MIPS_GPREL16:
@@ -344,6 +510,27 @@ void MIPS<ELFT>::relocateOne(uint8_t *Lo
   case R_MIPS_TLS_TPREL_LO16:
     writeRelocation<E>(Loc, Val, 16, 0);
     break;
+  case R_MICROMIPS_GOT_DISP:
+  case R_MICROMIPS_GOT_PAGE:
+  case R_MICROMIPS_GPREL16:
+  case R_MICROMIPS_TLS_GD:
+  case R_MICROMIPS_TLS_LDM:
+    checkInt<16>(Loc, Val, Type);
+    writeMicroRelocation32<E>(Loc, Val, 16, 0);
+    break;
+  case R_MICROMIPS_CALL16:
+  case R_MICROMIPS_CALL_LO16:
+  case R_MICROMIPS_GOT_OFST:
+  case R_MICROMIPS_LO16:
+  case R_MICROMIPS_TLS_DTPREL_LO16:
+  case R_MICROMIPS_TLS_GOTTPREL:
+  case R_MICROMIPS_TLS_TPREL_LO16:
+    writeMicroRelocation32<E>(Loc, Val, 16, 0);
+    break;
+  case R_MICROMIPS_GPREL7_S2:
+    checkInt<7>(Loc, Val, Type);
+    writeMicroRelocation32<E>(Loc, Val, 7, 2);
+    break;
   case R_MIPS_CALL_HI16:
   case R_MIPS_GOT_HI16:
   case R_MIPS_HI16:
@@ -352,13 +539,27 @@ void MIPS<ELFT>::relocateOne(uint8_t *Lo
   case R_MIPS_TLS_TPREL_HI16:
     writeRelocation<E>(Loc, Val + 0x8000, 16, 16);
     break;
+  case R_MICROMIPS_CALL_HI16:
+  case R_MICROMIPS_GOT_HI16:
+  case R_MICROMIPS_HI16:
+  case R_MICROMIPS_TLS_DTPREL_HI16:
+  case R_MICROMIPS_TLS_TPREL_HI16:
+    writeMicroRelocation32<E>(Loc, Val + 0x8000, 16, 16);
+    break;
   case R_MIPS_HIGHER:
     writeRelocation<E>(Loc, Val + 0x80008000, 16, 32);
     break;
   case R_MIPS_HIGHEST:
     writeRelocation<E>(Loc, Val + 0x800080008000, 16, 48);
     break;
+  case R_MICROMIPS_HIGHER:
+    writeMicroRelocation32<E>(Loc, Val + 0x80008000, 16, 32);
+    break;
+  case R_MICROMIPS_HIGHEST:
+    writeMicroRelocation32<E>(Loc, Val + 0x800080008000, 16, 48);
+    break;
   case R_MIPS_JALR:
+  case R_MICROMIPS_JALR:
     // Ignore this optimization relocation for now
     break;
   case R_MIPS_PC16:
@@ -384,6 +585,39 @@ void MIPS<ELFT>::relocateOne(uint8_t *Lo
   case R_MIPS_PC32:
     writeRelocation<E>(Loc, Val, 32, 0);
     break;
+  case R_MICROMIPS_26_S1:
+  case R_MICROMIPS_PC26_S1:
+    checkInt<27>(Loc, Val, Type);
+    writeMicroRelocation32<E>(Loc, Val, 26, 1);
+    break;
+  case R_MICROMIPS_PC7_S1:
+    checkInt<8>(Loc, Val, Type);
+    writeMicroRelocation16<E>(Loc, Val, 7, 1);
+    break;
+  case R_MICROMIPS_PC10_S1:
+    checkInt<11>(Loc, Val, Type);
+    writeMicroRelocation16<E>(Loc, Val, 10, 1);
+    break;
+  case R_MICROMIPS_PC16_S1:
+    checkInt<17>(Loc, Val, Type);
+    writeMicroRelocation32<E>(Loc, Val, 16, 1);
+    break;
+  case R_MICROMIPS_PC18_S3:
+    checkInt<21>(Loc, Val, Type);
+    writeMicroRelocation32<E>(Loc, Val, 18, 3);
+    break;
+  case R_MICROMIPS_PC19_S2:
+    checkInt<21>(Loc, Val, Type);
+    writeMicroRelocation32<E>(Loc, Val, 19, 2);
+    break;
+  case R_MICROMIPS_PC21_S1:
+    checkInt<22>(Loc, Val, Type);
+    writeMicroRelocation32<E>(Loc, Val, 21, 1);
+    break;
+  case R_MICROMIPS_PC23_S2:
+    checkInt<25>(Loc, Val, Type);
+    writeMicroRelocation32<E>(Loc, Val, 23, 2);
+    break;
   default:
     error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
   }
@@ -391,7 +625,8 @@ void MIPS<ELFT>::relocateOne(uint8_t *Lo
 
 template <class ELFT>
 bool MIPS<ELFT>::usesOnlyLowPageBits(uint32_t Type) const {
-  return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST;
+  return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST ||
+         Type == R_MICROMIPS_LO16 || Type == R_MICROMIPS_GOT_OFST;
 }
 
 template <class ELFT> TargetInfo *elf::getMipsTargetInfo() {

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=313028&r1=313027&r2=313028&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Tue Sep 12 06:08:24 2017
@@ -534,7 +534,7 @@ static uint64_t getRelocTargetVA(uint32_
     // formula for calculation "AHL + GP - P + 4". For details see p. 4-19 at
     // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
     uint64_t V = InX::MipsGot->getGp() + A - P;
-    if (Type == R_MIPS_LO16)
+    if (Type == R_MIPS_LO16 || Type == R_MICROMIPS_LO16)
       V += 4;
     return V;
   }

Modified: lld/trunk/ELF/Relocations.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=313028&r1=313027&r2=313028&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.cpp (original)
+++ lld/trunk/ELF/Relocations.cpp Tue Sep 12 06:08:24 2017
@@ -91,8 +91,12 @@ static bool isPreemptible(const SymbolBo
   // relocation types occupy eight bit. In case of N64 ABI we extract first
   // relocation from 3-in-1 packet because only the first relocation can
   // be against a real symbol.
-  if (Config->EMachine == EM_MIPS && (Type & 0xff) == R_MIPS_GPREL16)
-    return false;
+  if (Config->EMachine == EM_MIPS) {
+    Type &= 0xff;
+    if (Type == R_MIPS_GPREL16 || Type == R_MICROMIPS_GPREL16 ||
+        Type == R_MICROMIPS_GPREL7_S2)
+      return false;
+  }
   return Body.isPreemptible();
 }
 
@@ -301,6 +305,8 @@ static uint32_t getMipsPairType(uint32_t
     return R_MIPS_LO16;
   case R_MIPS_GOT16:
     return Sym.isLocal() ? R_MIPS_LO16 : R_MIPS_NONE;
+  case R_MICROMIPS_GOT16:
+    return Sym.isLocal() ? R_MICROMIPS_LO16 : R_MIPS_NONE;
   case R_MIPS_PCHI16:
     return R_MIPS_PCLO16;
   case R_MICROMIPS_HI16:

Added: lld/trunk/test/ELF/Inputs/mips-micro.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/mips-micro.s?rev=313028&view=auto
==============================================================================
--- lld/trunk/test/ELF/Inputs/mips-micro.s (added)
+++ lld/trunk/test/ELF/Inputs/mips-micro.s Tue Sep 12 06:08:24 2017
@@ -0,0 +1,12 @@
+  .text
+  .set micromips
+  .global foo
+  .type foo, at function
+foo:
+  nop
+
+  .set nomicromips
+  .global bar
+  .type bar, at function
+bar:
+  nop

Added: lld/trunk/test/ELF/mips-micro-got.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-micro-got.s?rev=313028&view=auto
==============================================================================
--- lld/trunk/test/ELF/mips-micro-got.s (added)
+++ lld/trunk/test/ELF/mips-micro-got.s Tue Sep 12 06:08:24 2017
@@ -0,0 +1,46 @@
+# Check microMIPS GOT relocations for O32 ABI.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux -mattr=micromips \
+# RUN:         %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux -mattr=micromips \
+# RUN:         %S/Inputs/mips-dynamic.s -o %t2.o
+# RUN: ld.lld %t2.o -shared -o %t.so
+# RUN: ld.lld %t1.o %t.so -o %t.exe
+# RUN: llvm-readobj -mips-plt-got %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Local entries [
+# CHECK-NEXT:   Entry {
+# CHECK-NEXT:     Address:
+# CHECK-NEXT:     Access: -32744
+# CHECK-NEXT:     Initial: 0x30000
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Entry {
+# CHECK-NEXT:     Address:
+# CHECK-NEXT:     Access: -32740
+# CHECK-NEXT:     Initial: 0x40000
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: Global entries [
+# CHECK-NEXT:   Entry {
+# CHECK-NEXT:     Address:
+# CHECK-NEXT:     Access: -32736
+# CHECK-NEXT:     Initial: 0x0
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Type: Function
+# CHECK-NEXT:     Section: Undefined
+# CHECK-NEXT:     Name: foo0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+  .text
+  .global __start
+__start:
+  lw       $4, %got(data)($28)
+  addiu    $4, $4, %lo(data)
+  lw      $25, %call16(foo0)($28)
+
+  .data
+data:
+  .word 0

Added: lld/trunk/test/ELF/mips-micro-got64.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-micro-got64.s?rev=313028&view=auto
==============================================================================
--- lld/trunk/test/ELF/mips-micro-got64.s (added)
+++ lld/trunk/test/ELF/mips-micro-got64.s Tue Sep 12 06:08:24 2017
@@ -0,0 +1,48 @@
+# Check microMIPS GOT relocations for N64 ABI.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux -mattr=micromips \
+# RUN:         %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux -mattr=micromips \
+# RUN:         %S/Inputs/mips-dynamic.s -o %t2.o
+# RUN: ld.lld %t2.o -shared -o %t.so
+# RUN: ld.lld %t1.o %t.so -o %t.exe
+# RUN: llvm-readobj -mips-plt-got %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Local entries [
+# CHECK-NEXT:   Entry {
+# CHECK-NEXT:     Address:
+# CHECK-NEXT:     Access: -32736
+# CHECK-NEXT:     Initial: 0x30000
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Entry {
+# CHECK-NEXT:     Address:
+# CHECK-NEXT:     Access: -32728
+# CHECK-NEXT:     Initial: 0x40000
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: Global entries [
+# CHECK-NEXT:   Entry {
+# CHECK-NEXT:     Address:
+# CHECK-NEXT:     Access: -32720
+# CHECK-NEXT:     Initial: 0x0
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Type: Function
+# CHECK-NEXT:     Section: Undefined
+# CHECK-NEXT:     Name: foo0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+  .text
+  .global __start
+__start:
+  lui     $28, %hi(%neg(%gp_rel(foo0)))
+  addiu   $28, $28, %lo(%neg(%gp_rel(foo0)))
+  lw       $4, %got_page(data)($28)
+  addiu    $4, $4, %got_ofst(data)
+  lw      $25, %call16(foo0)($28)
+
+  .data
+data:
+  .word 0

Added: lld/trunk/test/ELF/mips-micro-jal.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-micro-jal.s?rev=313028&view=auto
==============================================================================
--- lld/trunk/test/ELF/mips-micro-jal.s (added)
+++ lld/trunk/test/ELF/mips-micro-jal.s Tue Sep 12 06:08:24 2017
@@ -0,0 +1,125 @@
+# Check PLT creation for microMIPS to microMIPS calls.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mattr=micromips %S/Inputs/mips-micro.s -o %t1eb.o
+# RUN: ld.lld -shared -o %teb.so %t1eb.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mattr=micromips %s -o %t2eb.o
+# RUN: ld.lld -o %teb.exe %t2eb.o %teb.so
+# RUN: llvm-objdump -d -mattr=micromips %teb.exe | FileCheck --check-prefix=EB %s
+# RUN: llvm-readobj -mips-plt-got %teb.exe | FileCheck --check-prefix=PLT %s
+
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
+# RUN:         -mattr=micromips %S/Inputs/mips-micro.s -o %t1el.o
+# RUN: ld.lld -shared -o %tel.so %t1el.o
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
+# RUN:         -mattr=micromips %s -o %t2el.o
+# RUN: ld.lld -o %tel.exe %t2el.o %tel.so
+# RUN: llvm-objdump -d -mattr=micromips %tel.exe | FileCheck --check-prefix=EL %s
+# RUN: llvm-readobj -mips-plt-got %tel.exe | FileCheck --check-prefix=PLT %s
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mattr=micromips -mcpu=mips32r6 %S/Inputs/mips-micro.s -o %t1eb.o
+# RUN: ld.lld -shared -o %teb.so %t1eb.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mattr=micromips -mcpu=mips32r6 %s -o %t2eb.o
+# RUN: ld.lld -o %teb.exe %t2eb.o %teb.so
+# RUN: llvm-objdump -d -mattr=micromips %teb.exe | FileCheck --check-prefix=EBR6 %s
+
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
+# RUN:         -mattr=micromips -mcpu=mips32r6 %S/Inputs/mips-micro.s -o %t1el.o
+# RUN: ld.lld -shared -o %tel.so %t1el.o
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
+# RUN:         -mattr=micromips -mcpu=mips32r6 %s -o %t2el.o
+# RUN: ld.lld -o %tel.exe %t2el.o %tel.so
+# RUN: llvm-objdump -d -mattr=micromips %tel.exe | FileCheck --check-prefix=ELR6 %s
+
+# REQUIRES: mips
+
+# EB:      Disassembly of section .plt:
+# EB-NEXT: .plt:
+# EB-NEXT:    20010:       79 80 3f fd     addiupc $3, 65524
+# EB-NEXT:    20014:       ff 23 00 00     lw      $25, 0($3)
+# EB-NEXT:    20018:       05 35           subu16  $2, $2, $3
+# EB-NEXT:    2001a:       25 25           srl16   $2, $2, 2
+# EB-NEXT:    2001c:       33 02 ff fe     addiu   $24, $2, -2
+# EB-NEXT:    20020:       0d ff           move    $15, $ra
+# EB-NEXT:    20022:       45 f9           jalrs16 $25
+# EB-NEXT:    20024:       0f 83           move    $gp, $3
+# EB-NEXT:    20026:       0c 00           nop
+# EB-NEXT:    20028:       00 00 00 00     nop
+# EB-NEXT:    2002c:       00 00 00 00     nop
+
+# EB-NEXT:    20030:       79 00 3f f7     addiupc $2, 65500
+# EB-NEXT:    20034:       ff 22 00 00     lw      $25, 0($2)
+# EB-NEXT:    20038:       45 99           jr16    $25
+# EB-NEXT:    2003a:       0f 02           move    $24, $2
+
+# EL:      Disassembly of section .plt:
+# EL-NEXT: .plt:
+# EL-NEXT:    20010:       80 79 fd 3f     addiupc $3, 65524
+# EL-NEXT:    20014:       23 ff 00 00     lw      $25, 0($3)
+# EL-NEXT:    20018:       35 05           subu16  $2, $2, $3
+# EL-NEXT:    2001a:       25 25           srl16   $2, $2, 2
+# EL-NEXT:    2001c:       02 33 fe ff     addiu   $24, $2, -2
+# EL-NEXT:    20020:       ff 0d           move    $15, $ra
+# EL-NEXT:    20022:       f9 45           jalrs16 $25
+# EL-NEXT:    20024:       83 0f           move    $gp, $3
+# EL-NEXT:    20026:       00 0c           nop
+# EL-NEXT:    20028:       00 00 00 00     nop
+# EL-NEXT:    2002c:       00 00 00 00     nop
+
+# EL-NEXT:    20030:       00 79 f7 3f     addiupc $2, 65500
+# EL-NEXT:    20034:       22 ff 00 00     lw      $25, 0($2)
+# EL-NEXT:    20038:       99 45           jr16    $25
+# EL-NEXT:    2003a:       02 0f           move    $24, $2
+
+# EBR6:      Disassembly of section .plt:
+# EBR6-NEXT: .plt:
+# EBR6-NEXT:    20010:       78 60 3f fd     lapc    $3, 65524
+# EBR6-NEXT:    20014:       ff 23 00 00     lw      $25, 0($3)
+# EBR6-NEXT:    20018:       05 35           subu16  $2, $2, $3
+# EBR6-NEXT:    2001a:       25 25           srl16   $2, $2, 2
+# EBR6-NEXT:    2001c:       33 02 ff fe     addiu   $24, $2, -2
+# EBR6-NEXT:    20020:       0d ff           move16  $15, $ra
+# EBR6-NEXT:    20022:       0f 83           move16  $gp, $3
+# EBR6-NEXT:    20024:       47 2b           jalr    $25
+
+# EBR6:         20030:       78 40 3f f7     lapc    $2, 65500
+# EBR6-NEXT:    20034:       ff 22 00 00     lw      $25, 0($2)
+# EBR6-NEXT:    20038:       0f 02           move16  $24, $2
+# EBR6-NEXT:    2003a:       47 23           jrc16   $25
+
+# ELR6:      Disassembly of section .plt:
+# ELR6-NEXT: .plt:
+# ELR6-NEXT:    20010:       60 78 fd 3f     lapc    $3, 65524
+# ELR6-NEXT:    20014:       23 ff 00 00     lw      $25, 0($3)
+# ELR6-NEXT:    20018:       35 05           subu16  $2, $2, $3
+# ELR6-NEXT:    2001a:       25 25           srl16   $2, $2, 2
+# ELR6-NEXT:    2001c:       02 33 fe ff     addiu   $24, $2, -2
+# ELR6-NEXT:    20020:       ff 0d           move16  $15, $ra
+# ELR6-NEXT:    20022:       83 0f           move16  $gp, $3
+# ELR6-NEXT:    20024:       2b 47           jalr    $25
+
+# ELR6:         20030:       40 78 f7 3f     lapc    $2, 65500
+# ELR6-NEXT:    20034:       22 ff 00 00     lw      $25, 0($2)
+# ELR6-NEXT:    20038:       02 0f           move16  $24, $2
+# ELR6-NEXT:    2003a:       23 47           jrc16   $25
+
+# PLT:      Entries [
+# PLT-NEXT:   Entry {
+# PLT-NEXT:     Address: 0x3000C
+#                        ^ 0x20030 + 65500
+# PLT-NEXT:     Initial:
+# PLT-NEXT:     Value: 0x0
+# PLT-NEXT:     Type: Function
+# PLT-NEXT:     Section: Undefined
+# PLT-NEXT:     Name: foo
+# PLT-NEXT:   }
+# PLT-NEXT: ]
+
+  .text
+  .set micromips
+  .global __start
+__start:
+  jal foo

Added: lld/trunk/test/ELF/mips-micro-relocs.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-micro-relocs.s?rev=313028&view=auto
==============================================================================
--- lld/trunk/test/ELF/mips-micro-relocs.s (added)
+++ lld/trunk/test/ELF/mips-micro-relocs.s Tue Sep 12 06:08:24 2017
@@ -0,0 +1,59 @@
+# Check handling of microMIPS relocations.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mattr=micromips %S/Inputs/mips-micro.s -o %t1eb.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mattr=micromips %s -o %t2eb.o
+# RUN: ld.lld -o %teb.exe %t1eb.o %t2eb.o
+# RUN: llvm-objdump -d -t -mattr=micromips %teb.exe \
+# RUN:   | FileCheck --check-prefixes=EB,SYM %s
+
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
+# RUN:         -mattr=micromips %S/Inputs/mips-micro.s -o %t1el.o
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
+# RUN:         -mattr=micromips %s -o %t2el.o
+# RUN: ld.lld -o %tel.exe %t1el.o %t2el.o
+# RUN: llvm-objdump -d -t -mattr=micromips %tel.exe \
+# RUN:   | FileCheck --check-prefixes=EL,SYM %s
+
+# REQUIRES: mips
+
+# EB:      __start:
+# EB-NEXT:      20010:       41 a3 00 01     lui     $3, 1
+# EB-NEXT:      20014:       30 63 7f e0     addiu   $3, $3, 32736
+# EB-NEXT:      20018:       fc 7c 80 18     lw      $3, -32744($gp)
+# EB-NEXT:      2001c:       fc 63 80 18     lw      $3, -32744($3)
+# EB-NEXT:      20020:       8f 70           beqz16  $6, -32
+# EB-NEXT:      20022:       00 7e 00 00     sll     $3, $fp, 0
+# EB-NEXT:      20026:       cf ec           b16     -40
+# EB-NEXT:      20028:       00 00 00 00     nop
+# EB-NEXT:      2002c:       94 00 ff e8     b       -44
+
+# EL:      __start:
+# EL-NEXT:      20010:       a3 41 01 00     lui     $3, 1
+# EL-NEXT:      20014:       63 30 e0 7f     addiu   $3, $3, 32736
+# EL-NEXT:      20018:       7c fc 18 80     lw      $3, -32744($gp)
+# EL-NEXT:      2001c:       63 fc 18 80     lw      $3, -32744($3)
+# EL-NEXT:      20020:       70 8f           beqz16  $6, -32
+# EL-NEXT:      20022:       7e 00 00 00     sll     $3, $fp, 0
+# EL-NEXT:      20026:       ec cf           b16     -40
+# EL-NEXT:      20028:       00 00 00 00     nop
+# EL-NEXT:      2002c:       00 94 e8 ff     b       -44
+
+# SYM: 00037ff0         *ABS*           00000000 .hidden _gp
+# SYM: 00020000 g F     .text           00000000 foo
+# SYM: 00020010         .text           00000000 __start
+
+  .text
+  .set micromips
+  .global __start
+__start:
+  lui     $3, %hi(_gp_disp)       # R_MICROMIPS_HI16
+  addiu   $3, $3, %lo(_gp_disp)   # R_MICROMIPS_LO16
+
+  lw      $3, %call16(foo)($gp)   # R_MICROMIPS_CALL16
+  lw      $3, %got(foo)($3)       # R_MICROMIPS_GOT16
+
+  beqz16  $6, foo                 # R_MICROMIPS_PC7_S1
+  b16     foo                     # R_MICROMIPS_PC10_S1
+  b       foo                     # R_MICROMIPS_PC16_S1




More information about the llvm-commits mailing list