diff options
-rw-r--r-- | lld/ELF/Arch/Mips.cpp | 243 | ||||
-rw-r--r-- | lld/ELF/InputSection.cpp | 2 | ||||
-rw-r--r-- | lld/ELF/Relocations.cpp | 10 | ||||
-rw-r--r-- | lld/test/ELF/Inputs/mips-micro.s | 12 | ||||
-rw-r--r-- | lld/test/ELF/mips-micro-got.s | 46 | ||||
-rw-r--r-- | lld/test/ELF/mips-micro-got64.s | 48 | ||||
-rw-r--r-- | lld/test/ELF/mips-micro-jal.s | 125 | ||||
-rw-r--r-- | lld/test/ELF/mips-micro-relocs.s | 59 |
8 files changed, 538 insertions, 7 deletions
diff --git a/lld/ELF/Arch/Mips.cpp b/lld/ELF/Arch/Mips.cpp index 3a45f26840f..0427cbb0f82 100644 --- a/lld/ELF/Arch/Mips.cpp +++ b/lld/ELF/Arch/Mips.cpp @@ -80,14 +80,23 @@ RelExpr MIPS<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S, 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 Type, const SymbolBody &S, 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 Type, const SymbolBody &S, 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 *Buf, const SymbolBody &) const { 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, uint64_t V, uint8_t BitsSize, 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 isMipsR6() { 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 GotPltEntryAddr, 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, uint32_t Type, const InputFile *File, // 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(const uint8_t *Buf, uint32_t Type) const { 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(const uint8_t *Buf, uint32_t Type) const { 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, uint32_t Type, uint64_t Val) { 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 *Loc, uint32_t Type, uint64_t Val) const { // 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 *Loc, uint32_t Type, uint64_t Val) const { 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 *Loc, uint32_t Type, uint64_t Val) const { 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 *Loc, uint32_t Type, uint64_t Val) const { 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 *Loc, uint32_t Type, uint64_t Val) const { 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 *Loc, uint32_t Type, uint64_t Val) const { 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() { diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index f6a956a0656..9e50d970729 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -534,7 +534,7 @@ static uint64_t getRelocTargetVA(uint32_t Type, int64_t A, uint64_t P, // 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; } diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 0b37bb41fa7..131954629e2 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -91,8 +91,12 @@ static bool isPreemptible(const SymbolBody &Body, uint32_t Type) { // 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 Type, const SymbolBody &Sym) { 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: diff --git a/lld/test/ELF/Inputs/mips-micro.s b/lld/test/ELF/Inputs/mips-micro.s new file mode 100644 index 00000000000..0d0b11f6fdb --- /dev/null +++ b/lld/test/ELF/Inputs/mips-micro.s @@ -0,0 +1,12 @@ + .text + .set micromips + .global foo + .type foo,@function +foo: + nop + + .set nomicromips + .global bar + .type bar,@function +bar: + nop diff --git a/lld/test/ELF/mips-micro-got.s b/lld/test/ELF/mips-micro-got.s new file mode 100644 index 00000000000..8d077f2800f --- /dev/null +++ b/lld/test/ELF/mips-micro-got.s @@ -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 diff --git a/lld/test/ELF/mips-micro-got64.s b/lld/test/ELF/mips-micro-got64.s new file mode 100644 index 00000000000..653bfbfbe8c --- /dev/null +++ b/lld/test/ELF/mips-micro-got64.s @@ -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 diff --git a/lld/test/ELF/mips-micro-jal.s b/lld/test/ELF/mips-micro-jal.s new file mode 100644 index 00000000000..39193aed40a --- /dev/null +++ b/lld/test/ELF/mips-micro-jal.s @@ -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 diff --git a/lld/test/ELF/mips-micro-relocs.s b/lld/test/ELF/mips-micro-relocs.s new file mode 100644 index 00000000000..76db30ac237 --- /dev/null +++ b/lld/test/ELF/mips-micro-relocs.s @@ -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 |