diff options
author | Rafael Espindola <rafael.espindola@gmail.com> | 2016-02-28 00:10:58 +0000 |
---|---|---|
committer | Rafael Espindola <rafael.espindola@gmail.com> | 2016-02-28 00:10:58 +0000 |
commit | 3a4d0a7c17d90d78d299122b44576576da7d9311 (patch) | |
tree | b86319c5dc6c1b39e9a6530121a446be615af0ad /lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp | |
parent | 985ff20a9caff5091ade54ddc2e21dd8ef016194 (diff) | |
download | bcm5719-llvm-3a4d0a7c17d90d78d299122b44576576da7d9311.tar.gz bcm5719-llvm-3a4d0a7c17d90d78d299122b44576576da7d9311.zip |
Remove the old ELF linker.
I think it is clear by now that the new linker is viable.
llvm-svn: 262158
Diffstat (limited to 'lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp')
-rw-r--r-- | lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp | 1415 |
1 files changed, 0 insertions, 1415 deletions
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp deleted file mode 100644 index 45f6467c95c..00000000000 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp +++ /dev/null @@ -1,1415 +0,0 @@ -//===- lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp -------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "MipsELFFile.h" -#include "MipsLinkingContext.h" -#include "MipsRelocationPass.h" -#include "MipsTargetHandler.h" -#include "llvm/ADT/DenseSet.h" - -using namespace lld; -using namespace lld::elf; -using namespace llvm::ELF; - -// Lazy resolver -static const uint8_t mipsGot0AtomContent[] = { - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 -}; - -// Module pointer -static const uint8_t mipsGotModulePointerAtomContent[] = { - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x80 -}; - -// TLS GD Entry -static const uint8_t mipsGotTlsGdAtomContent[] = { - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 -}; - -// Regular big-endian PLT0 entry -static const uint8_t mipsBePlt0AtomContent[] = { - 0x3c, 0x1c, 0x00, 0x00, // lui $28, %hi(&GOTPLT[0]) - 0x8f, 0x99, 0x00, 0x00, // lw $25, %lo(&GOTPLT[0])($28) - 0x27, 0x9c, 0x00, 0x00, // addiu $28, $28, %lo(&GOTPLT[0]) - 0x03, 0x1c, 0xc0, 0x23, // subu $24, $24, $28 - 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 -}; - -// Regular little-endian PLT0 entry -static const uint8_t mipsLePlt0AtomContent[] = { - 0x00, 0x00, 0x1c, 0x3c, // lui $28, %hi(&GOTPLT[0]) - 0x00, 0x00, 0x99, 0x8f, // lw $25, %lo(&GOTPLT[0])($28) - 0x00, 0x00, 0x9c, 0x27, // addiu $28, $28, %lo(&GOTPLT[0]) - 0x23, 0xc0, 0x1c, 0x03, // subu $24, $24, $28 - 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 -}; - -// 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]) - . - 0xff, 0x23, 0x00, 0x00, // lw $25, 0($3) - 0x05, 0x35, // subu $2, $2, $3 - 0x25, 0x25, // srl $2, $2, 2 - 0x33, 0x02, 0xff, 0xfe, // subu $24, $2, 2 - 0x0d, 0xff, // move $15, $31 - 0x45, 0xf9, // jalrs $25 - 0x0f, 0x83, // move $28, $3 - 0x0c, 0x00 // nop -}; - -// microMIPS little-endian PLT0 entry -static const uint8_t microMipsLePlt0AtomContent[] = { - 0x80, 0x79, 0x00, 0x00, // addiupc $3, (&GOTPLT[0]) - . - 0x23, 0xff, 0x00, 0x00, // lw $25, 0($3) - 0x35, 0x05, // subu $2, $2, $3 - 0x25, 0x25, // srl $2, $2, 2 - 0x02, 0x33, 0xfe, 0xff, // subu $24, $2, 2 - 0xff, 0x0d, // move $15, $31 - 0xf9, 0x45, // jalrs $25 - 0x83, 0x0f, // move $28, $3 - 0x00, 0x0c // nop -}; - -// Regular big-endian PLT entry -static const uint8_t mipsBePltAAtomContent[] = { - 0x3c, 0x0f, 0x00, 0x00, // lui $15, %hi(.got.plt entry) - 0x8d, 0xf9, 0x00, 0x00, // l[wd] $25, %lo(.got.plt entry)($15) - 0x03, 0x20, 0x00, 0x08, // jr $25 - 0x25, 0xf8, 0x00, 0x00 // addiu $24, $15, %lo(.got.plt entry) -}; - -// Regular little-endian PLT entry -static const uint8_t mipsLePltAAtomContent[] = { - 0x00, 0x00, 0x0f, 0x3c, // lui $15, %hi(.got.plt entry) - 0x00, 0x00, 0xf9, 0x8d, // l[wd] $25, %lo(.got.plt entry)($15) - 0x08, 0x00, 0x20, 0x03, // jr $25 - 0x00, 0x00, 0xf8, 0x25 // addiu $24, $15, %lo(.got.plt entry) -}; - -// microMIPS big-endian PLT entry -static const uint8_t microMipsBePltAAtomContent[] = { - 0x79, 0x00, 0x00, 0x00, // addiupc $2, (.got.plt entry) - . - 0xff, 0x22, 0x00, 0x00, // lw $25, 0($2) - 0x45, 0x99, // jr $25 - 0x0f, 0x02 // move $24, $2 -}; - -// microMIPS little-endian PLT entry -static const uint8_t microMipsLePltAAtomContent[] = { - 0x00, 0x79, 0x00, 0x00, // addiupc $2, (.got.plt entry) - . - 0x22, 0xff, 0x00, 0x00, // lw $25, 0($2) - 0x99, 0x45, // jr $25 - 0x02, 0x0f // move $24, $2 -}; - -// R6 big-endian PLT entry -static const uint8_t mipsR6BePltAAtomContent[] = { - 0x3c, 0x0f, 0x00, 0x00, // lui $15, %hi(.got.plt entry) - 0x8d, 0xf9, 0x00, 0x00, // l[wd] $25, %lo(.got.plt entry)($15) - 0x03, 0x20, 0x00, 0x09, // jr $25 - 0x25, 0xf8, 0x00, 0x00 // addiu $24, $15, %lo(.got.plt entry) -}; - -// R6 little-endian PLT entry -static const uint8_t mipsR6LePltAAtomContent[] = { - 0x00, 0x00, 0x0f, 0x3c, // lui $15, %hi(.got.plt entry) - 0x00, 0x00, 0xf9, 0x8d, // l[wd] $25, %lo(.got.plt entry)($15) - 0x09, 0x00, 0x20, 0x03, // jr $25 - 0x00, 0x00, 0xf8, 0x25 // addiu $24, $15, %lo(.got.plt entry) -}; - -// LA25 big-endian stub entry -static const uint8_t mipsBeLA25AtomContent[] = { - 0x3c, 0x19, 0x00, 0x00, // lui $25, %hi(func) - 0x08, 0x00, 0x00, 0x00, // j func - 0x27, 0x39, 0x00, 0x00, // addiu $25, $25, %lo(func) - 0x00, 0x00, 0x00, 0x00 // nop -}; - -// LA25 little-endian stub entry -static const uint8_t mipsLeLA25AtomContent[] = { - 0x00, 0x00, 0x19, 0x3c, // lui $25, %hi(func) - 0x00, 0x00, 0x00, 0x08, // j func - 0x00, 0x00, 0x39, 0x27, // addiu $25, $25, %lo(func) - 0x00, 0x00, 0x00, 0x00 // nop -}; - -// microMIPS LA25 big-endian stub entry -static const uint8_t microMipsBeLA25AtomContent[] = { - 0x41, 0xbe, 0x00, 0x00, // lui $25, %hi(func) - 0xd4, 0x00, 0x00, 0x00, // j func - 0x33, 0x39, 0x00, 0x00, // addiu $25, $25, %lo(func) - 0x00, 0x00, 0x00, 0x00 // nop -}; - -// microMIPS LA25 little-endian stub entry -static const uint8_t microMipsLeLA25AtomContent[] = { - 0xb9, 0x41, 0x00, 0x00, // lui $25, %hi(func) - 0x00, 0xd4, 0x00, 0x00, // j func - 0x39, 0x33, 0x00, 0x00, // addiu $25, $25, %lo(func) - 0x00, 0x00, 0x00, 0x00 // nop -}; - -namespace { - -/// \brief Abstract base class represent MIPS GOT entries. -class MipsGOTAtom : public GOTAtom { -public: - MipsGOTAtom(const File &f) : GOTAtom(f, ".got") {} - - Alignment alignment() const override { return 4; } -}; - -/// \brief MIPS GOT entry initialized by zero. -template <typename ELFT> class GOT0Atom : public MipsGOTAtom { -public: - GOT0Atom(const File &f) : MipsGOTAtom(f) {} - - ArrayRef<uint8_t> rawContent() const override; -}; - -template <> ArrayRef<uint8_t> GOT0Atom<ELF32BE>::rawContent() const { - return llvm::makeArrayRef(mipsGot0AtomContent).slice(4); -} -template <> ArrayRef<uint8_t> GOT0Atom<ELF32LE>::rawContent() const { - return llvm::makeArrayRef(mipsGot0AtomContent).slice(4); -} -template <> ArrayRef<uint8_t> GOT0Atom<ELF64BE>::rawContent() const { - return llvm::makeArrayRef(mipsGot0AtomContent); -} -template <> ArrayRef<uint8_t> GOT0Atom<ELF64LE>::rawContent() const { - return llvm::makeArrayRef(mipsGot0AtomContent); -} - -/// \brief MIPS GOT entry initialized by zero. -template <typename ELFT> class GOTModulePointerAtom : public MipsGOTAtom { -public: - GOTModulePointerAtom(const File &f) : MipsGOTAtom(f) {} - - ArrayRef<uint8_t> rawContent() const override; -}; - -template <> -ArrayRef<uint8_t> GOTModulePointerAtom<ELF32BE>::rawContent() const { - return llvm::makeArrayRef(mipsGotModulePointerAtomContent).slice(4); -} -template <> -ArrayRef<uint8_t> GOTModulePointerAtom<ELF32LE>::rawContent() const { - return llvm::makeArrayRef(mipsGotModulePointerAtomContent).slice(4); -} -template <> -ArrayRef<uint8_t> GOTModulePointerAtom<ELF64BE>::rawContent() const { - return llvm::makeArrayRef(mipsGotModulePointerAtomContent); -} -template <> -ArrayRef<uint8_t> GOTModulePointerAtom<ELF64LE>::rawContent() const { - return llvm::makeArrayRef(mipsGotModulePointerAtomContent); -} - -/// \brief MIPS GOT TLS GD entry. -template <typename ELFT> class GOTTLSGdAtom : public MipsGOTAtom { -public: - GOTTLSGdAtom(const File &f) : MipsGOTAtom(f) {} - - ArrayRef<uint8_t> rawContent() const override; -}; - -template <> ArrayRef<uint8_t> GOTTLSGdAtom<ELF32BE>::rawContent() const { - return llvm::makeArrayRef(mipsGotTlsGdAtomContent).slice(8); -} -template <> ArrayRef<uint8_t> GOTTLSGdAtom<ELF32LE>::rawContent() const { - return llvm::makeArrayRef(mipsGotTlsGdAtomContent).slice(8); -} -template <> ArrayRef<uint8_t> GOTTLSGdAtom<ELF64BE>::rawContent() const { - return llvm::makeArrayRef(mipsGotTlsGdAtomContent); -} -template <> ArrayRef<uint8_t> GOTTLSGdAtom<ELF64LE>::rawContent() const { - return llvm::makeArrayRef(mipsGotTlsGdAtomContent); -} - -class GOTPLTAtom : public GOTAtom { -public: - GOTPLTAtom(const File &f) : GOTAtom(f, ".got.plt") {} - GOTPLTAtom(const Atom *a, const File &f) : GOTAtom(f, ".got.plt") { - // Create dynamic relocation to adjust the .got.plt entry at runtime. - addReferenceELF_Mips(R_MIPS_JUMP_SLOT, 0, a, 0); - } - - /// Setup reference to assign initial value to the .got.plt entry. - void setPLT0(const PLTAtom *plt0) { - addReferenceELF_Mips(R_MIPS_32, 0, plt0, 0); - } - - Alignment alignment() const override { return 4; } - - ArrayRef<uint8_t> rawContent() const override { - return llvm::makeArrayRef(mipsGot0AtomContent).slice(4); - } -}; - -template <class ELFT> class PLT0Atom : public PLTAtom { -public: - PLT0Atom(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> PLT0Atom<ELF32BE>::rawContent() const { - return llvm::makeArrayRef(mipsBePlt0AtomContent); -} -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") { - // Setup reference to fixup the PLT0 entry. - addReferenceELF_Mips(R_MICROMIPS_PC23_S2, 0, got, 0); - } - - CodeModel codeModel() const override { return codeMipsMicro; } - - ArrayRef<uint8_t> rawContent() const override { - llvm_unreachable("PLT0 is not applicable for this target"); - } -}; - -template <> ArrayRef<uint8_t> PLT0MicroAtom<ELF32BE>::rawContent() const { - return llvm::makeArrayRef(microMipsBePlt0AtomContent); -} -template <> ArrayRef<uint8_t> PLT0MicroAtom<ELF32LE>::rawContent() const { - return llvm::makeArrayRef(microMipsLePlt0AtomContent); -} - -class PLTAAtom : public PLTAtom { -public: - PLTAAtom(const GOTPLTAtom *got, const File &f) : PLTAtom(f, ".plt") { - // Setup reference to fixup the PLT entry. - addReferenceELF_Mips(R_MIPS_HI16, 0, got, 0); - addReferenceELF_Mips(R_MIPS_LO16, 4, got, 0); - addReferenceELF_Mips(R_MIPS_LO16, 12, got, 0); - } -}; - -template <class ELFT> class PLTARegAtom : public PLTAAtom { -public: - PLTARegAtom(const GOTPLTAtom *got, const File &f) : PLTAAtom(got, f) {} - - ArrayRef<uint8_t> rawContent() const override { - llvm_unreachable("PLT is not applicable for this target"); - } -}; - -template <> ArrayRef<uint8_t> PLTARegAtom<ELF32BE>::rawContent() const { - return llvm::makeArrayRef(mipsBePltAAtomContent); -} -template <> ArrayRef<uint8_t> PLTARegAtom<ELF32LE>::rawContent() const { - return llvm::makeArrayRef(mipsLePltAAtomContent); -} - -template <class ELFT> class PLTR6Atom : public PLTAAtom { -public: - PLTR6Atom(const GOTPLTAtom *got, const File &f) : PLTAAtom(got, f) {} - - ArrayRef<uint8_t> rawContent() const override { - llvm_unreachable("PLT is not applicable for this target"); - } -}; - -template <> ArrayRef<uint8_t> PLTR6Atom<ELF32BE>::rawContent() const { - return llvm::makeArrayRef(mipsR6BePltAAtomContent); -} -template <> ArrayRef<uint8_t> PLTR6Atom<ELF32LE>::rawContent() const { - return llvm::makeArrayRef(mipsR6LePltAAtomContent); -} - -template <class ELFT> class PLTMicroAtom : public PLTAtom { -public: - PLTMicroAtom(const GOTPLTAtom *got, const File &f) : PLTAtom(f, ".plt") { - // Setup reference to fixup the microMIPS PLT entry. - addReferenceELF_Mips(R_MICROMIPS_PC23_S2, 0, got, 0); - } - - Alignment alignment() const override { return 2; } - CodeModel codeModel() const override { return codeMipsMicro; } - - ArrayRef<uint8_t> rawContent() const override { - llvm_unreachable("PLT is not applicable for this target"); - } -}; - -template <> ArrayRef<uint8_t> PLTMicroAtom<ELF32BE>::rawContent() const { - return llvm::makeArrayRef(microMipsBePltAAtomContent); -} -template <> ArrayRef<uint8_t> PLTMicroAtom<ELF32LE>::rawContent() const { - return llvm::makeArrayRef(microMipsLePltAAtomContent); -} - -class LA25Atom : public PLTAtom { -public: - LA25Atom(const File &f) : PLTAtom(f, ".text") {} -}; - -template <typename ELFT> class LA25RegAtom : public LA25Atom { -public: - LA25RegAtom(const Atom *a, const File &f) : LA25Atom(f) { - // Setup reference to fixup the LA25 stub entry. - addReferenceELF_Mips(R_MIPS_HI16, 0, a, 0); - addReferenceELF_Mips(R_MIPS_26, 4, a, 0); - addReferenceELF_Mips(R_MIPS_LO16, 8, a, 0); - } - - ArrayRef<uint8_t> rawContent() const override { - llvm_unreachable("LA25 stubs are not applicable for this target"); - } -}; - -template <> ArrayRef<uint8_t> LA25RegAtom<ELF32BE>::rawContent() const { - return llvm::makeArrayRef(mipsBeLA25AtomContent); -} -template <> ArrayRef<uint8_t> LA25RegAtom<ELF32LE>::rawContent() const { - return llvm::makeArrayRef(mipsLeLA25AtomContent); -} - -template <typename ELFT> class LA25MicroAtom : public LA25Atom { -public: - LA25MicroAtom(const Atom *a, const File &f) : LA25Atom(f) { - // Setup reference to fixup the microMIPS LA25 stub entry. - addReferenceELF_Mips(R_MICROMIPS_HI16, 0, a, 0); - addReferenceELF_Mips(R_MICROMIPS_26_S1, 4, a, 0); - addReferenceELF_Mips(R_MICROMIPS_LO16, 8, a, 0); - } - - CodeModel codeModel() const override { return codeMipsMicro; } - - ArrayRef<uint8_t> rawContent() const override { - llvm_unreachable("LA25 stubs are not applicable for this target"); - } -}; - -template <> ArrayRef<uint8_t> LA25MicroAtom<ELF32BE>::rawContent() const { - return llvm::makeArrayRef(microMipsBeLA25AtomContent); -} -template <> ArrayRef<uint8_t> LA25MicroAtom<ELF32LE>::rawContent() const { - return llvm::makeArrayRef(microMipsLeLA25AtomContent); -} - -class MipsGlobalOffsetTableAtom : public GlobalOffsetTableAtom { -public: - MipsGlobalOffsetTableAtom(const File &f) : GlobalOffsetTableAtom(f) {} - - StringRef customSectionName() const override { return ".got"; } -}; - -template <typename ELFT> class MipsRldAtom : public SimpleELFDefinedAtom { -public: - MipsRldAtom(const File &f) : SimpleELFDefinedAtom(f) {} - - Scope scope() const override { return scopeGlobal; } - SectionChoice sectionChoice() const override { return sectionCustomRequired; } - StringRef customSectionName() const override { return ".rld_map"; } - ContentType contentType() const override { return typeData; } - uint64_t size() const override { return rawContent().size(); } - ContentPermissions permissions() const override { return permRW_; } - Alignment alignment() const override { return rawContent().size(); } - StringRef name() const override { return "__RLD_MAP"; } - ArrayRef<uint8_t> rawContent() const override { - return llvm::makeArrayRef(mipsGot0AtomContent) - .slice(ELFT::Is64Bits ? 0 : 4); - } -}; - -class RelocationPassFile : public SimpleFile { -public: - RelocationPassFile(const ELFLinkingContext &ctx) - : SimpleFile("RelocationPassFile", kindELFObject) { - setOrdinal(ctx.getNextOrdinalAndIncrement()); - } - - llvm::BumpPtrAllocator _alloc; -}; - -template <typename ELFT> class RelocationPass : public Pass { -public: - RelocationPass(MipsLinkingContext &ctx); - - std::error_code perform(SimpleFile &mf) override; - -private: - /// \brief Reference to the linking context. - const MipsLinkingContext &_ctx; - - /// \brief Owner of all the Atoms created by this pass. - RelocationPassFile _file; - - /// \brief Map Atoms and addend to local GOT entries. - typedef std::pair<const Atom *, int64_t> LocalGotMapKeyT; - llvm::DenseMap<LocalGotMapKeyT, GOTAtom *> _gotLocalMap; - llvm::DenseMap<LocalGotMapKeyT, GOTAtom *> _gotLocalPageMap; - - /// \brief Map Atoms to global GOT entries. - llvm::DenseMap<const Atom *, GOTAtom *> _gotGlobalMap; - - /// \brief Map Atoms to TLS GOT entries. - llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSMap; - - /// \brief Map Atoms to TLS GD GOT entries. - llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSGdMap; - - /// \brief GOT entry for the R_xxxMIPS_TLS_LDM relocations. - GOTTLSGdAtom<ELFT> *_gotLDMEntry = nullptr; - - /// \brief the list of local GOT atoms. - std::vector<GOTAtom *> _localGotVector; - - /// \brief the list of global GOT atoms. - std::vector<GOTAtom *> _globalGotVector; - - /// \brief the list of TLS GOT atoms. - std::vector<GOTAtom *> _tlsGotVector; - - /// \brief Map Atoms to their GOTPLT entries. - llvm::DenseMap<const Atom *, GOTPLTAtom *> _gotpltMap; - - /// \brief Map Atoms to their PLT entries. - llvm::DenseMap<const Atom *, PLTAAtom *> _pltRegMap; - llvm::DenseMap<const Atom *, PLTMicroAtom<ELFT> *> _pltMicroMap; - - /// \brief Map Atoms to their Object entries. - llvm::DenseMap<const Atom *, ObjectAtom *> _objectMap; - - /// \brief Map Atoms to their LA25 entries. - llvm::DenseMap<const Atom *, LA25Atom *> _la25RegMap; - llvm::DenseMap<const Atom *, LA25Atom *> _la25MicroMap; - - /// \brief Atoms referenced by static relocations. - llvm::DenseSet<const Atom *> _hasStaticRelocations; - - /// \brief Atoms require pointers equality. - llvm::DenseSet<const Atom *> _requiresPtrEquality; - - /// \brief References which are candidates for converting - /// to the R_MIPS_REL32 relocation. - std::vector<Reference *> _rel32Candidates; - - /// \brief the list of PLT atoms. - std::vector<PLTAtom *> _pltRegVector; - std::vector<PLTAtom *> _pltMicroVector; - - /// \brief the list of GOTPLT atoms. - std::vector<GOTPLTAtom *> _gotpltVector; - - /// \brief the list of Object entries. - std::vector<ObjectAtom *> _objectVector; - - /// \brief the list of LA25 entries. - std::vector<LA25Atom *> _la25Vector; - - /// \brief Handle a specific reference. - void handleReference(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref); - - /// \brief Collect information about the reference to use it - /// later in the handleReference() routine. - std::error_code collectReferenceInfo(const MipsELFDefinedAtom<ELFT> &atom, - Reference &ref); - - /// \brief Check that the relocation is valid for the current linking mode. - std::error_code validateRelocation(const DefinedAtom &atom, - const Reference &ref) const; - - void handlePlain(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref); - void handleBranch(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref); - void handleGOT(Reference &ref); - - const GOTAtom *getLocalGOTEntry(const Reference &ref); - const GOTAtom *getLocalGOTPageEntry(const Reference &ref); - const GOTAtom *getGlobalGOTEntry(const Atom *a); - const GOTAtom *getTLSGOTEntry(const Atom *a, Reference::Addend addend); - const GOTAtom *getTLSGdGOTEntry(const Atom *a, Reference::Addend addend); - const GOTAtom *getTLSLdmGOTEntry(const Atom *a); - const GOTPLTAtom *getGOTPLTEntry(const Atom *a); - const PLTAtom *getPLTEntry(const Atom *a); - const PLTAtom *getPLTRegEntry(const Atom *a); - const PLTAtom *getPLTMicroEntry(const Atom *a); - const LA25Atom *getLA25RegEntry(const Atom *a); - const LA25Atom *getLA25MicroEntry(const Atom *a); - const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a); - - PLTAtom *createPLTHeader(bool isMicroMips); - - bool isLocal(const Atom *a) const; - bool isLocalCall(const Atom *a) const; - bool isDynamic(const Atom *atom) const; - bool requireLA25Stub(const MipsELFDefinedAtom<ELFT> &atom, - const Reference &ref) const; - bool requirePLTEntry(const Atom *a) const; - bool requireCopy(const Atom *a) const; - bool mightBeDynamic(const MipsELFDefinedAtom<ELFT> &atom, - Reference::KindValue refKind) const; - bool hasPLTEntry(const Atom *atom) const; - - /// \brief Linked files contain microMIPS code. - bool isMicroMips(); - /// \brief Linked files contain MIPS R6 code. - bool isMipsR6(); -}; - -template <typename ELFT> -RelocationPass<ELFT>::RelocationPass(MipsLinkingContext &ctx) - : _ctx(ctx), _file(ctx) { - _localGotVector.push_back(new (_file._alloc) GOT0Atom<ELFT>(_file)); - _localGotVector.push_back(new (_file._alloc) - GOTModulePointerAtom<ELFT>(_file)); -} - -template <typename ELFT> -std::error_code RelocationPass<ELFT>::perform(SimpleFile &mf) { - for (const auto &atom : mf.defined()) - for (const auto &ref : *atom) { - const auto &da = *cast<MipsELFDefinedAtom<ELFT>>(atom); - if (auto ec = collectReferenceInfo(da, const_cast<Reference &>(*ref))) - return ec; - } - - // Process all references. - for (const auto &atom : mf.defined()) - for (const auto &ref : *atom) - handleReference(*cast<MipsELFDefinedAtom<ELFT>>(atom), - const_cast<Reference &>(*ref)); - - // Create R_MIPS_REL32 relocations. - for (auto *ref : _rel32Candidates) { - bool forceRel = isLocal(ref->target()) && _ctx.getOutputELFType() == ET_DYN; - if (!forceRel && (!isDynamic(ref->target()) || hasPLTEntry(ref->target()))) - continue; - ref->setKindValue(R_MIPS_REL32); - if (ELFT::Is64Bits) - static_cast<MipsELFReference<ELFT> *>(ref)->setTag(R_MIPS_64); - if (!isLocalCall(ref->target())) - getGlobalGOTEntry(ref->target()); - } - - uint64_t ordinal = 0; - - if (_ctx.isDynamic() && _ctx.getOutputELFType() == ET_EXEC) { - auto rlda = new (_file._alloc) MipsRldAtom<ELFT>(_file); - rlda->setOrdinal(ordinal++); - mf.addAtom(*rlda); - } - - if (!_localGotVector.empty() || !_globalGotVector.empty() || - !_tlsGotVector.empty()) { - SimpleDefinedAtom *ga = new (_file._alloc) MipsGlobalOffsetTableAtom(_file); - ga->setOrdinal(ordinal++); - mf.addAtom(*ga); - } - - for (auto &got : _localGotVector) { - got->setOrdinal(ordinal++); - mf.addAtom(*got); - } - - for (auto &got : _globalGotVector) { - got->setOrdinal(ordinal++); - mf.addAtom(*got); - } - - for (auto &got : _tlsGotVector) { - got->setOrdinal(ordinal++); - mf.addAtom(*got); - } - - // Create and emit PLT0 entry. - PLTAtom *plt0Atom = nullptr; - if (!_pltRegVector.empty()) - plt0Atom = createPLTHeader(false); - else if (!_pltMicroVector.empty()) - plt0Atom = createPLTHeader(true); - - if (plt0Atom) { - plt0Atom->setOrdinal(ordinal++); - mf.addAtom(*plt0Atom); - } - - // Emit regular PLT entries firts. - for (auto &plt : _pltRegVector) { - plt->setOrdinal(ordinal++); - mf.addAtom(*plt); - } - - // microMIPS PLT entries come after regular ones. - for (auto &plt : _pltMicroVector) { - plt->setOrdinal(ordinal++); - mf.addAtom(*plt); - } - - // Assign PLT0 to GOTPLT entries. - assert(_gotpltMap.empty() || plt0Atom); - for (auto &a: _gotpltMap) - a.second->setPLT0(plt0Atom); - - for (auto &gotplt : _gotpltVector) { - gotplt->setOrdinal(ordinal++); - mf.addAtom(*gotplt); - } - - for (auto obj : _objectVector) { - obj->setOrdinal(ordinal++); - mf.addAtom(*obj); - } - - for (auto la25 : _la25Vector) { - la25->setOrdinal(ordinal++); - mf.addAtom(*la25); - } - - return std::error_code(); -} - -static bool isMicroMipsReloc(Reference::KindValue kind) { - return R_MICROMIPS_26_S1 <= kind && kind <= R_MICROMIPS_PC19_S2; -} - -static bool isHiLo16Reloc(Reference::KindValue kind) { - return kind == R_MIPS_HI16 || kind == R_MIPS_LO16 || kind == R_MIPS_PCHI16 || - kind == R_MIPS_PCLO16 || kind == R_MICROMIPS_HI16 || - kind == R_MICROMIPS_LO16 || kind == R_MICROMIPS_HI0_LO16; -} - -static bool isBranchReloc(Reference::KindValue kind) { - return kind == R_MIPS_26 || kind == R_MICROMIPS_26_S1 || - kind == R_MIPS_PC16 || kind == R_MIPS_PC21_S2 || - kind == R_MIPS_PC26_S2 || kind == R_MICROMIPS_PC7_S1 || - kind == R_MICROMIPS_PC10_S1 || kind == R_MICROMIPS_PC16_S1 || - kind == R_MICROMIPS_PC23_S2; -} - -static bool isGotReloc(Reference::KindValue kind) { - return kind == R_MIPS_GOT16 || kind == R_MICROMIPS_GOT16; -} - -static bool isAllGotReloc(Reference::KindValue kind) { - return isGotReloc(kind) || kind == R_MIPS_GOT_HI16 || - kind == R_MIPS_GOT_LO16 || kind == R_MICROMIPS_GOT_HI16 || - kind == R_MICROMIPS_GOT_LO16; -} - -static bool isCallReloc(Reference::KindValue kind) { - return kind == R_MIPS_CALL16 || kind == R_MICROMIPS_CALL16; -} - -static bool isAllCallReloc(Reference::KindValue kind) { - return isCallReloc(kind) || kind == R_MIPS_CALL_HI16 || - kind == R_MIPS_CALL_LO16 || kind == R_MICROMIPS_CALL_HI16 || - kind == R_MICROMIPS_CALL_LO16; -} - -static bool isGotDispReloc(Reference::KindValue kind) { - return kind == R_MIPS_GOT_DISP || kind == R_MICROMIPS_GOT_DISP; -} - -static bool isGotPageReloc(Reference::KindValue kind) { - return kind == R_MIPS_GOT_PAGE || kind == R_MICROMIPS_GOT_PAGE; -} - -static bool isTlsDtpReloc(Reference::KindValue kind) { - return kind == R_MIPS_TLS_DTPREL_HI16 || kind == R_MIPS_TLS_DTPREL_LO16 || - kind == R_MICROMIPS_TLS_DTPREL_HI16 || - kind == R_MICROMIPS_TLS_DTPREL_LO16; -} - -static bool isTlsTpReloc(Reference::KindValue kind) { - return kind == R_MIPS_TLS_TPREL_HI16 || kind == R_MIPS_TLS_TPREL_LO16 || - kind == R_MICROMIPS_TLS_TPREL_HI16 || - kind == R_MICROMIPS_TLS_TPREL_LO16; -} - -static bool isTlsGdReloc(Reference::KindValue kind) { - return kind == R_MIPS_TLS_GD || kind == R_MICROMIPS_TLS_GD; -} - -static bool isTlsLdmReloc(Reference::KindValue kind) { - return kind == R_MIPS_TLS_LDM || kind == R_MICROMIPS_TLS_LDM; -} - -static bool isTlsGotTpReloc(Reference::KindValue kind) { - return kind == R_MIPS_TLS_GOTTPREL || kind == R_MICROMIPS_TLS_GOTTPREL; -} - -static bool isGpRelReloc(Reference::KindValue kind) { - return kind == R_MIPS_GPREL32 || kind == R_MIPS_GPREL16 || - kind == R_MICROMIPS_GPREL16 || kind == R_MICROMIPS_GPREL7_S2 || - kind == R_MIPS_LITERAL || kind == R_MICROMIPS_LITERAL; -} - -template <typename ELFT> -void RelocationPass<ELFT>::handleReference(const MipsELFDefinedAtom<ELFT> &atom, - Reference &ref) { - if (!ref.target()) - return; - if (ref.kindNamespace() != Reference::KindNamespace::ELF) - return; - - assert(ref.kindArch() == Reference::KindArch::Mips); - Reference::KindValue kind = ref.kindValue(); - if (isHiLo16Reloc(kind) || kind == R_MIPS_32 || kind == R_MIPS_PC32) - handlePlain(atom, ref); - else if (isBranchReloc(kind)) - handleBranch(atom, ref); - else if (isAllGotReloc(kind) || isAllCallReloc(kind) || - isGotDispReloc(kind) || isGotPageReloc(kind) || kind == R_MIPS_EH) - handleGOT(ref); - else if (isTlsDtpReloc(kind)) - ref.setAddend(ref.addend() - atom.file().getDTPOffset()); - else if (isTlsTpReloc(kind)) - ref.setAddend(ref.addend() - atom.file().getTPOffset()); - else if (isTlsGdReloc(kind)) - ref.setTarget(getTLSGdGOTEntry(ref.target(), ref.addend())); - else if (isTlsLdmReloc(kind)) - ref.setTarget(getTLSLdmGOTEntry(ref.target())); - else if (isTlsGotTpReloc(kind)) - ref.setTarget(getTLSGOTEntry(ref.target(), ref.addend())); - else if (kind == R_MIPS_GPREL32 || (isLocal(ref.target()) && isGpRelReloc(kind))) - ref.setAddend(ref.addend() + atom.file().getGP0()); - else if (kind == R_MIPS_JALR) { - if (_ctx.getOutputELFType() != ET_EXEC || !isLocalCall(ref.target())) - ref.setKindValue(R_MIPS_NONE); - } -} - -template <typename ELFT> -static bool isConstrainSym(const MipsELFDefinedAtom<ELFT> &atom, - Reference::KindValue refKind) { - if ((atom.section()->sh_flags & SHF_ALLOC) == 0) - return false; - switch (refKind) { - case R_MIPS_NONE: - case R_MIPS_JALR: - case R_MICROMIPS_JALR: - case R_MIPS_GPREL16: - case R_MIPS_GPREL32: - case R_MICROMIPS_GPREL16: - case R_MICROMIPS_GPREL7_S2: - case R_MIPS_LITERAL: - case R_MICROMIPS_LITERAL: - return false; - default: - return true; - } -} - -template <typename ELFT> -std::error_code -RelocationPass<ELFT>::collectReferenceInfo(const MipsELFDefinedAtom<ELFT> &atom, - Reference &ref) { - if (!ref.target()) - return std::error_code(); - if (ref.kindNamespace() != Reference::KindNamespace::ELF) - return std::error_code(); - - auto refKind = ref.kindValue(); - if (refKind == R_MIPS_EH && this->_ctx.mipsPcRelEhRel()) - ref.setKindValue(R_MIPS_PC32); - - if (auto ec = validateRelocation(atom, ref)) - return ec; - - if (!isConstrainSym(atom, refKind)) - return std::error_code(); - - if (!mightBeDynamic(atom, refKind)) - _hasStaticRelocations.insert(ref.target()); - else if (refKind == R_MIPS_32 || refKind == R_MIPS_64) - _rel32Candidates.push_back(&ref); - - if (!isBranchReloc(refKind) && !isAllCallReloc(refKind) && - refKind != R_MIPS_EH) - _requiresPtrEquality.insert(ref.target()); - - return std::error_code(); -} - -static std::error_code -make_reject_for_shared_lib_reloc_error(const ELFLinkingContext &ctx, - const DefinedAtom &atom, - const Reference &ref) { - StringRef kindValStr = "unknown"; - ctx.registry().referenceKindToString(ref.kindNamespace(), ref.kindArch(), - ref.kindValue(), kindValStr); - - return make_dynamic_error_code(Twine(kindValStr) + " (" + - Twine(ref.kindValue()) + - ") relocation cannot be used " - "when making a shared object, recompile " + - atom.file().path() + " with -fPIC"); -} - -static std::error_code -make_local_call16_reloc_error(const ELFLinkingContext &ctx, - const DefinedAtom &atom, const Reference &ref) { - return make_dynamic_error_code("R_MIPS_CALL16 (11) relocation cannot be used " - "against local symbol " + - ref.target()->name() + " in file " + - atom.file().path()); -} - -template <typename ELFT> -std::error_code -RelocationPass<ELFT>::validateRelocation(const DefinedAtom &atom, - const Reference &ref) const { - if (!ref.target()) - return std::error_code(); - - if (isCallReloc(ref.kindValue()) && isLocal(ref.target())) - return make_local_call16_reloc_error(this->_ctx, atom, ref); - - if (this->_ctx.getOutputELFType() != ET_DYN) - return std::error_code(); - - switch (ref.kindValue()) { - case R_MIPS16_HI16: - case R_MIPS_HI16: - case R_MIPS_HIGHER: - case R_MIPS_HIGHEST: - case R_MICROMIPS_HI16: - case R_MICROMIPS_HIGHER: - case R_MICROMIPS_HIGHEST: - // For shared object we accepts "high" relocations - // against the "_gp_disp" symbol only. - if (ref.target()->name() != "_gp_disp") - return make_reject_for_shared_lib_reloc_error(this->_ctx, atom, ref); - break; - case R_MIPS16_26: - case R_MIPS_26: - case R_MICROMIPS_26_S1: - // These relocations are position dependent - // and not acceptable in a shared object. - return make_reject_for_shared_lib_reloc_error(this->_ctx, atom, ref); - default: - break; - } - return std::error_code(); -} - -template <typename ELFT> -bool RelocationPass<ELFT>::isLocal(const Atom *a) const { - if (auto *da = dyn_cast<DefinedAtom>(a)) - return da->scope() == Atom::scopeTranslationUnit; - return false; -} - -template <typename ELFT> -static bool isMipsReadonly(const MipsELFDefinedAtom<ELFT> &atom) { - auto secFlags = atom.section()->sh_flags; - auto secType = atom.section()->sh_type; - - if ((secFlags & SHF_ALLOC) == 0) - return false; - if (secType == SHT_NOBITS) - return false; - if ((secFlags & SHF_WRITE) != 0) - return false; - return true; -} - -template <typename ELFT> -bool RelocationPass<ELFT>::mightBeDynamic(const MipsELFDefinedAtom<ELFT> &atom, - Reference::KindValue refKind) const { - if (isAllGotReloc(refKind) || isAllCallReloc(refKind)) - return true; - - if (refKind != R_MIPS_32 && refKind != R_MIPS_64) - return false; - if ((atom.section()->sh_flags & SHF_ALLOC) == 0) - return false; - - if (_ctx.getOutputELFType() == ET_DYN) - return true; - if (!isMipsReadonly(atom)) - return true; - if (atom.isPIC()) - return true; - - return false; -} - -template <typename ELFT> -bool RelocationPass<ELFT>::hasPLTEntry(const Atom *atom) const { - return _pltRegMap.count(atom) || _pltMicroMap.count(atom); -} - -template <typename ELFT> bool RelocationPass<ELFT>::isMicroMips() { - TargetHandler &handler = this->_ctx.getTargetHandler(); - return static_cast<MipsTargetHandler<ELFT> &>(handler) - .getAbiInfoHandler() - .isMicroMips(); -} - -template <typename ELFT> bool RelocationPass<ELFT>::isMipsR6() { - TargetHandler &handler = this->_ctx.getTargetHandler(); - return static_cast<MipsTargetHandler<ELFT> &>(handler) - .getAbiInfoHandler() - .isMipsR6(); -} - -template <typename ELFT> -bool RelocationPass<ELFT>::requirePLTEntry(const Atom *a) const { - if (!_hasStaticRelocations.count(a)) - return false; - const auto *sa = dyn_cast<ELFDynamicAtom<ELFT>>(a); - if (sa && sa->type() != SharedLibraryAtom::Type::Code) - return false; - const auto *da = dyn_cast<ELFDefinedAtom<ELFT>>(a); - if (da && da->contentType() != DefinedAtom::typeCode) - return false; - if (isLocalCall(a)) - return false; - return true; -} - -template <typename ELFT> -bool RelocationPass<ELFT>::requireCopy(const Atom *a) const { - if (!_hasStaticRelocations.count(a)) - return false; - const auto *sa = dyn_cast<ELFDynamicAtom<ELFT>>(a); - return sa && sa->type() == SharedLibraryAtom::Type::Data; -} - -template <typename ELFT> -bool RelocationPass<ELFT>::isDynamic(const Atom *atom) const { - const auto *da = dyn_cast<const DefinedAtom>(atom); - if (da && da->dynamicExport() == DefinedAtom::dynamicExportAlways) - return true; - if (isa<SharedLibraryAtom>(atom)) - return true; - if (_ctx.getOutputELFType() != ET_DYN) - return false; - if (da && da->scope() != DefinedAtom::scopeTranslationUnit) - return true; - return isa<UndefinedAtom>(atom); -} - -template <typename ELFT> -static bool isMicroMips(const MipsELFDefinedAtom<ELFT> &atom) { - return atom.codeModel() == DefinedAtom::codeMipsMicro || - atom.codeModel() == DefinedAtom::codeMipsMicroPIC; -} - -template <typename ELFT> -const PLTAtom *RelocationPass<ELFT>::getPLTEntry(const Atom *a) { - // If file contains microMIPS code try to reuse compressed PLT entry... - if (isMicroMips()) { - auto microPLT = _pltMicroMap.find(a); - if (microPLT != _pltMicroMap.end()) - return microPLT->second; - } - - // ... then try to reuse a regular PLT entry ... - auto regPLT = _pltRegMap.find(a); - if (regPLT != _pltRegMap.end()) - return regPLT->second; - - // ... and finally prefer to create new compressed PLT entry. - return isMicroMips() ? getPLTMicroEntry(a) : getPLTRegEntry(a); -} - -template <typename ELFT> -void RelocationPass<ELFT>::handlePlain(const MipsELFDefinedAtom<ELFT> &atom, - Reference &ref) { - if (!isDynamic(ref.target())) - return; - - if (requirePLTEntry(ref.target())) - ref.setTarget(getPLTEntry(ref.target())); - else if (requireCopy(ref.target())) - ref.setTarget(getObjectEntry(cast<SharedLibraryAtom>(ref.target()))); -} - -template <typename ELFT> -void RelocationPass<ELFT>::handleBranch(const MipsELFDefinedAtom<ELFT> &atom, - Reference &ref) { - bool isMicro = isMicroMipsReloc(ref.kindValue()); - if (const auto *sla = dyn_cast<SharedLibraryAtom>(ref.target())) { - if (sla->type() == SharedLibraryAtom::Type::Code) - ref.setTarget(isMicro ? getPLTMicroEntry(sla) : getPLTRegEntry(sla)); - } else if (requireLA25Stub(atom, ref)) { - if (isMicro) - ref.setTarget(getLA25MicroEntry(ref.target())); - else - ref.setTarget(getLA25RegEntry(ref.target())); - } - - if (!isLocal(ref.target())) { - if (ref.kindValue() == R_MICROMIPS_26_S1) - ref.setKindValue(LLD_R_MICROMIPS_GLOBAL_26_S1); - else if (ref.kindValue() == R_MIPS_26) - ref.setKindValue(LLD_R_MIPS_GLOBAL_26); - } -} - -template <typename ELFT> void RelocationPass<ELFT>::handleGOT(Reference &ref) { - if (!isLocalCall(ref.target())) - ref.setTarget(getGlobalGOTEntry(ref.target())); - else if (isGotPageReloc(ref.kindValue())) - ref.setTarget(getLocalGOTPageEntry(ref)); - else if (isLocal(ref.target()) && - (isCallReloc(ref.kindValue()) || isGotReloc(ref.kindValue()))) - ref.setTarget(getLocalGOTPageEntry(ref)); - else - ref.setTarget(getLocalGOTEntry(ref)); -} - -template <typename ELFT> -bool RelocationPass<ELFT>::isLocalCall(const Atom *a) const { - Atom::Scope scope; - if (auto *da = dyn_cast<DefinedAtom>(a)) - scope = da->scope(); - else if (auto *aa = dyn_cast<AbsoluteAtom>(a)) - scope = aa->scope(); - else - return false; - - // Local and hidden symbols must be local. - if (scope == Atom::scopeTranslationUnit || scope == Atom::scopeLinkageUnit) - return true; - - // Calls to external symbols defined in an executable file resolved locally. - if (_ctx.getOutputELFType() == ET_EXEC) - return true; - - return false; -} - -template <typename ELFT> -bool RelocationPass<ELFT>::requireLA25Stub(const MipsELFDefinedAtom<ELFT> &atom, - const Reference &ref) const { - if (atom.file().isPIC()) - return false; - if (auto *da = dyn_cast<DefinedAtom>(ref.target())) - return static_cast<const MipsELFDefinedAtom<ELFT> *>(da)->isPIC(); - return false; -} - -template <typename ELFT> -const GOTAtom *RelocationPass<ELFT>::getLocalGOTEntry(const Reference &ref) { - const Atom *a = ref.target(); - LocalGotMapKeyT key(a, ref.addend()); - - auto got = _gotLocalMap.find(key); - if (got != _gotLocalMap.end()) - return got->second; - - auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file); - _gotLocalMap[key] = ga; - - _localGotVector.push_back(ga); - - Reference::KindValue relKind = ELFT::Is64Bits ? R_MIPS_64 : R_MIPS_32; - ga->addReferenceELF_Mips(relKind, 0, a, 0); - - return ga; -} - -template <typename ELFT> -const GOTAtom * -RelocationPass<ELFT>::getLocalGOTPageEntry(const Reference &ref) { - const Atom *a = ref.target(); - LocalGotMapKeyT key(a, ref.addend()); - - auto got = _gotLocalPageMap.find(key); - if (got != _gotLocalPageMap.end()) - return got->second; - - auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file); - _gotLocalPageMap[key] = ga; - - _localGotVector.push_back(ga); - - Reference::KindValue relKind = - ELFT::Is64Bits ? LLD_R_MIPS_64_HI16 : LLD_R_MIPS_32_HI16; - ga->addReferenceELF_Mips(relKind, 0, a, ref.addend()); - - return ga; -} - -template <typename ELFT> -const GOTAtom *RelocationPass<ELFT>::getGlobalGOTEntry(const Atom *a) { - auto got = _gotGlobalMap.find(a); - if (got != _gotGlobalMap.end()) - return got->second; - - auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file); - _gotGlobalMap[a] = ga; - - _globalGotVector.push_back(ga); - ga->addReferenceELF_Mips(LLD_R_MIPS_GLOBAL_GOT, 0, a, 0); - - if (const DefinedAtom *da = dyn_cast<DefinedAtom>(a)) - ga->addReferenceELF_Mips(R_MIPS_32, 0, da, 0); - - return ga; -} - -template <typename ELFT> -const GOTAtom *RelocationPass<ELFT>::getTLSGOTEntry(const Atom *a, - Reference::Addend addend) { - auto got = _gotTLSMap.find(a); - if (got != _gotTLSMap.end()) - return got->second; - - auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file); - _gotTLSMap[a] = ga; - - _tlsGotVector.push_back(ga); - Reference::KindValue relKind = - ELFT::Is64Bits ? R_MIPS_TLS_TPREL64 : R_MIPS_TLS_TPREL32; - ga->addReferenceELF_Mips(relKind, 0, a, addend); - - return ga; -} - -template <typename ELFT> -const GOTAtom * -RelocationPass<ELFT>::getTLSGdGOTEntry(const Atom *a, - Reference::Addend addend) { - auto got = _gotTLSGdMap.find(a); - if (got != _gotTLSGdMap.end()) - return got->second; - - auto ga = new (_file._alloc) GOTTLSGdAtom<ELFT>(_file); - _gotTLSGdMap[a] = ga; - - _tlsGotVector.push_back(ga); - if (ELFT::Is64Bits) { - ga->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD64, 0, a, addend); - ga->addReferenceELF_Mips(R_MIPS_TLS_DTPREL64, 8, a, addend); - } else { - ga->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD32, 0, a, addend); - ga->addReferenceELF_Mips(R_MIPS_TLS_DTPREL32, 4, a, addend); - } - - return ga; -} - -template <typename ELFT> -const GOTAtom *RelocationPass<ELFT>::getTLSLdmGOTEntry(const Atom *a) { - if (_gotLDMEntry) - return _gotLDMEntry; - - _gotLDMEntry = new (_file._alloc) GOTTLSGdAtom<ELFT>(_file); - _tlsGotVector.push_back(_gotLDMEntry); - if (ELFT::Is64Bits) - _gotLDMEntry->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD64, 0, _gotLDMEntry, 0); - else - _gotLDMEntry->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD32, 0, _gotLDMEntry, 0); - - return _gotLDMEntry; -} - -template <typename ELFT> -PLTAtom *RelocationPass<ELFT>::createPLTHeader(bool isMicroMips) { - auto ga1 = new (_file._alloc) GOTPLTAtom(_file); - _gotpltVector.insert(_gotpltVector.begin(), ga1); - auto ga0 = new (_file._alloc) GOTPLTAtom(_file); - _gotpltVector.insert(_gotpltVector.begin(), ga0); - - 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); -} - -template <typename ELFT> -const GOTPLTAtom *RelocationPass<ELFT>::getGOTPLTEntry(const Atom *a) { - auto it = _gotpltMap.find(a); - if (it != _gotpltMap.end()) - return it->second; - - auto ga = new (_file._alloc) GOTPLTAtom(a, _file); - _gotpltMap[a] = ga; - _gotpltVector.push_back(ga); - return ga; -} - -template <typename ELFT> -const PLTAtom *RelocationPass<ELFT>::getPLTRegEntry(const Atom *a) { - auto plt = _pltRegMap.find(a); - if (plt != _pltRegMap.end()) - return plt->second; - - PLTAAtom *pa = nullptr; - if (isMipsR6()) - pa = new (_file._alloc) PLTR6Atom<ELFT>(getGOTPLTEntry(a), _file); - else - pa = new (_file._alloc) PLTARegAtom<ELFT>(getGOTPLTEntry(a), _file); - _pltRegMap[a] = pa; - _pltRegVector.push_back(pa); - - // Check that 'a' dynamic symbol table record should point to the PLT. - if (_hasStaticRelocations.count(a) && _requiresPtrEquality.count(a)) - pa->addReferenceELF_Mips(LLD_R_MIPS_STO_PLT, 0, a, 0); - - return pa; -} - -template <typename ELFT> -const PLTAtom *RelocationPass<ELFT>::getPLTMicroEntry(const Atom *a) { - auto plt = _pltMicroMap.find(a); - if (plt != _pltMicroMap.end()) - return plt->second; - - auto pa = new (_file._alloc) PLTMicroAtom<ELFT>(getGOTPLTEntry(a), _file); - _pltMicroMap[a] = pa; - _pltMicroVector.push_back(pa); - - // Check that 'a' dynamic symbol table record should point to the PLT. - if (_hasStaticRelocations.count(a) && _requiresPtrEquality.count(a)) - pa->addReferenceELF_Mips(LLD_R_MIPS_STO_PLT, 0, a, 0); - - return pa; -} - -template <typename ELFT> -const LA25Atom *RelocationPass<ELFT>::getLA25RegEntry(const Atom *a) { - auto la25 = _la25RegMap.find(a); - if (la25 != _la25RegMap.end()) - return la25->second; - - auto sa = new (_file._alloc) LA25RegAtom<ELFT>(a, _file); - _la25RegMap[a] = sa; - _la25Vector.push_back(sa); - - return sa; -} - -template <typename ELFT> -const LA25Atom *RelocationPass<ELFT>::getLA25MicroEntry(const Atom *a) { - auto la25 = _la25MicroMap.find(a); - if (la25 != _la25MicroMap.end()) - return la25->second; - - auto sa = new (_file._alloc) LA25MicroAtom<ELFT>(a, _file); - _la25MicroMap[a] = sa; - _la25Vector.push_back(sa); - - return sa; -} - -template <typename ELFT> -const ObjectAtom * -RelocationPass<ELFT>::getObjectEntry(const SharedLibraryAtom *a) { - auto obj = _objectMap.find(a); - if (obj != _objectMap.end()) - return obj->second; - - auto oa = new (_file._alloc) ObjectAtom(_file); - oa->addReferenceELF_Mips(R_MIPS_COPY, 0, oa, 0); - oa->_name = a->name(); - oa->_size = a->size(); - - _objectMap[a] = oa; - _objectVector.push_back(oa); - - return oa; -} - -} // end anon namespace - -static std::unique_ptr<Pass> createPass(MipsLinkingContext &ctx) { - switch (ctx.getTriple().getArch()) { - case llvm::Triple::mips: - return llvm::make_unique<RelocationPass<ELF32BE>>(ctx); - case llvm::Triple::mipsel: - return llvm::make_unique<RelocationPass<ELF32LE>>(ctx); - case llvm::Triple::mips64: - return llvm::make_unique<RelocationPass<ELF64BE>>(ctx); - case llvm::Triple::mips64el: - return llvm::make_unique<RelocationPass<ELF64LE>>(ctx); - default: - llvm_unreachable("Unhandled arch"); - } -} - -std::unique_ptr<Pass> -lld::elf::createMipsRelocationPass(MipsLinkingContext &ctx) { - switch (ctx.getOutputELFType()) { - case ET_EXEC: - case ET_DYN: - return createPass(ctx); - case ET_REL: - return nullptr; - default: - llvm_unreachable("Unhandled output file type"); - } -} |