diff options
| -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 | 

