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;
-}
+static bool isMicroMips() { return Config->MipsEFlags & 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;
+static bool isMipsR6() {
+ uint32_t Arch = Config->MipsEFlags & EF_MIPS_ARCH;
return Arch == EF_MIPS_ARCH_32R6 || Arch == EF_MIPS_ARCH_64R6;
}
template <class ELFT> void MIPS<ELFT>::writePltHeader(uint8_t *Buf) const {
const endianness E = ELFT::TargetEndianness;
- if (isMicroMips<ELFT>()) {
+ if (isMicroMips()) {
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, isMipsR6() ? 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>()) {
+ if (isMipsR6()) {
write16<E>(Buf + 18, 0x0f83); // move $28, $3
write16<E>(Buf + 20, 0x472b); // jalrc $25
write16<E>(Buf + 22, 0x0c00); // nop
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
const endianness E = ELFT::TargetEndianness;
- if (isMicroMips<ELFT>()) {
+ if (isMicroMips()) {
// Overwrite trap instructions written by Writer::writeTrapInstr.
memset(Buf, 0, PltEntrySize);
- if (isMipsR6<ELFT>()) {
+ if (isMipsR6()) {
write16<E>(Buf, 0x7840); // addiupc $2, (GOTPLT) - .
write16<E>(Buf + 4, 0xff22); // lw $25, 0($2)
write16<E>(Buf + 8, 0x0f02); // move $24, $2
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
- write32<E>(Buf + 8, isMipsR6<ELFT>() ? 0x03200009 : 0x03200008);
+ write32<E>(Buf + 8, isMipsR6() ? 0x03200009 : 0x03200008); // jr $25
write32<E>(Buf + 12, 0x25f80000); // addiu $24, $15, %lo(.got.plt entry)
writeRelocation<E>(Buf, GotPltEntryAddr + 0x8000, 16, 16);
writeRelocation<E>(Buf + 4, GotPltEntryAddr, 16, 0);
return Ret;
}
-template <class ELFT> uint32_t elf::getMipsEFlags() {
+template <class ELFT> uint32_t elf::calcMipsEFlags() {
std::vector<FileFlags> V;
for (InputFile *F : ObjectFiles)
V.push_back(
}
}
-template uint32_t elf::getMipsEFlags<ELF32LE>();
-template uint32_t elf::getMipsEFlags<ELF32BE>();
-template uint32_t elf::getMipsEFlags<ELF64LE>();
-template uint32_t elf::getMipsEFlags<ELF64BE>();
+template uint32_t elf::calcMipsEFlags<ELF32LE>();
+template uint32_t elf::calcMipsEFlags<ELF32BE>();
+template uint32_t elf::calcMipsEFlags<ELF64LE>();
+template uint32_t elf::calcMipsEFlags<ELF64BE>();
// if that's true.)
bool IsMips64EL;
+ // Holds set of ELF header flags for MIPS targets. The set calculated
+ // by the `elf::calcMipsEFlags` function and cached in this field. For
+ // the calculation we iterate over all input object files and combine
+ // their ELF flags.
+ uint32_t MipsEFlags = 0;
+
// The ELF spec defines two types of relocation table entries, RELA and
// REL. RELA is a triplet of (offset, info, addend) while REL is a
// tuple of (offset, info). Addends for REL are implicit and read from
for (InputSectionBase *S : F->getSections())
InputSections.push_back(cast<InputSection>(S));
+ if (Config->EMachine == EM_MIPS)
+ Config->MipsEFlags = calcMipsEFlags<ELFT>();
+
// This adds a .comment section containing a version string. We have to add it
// before decompressAndMergeSections because the .comment section is a
// mergeable section.
return nullptr;
}
- // LLD checks ISA compatibility in getMipsEFlags(). Here we just
+ // LLD checks ISA compatibility in calcMipsEFlags(). Here we just
// select the highest number of ISA/Rev/Ext.
Flags.isa_level = std::max(Flags.isa_level, S->isa_level);
Flags.isa_rev = std::max(Flags.isa_rev, S->isa_rev);
// kernels (as of 2016) require an EABI version to be set.
EHdr->e_flags = EF_ARM_EABI_VER5;
else if (Config->EMachine == EM_MIPS)
- EHdr->e_flags = getMipsEFlags<ELFT>();
+ EHdr->e_flags = Config->MipsEFlags;
if (!Config->Relocatable) {
EHdr->e_phoff = sizeof(Elf_Ehdr);
llvm::StringRef getOutputSectionName(llvm::StringRef Name);
-template <class ELFT> uint32_t getMipsEFlags();
+template <class ELFT> uint32_t calcMipsEFlags();
uint8_t getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag,
llvm::StringRef FileName);
# RUN: llvm-readobj -h -mips-abi-flags %t.exe \
# RUN: | FileCheck -check-prefix=OCTEON %s
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN: -mattr=micromips %S/Inputs/mips-fpic.s -o %t-mm.o
+# RUN: ld.lld %t.o %t-mm.o -o %t.exe
+# RUN: llvm-readobj -h -mips-abi-flags %t.exe | FileCheck -check-prefix=MICRO %s
+
# REQUIRES: mips
.text
# OCTEON-NEXT: ]
# OCTEON-NEXT: Flags 2: 0x0
# OCTEON-NEXT: }
+
+# MICRO: Flags [
+# MICRO-NEXT: EF_MIPS_ABI_O32
+# MICRO-NEXT: EF_MIPS_ARCH_32
+# MICRO-NEXT: EF_MIPS_CPIC
+# MICRO-NEXT: EF_MIPS_MICROMIPS
+# MICRO-NEXT: ]
+# MICRO: MIPS ABI Flags {
+# MICRO-NEXT: Version: 0
+# MICRO-NEXT: ISA: MIPS32
+# MICRO-NEXT: ISA Extension: None
+# MICRO-NEXT: ASEs [
+# MICRO-NEXT: microMIPS
+# MICRO-NEXT: ]
+# MICRO-NEXT: FP ABI: Hard float (double precision)
+# MICRO-NEXT: GPR size: 32
+# MICRO-NEXT: CPR1 size: 32
+# MICRO-NEXT: CPR2 size: 0
+# MICRO-NEXT: Flags 1 [
+# MICRO-NEXT: ODDSPREG
+# MICRO-NEXT: ]
+# MICRO-NEXT: Flags 2: 0x0
+# MICRO-NEXT: }
# RUN: ld.lld -o %tel.exe %t2el.o %tel.so
# RUN: llvm-objdump -d -mattr=micromips %tel.exe | FileCheck --check-prefix=ELR6 %s
+# 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: %S/Inputs/mips-fpic.s -o %t-reg.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN: -mattr=micromips %s -o %t2eb.o
+# RUN: ld.lld --no-threads -o %teb.exe %t-reg.o %t2eb.o %teb.so
+# RUN: llvm-objdump -d -mattr=micromips %teb.exe \
+# RUN: | FileCheck --check-prefix=MIXED %s
+
# REQUIRES: mips
# EB: Disassembly of section .plt:
# ELR6-NEXT: 20038: 02 0f move16 $24, $2
# ELR6-NEXT: 2003a: 23 47 jrc16 $25
+# MIXED: Disassembly of section .plt:
+# MIXED-NEXT: .plt:
+# MIXED-NEXT: 20020: 79 80 3f f9 addiupc $3, 65508
+# MIXED-NEXT: 20024: ff 23 00 00 lw $25, 0($3)
+# MIXED-NEXT: 20028: 05 35 subu16 $2, $2, $3
+# MIXED-NEXT: 2002a: 25 25 srl16 $2, $2, 2
+# MIXED-NEXT: 2002c: 33 02 ff fe addiu $24, $2, -2
+# MIXED-NEXT: 20030: 0d ff move $15, $ra
+# MIXED-NEXT: 20032: 45 f9 jalrs16 $25
+# MIXED-NEXT: 20034: 0f 83 move $gp, $3
+# MIXED-NEXT: 20036: 0c 00 nop
+# MIXED-NEXT: 20038: 00 00 00 00 nop
+# MIXED-NEXT: 2003c: 00 00 00 00 nop
+
+# MIXED-NEXT: 20040: 79 00 3f f3 addiupc $2, 65484
+# MIXED-NEXT: 20044: ff 22 00 00 lw $25, 0($2)
+# MIXED-NEXT: 20048: 45 99 jr16 $25
+# MIXED-NEXT: 2004a: 0f 02 move $24, $2
+
# PLT: Entries [
# PLT-NEXT: Entry {
# PLT-NEXT: Address: 0x3000C