diff options
| author | Simon Atanasyan <simon@atanasyan.com> | 2014-03-24 14:09:17 +0000 |
|---|---|---|
| committer | Simon Atanasyan <simon@atanasyan.com> | 2014-03-24 14:09:17 +0000 |
| commit | 1ebfb22638f45b01606b054510d15b4f065a843e (patch) | |
| tree | 149fd8341e47283e4d2b08e33c0fe07e18e9fedc | |
| parent | a771fefb72a052b2f15b3ef65ffc7a0b1a9a525b (diff) | |
| download | bcm5719-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.cpp | 38 | ||||
| -rw-r--r-- | lld/test/elf/Mips/hilo16-4.test | 40 |
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 |

