bool GnuHash = false;
bool ICF;
bool Mips64EL = false;
+ bool MipsN32Abi = false;
bool NoGnuUnique;
bool NoUndefinedVersion;
bool Nostdlib;
}
// Parses a linker -m option.
-static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) {
+static std::tuple<ELFKind, uint16_t, uint8_t, bool>
+parseEmulation(StringRef Emul) {
uint8_t OSABI = 0;
StringRef S = Emul;
if (S.endswith("_fbsd")) {
.Case("elf32_x86_64", {ELF32LEKind, EM_X86_64})
.Case("elf32btsmip", {ELF32BEKind, EM_MIPS})
.Case("elf32ltsmip", {ELF32LEKind, EM_MIPS})
+ .Case("elf32btsmipn32", {ELF32BEKind, EM_MIPS})
+ .Case("elf32ltsmipn32", {ELF32LEKind, EM_MIPS})
.Case("elf32ppc", {ELF32BEKind, EM_PPC})
.Case("elf64btsmip", {ELF64BEKind, EM_MIPS})
.Case("elf64ltsmip", {ELF64LEKind, EM_MIPS})
else
error("unknown emulation: " + Emul);
}
- return std::make_tuple(Ret.first, Ret.second, OSABI);
+ bool IsMipsN32ABI = S == "elf32btsmipn32" || S == "elf32ltsmipn32";
+ return std::make_tuple(Ret.first, Ret.second, OSABI, IsMipsN32ABI);
}
// Returns slices of MB by parsing MB as an archive file.
if (auto *Arg = Args.getLastArg(OPT_m)) {
// Parse ELF{32,64}{LE,BE} and CPU type.
StringRef S = Arg->getValue();
- std::tie(Config->EKind, Config->EMachine, Config->OSABI) =
- parseEmulation(S);
+ std::tie(Config->EKind, Config->EMachine, Config->OSABI,
+ Config->MipsN32Abi) = parseEmulation(S);
Config->Emulation = S;
}
Config->EKind = F->EKind;
Config->EMachine = F->EMachine;
Config->OSABI = F->OSABI;
+ Config->MipsN32Abi = Config->EMachine == EM_MIPS && isMipsN32Abi(F);
return;
}
error("target emulation unknown: -m or at least one .o file required");
LinkerScript<ELFT> LS;
ScriptBase = Script<ELFT>::X = &LS;
- Config->Rela = ELFT::Is64Bits || Config->EMachine == EM_X86_64;
+ Config->Rela =
+ ELFT::Is64Bits || Config->EMachine == EM_X86_64 || Config->MipsN32Abi;
Config->Mips64EL =
(Config->EMachine == EM_MIPS && Config->EKind == ELF64LEKind);
Config->ImageBase = getImageBase(Args);
return OldFlag;
}
+template <class ELFT> static bool isN32Abi(const InputFile *F) {
+ if (auto *EF = dyn_cast<ELFFileBase<ELFT>>(F))
+ return EF->getObj().getHeader()->e_flags & EF_MIPS_ABI2;
+ return false;
+}
+
+bool elf::isMipsN32Abi(const InputFile *F) {
+ switch (Config->EKind) {
+ case ELF32LEKind:
+ return isN32Abi<ELF32LE>(F);
+ case ELF32BEKind:
+ return isN32Abi<ELF32BE>(F);
+ case ELF64LEKind:
+ return isN32Abi<ELF64LE>(F);
+ case ELF64BEKind:
+ return isN32Abi<ELF64BE>(F);
+ default:
+ llvm_unreachable("unknown Config->EKind");
+ }
+}
+
template uint32_t elf::getMipsEFlags<ELF32LE>();
template uint32_t elf::getMipsEFlags<ELF32BE>();
template uint32_t elf::getMipsEFlags<ELF64LE>();
error(Msg);
}
+template <class RelTy>
+static std::pair<uint32_t, uint32_t>
+mergeMipsN32RelTypes(uint32_t Type, uint32_t Offset, RelTy *I, RelTy *E) {
+ // MIPS N32 ABI treats series of successive relocations with the same offset
+ // as a single relocation. The similar approach used by N64 ABI, but this ABI
+ // packs all relocations into the single relocation record. Here we emulate
+ // this for the N32 ABI. Iterate over relocation with the same offset and put
+ // theirs types into the single bit-set.
+ uint32_t Processed = 0;
+ for (; I != E && Offset == I->r_offset; ++I) {
+ ++Processed;
+ Type |= I->getType(Config->Mips64EL) << (8 * Processed);
+ }
+ return std::make_pair(Type, Processed);
+}
+
// The reason we have to do this early scan is as follows
// * To mmap the output file, we need to know the size
// * For that, we need to know how many dynamic relocs we will have.
SymbolBody &Body = File.getRelocTargetSym(RI);
uint32_t Type = RI.getType(Config->Mips64EL);
+ if (Config->MipsN32Abi) {
+ uint32_t Processed;
+ std::tie(Type, Processed) =
+ mergeMipsN32RelTypes(Type, RI.r_offset, I + 1, E);
+ I += Processed;
+ }
+
// We only report undefined symbols if they are referenced somewhere in the
// code.
if (!Body.isLocal() && Body.isUndefined() && !Body.symbol()->isWeak())
template <class ELFT> static bool isCompatible(InputFile *F) {
if (!isa<ELFFileBase<ELFT>>(F) && !isa<BitcodeFile>(F))
return true;
- if (F->EKind == Config->EKind && F->EMachine == Config->EMachine)
- return true;
+ if (F->EKind == Config->EKind && F->EMachine == Config->EMachine) {
+ if (Config->EMachine != EM_MIPS)
+ return true;
+ if (isMipsN32Abi(F) == Config->MipsN32Abi)
+ return true;
+ }
StringRef A = F->getName();
StringRef B = Config->Emulation;
if (B.empty())
#include "OutputSections.h"
#include "Symbols.h"
#include "Thunks.h"
+#include "Writer.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Object/ELF.h"
template <class ELFT>
RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type,
const SymbolBody &S) const {
- if (ELFT::Is64Bits)
- // See comment in the calculateMips64RelChain.
+ // See comment in the calculateMipsRelChain.
+ if (ELFT::Is64Bits || Config->MipsN32Abi)
Type &= 0xff;
switch (Type) {
default:
template <class ELFT>
void MipsTargetInfo<ELFT>::writePltHeader(uint8_t *Buf) const {
const endianness E = ELFT::TargetEndianness;
- write32<E>(Buf, 0x3c1c0000); // lui $28, %hi(&GOTPLT[0])
- write32<E>(Buf + 4, 0x8f990000); // lw $25, %lo(&GOTPLT[0])($28)
- write32<E>(Buf + 8, 0x279c0000); // addiu $28, $28, %lo(&GOTPLT[0])
- write32<E>(Buf + 12, 0x031cc023); // subu $24, $24, $28
+ if (Config->MipsN32Abi) {
+ write32<E>(Buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0])
+ write32<E>(Buf + 4, 0x8dd90000); // lw $25, %lo(&GOTPLT[0])($14)
+ write32<E>(Buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0])
+ write32<E>(Buf + 12, 0x030ec023); // subu $24, $24, $14
+ } else {
+ write32<E>(Buf, 0x3c1c0000); // lui $28, %hi(&GOTPLT[0])
+ write32<E>(Buf + 4, 0x8f990000); // lw $25, %lo(&GOTPLT[0])($28)
+ write32<E>(Buf + 8, 0x279c0000); // addiu $28, $28, %lo(&GOTPLT[0])
+ write32<E>(Buf + 12, 0x031cc023); // subu $24, $24, $28
+ }
write32<E>(Buf + 16, 0x03e07825); // move $15, $31
write32<E>(Buf + 20, 0x0018c082); // srl $24, $24, 2
write32<E>(Buf + 24, 0x0320f809); // jalr $25
}
}
-static std::pair<uint32_t, uint64_t> calculateMips64RelChain(uint32_t Type,
- uint64_t Val) {
+static std::pair<uint32_t, uint64_t> calculateMipsRelChain(uint32_t Type,
+ uint64_t Val) {
// MIPS N64 ABI packs multiple relocations into the single relocation
// record. In general, all up to three relocations can have arbitrary
// types. In fact, Clang and GCC uses only a few combinations. For now,
else if (Type == R_MIPS_TLS_TPREL_HI16 || Type == R_MIPS_TLS_TPREL_LO16 ||
Type == R_MIPS_TLS_TPREL32 || Type == R_MIPS_TLS_TPREL64)
Val -= 0x7000;
- if (ELFT::Is64Bits)
- std::tie(Type, Val) = calculateMips64RelChain(Type, Val);
+ if (ELFT::Is64Bits || Config->MipsN32Abi)
+ std::tie(Type, Val) = calculateMipsRelChain(Type, Val);
switch (Type) {
case R_MIPS_32:
case R_MIPS_GPREL32:
namespace lld {
namespace elf {
+class InputFile;
template <class ELFT> class OutputSectionBase;
template <class ELFT> class InputSectionBase;
template <class ELFT> class ObjectFile;
uint8_t getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag,
llvm::StringRef FileName);
+
+bool isMipsN32Abi(const InputFile *F);
}
}
# OCTEON-NEXT: EF_MIPS_PIC
# OCTEON-NEXT: ]
-# N32O32: target ABI 'n32' is incompatible with 'o32': {{.*}}mips-elf-flags-err.s.tmp2.o
+# N32O32: error: {{.*}}mips-elf-flags-err.s.tmp2.o is incompatible with {{.*}}mips-elf-flags-err.s.tmp1.o
# NAN: target -mnan=2008 is incompatible with -mnan=legacy: {{.*}}mips-elf-flags-err.s.tmp2.o
--- /dev/null
+# Check that LLD shows an error when N32 ABI emulation argument
+# is combined with non-N32 ABI object files.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: not ld.lld -m elf32btsmipn32 %t.o -o %t.exe 2>&1 | FileCheck %s
+
+# REQUIRES: mips
+
+ .text
+ .global __start
+__start:
+ nop
+
+# CHECK: error: {{.*}}mips-n32-emul.s.tmp.o is incompatible with elf32btsmipn32
--- /dev/null
+# Check handling of N32 ABI relocation records.
+
+# For now llvm-mc generates incorrect object files for N32 ABI.
+# We use the binary input file generated by GNU tool.
+# llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# -target-abi n32 %s -o %t.o
+# RUN: ld.lld %S/Inputs/mips-n32-rels.o -o %t.exe
+# RUN: llvm-objdump -t -d -s %t.exe | FileCheck %s
+# RUN: llvm-readobj -h %t.exe | FileCheck -check-prefix=ELF %s
+
+# REQUIRES: mips
+
+# .text
+# .type __start, @function
+# .global __start
+# __start:
+# lui $gp,%hi(%neg(%gp_rel(__start))) # R_MIPS_GPREL16
+# # R_MIPS_SUB
+# # R_MIPS_HI16
+# loc:
+# daddiu $gp,$gp,%lo(%neg(%gp_rel(__start))) # R_MIPS_GPREL16
+# # R_MIPS_SUB
+# # R_MIPS_LO16
+#
+# .section .rodata,"a",@progbits
+# .gpword(loc) # R_MIPS_32
+
+# CHECK: Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT: 20000: 3c 1c 00 01 lui $gp, 1
+# ^-- 0x20000 - 0x37ff0
+# ^-- 0 - 0xfffe8010
+# ^-- %hi(0x17ff0)
+# CHECK: loc:
+# CHECK-NEXT: 20004: 67 9c 7f f0 daddiu $gp, $gp, 32752
+# ^-- 0x20000 - 0x37ff0
+# ^-- 0 - 0xfffe8010
+# ^-- %lo(0x17ff0)
+
+# CHECK: Contents of section .rodata:
+# CHECK-NEXT: 10128 00020004
+# ^-- loc
+
+# CHECK: 00020004 .text 00000000 loc
+# CHECK: 00037ff0 .got 00000000 .hidden _gp
+# CHECK: 00020000 g F .text 00000000 __start
+
+# ELF: Format: ELF32-mips
+# ELF-NEXT: Arch: mips
+# ELF-NEXT: AddressSize: 32bit
+# ELF-NEXT: LoadName:
+# ELF-NEXT: ElfHeader {
+# ELF-NEXT: Ident {
+# ELF-NEXT: Magic: (7F 45 4C 46)
+# ELF-NEXT: Class: 32-bit (0x1)
+# ELF-NEXT: DataEncoding: BigEndian (0x2)
+# ELF-NEXT: FileVersion: 1
+# ELF-NEXT: OS/ABI: SystemV (0x0)
+# ELF-NEXT: ABIVersion: 0
+# ELF-NEXT: Unused: (00 00 00 00 00 00 00)
+# ELF-NEXT: }
+# ELF-NEXT: Type: Executable (0x2)
+# ELF-NEXT: Machine: EM_MIPS (0x8)
+# ELF-NEXT: Version: 1
+# ELF-NEXT: Entry: 0x20000
+# ELF-NEXT: ProgramHeaderOffset:
+# ELF-NEXT: SectionHeaderOffset:
+# ELF-NEXT: Flags [
+# ELF-NEXT: EF_MIPS_ABI2
+# ELF-NEXT: EF_MIPS_ARCH_64R2
+# ELF-NEXT: ]