[lld] r260224 - Use the plt entry as the address of some symbols.

Rui Ueyama via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 9 16:18:50 PST 2016


On Tue, Feb 9, 2016 at 7:11 AM, Rafael Espindola via llvm-commits <
llvm-commits at lists.llvm.org> wrote:

> Author: rafael
> Date: Tue Feb  9 09:11:01 2016
> New Revision: 260224
>
> URL: http://llvm.org/viewvc/llvm-project?rev=260224&view=rev
> Log:
> Use the plt entry as the address of some symbols.
>
> This is the function equivalent of a copy relocation.
>
> Since functions are expected to change sizes, we cannot use copy
> relocations. In situations where one would be needed, what is done
> instead is:
> * Create a plt entry
> * Output an undefined symbol whose addr is the plt entry.
>
> The dynamic linker makes sure any shared library uses the plt entry as
> the function address.
>
> Added:
>     lld/trunk/test/ELF/Inputs/undef-with-plt-addr.s
>     lld/trunk/test/ELF/undef-with-plt-addr.s
> Modified:
>     lld/trunk/ELF/OutputSections.cpp
>     lld/trunk/ELF/Symbols.cpp
>     lld/trunk/ELF/Symbols.h
>     lld/trunk/ELF/Target.cpp
>     lld/trunk/ELF/Target.h
>     lld/trunk/ELF/Writer.cpp
>     lld/trunk/test/ELF/symbol-override.s
>
> Modified: lld/trunk/ELF/OutputSections.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=260224&r1=260223&r2=260224&view=diff
>
> ==============================================================================
> --- lld/trunk/ELF/OutputSections.cpp (original)
> +++ lld/trunk/ELF/OutputSections.cpp Tue Feb  9 09:11:01 2016
> @@ -1328,7 +1328,7 @@ void SymbolTableSection<ELFT>::writeGlob
>        OutSec = Out<ELFT>::Bss;
>        break;
>      case SymbolBody::SharedKind: {
> -      if (cast<SharedSymbol<ELFT>>(Body)->NeedsCopy)
> +      if (cast<SharedSymbol<ELFT>>(Body)->needsCopy())
>          OutSec = Out<ELFT>::Bss;
>        break;
>      }
>
> Modified: lld/trunk/ELF/Symbols.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.cpp?rev=260224&r1=260223&r2=260224&view=diff
>
> ==============================================================================
> --- lld/trunk/ELF/Symbols.cpp (original)
> +++ lld/trunk/ELF/Symbols.cpp Tue Feb  9 09:11:01 2016
> @@ -56,9 +56,12 @@ typename ELFFile<ELFT>::uintX_t SymbolBo
>      return Out<ELFT>::Bss->getVA() +
> cast<DefinedCommon>(this)->OffsetInBss;
>    case SharedKind: {
>      auto *SS = cast<SharedSymbol<ELFT>>(this);
> -    if (SS->NeedsCopy)
> +    if (!SS->NeedsCopyOrPltAddr)
> +      return 0;
> +    if (SS->IsFunc)
> +      return getPltVA<ELFT>();
> +    else
>        return Out<ELFT>::Bss->getVA() + SS->OffsetInBss;
> -    return 0;
>    }
>    case UndefinedElfKind:
>    case UndefinedKind:
>
> Modified: lld/trunk/ELF/Symbols.h
> URL:
> http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.h?rev=260224&r1=260223&r2=260224&view=diff
>
> ==============================================================================
> --- lld/trunk/ELF/Symbols.h (original)
> +++ lld/trunk/ELF/Symbols.h Tue Feb  9 09:11:01 2016
> @@ -130,7 +130,8 @@ protected:
>    SymbolBody(Kind K, StringRef Name, bool IsWeak, uint8_t Visibility,
>               bool IsTls, bool IsFunc)
>        : SymbolKind(K), IsWeak(IsWeak), Visibility(Visibility),
> -        MustBeInDynSym(false), IsTls(IsTls), IsFunc(IsFunc), Name(Name) {
> +        MustBeInDynSym(false), NeedsCopyOrPltAddr(false), IsTls(IsTls),
> +        IsFunc(IsFunc), Name(Name) {
>      IsUsedInRegularObj = K != SharedKind && K != LazyKind;
>    }
>
> @@ -148,9 +149,14 @@ public:
>    // If true, the symbol is added to .dynsym symbol table.
>    unsigned MustBeInDynSym : 1;
>
> +  // True if the linker has to generate a copy relocation for this shared
> +  // symbol or if the symbol should point to its plt entry.
> +  unsigned NeedsCopyOrPltAddr : 1;
> +
>  protected:
>    unsigned IsTls : 1;
>    unsigned IsFunc : 1;
> +
>    StringRef Name;
>    Symbol *Backref = nullptr;
>  };
> @@ -280,10 +286,10 @@ public:
>
>    SharedFile<ELFT> *File;
>
> -  // True if the linker has to generate a copy relocation for this shared
> -  // symbol. OffsetInBss is significant only when NeedsCopy is true.
> -  bool NeedsCopy = false;
> +  // OffsetInBss is significant only when needsCopy() is true.
>    uintX_t OffsetInBss = 0;
> +
> +  bool needsCopy() const { return this->NeedsCopyOrPltAddr &&
> !this->IsFunc; }
>  };
>
>  // This class represents a symbol defined in an archive file. It is
>
> Modified: lld/trunk/ELF/Target.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=260224&r1=260223&r2=260224&view=diff
>
> ==============================================================================
> --- lld/trunk/ELF/Target.cpp (original)
> +++ lld/trunk/ELF/Target.cpp Tue Feb  9 09:11:01 2016
> @@ -90,8 +90,8 @@ public:
>                  int32_t Index, unsigned RelOff) const override;
>    bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override;
>    bool needsDynRelative(unsigned Type) const override;
> -  bool needsGot(uint32_t Type, const SymbolBody &S) const override;
> -  bool needsPlt(uint32_t Type, const SymbolBody &S) const override;
> +  bool needsGot(uint32_t Type, SymbolBody &S) const override;
> +  bool needsPlt(uint32_t Type, SymbolBody &S) const override;
>    void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t
> P,
>                     uint64_t SA, uint64_t ZA = 0,
>                     uint8_t *PairedLoc = nullptr) const override;
> @@ -121,8 +121,8 @@ public:
>    void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t
> PltEntryAddr,
>                  int32_t Index, unsigned RelOff) const override;
>    bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override;
> -  bool needsGot(uint32_t Type, const SymbolBody &S) const override;
> -  bool needsPlt(uint32_t Type, const SymbolBody &S) const override;
> +  bool needsGot(uint32_t Type, SymbolBody &S) const override;
> +  bool needsPlt(uint32_t Type, SymbolBody &S) const override;
>    void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t
> P,
>                     uint64_t SA, uint64_t ZA = 0,
>                     uint8_t *PairedLoc = nullptr) const override;
> @@ -157,8 +157,8 @@ public:
>    PPC64TargetInfo();
>    void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t
> PltEntryAddr,
>                  int32_t Index, unsigned RelOff) const override;
> -  bool needsGot(uint32_t Type, const SymbolBody &S) const override;
> -  bool needsPlt(uint32_t Type, const SymbolBody &S) const override;
> +  bool needsGot(uint32_t Type, SymbolBody &S) const override;
> +  bool needsPlt(uint32_t Type, SymbolBody &S) const override;
>    void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t
> P,
>                     uint64_t SA, uint64_t ZA = 0,
>                     uint8_t *PairedLoc = nullptr) const override;
> @@ -176,8 +176,8 @@ public:
>    unsigned getTlsGotRel(unsigned Type = -1) const override;
>    bool isTlsDynRel(unsigned Type, const SymbolBody &S) const override;
>    bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override;
> -  bool needsGot(uint32_t Type, const SymbolBody &S) const override;
> -  bool needsPlt(uint32_t Type, const SymbolBody &S) const override;
> +  bool needsGot(uint32_t Type, SymbolBody &S) const override;
> +  bool needsPlt(uint32_t Type, SymbolBody &S) const override;
>    void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t
> P,
>                     uint64_t SA, uint64_t ZA = 0,
>                     uint8_t *PairedLoc = nullptr) const override;
> @@ -197,8 +197,8 @@ public:
>    unsigned getDynRel(unsigned Type) const override;
>    void writeGotHeader(uint8_t *Buf) const override;
>    bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override;
> -  bool needsGot(uint32_t Type, const SymbolBody &S) const override;
> -  bool needsPlt(uint32_t Type, const SymbolBody &S) const override;
> +  bool needsGot(uint32_t Type, SymbolBody &S) const override;
> +  bool needsPlt(uint32_t Type, SymbolBody &S) const override;
>    void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t
> P,
>                     uint64_t SA, uint64_t ZA = 0,
>                     uint8_t *PairedLoc = nullptr) const override;
> @@ -263,13 +263,9 @@ bool TargetInfo::isHintRel(uint32_t Type
>  bool TargetInfo::isRelRelative(uint32_t Type) const { return true; }
>  bool TargetInfo::isSizeRel(uint32_t Type) const { return false; }
>
> -bool TargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const {
> -  return false;
> -}
> +bool TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const { return
> false; }
>
> -bool TargetInfo::needsPlt(uint32_t Type, const SymbolBody &S) const {
> -  return false;
> -}
> +bool TargetInfo::needsPlt(uint32_t Type, SymbolBody &S) const { return
> false; }
>
>  unsigned TargetInfo::relaxTls(uint8_t *Loc, uint8_t *BufEnd, uint32_t
> Type,
>                                uint64_t P, uint64_t SA,
> @@ -376,7 +372,7 @@ bool X86TargetInfo::needsCopyRel(uint32_
>    return false;
>  }
>
> -bool X86TargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const {
> +bool X86TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const {
>    if (S.isTls() && Type == R_386_TLS_GD)
>      return Target->canRelaxTls(Type, &S) && canBePreempted(&S, true);
>    if (Type == R_386_TLS_GOTIE || Type == R_386_TLS_IE)
> @@ -384,7 +380,7 @@ bool X86TargetInfo::needsGot(uint32_t Ty
>    return Type == R_386_GOT32 || needsPlt(Type, S);
>  }
>
> -bool X86TargetInfo::needsPlt(uint32_t Type, const SymbolBody &S) const {
> +bool X86TargetInfo::needsPlt(uint32_t Type, SymbolBody &S) const {
>    return isGnuIFunc<ELF32LE>(S) ||
>           (Type == R_386_PLT32 && canBePreempted(&S, true)) ||
>           (Type == R_386_PC32 && S.isShared());
> @@ -646,7 +642,7 @@ bool X86_64TargetInfo::needsCopyRel(uint
>    return false;
>  }
>
> -bool X86_64TargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const
> {
> +bool X86_64TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const {
>    if (Type == R_X86_64_TLSGD)
>      return Target->canRelaxTls(Type, &S) && canBePreempted(&S, true);
>    if (Type == R_X86_64_GOTTPOFF)
> @@ -658,7 +654,7 @@ bool X86_64TargetInfo::isTlsDynRel(unsig
>    return Type == R_X86_64_GOTTPOFF || Type == R_X86_64_TLSGD;
>  }
>
> -bool X86_64TargetInfo::needsPlt(uint32_t Type, const SymbolBody &S) const
> {
> +bool X86_64TargetInfo::needsPlt(uint32_t Type, SymbolBody &S) const {
>    if (needsCopyRel(Type, S))
>      return false;
>    if (isGnuIFunc<ELF64LE>(S))
> @@ -684,17 +680,19 @@ bool X86_64TargetInfo::needsPlt(uint32_t
>      // For the static linking part, we just return true and everything
> else
>      // will use the the PLT entry as the address.
>      //
> -    // The remaining (unimplemented) problem is making sure pointer
> equality
> -    // still works. We need the help of the dynamic linker for that. We
> -    // let it know that we have a direct reference to a so symbol by
> creating
> -    // an undefined symbol with a non zero st_value. Seeing that, the
> -    // dynamic linker resolves the symbol to the value of the symbol we
> created.
> -    // This is true even for got entries, so pointer equality is
> maintained.
> -    // To avoid an infinite loop, the only entry that points to the
> -    // real function is a dedicated got entry used by the plt. That is
> -    // identified by special relocation types (R_X86_64_JUMP_SLOT,
> +    // The remaining problem is making sure pointer equality still works.
> We
> +    // need the help of the dynamic linker for that. We let it know that
> we have
> +    // a direct reference to a so symbol by creating an undefined symbol
> with a
> +    // non zero st_value. Seeing that, the dynamic linker resolves the
> symbol to
> +    // the value of the symbol we created. This is true even for got
> entries, so
> +    // pointer equality is maintained. To avoid an infinite loop, the
> only entry
> +    // that points to the real function is a dedicated got entry used by
> the
> +    // plt. That is identified by special relocation types
> (R_X86_64_JUMP_SLOT,
>      // R_386_JMP_SLOT, etc).
> -    return S.isShared();
> +    if (!S.isShared())
> +      return false;
> +    S.NeedsCopyOrPltAddr = true;
>

Can you move this to a caller of needsPlt (probably to scanRelocs)?
needsPlt is, by its name implies, a predicate, so it is not expected to
mutate a given object.

+    return true;
>    case R_X86_64_PLT32:
>      return canBePreempted(&S, true);
>    }
> @@ -989,7 +987,7 @@ void PPC64TargetInfo::writePlt(uint8_t *
>    write32be(Buf + 28, 0x4e800420);                   // bctr
>  }
>
> -bool PPC64TargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const {
> +bool PPC64TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const {
>    if (needsPlt(Type, S))
>      return true;
>
> @@ -1005,7 +1003,7 @@ bool PPC64TargetInfo::needsGot(uint32_t
>    }
>  }
>
> -bool PPC64TargetInfo::needsPlt(uint32_t Type, const SymbolBody &S) const {
> +bool PPC64TargetInfo::needsPlt(uint32_t Type, SymbolBody &S) const {
>    // These are function calls that need to be redirected through a PLT
> stub.
>    return Type == R_PPC64_REL24 && canBePreempted(&S, false);
>  }
> @@ -1240,7 +1238,7 @@ bool AArch64TargetInfo::needsCopyRel(uin
>    }
>  }
>
> -bool AArch64TargetInfo::needsGot(uint32_t Type, const SymbolBody &S)
> const {
> +bool AArch64TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const {
>    switch (Type) {
>    case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
>    case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
> @@ -1252,7 +1250,7 @@ bool AArch64TargetInfo::needsGot(uint32_
>    }
>  }
>
> -bool AArch64TargetInfo::needsPlt(uint32_t Type, const SymbolBody &S)
> const {
> +bool AArch64TargetInfo::needsPlt(uint32_t Type, SymbolBody &S) const {
>    if (isGnuIFunc<ELF64LE>(S))
>      return true;
>    switch (Type) {
> @@ -1439,12 +1437,12 @@ bool MipsTargetInfo<ELFT>::needsCopyRel(
>  }
>
>  template <class ELFT>
> -bool MipsTargetInfo<ELFT>::needsGot(uint32_t Type, const SymbolBody &S)
> const {
> +bool MipsTargetInfo<ELFT>::needsGot(uint32_t Type, SymbolBody &S) const {
>    return Type == R_MIPS_GOT16 || Type == R_MIPS_CALL16;
>  }
>
>  template <class ELFT>
> -bool MipsTargetInfo<ELFT>::needsPlt(uint32_t Type, const SymbolBody &S)
> const {
> +bool MipsTargetInfo<ELFT>::needsPlt(uint32_t Type, SymbolBody &S) const {
>    return false;
>  }
>
>
> Modified: lld/trunk/ELF/Target.h
> URL:
> http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.h?rev=260224&r1=260223&r2=260224&view=diff
>
> ==============================================================================
> --- lld/trunk/ELF/Target.h (original)
> +++ lld/trunk/ELF/Target.h Tue Feb  9 09:11:01 2016
> @@ -54,8 +54,8 @@ public:
>
>    virtual bool isSizeRel(uint32_t Type) const;
>    virtual bool needsDynRelative(unsigned Type) const { return false; }
> -  virtual bool needsGot(uint32_t Type, const SymbolBody &S) const;
> -  virtual bool needsPlt(uint32_t Type, const SymbolBody &S) const;
> +  virtual bool needsGot(uint32_t Type, SymbolBody &S) const;
> +  virtual bool needsPlt(uint32_t Type, SymbolBody &S) const;
>    virtual void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
>                             uint64_t P, uint64_t SA, uint64_t ZA = 0,
>                             uint8_t *PairedLoc = nullptr) const = 0;
>
> Modified: lld/trunk/ELF/Writer.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=260224&r1=260223&r2=260224&view=diff
>
> ==============================================================================
> --- lld/trunk/ELF/Writer.cpp (original)
> +++ lld/trunk/ELF/Writer.cpp Tue Feb  9 09:11:01 2016
> @@ -302,10 +302,10 @@ void Writer<ELFT>::scanRelocs(
>      // If a symbol in a DSO is referenced directly instead of through GOT,
>      // we need to create a copy relocation for the symbol.
>      if (auto *B = dyn_cast_or_null<SharedSymbol<ELFT>>(Body)) {
> -      if (B->NeedsCopy)
> +      if (B->needsCopy())
>          continue;
>        if (Target->needsCopyRel(Type, *B)) {
> -        B->NeedsCopy = true;
> +        B->NeedsCopyOrPltAddr = true;
>          Out<ELFT>::RelaDyn->addReloc(
>              {Target->CopyRel, DynamicReloc<ELFT>::Off_Bss, B});
>          continue;
> @@ -968,7 +968,7 @@ template <class ELFT> bool Writer<ELFT>:
>      if (auto *C = dyn_cast<DefinedCommon>(Body))
>        CommonSymbols.push_back(C);
>      if (auto *SC = dyn_cast<SharedSymbol<ELFT>>(Body))
> -      if (SC->NeedsCopy)
> +      if (SC->needsCopy())
>          CopyRelSymbols.push_back(SC);
>
>      if (!includeInSymtab<ELFT>(*Body))
>
> Added: lld/trunk/test/ELF/Inputs/undef-with-plt-addr.s
> URL:
> http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/undef-with-plt-addr.s?rev=260224&view=auto
>
> ==============================================================================
> --- lld/trunk/test/ELF/Inputs/undef-with-plt-addr.s (added)
> +++ lld/trunk/test/ELF/Inputs/undef-with-plt-addr.s Tue Feb  9 09:11:01
> 2016
> @@ -0,0 +1,4 @@
> +       .globl  set_data
> +       .type   set_data, at function
> +set_data:
> +       retq
>
> Modified: lld/trunk/test/ELF/symbol-override.s
> URL:
> http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/symbol-override.s?rev=260224&r1=260223&r2=260224&view=diff
>
> ==============================================================================
> --- lld/trunk/test/ELF/symbol-override.s (original)
> +++ lld/trunk/test/ELF/symbol-override.s Tue Feb  9 09:11:01 2016
> @@ -43,4 +43,4 @@ nop
>  .text
>  .globl _start
>  _start:
> -callq do
> +callq do at plt
>
> Added: lld/trunk/test/ELF/undef-with-plt-addr.s
> URL:
> http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/undef-with-plt-addr.s?rev=260224&view=auto
>
> ==============================================================================
> --- lld/trunk/test/ELF/undef-with-plt-addr.s (added)
> +++ lld/trunk/test/ELF/undef-with-plt-addr.s Tue Feb  9 09:11:01 2016
> @@ -0,0 +1,23 @@
> +// REQUIRES: x86
> +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
> +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux
> %p/Inputs/undef-with-plt-addr.s -o %t2.o
> +// RUN: ld.lld %t2.o -o %t2.so -shared
> +// RUN: ld.lld %t.o %t2.so -o %t3
> +// RUN: llvm-readobj -t -s %t3 | FileCheck %s
> +
> +.globl _start
> +_start:
> +movabsq        $set_data, %rax
> +
> +// Test that set_data has an address in the .plt
> +
> +// CHECK:      Name: .plt
> +// CHECK-NEXT: Type: SHT_PROGBITS
> +// CHECK-NEXT: Flags [
> +// CHECK-NEXT:   SHF_ALLOC
> +// CHECK-NEXT:   SHF_EXECINSTR
> +// CHECK-NEXT: ]
> +// CHECK-NEXT: Address: 0x11010
> +
> +// CHECK:      Name:    set_data
> +// CHECK-NEXT: Value:   0x11020
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20160209/30a5d2ed/attachment.html>


More information about the llvm-commits mailing list