summaryrefslogtreecommitdiffstats
path: root/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp')
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp38
1 files changed, 29 insertions, 9 deletions
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
index 1cf3493b456..ee2ab033ca5 100644
--- a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
@@ -266,27 +266,47 @@ inline int64_t calcAHL(int64_t AHI, int64_t ALO) {
template <typename ELFT>
void RelocationPass<ELFT>::calculateAHLs(const DefinedAtom &atom) {
- std::vector<Reference *> references;
+ std::vector<const Reference *> lo16Refs;
+ std::vector<Reference *> hi16Refs;
for (const auto &ref : atom) {
if (ref->kindNamespace() != lld::Reference::KindNamespace::ELF)
continue;
assert(ref->kindArch() == Reference::KindArch::Mips);
switch (ref->kindValue()) {
case R_MIPS_HI16:
- references.push_back(const_cast<Reference *>(ref));
+ hi16Refs.push_back(const_cast<Reference *>(ref));
+ case R_MIPS_LO16:
+ lo16Refs.push_back(ref);
break;
case R_MIPS_GOT16:
if (isLocal(ref->target()))
- references.push_back(const_cast<Reference *>(ref));
- break;
- case R_MIPS_LO16:
- for (auto &sr : references)
- sr->setAddend(calcAHL(sr->addend(), ref->addend()));
- references.clear();
+ hi16Refs.push_back(const_cast<Reference *>(ref));
break;
}
}
- assert(references.empty());
+
+ std::sort(lo16Refs.begin(), lo16Refs.end(),
+ [](const Reference *a, const Reference *b) {
+ return a->offsetInAtom() < b->offsetInAtom();
+ });
+ std::sort(hi16Refs.begin(), hi16Refs.end(),
+ [](const Reference *a, const Reference *b) {
+ return a->offsetInAtom() < b->offsetInAtom();
+ });
+
+ // Iterate over R_MIPS_LO16 relocations sorted by theirs offsets in the atom.
+ // Calculate AHL addend for each R_MIPS_HI16 amd R_MIPS_GOT16 relocation
+ // precedes the current R_MIPS_LO16 one.
+
+ auto hic = hi16Refs.begin();
+ for (const auto &lo : lo16Refs) {
+ for (; hic != hi16Refs.end(); ++hic) {
+ if ((*hic)->offsetInAtom() > lo->offsetInAtom())
+ break;
+ (*hic)->setAddend(calcAHL((*hic)->addend(), lo->addend()));
+ }
+ }
+ assert(hic == hi16Refs.end());
}
template <typename ELFT>
OpenPOWER on IntegriCloud