[lld] r254461 - [ELF] MIPS paired R_MIPS_HI16/LO16 relocations support

Hal Finkel via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 1 13:51:07 PST 2015


----- Original Message -----
> From: "Simon Atanasyan via llvm-commits" <llvm-commits at lists.llvm.org>
> To: llvm-commits at lists.llvm.org
> Sent: Tuesday, December 1, 2015 3:24:46 PM
> Subject: [lld] r254461 - [ELF] MIPS paired R_MIPS_HI16/LO16 relocations support
> 
> Author: atanasyan
> Date: Tue Dec  1 15:24:45 2015
> New Revision: 254461
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=254461&view=rev
> Log:
> [ELF] MIPS paired R_MIPS_HI16/LO16 relocations support
> 
> Some MIPS relocations including `R_MIPS_HI16/R_MIPS_LO16` use
> combined
> addends. Such addend is calculated using addends of both paired
> relocations.
> Each `R_MIPS_HI16` relocation is paired with the next `R_MIPS_LO16`
> relocation. ABI requires to compute such combined addend in case of
> REL
> relocation record format only.
> 
> For details see p. 4-17 at
> ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
> 
> This patch implements lookup of the next paired relocation suing new
> `InputSectionBase::findPairedRelocLocation` method. The primary
> disadvantage of this approach is that we put MIPS specific logic into
> the common code. The next disadvantage is that we lookup
> `R_MIPS_LO16`
> for each `R_MIPS_HI16` relocation, while in fact multiple
> `R_MIPS_HI16`
> might be paired with the single `R_MIPS_LO16`. From the other side
> this way allows us to keep `MipsTargetInfo` class stateless and
> implement
> later relocation handling in parallel.
> 
> This patch does not support `R_MIPS_HI16/R_MIPS_LO16` relocations
> against
> `_gp_disp` symbol. In that case the relocations use a special formula
> for
> the calculation. That will be implemented later.
> 
> Differential Revision: http://reviews.llvm.org/D15112
> 
> Added:
>     lld/trunk/test/ELF/mips-hilo-hi-only.s
>     lld/trunk/test/ELF/mips-hilo.s
> Modified:
>     lld/trunk/ELF/InputSection.cpp
>     lld/trunk/ELF/InputSection.h
>     lld/trunk/ELF/Target.cpp
>     lld/trunk/ELF/Target.h
> 
> Modified: lld/trunk/ELF/InputSection.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=254461&r1=254460&r2=254461&view=diff
> ==============================================================================
> --- lld/trunk/ELF/InputSection.cpp (original)
> +++ lld/trunk/ELF/InputSection.cpp Tue Dec  1 15:24:45 2015
> @@ -94,9 +94,38 @@ bool InputSection<ELFT>::classof(const I
>  
>  template <class ELFT>
>  template <bool isRela>
> -void InputSectionBase<ELFT>::relocate(
> -    uint8_t *Buf, uint8_t *BufEnd,
> -    iterator_range<const Elf_Rel_Impl<ELFT, isRela> *> Rels) {
> +uint8_t *
> +InputSectionBase<ELFT>::findMipsPairedReloc(uint8_t *Buf, uint32_t
> Type,
> +                                            RelIteratorRange<isRela>
> Rels) {
> +  // Some MIPS relocations use addend calculated from addend of the
> relocation
> +  // itself and addend of paired relocation. ABI requires to compute
> such
> +  // combined addend in case of REL relocation record format only.
> +  // See p. 4-17 at
> ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
> +  if (isRela || Config->EMachine != EM_MIPS)
> +    return nullptr;
> +  if (Type == R_MIPS_HI16)
> +    Type = R_MIPS_LO16;
> +  else if (Type == R_MIPS_PCHI16)
> +    Type = R_MIPS_PCLO16;
> +  else if (Type == R_MICROMIPS_HI16)
> +    Type = R_MICROMIPS_LO16;
> +  else
> +    return nullptr;
> +  for (const auto &RI : Rels) {
> +    if (RI.getType(Config->Mips64EL) != Type)
> +      continue;
> +    uintX_t Offset = getOffset(RI.r_offset);
> +    if (Offset == (uintX_t)-1)
> +      return nullptr;
> +    return Buf + Offset;
> +  }
> +  return nullptr;
> +}
> +
> +template <class ELFT>
> +template <bool isRela>
> +void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd,
> +                                      RelIteratorRange<isRela> Rels)
> {
>    typedef Elf_Rel_Impl<ELFT, isRela> RelType;
>    size_t Num = Rels.end() - Rels.begin();
>    for (size_t I = 0; I < Num; ++I) {
> @@ -109,6 +138,7 @@ void InputSectionBase<ELFT>::relocate(
>  
>      uint8_t *BufLoc = Buf + Offset;
>      uintX_t AddrLoc = OutSec->getVA() + Offset;
> +    auto NextRelocs = llvm::make_range(&RI, Rels.end());

If I'm reading this correctly, this search is O(N^2/2) in the worst case. Is there some reason you don't get that behavior in practice?

It seems like if we presorted a list by <type, offset>, we could easily make this O(N*ln(N)) instead.

 -Hal

>  
>      if (Target->isTlsLocalDynamicReloc(Type) &&
>          !Target->isTlsOptimized(Type, nullptr)) {
> @@ -123,7 +153,8 @@ void InputSectionBase<ELFT>::relocate(
>      const Elf_Shdr *SymTab = File->getSymbolTable();
>      if (SymIndex < SymTab->sh_info) {
>        uintX_t SymVA = getLocalRelTarget(*File, RI);
> -      Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA);
> +      Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA,
> +                          findMipsPairedReloc(Buf, Type,
> NextRelocs));
>        continue;
>      }
>  
> @@ -161,7 +192,8 @@ void InputSectionBase<ELFT>::relocate(
>        continue;
>      }
>      Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc,
> -                        SymVA + getAddend<ELFT>(RI));
> +                        SymVA + getAddend<ELFT>(RI),
> +                        findMipsPairedReloc(Buf, Type, NextRelocs));
>    }
>  }
>  
> 
> Modified: lld/trunk/ELF/InputSection.h
> URL:
> http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.h?rev=254461&r1=254460&r2=254461&view=diff
> ==============================================================================
> --- lld/trunk/ELF/InputSection.h (original)
> +++ lld/trunk/ELF/InputSection.h Tue Dec  1 15:24:45 2015
> @@ -76,9 +76,16 @@ public:
>    InputSectionBase<ELFT> *getRelocTarget(const Elf_Rela &Rel);
>  
>    template <bool isRela>
> -  void relocate(uint8_t *Buf, uint8_t *BufEnd,
> -                llvm::iterator_range<
> -                    const llvm::object::Elf_Rel_Impl<ELFT, isRela>
> *> Rels);
> +  using RelIteratorRange =
> +      llvm::iterator_range<const llvm::object::Elf_Rel_Impl<ELFT,
> isRela> *>;
> +
> +  template <bool isRela>
> +  void relocate(uint8_t *Buf, uint8_t *BufEnd,
> RelIteratorRange<isRela> Rels);
> +
> +private:
> +  template <bool isRela>
> +  uint8_t *findMipsPairedReloc(uint8_t *Buf, uint32_t Type,
> +                               RelIteratorRange<isRela> Rels);
>  };
>  
>  template <class ELFT>
> 
> Modified: lld/trunk/ELF/Target.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=254461&r1=254460&r2=254461&view=diff
> ==============================================================================
> --- lld/trunk/ELF/Target.cpp (original)
> +++ lld/trunk/ELF/Target.cpp Tue Dec  1 15:24:45 2015
> @@ -87,7 +87,7 @@ public:
>    bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const
>    override;
>    bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const
>    override;
>    void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
>    uint64_t P,
> -                   uint64_t SA) const override;
> +                   uint64_t SA, uint8_t *PairedLoc = nullptr) const
> override;
>  };
>  
>  class X86_64TargetInfo final : public TargetInfo {
> @@ -106,7 +106,7 @@ public:
>    bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const
>    override;
>    bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const
>    override;
>    void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
>    uint64_t P,
> -                   uint64_t SA) const override;
> +                   uint64_t SA, uint8_t *PairedLoc = nullptr) const
> override;
>    bool isRelRelative(uint32_t Type) const override;
>    bool isTlsOptimized(unsigned Type, const SymbolBody *S) const
>    override;
>    unsigned relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd,
>    uint32_t Type,
> @@ -133,7 +133,7 @@ public:
>    bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const
>    override;
>    bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const
>    override;
>    void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
>    uint64_t P,
> -                   uint64_t SA) const override;
> +                   uint64_t SA, uint8_t *PairedLoc = nullptr) const
> override;
>    bool isRelRelative(uint32_t Type) const override;
>  };
>  
> @@ -150,7 +150,7 @@ public:
>    bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const
>    override;
>    bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const
>    override;
>    void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
>    uint64_t P,
> -                   uint64_t SA) const override;
> +                   uint64_t SA, uint8_t *PairedLoc = nullptr) const
> override;
>  };
>  
>  template <class ELFT> class MipsTargetInfo final : public TargetInfo
>  {
> @@ -166,7 +166,7 @@ public:
>    bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const
>    override;
>    bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const
>    override;
>    void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
>    uint64_t P,
> -                   uint64_t SA) const override;
> +                   uint64_t SA, uint8_t *PairedLoc = nullptr) const
> override;
>  };
>  } // anonymous namespace
>  
> @@ -308,7 +308,8 @@ bool X86TargetInfo::relocNeedsPlt(uint32
>  }
>  
>  void X86TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd,
>  uint32_t Type,
> -                                uint64_t P, uint64_t SA) const {
> +                                uint64_t P, uint64_t SA,
> +                                uint8_t *PairedLoc) const {
>    switch (Type) {
>    case R_386_32:
>      add32le(Loc, SA);
> @@ -581,7 +582,8 @@ unsigned X86_64TargetInfo::relocateTlsOp
>  }
>  
>  void X86_64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd,
>  uint32_t Type,
> -                                   uint64_t P, uint64_t SA) const {
> +                                   uint64_t P, uint64_t SA,
> +                                   uint8_t *PairedLoc) const {
>    switch (Type) {
>    case R_X86_64_32:
>      checkUInt<32>(SA, Type);
> @@ -728,7 +730,8 @@ bool PPC64TargetInfo::isRelRelative(uint
>  }
>  
>  void PPC64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd,
>  uint32_t Type,
> -                                  uint64_t P, uint64_t SA) const {
> +                                  uint64_t P, uint64_t SA,
> +                                  uint8_t *PairedLoc) const {
>    uint64_t TB = getPPC64TocBase();
>  
>    // For a TOC-relative relocation, adjust the addend and proceed in
>    terms of
> @@ -933,8 +936,8 @@ static uint64_t getAArch64Page(uint64_t
>  }
>  
>  void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd,
> -                                    uint32_t Type, uint64_t P,
> -                                    uint64_t SA) const {
> +                                    uint32_t Type, uint64_t P,
> uint64_t SA,
> +                                    uint8_t *PairedLoc) const {
>    switch (Type) {
>    case R_AARCH64_ABS16:
>      checkIntUInt<16>(SA, Type);
> @@ -1046,13 +1049,31 @@ bool MipsTargetInfo<ELFT>::relocNeedsPlt
>  
>  template <class ELFT>
>  void MipsTargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint8_t
>  *BufEnd,
> -                                       uint32_t Type, uint64_t P,
> -                                       uint64_t SA) const {
> +                                       uint32_t Type, uint64_t P,
> uint64_t SA,
> +                                       uint8_t *PairedLoc) const {
>    const endianness E = ELFT::TargetEndianness;
>    switch (Type) {
>    case R_MIPS_32:
>      add32<E>(Loc, SA);
>      break;
> +  case R_MIPS_HI16: {
> +    uint32_t Instr = read32<E>(Loc);
> +    if (PairedLoc) {
> +      uint64_t AHL = ((Instr & 0xffff) << 16) +
> +                     llvm::SignExtend64<16>(read32<E>(PairedLoc) &
> 0xffff);
> +      write32<E>(Loc, (Instr & 0xffff0000) | (((SA + AHL) >> 16) &
> 0xffff));
> +    } else {
> +      warning("Can't find matching R_MIPS_LO16 relocation for
> R_MIPS_HI16");
> +      write32<E>(Loc, (Instr & 0xffff0000) | ((SA >> 16) & 0xffff));
> +    }
> +    break;
> +  }
> +  case R_MIPS_LO16: {
> +    uint32_t Instr = read32<E>(Loc);
> +    int64_t AHL = llvm::SignExtend64<16>(Instr & 0xffff);
> +    write32<E>(Loc, (Instr & 0xffff0000) | ((SA + AHL) & 0xffff));
> +    break;
> +  }
>    case R_MIPS_CALL16:
>    case R_MIPS_GOT16: {
>      int64_t V = SA - getMipsGpAddr<ELFT>();
> 
> Modified: lld/trunk/ELF/Target.h
> URL:
> http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.h?rev=254461&r1=254460&r2=254461&view=diff
> ==============================================================================
> --- lld/trunk/ELF/Target.h (original)
> +++ lld/trunk/ELF/Target.h Tue Dec  1 15:24:45 2015
> @@ -57,7 +57,8 @@ public:
>    virtual bool relocNeedsGot(uint32_t Type, const SymbolBody &S)
>    const = 0;
>    virtual bool relocNeedsPlt(uint32_t Type, const SymbolBody &S)
>    const = 0;
>    virtual void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t
>    Type,
> -                           uint64_t P, uint64_t SA) const = 0;
> +                           uint64_t P, uint64_t SA,
> +                           uint8_t *PairedLoc = nullptr) const = 0;
>    virtual bool isTlsOptimized(unsigned Type, const SymbolBody *S)
>    const;
>    virtual unsigned relocateTlsOptimize(uint8_t *Loc, uint8_t
>    *BufEnd,
>                                         uint32_t Type, uint64_t P,
> 
> Added: lld/trunk/test/ELF/mips-hilo-hi-only.s
> URL:
> http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-hilo-hi-only.s?rev=254461&view=auto
> ==============================================================================
> --- lld/trunk/test/ELF/mips-hilo-hi-only.s (added)
> +++ lld/trunk/test/ELF/mips-hilo-hi-only.s Tue Dec  1 15:24:45 2015
> @@ -0,0 +1,22 @@
> +# Check warning on orphaned R_MIPS_HI16 relocations.
> +
> +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
> +# RUN: ld.lld %t.o -o %t.exe 2>&1 | FileCheck -check-prefix=WARN %s
> +# RUN: llvm-objdump -d -t %t.exe | FileCheck %s
> +
> +# REQUIRES: mips
> +
> +  .text
> +  .globl  __start
> +__start:
> +  lui    $t0,%hi(__start+0x10000)
> +
> +# WARN: Can't find matching R_MIPS_LO16 relocation for R_MIPS_HI16
> +
> +# CHECK:      Disassembly of section .text:
> +# CHECK-NEXT: __start:
> +# CHECK-NEXT:  20000:   3c 08 00 02   lui    $8, 2
> +#                                                ^-- %hi(__start)
> w/o addend
> +
> +# CHECK: SYMBOL TABLE:
> +# CHECK: 0020000     .text   00000000 __start
> 
> Added: lld/trunk/test/ELF/mips-hilo.s
> URL:
> http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-hilo.s?rev=254461&view=auto
> ==============================================================================
> --- lld/trunk/test/ELF/mips-hilo.s (added)
> +++ lld/trunk/test/ELF/mips-hilo.s Tue Dec  1 15:24:45 2015
> @@ -0,0 +1,53 @@
> +# Check R_MIPS_HI16 / LO16 relocations calculation.
> +
> +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
> +# RUN: ld.lld %t.o -o %t.exe
> +# RUN: llvm-objdump -d -t %t.exe | FileCheck %s
> +
> +# REQUIRES: mips
> +
> +  .text
> +  .globl  __start
> +__start:
> +  lui    $t0,%hi(__start)
> +  lui    $t1,%hi(g1)
> +  addi   $t0,$t0,%lo(__start+4)
> +  addi   $t0,$t0,%lo(g1+8)
> +
> +  lui    $t0,%hi(l1+0x10000)
> +  lui    $t1,%hi(l1+0x20000)
> +  addi   $t0,$t0,%lo(l1+(-4))
> +
> +  .data
> +  .type  l1, at object
> +  .size  l1,4
> +l1:
> +  .word 0
> +
> +  .globl g1
> +  .type  g1, at object
> +  .size  g1,4
> +g1:
> +  .word 0
> +
> +# CHECK:      Disassembly of section .text:
> +# CHECK-NEXT: __start:
> +# CHECK-NEXT:  20000:   3c 08 00 02   lui    $8, 2
> +#                                                ^-- %hi(__start+4)
> +# CHECK-NEXT:  20004:   3c 09 00 03   lui    $9, 3
> +#                                                ^-- %hi(g1+8)
> +# CHECK-NEXT:  20008:   21 08 00 04   addi   $8, $8, 4
> +#                                                    ^--
> %lo(__start+4)
> +# CHECK-NEXT:  2000c:   21 08 00 0c   addi   $8, $8, 12
> +#                                                    ^-- %lo(g1+8)
> +# CHECK-NEXT:  20010:   3c 08 00 03   lui    $8, 3
> +#                                                ^--
> %hi(l1+0x10000-4)
> +# CHECK-NEXT:  20014:   3c 09 00 04   lui    $9, 4
> +#                                                ^--
> %hi(l1+0x20000-4)
> +# CHECK-NEXT:  20018:   21 08 ff fc   addi   $8, $8, -4
> +#                                                    ^-- %lo(l1-4)
> +
> +# CHECK: SYMBOL TABLE:
> +# CHECK: 0030000 l   .data   00000004 l1
> +# CHECK: 0020000     .text   00000000 __start
> +# CHECK: 0030004 g   .data   00000004 g1
> 
> 
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
> 

-- 
Hal Finkel
Assistant Computational Scientist
Leadership Computing Facility
Argonne National Laboratory


More information about the llvm-commits mailing list