summaryrefslogtreecommitdiff
path: root/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp')
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp783
1 files changed, 564 insertions, 219 deletions
diff --git a/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp b/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
index a1b3530dfcdf..b47c7d2210db 100644
--- a/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
+++ b/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
@@ -37,20 +37,69 @@ static const uint8_t mipsGotTlsGdAtomContent[] = {
0x00, 0x00, 0x00, 0x00
};
-// Regular PLT0 entry
-static const uint8_t mipsPlt0AtomContent[] = {
+// 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
- 0x21, 0x78, 0xe0, 0x03, // move $15, $31
+ 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 PLT0 entry
-static const uint8_t micromipsPlt0AtomContent[] = {
+// 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
@@ -62,40 +111,80 @@ static const uint8_t micromipsPlt0AtomContent[] = {
0x00, 0x0c // nop
};
-// Regular PLT entry
-static const uint8_t mipsPltAAtomContent[] = {
+// 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 PLT entry
-static const uint8_t micromipsPltAtomContent[] = {
+// 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 PLT entry
-static const uint8_t mipsR6PltAAtomContent[] = {
+// 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 stub entry
-static const uint8_t mipsLA25AtomContent[] = {
+// 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 stub entry
-static const uint8_t micromipsLA25AtomContent[] = {
+// 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)
@@ -109,7 +198,7 @@ class MipsGOTAtom : public GOTAtom {
public:
MipsGOTAtom(const File &f) : GOTAtom(f, ".got") {}
- Alignment alignment() const override { return Alignment(2); }
+ Alignment alignment() const override { return 4; }
};
/// \brief MIPS GOT entry initialized by zero.
@@ -120,10 +209,16 @@ public:
ArrayRef<uint8_t> rawContent() const override;
};
-template <> ArrayRef<uint8_t> GOT0Atom<Mips32ELType>::rawContent() const {
+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<Mips64ELType>::rawContent() const {
+template <> ArrayRef<uint8_t> GOT0Atom<ELF64BE>::rawContent() const {
+ return llvm::makeArrayRef(mipsGot0AtomContent);
+}
+template <> ArrayRef<uint8_t> GOT0Atom<ELF64LE>::rawContent() const {
return llvm::makeArrayRef(mipsGot0AtomContent);
}
@@ -136,11 +231,19 @@ public:
};
template <>
-ArrayRef<uint8_t> GOTModulePointerAtom<Mips32ELType>::rawContent() const {
+ArrayRef<uint8_t> GOTModulePointerAtom<ELF32BE>::rawContent() const {
return llvm::makeArrayRef(mipsGotModulePointerAtomContent).slice(4);
}
template <>
-ArrayRef<uint8_t> GOTModulePointerAtom<Mips64ELType>::rawContent() const {
+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);
}
@@ -152,12 +255,17 @@ public:
ArrayRef<uint8_t> rawContent() const override;
};
-template <> ArrayRef<uint8_t> GOTTLSGdAtom<Mips32ELType>::rawContent() const {
- return llvm::makeArrayRef(mipsGotTlsGdAtomContent).slice(8);
+template <> ArrayRef<uint8_t> GOTTLSGdAtom<ELF32BE>::rawContent() const {
+ return llvm::makeArrayRef(mipsGotTlsGdAtomContent).slice(8);
}
-
-template <> ArrayRef<uint8_t> GOTTLSGdAtom<Mips64ELType>::rawContent() const {
- return llvm::makeArrayRef(mipsGotTlsGdAtomContent);
+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 {
@@ -173,28 +281,56 @@ public:
addReferenceELF_Mips(R_MIPS_32, 0, plt0, 0);
}
- Alignment alignment() const override { return Alignment(2); }
+ Alignment alignment() const override { return 4; }
ArrayRef<uint8_t> rawContent() const override {
return llvm::makeArrayRef(mipsGot0AtomContent).slice(4);
}
};
-class PLT0Atom : public PLTAtom {
+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(LLD_R_MIPS_HI16, 0, got, 0);
- addReferenceELF_Mips(LLD_R_MIPS_LO16, 4, got, 0);
- addReferenceELF_Mips(LLD_R_MIPS_LO16, 8, got, 0);
+ 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 {
- return llvm::makeArrayRef(mipsPlt0AtomContent);
+ llvm_unreachable("PLT0 is not applicable for this target");
}
};
-class PLT0MicroAtom : public PLTAtom {
+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.
@@ -204,54 +340,87 @@ public:
CodeModel codeModel() const override { return codeMipsMicro; }
ArrayRef<uint8_t> rawContent() const override {
- return llvm::makeArrayRef(micromipsPlt0AtomContent);
+ 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(LLD_R_MIPS_HI16, 0, got, 0);
- addReferenceELF_Mips(LLD_R_MIPS_LO16, 4, got, 0);
- addReferenceELF_Mips(LLD_R_MIPS_LO16, 12, got, 0);
+ 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 {
- return llvm::makeArrayRef(mipsPltAAtomContent);
+ llvm_unreachable("PLT is not applicable for this target");
}
};
-class PLTR6Atom : public PLTAAtom {
+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 {
- return llvm::makeArrayRef(mipsR6PltAAtomContent);
+ llvm_unreachable("PLT is not applicable for this target");
}
};
-class PLTMicroAtom : public PLTAtom {
+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 Alignment(1); }
+ Alignment alignment() const override { return 2; }
CodeModel codeModel() const override { return codeMipsMicro; }
ArrayRef<uint8_t> rawContent() const override {
- return llvm::makeArrayRef(micromipsPltAtomContent);
+ 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") {}
};
-class LA25RegAtom : public LA25Atom {
+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.
@@ -261,11 +430,18 @@ public:
}
ArrayRef<uint8_t> rawContent() const override {
- return llvm::makeArrayRef(mipsLA25AtomContent);
+ llvm_unreachable("LA25 stubs are not applicable for this target");
}
};
-class LA25MicroAtom : public LA25Atom {
+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.
@@ -277,7 +453,39 @@ public:
CodeModel codeModel() const override { return codeMipsMicro; }
ArrayRef<uint8_t> rawContent() const override {
- return llvm::makeArrayRef(micromipsLA25AtomContent);
+ 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);
}
};
@@ -295,7 +503,7 @@ template <typename ELFT> class RelocationPass : public Pass {
public:
RelocationPass(MipsLinkingContext &ctx);
- void perform(std::unique_ptr<MutableFile> &mf) override;
+ std::error_code perform(SimpleFile &mf) override;
private:
/// \brief Reference to the linking context.
@@ -319,7 +527,7 @@ private:
llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSGdMap;
/// \brief GOT entry for the R_xxxMIPS_TLS_LDM relocations.
- GOTTLSGdAtom<ELFT> *_gotLDMEntry;
+ GOTTLSGdAtom<ELFT> *_gotLDMEntry = nullptr;
/// \brief the list of local GOT atoms.
std::vector<GOTAtom *> _localGotVector;
@@ -335,14 +543,14 @@ private:
/// \brief Map Atoms to their PLT entries.
llvm::DenseMap<const Atom *, PLTAAtom *> _pltRegMap;
- llvm::DenseMap<const Atom *, PLTMicroAtom *> _pltMicroMap;
+ 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 *, LA25RegAtom *> _la25RegMap;
- llvm::DenseMap<const Atom *, LA25MicroAtom *> _la25MicroMap;
+ llvm::DenseMap<const Atom *, LA25Atom *> _la25RegMap;
+ llvm::DenseMap<const Atom *, LA25Atom *> _la25MicroMap;
/// \brief Atoms referenced by static relocations.
llvm::DenseSet<const Atom *> _hasStaticRelocations;
@@ -372,24 +580,27 @@ private:
/// \brief Collect information about the reference to use it
/// later in the handleReference() routine.
- void collectReferenceInfo(const MipsELFDefinedAtom<ELFT> &atom,
- Reference &ref);
+ 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 handle26(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);
- const GOTAtom *getTLSGdGOTEntry(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 *getLA25Entry(const Atom *target, bool isMicroMips);
const LA25Atom *getLA25RegEntry(const Atom *a);
const LA25Atom *getLA25MicroEntry(const Atom *a);
const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a);
@@ -399,40 +610,47 @@ private:
bool isLocal(const Atom *a) const;
bool isLocalCall(const Atom *a) const;
bool isDynamic(const Atom *atom) const;
- bool requireLA25Stub(const Atom *a) 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;
- bool isR6Target() 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), _gotLDMEntry(nullptr) {
+ : _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>
-void RelocationPass<ELFT>::perform(std::unique_ptr<MutableFile> &mf) {
- for (const auto &atom : mf->defined())
- for (const auto &ref : *atom)
- collectReferenceInfo(*cast<MipsELFDefinedAtom<ELFT>>(atom),
- const_cast<Reference &>(*ref));
+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 &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) {
- if (!isDynamic(ref->target()) || hasPLTEntry(ref->target()))
+ 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)
@@ -443,19 +661,32 @@ void RelocationPass<ELFT>::perform(std::unique_ptr<MutableFile> &mf) {
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);
+ mf.addAtom(*got);
}
for (auto &got : _globalGotVector) {
got->setOrdinal(ordinal++);
- mf->addAtom(*got);
+ mf.addAtom(*got);
}
for (auto &got : _tlsGotVector) {
got->setOrdinal(ordinal++);
- mf->addAtom(*got);
+ mf.addAtom(*got);
}
// Create and emit PLT0 entry.
@@ -467,19 +698,19 @@ void RelocationPass<ELFT>::perform(std::unique_ptr<MutableFile> &mf) {
if (plt0Atom) {
plt0Atom->setOrdinal(ordinal++);
- mf->addAtom(*plt0Atom);
+ mf.addAtom(*plt0Atom);
}
// Emit regular PLT entries firts.
for (auto &plt : _pltRegVector) {
plt->setOrdinal(ordinal++);
- mf->addAtom(*plt);
+ mf.addAtom(*plt);
}
// microMIPS PLT entries come after regular ones.
for (auto &plt : _pltMicroVector) {
plt->setOrdinal(ordinal++);
- mf->addAtom(*plt);
+ mf.addAtom(*plt);
}
// Assign PLT0 to GOTPLT entries.
@@ -489,18 +720,96 @@ void RelocationPass<ELFT>::perform(std::unique_ptr<MutableFile> &mf) {
for (auto &gotplt : _gotpltVector) {
gotplt->setOrdinal(ordinal++);
- mf->addAtom(*gotplt);
+ mf.addAtom(*gotplt);
}
for (auto obj : _objectVector) {
obj->setOrdinal(ordinal++);
- mf->addAtom(*obj);
+ mf.addAtom(*obj);
}
for (auto la25 : _la25Vector) {
la25->setOrdinal(ordinal++);
- mf->addAtom(*la25);
+ 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>
@@ -508,67 +817,33 @@ void RelocationPass<ELFT>::handleReference(const MipsELFDefinedAtom<ELFT> &atom,
Reference &ref) {
if (!ref.target())
return;
- if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF)
+ if (ref.kindNamespace() != Reference::KindNamespace::ELF)
return;
+
assert(ref.kindArch() == Reference::KindArch::Mips);
- switch (ref.kindValue()) {
- case R_MIPS_32:
- case R_MIPS_PC32:
- case R_MIPS_HI16:
- case R_MIPS_LO16:
- case R_MIPS_PCHI16:
- case R_MIPS_PCLO16:
- case R_MICROMIPS_HI16:
- case R_MICROMIPS_LO16:
- // FIXME (simon): Handle dynamic/static linking differently.
+ Reference::KindValue kind = ref.kindValue();
+ if (isHiLo16Reloc(kind) || kind == R_MIPS_32 || kind == R_MIPS_PC32)
handlePlain(atom, ref);
- break;
- case R_MIPS_26:
- case R_MICROMIPS_26_S1:
- handle26(atom, ref);
- break;
- case R_MIPS_GOT16:
- case R_MIPS_CALL16:
- case R_MICROMIPS_GOT16:
- case R_MICROMIPS_CALL16:
- case R_MIPS_GOT_DISP:
- case R_MIPS_GOT_PAGE:
+ else if (isBranchReloc(kind))
+ handleBranch(atom, ref);
+ else if (isAllGotReloc(kind) || isAllCallReloc(kind) ||
+ isGotDispReloc(kind) || isGotPageReloc(kind) || kind == R_MIPS_EH)
handleGOT(ref);
- break;
- case R_MIPS_GOT_OFST:
- // Nothing to do. We create GOT page entry in the R_MIPS_GOT_PAGE handler.
- break;
- case R_MIPS_GPREL16:
- if (isLocal(ref.target()))
- ref.setAddend(ref.addend() + atom.file().getGP0());
- break;
- case R_MIPS_GPREL32:
- ref.setAddend(ref.addend() + atom.file().getGP0());
- break;
- case R_MIPS_TLS_DTPREL_HI16:
- case R_MIPS_TLS_DTPREL_LO16:
- case R_MICROMIPS_TLS_DTPREL_HI16:
- case R_MICROMIPS_TLS_DTPREL_LO16:
+ else if (isTlsDtpReloc(kind))
ref.setAddend(ref.addend() - atom.file().getDTPOffset());
- break;
- case R_MIPS_TLS_TPREL_HI16:
- case R_MIPS_TLS_TPREL_LO16:
- case R_MICROMIPS_TLS_TPREL_HI16:
- case R_MICROMIPS_TLS_TPREL_LO16:
+ else if (isTlsTpReloc(kind))
ref.setAddend(ref.addend() - atom.file().getTPOffset());
- break;
- case R_MIPS_TLS_GD:
- case R_MICROMIPS_TLS_GD:
- ref.setTarget(getTLSGdGOTEntry(ref.target()));
- break;
- case R_MIPS_TLS_LDM:
- case R_MICROMIPS_TLS_LDM:
+ else if (isTlsGdReloc(kind))
+ ref.setTarget(getTLSGdGOTEntry(ref.target(), ref.addend()));
+ else if (isTlsLdmReloc(kind))
ref.setTarget(getTLSLdmGOTEntry(ref.target()));
- break;
- case R_MIPS_TLS_GOTTPREL:
- case R_MICROMIPS_TLS_GOTTPREL:
- ref.setTarget(getTLSGOTEntry(ref.target()));
- break;
+ 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);
}
}
@@ -583,6 +858,10 @@ static bool isConstrainSym(const MipsELFDefinedAtom<ELFT> &atom,
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;
@@ -590,25 +869,96 @@ static bool isConstrainSym(const MipsELFDefinedAtom<ELFT> &atom,
}
template <typename ELFT>
-void RelocationPass<ELFT>::collectReferenceInfo(
- const MipsELFDefinedAtom<ELFT> &atom, Reference &ref) {
+std::error_code
+RelocationPass<ELFT>::collectReferenceInfo(const MipsELFDefinedAtom<ELFT> &atom,
+ Reference &ref) {
if (!ref.target())
- return;
- if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF)
- return;
+ 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;
+ return std::error_code();
- if (mightBeDynamic(atom, refKind))
- _rel32Candidates.push_back(&ref);
- else
+ if (!mightBeDynamic(atom, refKind))
_hasStaticRelocations.insert(ref.target());
+ else if (refKind == R_MIPS_32 || refKind == R_MIPS_64)
+ _rel32Candidates.push_back(&ref);
- if (refKind != R_MIPS_CALL16 && refKind != R_MICROMIPS_CALL16 &&
- refKind != R_MIPS_26 && refKind != R_MICROMIPS_26_S1)
+ 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>
@@ -635,8 +985,7 @@ static bool isMipsReadonly(const MipsELFDefinedAtom<ELFT> &atom) {
template <typename ELFT>
bool RelocationPass<ELFT>::mightBeDynamic(const MipsELFDefinedAtom<ELFT> &atom,
Reference::KindValue refKind) const {
- if (refKind == R_MIPS_CALL16 || refKind == R_MIPS_GOT16 ||
- refKind == R_MICROMIPS_CALL16 || refKind == R_MICROMIPS_GOT16)
+ if (isAllGotReloc(refKind) || isAllCallReloc(refKind))
return true;
if (refKind != R_MIPS_32 && refKind != R_MIPS_64)
@@ -648,7 +997,7 @@ bool RelocationPass<ELFT>::mightBeDynamic(const MipsELFDefinedAtom<ELFT> &atom,
return true;
if (!isMipsReadonly(atom))
return true;
- if (atom.file().isPIC())
+ if (atom.isPIC())
return true;
return false;
@@ -659,14 +1008,18 @@ bool RelocationPass<ELFT>::hasPLTEntry(const Atom *atom) const {
return _pltRegMap.count(atom) || _pltMicroMap.count(atom);
}
-template <typename ELFT> bool RelocationPass<ELFT>::isR6Target() const {
- switch (_ctx.getMergedELFFlags() & EF_MIPS_ARCH) {
- case EF_MIPS_ARCH_32R6:
- case EF_MIPS_ARCH_64R6:
- return true;
- default:
- return false;
- }
+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>
@@ -697,21 +1050,13 @@ bool RelocationPass<ELFT>::isDynamic(const Atom *atom) const {
const auto *da = dyn_cast<const DefinedAtom>(atom);
if (da && da->dynamicExport() == DefinedAtom::dynamicExportAlways)
return true;
-
- const auto *sa = dyn_cast<SharedLibraryAtom>(atom);
- if (sa)
+ if (isa<SharedLibraryAtom>(atom))
return true;
-
- if (_ctx.getOutputELFType() == ET_DYN) {
- if (da && da->scope() != DefinedAtom::scopeTranslationUnit)
- return true;
-
- const auto *ua = dyn_cast<UndefinedAtom>(atom);
- if (ua)
- return true;
- }
-
- return false;
+ if (_ctx.getOutputELFType() != ET_DYN)
+ return false;
+ if (da && da->scope() != DefinedAtom::scopeTranslationUnit)
+ return true;
+ return isa<UndefinedAtom>(atom);
}
template <typename ELFT>
@@ -721,17 +1066,9 @@ static bool isMicroMips(const MipsELFDefinedAtom<ELFT> &atom) {
}
template <typename ELFT>
-const LA25Atom *RelocationPass<ELFT>::getLA25Entry(const Atom *target,
- bool isMicroMips) {
- return isMicroMips ? getLA25MicroEntry(target) : getLA25RegEntry(target);
-}
-
-template <typename ELFT>
const PLTAtom *RelocationPass<ELFT>::getPLTEntry(const Atom *a) {
- bool hasMicroCode = _ctx.getMergedELFFlags() & EF_MIPS_MICROMIPS;
-
// If file contains microMIPS code try to reuse compressed PLT entry...
- if (hasMicroCode) {
+ if (isMicroMips()) {
auto microPLT = _pltMicroMap.find(a);
if (microPLT != _pltMicroMap.end())
return microPLT->second;
@@ -743,7 +1080,7 @@ const PLTAtom *RelocationPass<ELFT>::getPLTEntry(const Atom *a) {
return regPLT->second;
// ... and finally prefer to create new compressed PLT entry.
- return hasMicroCode ? getPLTMicroEntry(a) : getPLTRegEntry(a);
+ return isMicroMips() ? getPLTMicroEntry(a) : getPLTRegEntry(a);
}
template <typename ELFT>
@@ -759,37 +1096,34 @@ void RelocationPass<ELFT>::handlePlain(const MipsELFDefinedAtom<ELFT> &atom,
}
template <typename ELFT>
-void RelocationPass<ELFT>::handle26(const MipsELFDefinedAtom<ELFT> &atom,
- Reference &ref) {
- bool isMicro = ref.kindValue() == R_MICROMIPS_26_S1;
- assert((isMicro || ref.kindValue() == R_MIPS_26) && "Unexpected relocation");
-
- const auto *sla = dyn_cast<SharedLibraryAtom>(ref.target());
- if (sla && sla->type() == SharedLibraryAtom::Type::Code)
- ref.setTarget(isMicro ? getPLTMicroEntry(sla) : getPLTRegEntry(sla));
-
- if (requireLA25Stub(ref.target()))
- ref.setTarget(getLA25Entry(ref.target(), isMicro));
+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 (isMicro)
+ if (ref.kindValue() == R_MICROMIPS_26_S1)
ref.setKindValue(LLD_R_MICROMIPS_GLOBAL_26_S1);
- else
+ 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())) {
+ if (!isLocalCall(ref.target()))
ref.setTarget(getGlobalGOTEntry(ref.target()));
- return;
- }
-
- if (ref.kindValue() == R_MIPS_GOT_PAGE)
+ else if (isGotPageReloc(ref.kindValue()))
ref.setTarget(getLocalGOTPageEntry(ref));
- else if (ref.kindValue() == R_MIPS_GOT_DISP)
- ref.setTarget(getLocalGOTEntry(ref));
- else if (isLocal(ref.target()))
+ else if (isLocal(ref.target()) &&
+ (isCallReloc(ref.kindValue()) || isGotReloc(ref.kindValue())))
ref.setTarget(getLocalGOTPageEntry(ref));
else
ref.setTarget(getLocalGOTEntry(ref));
@@ -817,11 +1151,12 @@ bool RelocationPass<ELFT>::isLocalCall(const Atom *a) const {
}
template <typename ELFT>
-bool RelocationPass<ELFT>::requireLA25Stub(const Atom *a) const {
- if (isLocal(a))
+bool RelocationPass<ELFT>::requireLA25Stub(const MipsELFDefinedAtom<ELFT> &atom,
+ const Reference &ref) const {
+ if (atom.file().isPIC())
return false;
- if (auto *da = dyn_cast<DefinedAtom>(a))
- return static_cast<const MipsELFDefinedAtom<ELFT> *>(da)->file().isPIC();
+ if (auto *da = dyn_cast<DefinedAtom>(ref.target()))
+ return static_cast<const MipsELFDefinedAtom<ELFT> *>(da)->isPIC();
return false;
}
@@ -886,7 +1221,8 @@ const GOTAtom *RelocationPass<ELFT>::getGlobalGOTEntry(const Atom *a) {
}
template <typename ELFT>
-const GOTAtom *RelocationPass<ELFT>::getTLSGOTEntry(const Atom *a) {
+const GOTAtom *RelocationPass<ELFT>::getTLSGOTEntry(const Atom *a,
+ Reference::Addend addend) {
auto got = _gotTLSMap.find(a);
if (got != _gotTLSMap.end())
return got->second;
@@ -897,13 +1233,15 @@ const GOTAtom *RelocationPass<ELFT>::getTLSGOTEntry(const Atom *a) {
_tlsGotVector.push_back(ga);
Reference::KindValue relKind =
ELFT::Is64Bits ? R_MIPS_TLS_TPREL64 : R_MIPS_TLS_TPREL32;
- ga->addReferenceELF_Mips(relKind, 0, a, 0);
+ ga->addReferenceELF_Mips(relKind, 0, a, addend);
return ga;
}
template <typename ELFT>
-const GOTAtom *RelocationPass<ELFT>::getTLSGdGOTEntry(const Atom *a) {
+const GOTAtom *
+RelocationPass<ELFT>::getTLSGdGOTEntry(const Atom *a,
+ Reference::Addend addend) {
auto got = _gotTLSGdMap.find(a);
if (got != _gotTLSGdMap.end())
return got->second;
@@ -913,11 +1251,11 @@ const GOTAtom *RelocationPass<ELFT>::getTLSGdGOTEntry(const Atom *a) {
_tlsGotVector.push_back(ga);
if (ELFT::Is64Bits) {
- ga->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD64, 0, a, 0);
- ga->addReferenceELF_Mips(R_MIPS_TLS_DTPREL64, 8, a, 0);
+ 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, 0);
- ga->addReferenceELF_Mips(R_MIPS_TLS_DTPREL32, 4, a, 0);
+ ga->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD32, 0, a, addend);
+ ga->addReferenceELF_Mips(R_MIPS_TLS_DTPREL32, 4, a, addend);
}
return ga;
@@ -946,9 +1284,10 @@ PLTAtom *RelocationPass<ELFT>::createPLTHeader(bool isMicroMips) {
_gotpltVector.insert(_gotpltVector.begin(), ga0);
if (isMicroMips)
- return new (_file._alloc) PLT0MicroAtom(ga0, _file);
- else
- return new (_file._alloc) PLT0Atom(ga0, _file);
+ 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>
@@ -969,9 +1308,11 @@ const PLTAtom *RelocationPass<ELFT>::getPLTRegEntry(const Atom *a) {
if (plt != _pltRegMap.end())
return plt->second;
- PLTAAtom *pa = isR6Target()
- ? new (_file._alloc) PLTR6Atom(getGOTPLTEntry(a), _file)
- : new (_file._alloc) PLTAAtom(getGOTPLTEntry(a), _file);
+ 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);
@@ -988,7 +1329,7 @@ const PLTAtom *RelocationPass<ELFT>::getPLTMicroEntry(const Atom *a) {
if (plt != _pltMicroMap.end())
return plt->second;
- auto pa = new (_file._alloc) PLTMicroAtom(getGOTPLTEntry(a), _file);
+ auto pa = new (_file._alloc) PLTMicroAtom<ELFT>(getGOTPLTEntry(a), _file);
_pltMicroMap[a] = pa;
_pltMicroVector.push_back(pa);
@@ -1005,7 +1346,7 @@ const LA25Atom *RelocationPass<ELFT>::getLA25RegEntry(const Atom *a) {
if (la25 != _la25RegMap.end())
return la25->second;
- auto sa = new (_file._alloc) LA25RegAtom(a, _file);
+ auto sa = new (_file._alloc) LA25RegAtom<ELFT>(a, _file);
_la25RegMap[a] = sa;
_la25Vector.push_back(sa);
@@ -1018,7 +1359,7 @@ const LA25Atom *RelocationPass<ELFT>::getLA25MicroEntry(const Atom *a) {
if (la25 != _la25MicroMap.end())
return la25->second;
- auto sa = new (_file._alloc) LA25MicroAtom(a, _file);
+ auto sa = new (_file._alloc) LA25MicroAtom<ELFT>(a, _file);
_la25MicroMap[a] = sa;
_la25Vector.push_back(sa);
@@ -1047,10 +1388,14 @@ RelocationPass<ELFT>::getObjectEntry(const SharedLibraryAtom *a) {
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<Mips32ELType>>(ctx);
+ 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<Mips64ELType>>(ctx);
+ return llvm::make_unique<RelocationPass<ELF64LE>>(ctx);
default:
llvm_unreachable("Unhandled arch");
}