diff options
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.cpp | 33 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.h | 4 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp | 27 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h | 3 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp | 47 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp | 4 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h | 9 | ||||
| -rw-r--r-- | lld/test/elf/Mips/e-flags-merge-12.test | 44 | ||||
| -rw-r--r-- | lld/test/elf/Mips/exe-fileheader-n32.test | 65 | ||||
| -rw-r--r-- | lld/test/elf/Mips/interpreter-n32.test | 27 |
10 files changed, 253 insertions, 10 deletions
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.cpp index 2c2f528f8a0..ad4e62e6468 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.cpp +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.cpp @@ -489,6 +489,21 @@ MipsAbiInfoHandler<ELFT>::getAbiFlags() const { return sec; } +template <class ELFT> MipsAbi MipsAbiInfoHandler<ELFT>::getAbi() const { + if (!_abiFlags.hasValue()) + return ELFT::Is64Bits ? MipsAbi::N64 : MipsAbi::O32; + switch (_abiFlags->_abi & (EF_MIPS_ABI_O32 | EF_MIPS_ABI2)) { + case EF_MIPS_ABI_O32: + return MipsAbi::O32; + case EF_MIPS_ABI2: + return MipsAbi::N32; + case 0: + return MipsAbi::N64; + default: + llvm_unreachable("Unknown ABI flag"); + } +} + template <class ELFT> std::error_code MipsAbiInfoHandler<ELFT>::mergeFlags(uint32_t newFlags, @@ -499,11 +514,15 @@ MipsAbiInfoHandler<ELFT>::mergeFlags(uint32_t newFlags, if (auto ec = abiFlags.getError()) return ec; - // We support two ABI: O32 and N64. The last one does not have + // We support three ABI: O32, N32, and N64. The last one does not have // the corresponding ELF flag. - uint32_t supportedAbi = ELFT::Is64Bits ? 0 : uint32_t(EF_MIPS_ABI_O32); - if (abiFlags->_abi != supportedAbi) - return make_dynamic_error_code("Unsupported ABI"); + if (ELFT::Is64Bits) { + if (abiFlags->_abi) + return make_dynamic_error_code("Unsupported ABI"); + } else { + if (!(abiFlags->_abi & (EF_MIPS_ABI_O32 | EF_MIPS_ABI2))) + return make_dynamic_error_code("Unsupported ABI"); + } // ... and still do not support MIPS-16 extension. if (abiFlags->_ases & AFL_ASE_MIPS16) @@ -520,6 +539,10 @@ MipsAbiInfoHandler<ELFT>::mergeFlags(uint32_t newFlags, return std::error_code(); } + // Check ABI compatibility. + if (abiFlags->_abi != _abiFlags->_abi) + return make_dynamic_error_code("Linking modules with incompatible ABI"); + // Check PIC / CPIC flags compatibility. if (abiFlags->_isCPic != _abiFlags->_isCPic) llvm::errs() << "lld warning: linking abicalls and non-abicalls files\n"; @@ -614,7 +637,7 @@ MipsAbiInfoHandler<ELFT>::createAbiFromHeaderFlags(uint32_t flags) { return ec; abi._ases = *ases; abi._flags1 = 0; - abi._abi = flags & EF_MIPS_ABI; + abi._abi = flags & (EF_MIPS_ABI | EF_MIPS_ABI2); abi._isPic = flags & EF_MIPS_PIC; abi._isCPic = flags & EF_MIPS_CPIC; abi._isNoReorder = flags & EF_MIPS_NOREORDER; diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.h b/lld/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.h index a18eaf65dbc..44da29f0921 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.h +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.h @@ -18,6 +18,8 @@ namespace lld { namespace elf { +enum class MipsAbi { O32, N32, N64 }; + struct MipsAbiFlags { unsigned _isa = 0; unsigned _fpAbi = 0; @@ -53,6 +55,8 @@ public: llvm::Optional<Elf_Mips_RegInfo> getRegistersMask() const; llvm::Optional<Elf_Mips_ABIFlags> getAbiFlags() const; + MipsAbi getAbi() const; + /// \brief Merge saved ELF header flags and the new set of flags. std::error_code mergeFlags(uint32_t newFlags, const Elf_Mips_ABIFlags *newAbi); diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp index b905fa5f3ab..2e72fa39ee2 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp @@ -46,9 +46,16 @@ MipsLinkingContext::MipsLinkingContext(llvm::Triple triple) : ELFLinkingContext(triple, createTarget(triple, *this)) {} uint64_t MipsLinkingContext::getBaseAddress() const { - if (_baseAddress == 0 && getOutputELFType() == llvm::ELF::ET_EXEC) - return getTriple().isArch64Bit() ? 0x120000000 : 0x400000; - return _baseAddress; + if (_baseAddress != 0 || getOutputELFType() != llvm::ELF::ET_EXEC) + return _baseAddress; + switch (getAbi()) { + case MipsAbi::O32: + return 0x0400000; + case MipsAbi::N32: + return 0x10000000; + case MipsAbi::N64: + return 0x120000000; + } } StringRef MipsLinkingContext::entrySymbolName() const { @@ -58,7 +65,14 @@ StringRef MipsLinkingContext::entrySymbolName() const { } StringRef MipsLinkingContext::getDefaultInterpreter() const { - return getTriple().isArch64Bit() ? "/lib64/ld.so.1" : "/lib/ld.so.1"; + switch (getAbi()) { + case MipsAbi::O32: + return "/lib/ld.so.1"; + case MipsAbi::N32: + return "/lib32/ld.so.1"; + case MipsAbi::N64: + return "/lib64/ld.so.1"; + } } void MipsLinkingContext::addPasses(PassManager &pm) { @@ -124,6 +138,11 @@ bool MipsLinkingContext::isRelativeReloc(const Reference &r) const { } } +MipsAbi MipsLinkingContext::getAbi() const { + auto &handler = static_cast<MipsBaseTargetHandler &>(getTargetHandler()); + return handler.getAbi(); +} + const Registry::KindStrings kindStrings[] = { #define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name), #include "llvm/Support/ELFRelocs/Mips.def" diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h b/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h index 123458d2c57..414d2c785e1 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h @@ -9,6 +9,7 @@ #ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_LINKING_CONTEXT_H #define LLD_READER_WRITER_ELF_MIPS_MIPS_LINKING_CONTEXT_H +#include "MipsAbiInfoHandler.h" #include "lld/ReaderWriter/ELFLinkingContext.h" namespace lld { @@ -45,6 +46,8 @@ public: bool isCopyRelocation(const Reference &r) const override; bool isPLTRelocation(const Reference &r) const override; bool isRelativeReloc(const Reference &r) const override; + + MipsAbi getAbi() const; }; } // elf diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp index 326488e55c1..0800218e033 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp @@ -61,6 +61,30 @@ static const uint8_t mipsLePlt0AtomContent[] = { 0xfe, 0xff, 0x18, 0x27 // subu $24, $24, 2 }; +// N32 big-endian PLT0 entry +static const uint8_t mipsN32BePlt0AtomContent[] = { + 0x3c, 0x0e, 0x00, 0x00, // lui $14, %hi(&GOTPLT[0]) + 0x8d, 0xd9, 0x00, 0x00, // lw $25, %lo(&GOTPLT[0])($14) + 0x25, 0xce, 0x00, 0x00, // addiu $14, $14, %lo(&GOTPLT[0]) + 0x03, 0x0e, 0xc0, 0x23, // subu $24, $24, $14 + 0x03, 0xe0, 0x78, 0x25, // move $15, $31 + 0x00, 0x18, 0xc0, 0x82, // srl $24, $24, 2 + 0x03, 0x20, 0xf8, 0x09, // jalr $25 + 0x27, 0x18, 0xff, 0xfe // subu $24, $24, 2 +}; + +// N32 little-endian PLT0 entry +static const uint8_t mipsN32LePlt0AtomContent[] = { + 0x00, 0x00, 0x0e, 0x3c, // lui $14, %hi(&GOTPLT[0]) + 0x00, 0x00, 0xd9, 0x8d, // lw $25, %lo(&GOTPLT[0])($14) + 0x00, 0x00, 0xce, 0x25, // addiu $14, $14, %lo(&GOTPLT[0]) + 0x23, 0xc0, 0x0e, 0x03, // subu $24, $24, $14 + 0x25, 0x78, 0xe0, 0x03, // move $15, $31 + 0x82, 0xc0, 0x18, 0x00, // srl $24, $24, 2 + 0x09, 0xf8, 0x20, 0x03, // jalr $25 + 0xfe, 0xff, 0x18, 0x27 // subu $24, $24, 2 +}; + // microMIPS big-endian PLT0 entry static const uint8_t microMipsBePlt0AtomContent[] = { 0x79, 0x80, 0x00, 0x00, // addiupc $3, (&GOTPLT[0]) - . @@ -285,6 +309,27 @@ template <> ArrayRef<uint8_t> PLT0Atom<ELF32LE>::rawContent() const { return llvm::makeArrayRef(mipsLePlt0AtomContent); } +template <class ELFT> class PLT0N32Atom : public PLTAtom { +public: + PLT0N32Atom(const Atom *got, const File &f) : PLTAtom(f, ".plt") { + // Setup reference to fixup the PLT0 entry. + addReferenceELF_Mips(R_MIPS_HI16, 0, got, 0); + addReferenceELF_Mips(R_MIPS_LO16, 4, got, 0); + addReferenceELF_Mips(R_MIPS_LO16, 8, got, 0); + } + + ArrayRef<uint8_t> rawContent() const override { + llvm_unreachable("PLT0 is not applicable for this target"); + } +}; + +template <> ArrayRef<uint8_t> PLT0N32Atom<ELF32BE>::rawContent() const { + return llvm::makeArrayRef(mipsN32BePlt0AtomContent); +} +template <> ArrayRef<uint8_t> PLT0N32Atom<ELF32LE>::rawContent() const { + return llvm::makeArrayRef(mipsN32LePlt0AtomContent); +} + template <class ELFT> class PLT0MicroAtom : public PLTAtom { public: PLT0MicroAtom(const Atom *got, const File &f) : PLTAtom(f, ".plt") { @@ -1253,6 +1298,8 @@ PLTAtom *RelocationPass<ELFT>::createPLTHeader(bool isMicroMips) { if (isMicroMips) return new (_file._alloc) PLT0MicroAtom<ELFT>(ga0, _file); + if (_ctx.getAbi() == MipsAbi::N32) + return new (_file._alloc) PLT0N32Atom<ELFT>(ga0, _file); return new (_file._alloc) PLT0Atom<ELFT>(ga0, _file); } diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp index d78fc466b4d..817e2944466 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp @@ -53,6 +53,10 @@ std::unique_ptr<Writer> MipsTargetHandler<ELFT>::getWriter() { } } +template <class ELFT> MipsAbi MipsTargetHandler<ELFT>::getAbi() const { + return _abiInfoHandler.getAbi(); +} + template class MipsTargetHandler<ELF32BE>; template class MipsTargetHandler<ELF32LE>; template class MipsTargetHandler<ELF64BE>; diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h index 7625f12bd90..e4a35bdd323 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h @@ -17,8 +17,14 @@ namespace lld { namespace elf { +class MipsBaseTargetHandler : public TargetHandler { +public: + virtual MipsAbi getAbi() const = 0; +}; + /// \brief TargetHandler for Mips -template <class ELFT> class MipsTargetHandler final : public TargetHandler { +template <class ELFT> +class MipsTargetHandler final : public MipsBaseTargetHandler { public: MipsTargetHandler(MipsLinkingContext &ctx); @@ -28,6 +34,7 @@ public: std::unique_ptr<Reader> getDSOReader() override; const TargetRelocationHandler &getRelocationHandler() const override; std::unique_ptr<Writer> getWriter() override; + MipsAbi getAbi() const override; private: MipsLinkingContext &_ctx; diff --git a/lld/test/elf/Mips/e-flags-merge-12.test b/lld/test/elf/Mips/e-flags-merge-12.test new file mode 100644 index 00000000000..3cc55792e20 --- /dev/null +++ b/lld/test/elf/Mips/e-flags-merge-12.test @@ -0,0 +1,44 @@ +# Check that LLD shows an error and does not link files with O32 and N32 ABIs. + +# RUN: yaml2obj -format=elf -docnum 1 %s > %t-o32.o +# RUN: yaml2obj -format=elf -docnum 2 %s > %t-n32.o + +# RUN: not lld -flavor gnu -target mipsel -shared -o %t.so \ +# RUN: %t-o32.o %t-n32.o 2>&1 | FileCheck %s + +# CHECK: Linking modules with incompatible ABI + +# o32.o +--- +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_MIPS + Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, + EF_MIPS_32BITMODE, EF_MIPS_ARCH_64] + +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x04 + Size: 0x04 + +# n32.o +--- +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_MIPS + Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI2, + EF_MIPS_ARCH_64] + +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x04 + Size: 0x04 +... diff --git a/lld/test/elf/Mips/exe-fileheader-n32.test b/lld/test/elf/Mips/exe-fileheader-n32.test new file mode 100644 index 00000000000..155414f537d --- /dev/null +++ b/lld/test/elf/Mips/exe-fileheader-n32.test @@ -0,0 +1,65 @@ +# Check ELF Header for N32 ABI executable file. + +# RUN: yaml2obj -format=elf %s > %t.o +# RUN: lld -flavor gnu -target mipsel -o %t.exe %t.o +# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s + +# CHECK: Format: ELF32-mips +# CHECK-NEXT: Arch: mipsel +# CHECK-NEXT: AddressSize: 32bit +# CHECK-NEXT: LoadName: +# CHECK-NEXT: ElfHeader { +# CHECK-NEXT: Ident { +# CHECK-NEXT: Magic: (7F 45 4C 46) +# CHECK-NEXT: Class: 32-bit +# CHECK-NEXT: DataEncoding: LittleEndian +# CHECK-NEXT: FileVersion: 1 +# CHECK-NEXT: OS/ABI: SystemV +# CHECK-NEXT: ABIVersion: 0 +# CHECK-NEXT: Unused: (00 00 00 00 00 00 00) +# CHECK-NEXT: } +# CHECK-NEXT: Type: Executable +# CHECK-NEXT: Machine: EM_MIPS +# CHECK-NEXT: Version: 1 +# CHECK-NEXT: Entry: 0x10000130 +# CHECK-NEXT: ProgramHeaderOffset: 0x34 +# CHECK-NEXT: SectionHeaderOffset: 0x22C0 +# CHECK-NEXT: Flags [ (0x60000027) +# CHECK-NEXT: EF_MIPS_ABI2 +# CHECK-NEXT: EF_MIPS_ARCH_64 +# CHECK-NEXT: EF_MIPS_CPIC +# CHECK-NEXT: EF_MIPS_NOREORDER +# CHECK-NEXT: EF_MIPS_PIC +# CHECK-NEXT: ] +# CHECK-NEXT: HeaderSize: 52 +# CHECK-NEXT: ProgramHeaderEntrySize: 32 +# CHECK-NEXT: ProgramHeaderCount: {{[0-9]+}} +# CHECK-NEXT: SectionHeaderEntrySize: 40 +# CHECK-NEXT: SectionHeaderCount: {{[0-9]+}} +# CHECK-NEXT: StringTableSectionIndex: {{[0-9]+}} +# CHECK-NEXT: } + +--- +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_MIPS + Flags: [ EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC, + EF_MIPS_ABI2, EF_MIPS_ARCH_64 ] +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 16 + Size: 8 + +Symbols: + Local: + - Name: .text + Type: STT_SECTION + Section: .text + Global: + - Name: __start + Section: .text +... diff --git a/lld/test/elf/Mips/interpreter-n32.test b/lld/test/elf/Mips/interpreter-n32.test new file mode 100644 index 00000000000..9fc0b601d97 --- /dev/null +++ b/lld/test/elf/Mips/interpreter-n32.test @@ -0,0 +1,27 @@ +# Check program interpreter setup in case of N32 ABI. + +# RUN: yaml2obj -format=elf %s > %t.o +# RUN: lld -flavor gnu -target mipsel -o %t.exe %t.o +# RUN: llvm-objdump -s %t.exe | FileCheck %s + +# CHECK: Contents of section .interp: +# CHECK-NEXT: {{[0-9a-f ]+}} /lib32/ld.so.1. + +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_MIPS + Flags: [ EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ARCH_64, EF_MIPS_ABI2 ] + +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 16 + Size: 8 + +Symbols: + Global: + - Name: __start + Section: .text |

