summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Atanasyan <simon@atanasyan.com>2014-03-24 14:09:17 +0000
committerSimon Atanasyan <simon@atanasyan.com>2014-03-24 14:09:17 +0000
commit1ebfb22638f45b01606b054510d15b4f065a843e (patch)
tree149fd8341e47283e4d2b08e33c0fe07e18e9fedc
parenta771fefb72a052b2f15b3ef65ffc7a0b1a9a525b (diff)
downloadbcm5719-llvm-1ebfb22638f45b01606b054510d15b4f065a843e.tar.gz
bcm5719-llvm-1ebfb22638f45b01606b054510d15b4f065a843e.zip
[Mips] Sort R_MIPS_LO16 / R_MIPS_HI16 / R_MIPS_GOT16 before finding
pairs and calculate AHL addend. llvm-svn: 204606
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp38
-rw-r--r--lld/test/elf/Mips/hilo16-4.test40
2 files changed, 69 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>
diff --git a/lld/test/elf/Mips/hilo16-4.test b/lld/test/elf/Mips/hilo16-4.test
new file mode 100644
index 00000000000..310628bf505
--- /dev/null
+++ b/lld/test/elf/Mips/hilo16-4.test
@@ -0,0 +1,40 @@
+# Check handling HI16/LO16 relocations go in mixed order.
+#
+# RUN: llvm-mc -triple=mipsel -filetype=obj -o=%t-obj %s
+# RUN: lld -flavor gnu -target mipsel -e A -o %t-exe %t-obj
+# RUN: llvm-objdump -t -disassemble %t-exe | FileCheck %s
+
+# CHECK: Disassembly of section .text:
+# CHECK: A:
+# CHECK-NEXT: 400128: 42 00 08 3c lui $8, 66
+# CHECK-NEXT: 40012c: 40 00 08 3c lui $8, 64
+# CHECK-NEXT: 400130: 28 01 08 85 lh $8, 296($8)
+# CHECK-NEXT: 400134: 38 01 08 85 lh $8, 312($8)
+
+# CHECK: B:
+# CHECK-NEXT: 400138: 42 00 08 3c lui $8, 66
+# CHECK-NEXT: 40013c: 40 00 08 3c lui $8, 64
+# CHECK-NEXT: 400140: 38 01 08 85 lh $8, 312($8)
+# CHECK-NEXT: 400144: 28 01 08 85 lh $8, 296($8)
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 00400128 g F .text 00000010 A
+# CHECK: 00400138 g F .text 00000010 B
+
+ .global A
+ .ent A
+A:
+ lui $t0,%hi(A+0x1ffff)
+ lui $t0,%hi(B)
+ lh $t0,%lo(A)($t0)
+ lh $t0,%lo(B)($t0)
+ .end A
+
+ .global B
+ .ent B
+B:
+ lui $t0,%hi(A+0x1ffff)
+ lui $t0,%hi(B)
+ lh $t0,%lo(B)($t0)
+ lh $t0,%lo(A)($t0)
+ .end B
OpenPOWER on IntegriCloud