summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp47
-rw-r--r--lld/test/elf/Mips/validate-rel-03.test56
2 files changed, 89 insertions, 14 deletions
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
index 13dceafd2dc..fe762eaad15 100644
--- a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
@@ -547,15 +547,23 @@ static bool isBranchReloc(Reference::KindValue kind) {
}
static bool isGotReloc(Reference::KindValue kind) {
- return kind == R_MIPS_GOT16 || kind == R_MIPS_GOT_HI16 ||
- kind == R_MIPS_GOT_LO16 || kind == R_MICROMIPS_GOT16 ||
- kind == R_MICROMIPS_GOT_HI16 || kind == R_MICROMIPS_GOT_LO16;
+ 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_MIPS_CALL_HI16 ||
- kind == R_MIPS_CALL_LO16 || kind == R_MICROMIPS_CALL16 ||
- kind == R_MICROMIPS_CALL_HI16 || kind == R_MICROMIPS_CALL_LO16;
+ 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) {
@@ -610,8 +618,8 @@ void RelocationPass<ELFT>::handleReference(const MipsELFDefinedAtom<ELFT> &atom,
handlePlain(atom, ref);
else if (isBranchReloc(kind))
handleBranch(atom, ref);
- else if (isGotReloc(kind) || isCallReloc(kind) || isGotDispReloc(kind) ||
- isGotPageReloc(kind) || kind == R_MIPS_EH)
+ 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());
@@ -672,7 +680,8 @@ RelocationPass<ELFT>::collectReferenceInfo(const MipsELFDefinedAtom<ELFT> &atom,
else
_hasStaticRelocations.insert(ref.target());
- if (!isBranchReloc(refKind) && !isCallReloc(refKind) && refKind != R_MIPS_EH)
+ if (!isBranchReloc(refKind) && !isAllCallReloc(refKind) &&
+ refKind != R_MIPS_EH)
_requiresPtrEquality.insert(ref.target());
return std::error_code();
@@ -703,6 +712,15 @@ make_external_gprel32_reloc_error(const ELFLinkingContext &ctx,
ref.target()->name() + " in file " + atom.file().path());
}
+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,
@@ -713,6 +731,9 @@ RelocationPass<ELFT>::validateRelocation(const DefinedAtom &atom,
if (ref.kindValue() == R_MIPS_GPREL32 && !isLocal(ref.target()))
return make_external_gprel32_reloc_error(this->_ctx, atom, ref);
+ 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();
@@ -765,7 +786,7 @@ static bool isMipsReadonly(const MipsELFDefinedAtom<ELFT> &atom) {
template <typename ELFT>
bool RelocationPass<ELFT>::mightBeDynamic(const MipsELFDefinedAtom<ELFT> &atom,
Reference::KindValue refKind) const {
- if (isGotReloc(refKind) || isCallReloc(refKind))
+ if (isAllGotReloc(refKind) || isAllCallReloc(refKind))
return true;
if (refKind != R_MIPS_32 && refKind != R_MIPS_64)
@@ -902,10 +923,8 @@ template <typename ELFT> void RelocationPass<ELFT>::handleGOT(Reference &ref) {
ref.setTarget(getGlobalGOTEntry(ref.target()));
else if (isGotPageReloc(ref.kindValue()))
ref.setTarget(getLocalGOTPageEntry(ref));
- else if (isLocal(ref.target()) && (ref.kindValue() == R_MIPS_GOT16 ||
- ref.kindValue() == R_MIPS_CALL16 ||
- ref.kindValue() == R_MICROMIPS_GOT16 ||
- ref.kindValue() == R_MICROMIPS_CALL16))
+ else if (isLocal(ref.target()) &&
+ (isCallReloc(ref.kindValue()) || isGotReloc(ref.kindValue())))
ref.setTarget(getLocalGOTPageEntry(ref));
else
ref.setTarget(getLocalGOTEntry(ref));
diff --git a/lld/test/elf/Mips/validate-rel-03.test b/lld/test/elf/Mips/validate-rel-03.test
new file mode 100644
index 00000000000..15aefa5114a
--- /dev/null
+++ b/lld/test/elf/Mips/validate-rel-03.test
@@ -0,0 +1,56 @@
+# Check that the linker does not accept R_MIPS_CALL16 relocation
+# against local symbol.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t.o
+# RUN: not lld -flavor gnu -target mipsel -e T0 -o %t.exe %t.o 2>&1 \
+# RUN: | FileCheck %s
+
+# CHECK: R_MIPS_CALL16 (11) relocation cannot be used against local symbol L0 in file {{.*}}validate-rel-03.test.tmp.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_ARCH_32]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 16
+ Size: 16
+
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 4
+ Info: .text
+ Relocations:
+ - Offset: 8
+ Symbol: T0
+ Type: R_MIPS_CALL16
+ - Offset: 4
+ Symbol: L0
+ Type: R_MIPS_CALL16
+
+Symbols:
+ Local:
+ - Name: L0
+ Type: STT_FUNC
+ Section: .text
+ Value: 0
+ Size: 4
+ Global:
+ - Name: T0
+ Type: STT_FUNC
+ Section: .text
+ Value: 4
+ Size: 4
+ - Name: T1
+ Type: STT_FUNC
+ Section: .text
+ Value: 8
+ Size: 8
+...
OpenPOWER on IntegriCloud