diff options
Diffstat (limited to 'ELF/Relocations.cpp')
| -rw-r--r-- | ELF/Relocations.cpp | 812 | 
1 files changed, 419 insertions, 393 deletions
diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp index 1aa0957b1d01..467219ad0542 100644 --- a/ELF/Relocations.cpp +++ b/ELF/Relocations.cpp @@ -45,14 +45,14 @@  #include "Config.h"  #include "LinkerScript.h"  #include "OutputSections.h" -#include "Strings.h"  #include "SymbolTable.h"  #include "Symbols.h"  #include "SyntheticSections.h"  #include "Target.h"  #include "Thunks.h"  #include "lld/Common/Memory.h" - +#include "lld/Common/Strings.h" +#include "llvm/ADT/SmallSet.h"  #include "llvm/Support/Endian.h"  #include "llvm/Support/raw_ostream.h"  #include <algorithm> @@ -80,55 +80,22 @@ static std::string getLocation(InputSectionBase &S, const Symbol &Sym,    return Msg + S.getObjMsg(Off);  } -// This is a MIPS-specific rule. -// -// In case of MIPS GP-relative relocations always resolve to a definition -// in a regular input file, ignoring the one-definition rule. So we, -// for example, should not attempt to create a dynamic relocation even -// if the target symbol is preemptible. There are two two MIPS GP-relative -// relocations R_MIPS_GPREL16 and R_MIPS_GPREL32. But only R_MIPS_GPREL16 -// can be against a preemptible symbol. -// -// To get MIPS relocation type we apply 0xff mask. In case of O32 ABI all -// relocation types occupy eight bit. In case of N64 ABI we extract first -// relocation from 3-in-1 packet because only the first relocation can -// be against a real symbol. -static bool isMipsGprel(RelType Type) { -  if (Config->EMachine != EM_MIPS) -    return false; -  Type &= 0xff; -  return Type == R_MIPS_GPREL16 || Type == R_MICROMIPS_GPREL16 || -         Type == R_MICROMIPS_GPREL7_S2; -} -  // This function is similar to the `handleTlsRelocation`. MIPS does not  // support any relaxations for TLS relocations so by factoring out MIPS  // handling in to the separate function we can simplify the code and do not  // pollute other `handleTlsRelocation` by MIPS `ifs` statements.  // Mips has a custom MipsGotSection that handles the writing of GOT entries  // without dynamic relocations. -template <class ELFT>  static unsigned handleMipsTlsRelocation(RelType Type, Symbol &Sym,                                          InputSectionBase &C, uint64_t Offset,                                          int64_t Addend, RelExpr Expr) {    if (Expr == R_MIPS_TLSLD) { -    if (InX::MipsGot->addTlsIndex() && Config->Pic) -      InX::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::MipsGot, -                              InX::MipsGot->getTlsIndexOff(), false, nullptr, -                              0}); +    InX::MipsGot->addTlsIndex(*C.File);      C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});      return 1;    } -    if (Expr == R_MIPS_TLSGD) { -    if (InX::MipsGot->addDynTlsEntry(Sym) && Sym.IsPreemptible) { -      uint64_t Off = InX::MipsGot->getGlobalDynOffset(Sym); -      InX::RelaDyn->addReloc( -          {Target->TlsModuleIndexRel, InX::MipsGot, Off, false, &Sym, 0}); -      if (Sym.IsPreemptible) -        InX::RelaDyn->addReloc({Target->TlsOffsetRel, InX::MipsGot, -                                Off + Config->Wordsize, false, &Sym, 0}); -    } +    InX::MipsGot->addDynTlsEntry(*C.File, Sym);      C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});      return 1;    } @@ -161,7 +128,7 @@ static unsigned handleARMTlsRelocation(RelType Type, Symbol &Sym,    auto AddTlsReloc = [&](uint64_t Off, RelType Type, Symbol *Dest, bool Dyn) {      if (Dyn) -      InX::RelaDyn->addReloc({Type, InX::Got, Off, false, Dest, 0}); +      InX::RelaDyn->addReloc(Type, InX::Got, Off, Dest);      else        InX::Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest});    }; @@ -207,7 +174,7 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,    if (Config->EMachine == EM_ARM)      return handleARMTlsRelocation<ELFT>(Type, Sym, C, Offset, Addend, Expr);    if (Config->EMachine == EM_MIPS) -    return handleMipsTlsRelocation<ELFT>(Type, Sym, C, Offset, Addend, Expr); +    return handleMipsTlsRelocation(Type, Sym, C, Offset, Addend, Expr);    if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) &&        Config->Shared) { @@ -221,40 +188,62 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,      return 1;    } -  if (isRelExprOneOf<R_TLSLD_PC, R_TLSLD>(Expr)) { +  if (isRelExprOneOf<R_TLSLD_GOT, R_TLSLD_GOT_FROM_END, R_TLSLD_PC, +                     R_TLSLD_HINT>(Expr)) {      // Local-Dynamic relocs can be relaxed to Local-Exec.      if (!Config->Shared) {        C.Relocations.push_back( -          {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym}); -      return 2; +          {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type, +           Offset, Addend, &Sym}); +      return Target->TlsGdRelaxSkip;      } +    if (Expr == R_TLSLD_HINT) +      return 1;      if (InX::Got->addTlsIndex()) -      InX::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::Got, -                              InX::Got->getTlsIndexOff(), false, nullptr, 0}); +      InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::Got, +                             InX::Got->getTlsIndexOff(), nullptr);      C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});      return 1;    }    // Local-Dynamic relocs can be relaxed to Local-Exec. -  if (isRelExprOneOf<R_ABS, R_TLSLD, R_TLSLD_PC>(Expr) && !Config->Shared) { -    C.Relocations.push_back({R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym}); +  if (Expr == R_ABS && !Config->Shared) { +    C.Relocations.push_back( +        {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type, +         Offset, Addend, &Sym});      return 1;    } -  if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL, R_TLSGD, -                     R_TLSGD_PC>(Expr)) { +  // Local-Dynamic sequence where offset of tls variable relative to dynamic +  // thread pointer is stored in the got. +  if (Expr == R_TLSLD_GOT_OFF) { +    // Local-Dynamic relocs can be relaxed to local-exec +    if (!Config->Shared) { +      C.Relocations.push_back({R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym}); +      return 1; +    } +    if (!Sym.isInGot()) { +      InX::Got->addEntry(Sym); +      uint64_t Off = Sym.getGotOffset(); +      InX::Got->Relocations.push_back({R_ABS, Target->TlsOffsetRel, Off, 0, &Sym}); +    } +    C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); +    return 1; +  } + +  if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL, R_TLSGD_GOT, +                     R_TLSGD_GOT_FROM_END, R_TLSGD_PC>(Expr)) {      if (Config->Shared) {        if (InX::Got->addDynTlsEntry(Sym)) {          uint64_t Off = InX::Got->getGlobalDynOffset(Sym); -        InX::RelaDyn->addReloc( -            {Target->TlsModuleIndexRel, InX::Got, Off, false, &Sym, 0}); +        InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::Got, Off, &Sym);          // If the symbol is preemptible we need the dynamic linker to write          // the offset too.          uint64_t OffsetOff = Off + Config->Wordsize;          if (Sym.IsPreemptible) -          InX::RelaDyn->addReloc( -              {Target->TlsOffsetRel, InX::Got, OffsetOff, false, &Sym, 0}); +          InX::RelaDyn->addReloc(Target->TlsOffsetRel, InX::Got, OffsetOff, +                                 &Sym);          else            InX::Got->Relocations.push_back(                {R_ABS, Target->TlsOffsetRel, OffsetOff, 0, &Sym}); @@ -271,8 +260,8 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,             Offset, Addend, &Sym});        if (!Sym.isInGot()) {          InX::Got->addEntry(Sym); -        InX::RelaDyn->addReloc( -            {Target->TlsGotRel, InX::Got, Sym.getGotOffset(), false, &Sym, 0}); +        InX::RelaDyn->addReloc(Target->TlsGotRel, InX::Got, Sym.getGotOffset(), +                               &Sym);        }      } else {        C.Relocations.push_back( @@ -336,7 +325,7 @@ static bool isAbsoluteValue(const Symbol &Sym) {  // Returns true if Expr refers a PLT entry.  static bool needsPlt(RelExpr Expr) { -  return isRelExprOneOf<R_PLT_PC, R_PPC_PLT_OPD, R_PLT, R_PLT_PAGE_PC>(Expr); +  return isRelExprOneOf<R_PLT_PC, R_PPC_CALL_PLT, R_PLT, R_PLT_PAGE_PC>(Expr);  }  // Returns true if Expr refers a GOT entry. Note that this function @@ -352,7 +341,8 @@ static bool needsGot(RelExpr Expr) {  // file (PC, or GOT for example).  static bool isRelExpr(RelExpr Expr) {    return isRelExprOneOf<R_PC, R_GOTREL, R_GOTREL_FROM_END, R_MIPS_GOTREL, -                        R_PAGE_PC, R_RELAX_GOT_PC>(Expr); +                        R_PPC_CALL, R_PPC_CALL_PLT, R_PAGE_PC, +                        R_RELAX_GOT_PC>(Expr);  }  // Returns true if a given relocation can be computed at link-time. @@ -367,11 +357,13 @@ static bool isRelExpr(RelExpr Expr) {  static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym,                                       InputSectionBase &S, uint64_t RelOff) {    // These expressions always compute a constant -  if (isRelExprOneOf<R_SIZE, R_GOT_FROM_END, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, -                     R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC, -                     R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, -                     R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_PC, R_TLSGD, -                     R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT>(E)) +  if (isRelExprOneOf< +          R_GOT_FROM_END, R_GOT_OFF, R_TLSLD_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, +          R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC, +          R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, +          R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_GOT, R_TLSGD_GOT_FROM_END, +          R_TLSGD_PC, R_PPC_CALL_PLT, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT, +          R_TLSLD_HINT>(E))      return true;    // These never do, except if the entire file is position dependent or if @@ -384,6 +376,10 @@ static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym,    if (!Config->Pic)      return true; +  // The size of a non preemptible symbol is a constant. +  if (E == R_SIZE) +    return true; +    // For the target and the relocation, we want to know if they are    // absolute or relative.    bool AbsVal = isAbsoluteValue(Sym); @@ -413,39 +409,45 @@ static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym,  }  static RelExpr toPlt(RelExpr Expr) { -  if (Expr == R_PPC_OPD) -    return R_PPC_PLT_OPD; -  if (Expr == R_PC) +  switch (Expr) { +  case R_PPC_CALL: +    return R_PPC_CALL_PLT; +  case R_PC:      return R_PLT_PC; -  if (Expr == R_PAGE_PC) +  case R_PAGE_PC:      return R_PLT_PAGE_PC; -  if (Expr == R_ABS) +  case R_ABS:      return R_PLT; -  return Expr; +  default: +    return Expr; +  }  }  static RelExpr fromPlt(RelExpr Expr) {    // We decided not to use a plt. Optimize a reference to the plt to a    // reference to the symbol itself. -  if (Expr == R_PLT_PC) +  switch (Expr) { +  case R_PLT_PC:      return R_PC; -  if (Expr == R_PPC_PLT_OPD) -    return R_PPC_OPD; -  if (Expr == R_PLT) +  case R_PPC_CALL_PLT: +    return R_PPC_CALL; +  case R_PLT:      return R_ABS; -  return Expr; +  default: +    return Expr; +  }  }  // Returns true if a given shared symbol is in a read-only segment in a DSO. -template <class ELFT> static bool isReadOnly(SharedSymbol *SS) { +template <class ELFT> static bool isReadOnly(SharedSymbol &SS) {    typedef typename ELFT::Phdr Elf_Phdr;    // Determine if the symbol is read-only by scanning the DSO's program headers. -  const SharedFile<ELFT> &File = SS->getFile<ELFT>(); +  const SharedFile<ELFT> &File = SS.getFile<ELFT>();    for (const Elf_Phdr &Phdr : check(File.getObj().program_headers()))      if ((Phdr.p_type == ELF::PT_LOAD || Phdr.p_type == ELF::PT_GNU_RELRO) && -        !(Phdr.p_flags & ELF::PF_W) && SS->Value >= Phdr.p_vaddr && -        SS->Value < Phdr.p_vaddr + Phdr.p_memsz) +        !(Phdr.p_flags & ELF::PF_W) && SS.Value >= Phdr.p_vaddr && +        SS.Value < Phdr.p_vaddr + Phdr.p_memsz)        return true;    return false;  } @@ -454,26 +456,45 @@ template <class ELFT> static bool isReadOnly(SharedSymbol *SS) {  //  // If two or more symbols are at the same offset, and at least one of  // them are copied by a copy relocation, all of them need to be copied. -// Otherwise, they would refer different places at runtime. +// Otherwise, they would refer to different places at runtime.  template <class ELFT> -static std::vector<SharedSymbol *> getSymbolsAt(SharedSymbol *SS) { +static SmallSet<SharedSymbol *, 4> getSymbolsAt(SharedSymbol &SS) {    typedef typename ELFT::Sym Elf_Sym; -  SharedFile<ELFT> &File = SS->getFile<ELFT>(); +  SharedFile<ELFT> &File = SS.getFile<ELFT>(); -  std::vector<SharedSymbol *> Ret; +  SmallSet<SharedSymbol *, 4> Ret;    for (const Elf_Sym &S : File.getGlobalELFSyms()) {      if (S.st_shndx == SHN_UNDEF || S.st_shndx == SHN_ABS || -        S.st_value != SS->Value) +        S.st_value != SS.Value)        continue;      StringRef Name = check(S.getName(File.getStringTable()));      Symbol *Sym = Symtab->find(Name);      if (auto *Alias = dyn_cast_or_null<SharedSymbol>(Sym)) -      Ret.push_back(Alias); +      Ret.insert(Alias);    }    return Ret;  } +// When a symbol is copy relocated or we create a canonical plt entry, it is +// effectively a defined symbol. In the case of copy relocation the symbol is +// in .bss and in the case of a canonical plt entry it is in .plt. This function +// replaces the existing symbol with a Defined pointing to the appropriate +// location. +static void replaceWithDefined(Symbol &Sym, SectionBase *Sec, uint64_t Value, +                               uint64_t Size) { +  Symbol Old = Sym; +  replaceSymbol<Defined>(&Sym, Sym.File, Sym.getName(), Sym.Binding, +                         Sym.StOther, Sym.Type, Value, Size, Sec); +  Sym.PltIndex = Old.PltIndex; +  Sym.GotIndex = Old.GotIndex; +  Sym.VerdefIndex = Old.VerdefIndex; +  Sym.IsPreemptible = true; +  Sym.ExportDynamic = true; +  Sym.IsUsedInRegularObj = true; +  Sym.Used = true; +} +  // Reserve space in .bss or .bss.rel.ro for copy relocation.  //  // The copy relocation is pretty much a hack. If you use a copy relocation @@ -516,17 +537,17 @@ static std::vector<SharedSymbol *> getSymbolsAt(SharedSymbol *SS) {  // to the variable in .bss. This kind of issue is sometimes very hard to  // debug. What's a solution? Instead of exporting a varaible V from a DSO,  // define an accessor getV(). -template <class ELFT> static void addCopyRelSymbol(SharedSymbol *SS) { +template <class ELFT> static void addCopyRelSymbol(SharedSymbol &SS) {    // Copy relocation against zero-sized symbol doesn't make sense. -  uint64_t SymSize = SS->getSize(); -  if (SymSize == 0) -    fatal("cannot create a copy relocation for symbol " + toString(*SS)); +  uint64_t SymSize = SS.getSize(); +  if (SymSize == 0 || SS.Alignment == 0) +    fatal("cannot create a copy relocation for symbol " + toString(SS));    // See if this symbol is in a read-only segment. If so, preserve the symbol's    // memory protection by reserving space in the .bss.rel.ro section.    bool IsReadOnly = isReadOnly<ELFT>(SS);    BssSection *Sec = make<BssSection>(IsReadOnly ? ".bss.rel.ro" : ".bss", -                                     SymSize, SS->Alignment); +                                     SymSize, SS.Alignment);    if (IsReadOnly)      InX::BssRelRo->getParent()->addSection(Sec);    else @@ -535,125 +556,10 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol *SS) {    // Look through the DSO's dynamic symbol table for aliases and create a    // dynamic symbol for each one. This causes the copy relocation to correctly    // interpose any aliases. -  for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS)) { -    Sym->CopyRelSec = Sec; -    Sym->IsPreemptible = false; -    Sym->IsUsedInRegularObj = true; -    Sym->Used = true; -  } - -  InX::RelaDyn->addReloc({Target->CopyRel, Sec, 0, false, SS, 0}); -} - -static void errorOrWarn(const Twine &Msg) { -  if (!Config->NoinhibitExec) -    error(Msg); -  else -    warn(Msg); -} - -// Returns PLT relocation expression. -// -// This handles a non PIC program call to function in a shared library. In -// an ideal world, we could just report an error saying the relocation can -// overflow at runtime. In the real world with glibc, crt1.o has a -// R_X86_64_PC32 pointing to libc.so. -// -// The general idea on how to handle such cases is to create a PLT entry and -// use that as the function value. -// -// For the static linking part, we just return a plt expr and everything -// else will use the the PLT entry as the address. -// -// 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). -static RelExpr getPltExpr(Symbol &Sym, RelExpr Expr, bool &IsConstant) { -  Sym.NeedsPltAddr = true; -  Sym.IsPreemptible = false; -  IsConstant = true; -  return toPlt(Expr); -} - -// This modifies the expression if we can use a copy relocation or point the -// symbol to the PLT. -template <class ELFT> -static RelExpr adjustExpr(Symbol &Sym, RelExpr Expr, RelType Type, -                          InputSectionBase &S, uint64_t RelOff, -                          bool &IsConstant) { -  // If a relocation can be applied at link-time, we don't need to -  // create a dynamic relocation in the first place. -  if (IsConstant) -    return Expr; - -  // If the relocation is to a weak undef, and we are producing -  // executable, give up on it and produce a non preemptible 0. -  if (!Config->Shared && Sym.isUndefWeak()) { -    Sym.IsPreemptible = false; -    IsConstant = true; -    return Expr; -  } - -  // We can create any dynamic relocation supported by the dynamic linker if a -  // section is writable or we are passed -z notext. -  bool CanWrite = (S.Flags & SHF_WRITE) || !Config->ZText; -  if (CanWrite && Target->isPicRel(Type)) -    return Expr; - -  // If we got here we know that this relocation would require the dynamic -  // linker to write a value to read only memory or use an unsupported -  // relocation. - -  // We can hack around it if we are producing an executable and -  // the refered symbol can be preemepted to refer to the executable. -  if (!CanWrite && (Config->Shared || (Config->Pic && !isRelExpr(Expr)))) { -    error( -        "can't create dynamic relocation " + toString(Type) + " against " + -        (Sym.getName().empty() ? "local symbol" : "symbol: " + toString(Sym)) + -        " in readonly segment; recompile object files with -fPIC" + -        getLocation(S, Sym, RelOff)); -    return Expr; -  } - -  // Copy relocations are only possible if we are creating an executable and the -  // symbol is shared. -  if (!Sym.isShared() || Config->Shared) -    return Expr; - -  if (Sym.getVisibility() != STV_DEFAULT) { -    error("cannot preempt symbol: " + toString(Sym) + -          getLocation(S, Sym, RelOff)); -    return Expr; -  } - -  if (Sym.isObject()) { -    // Produce a copy relocation. -    auto *B = dyn_cast<SharedSymbol>(&Sym); -    if (B && !B->CopyRelSec) { -      if (Config->ZNocopyreloc) -        error("unresolvable relocation " + toString(Type) + -              " against symbol '" + toString(*B) + -              "'; recompile with -fPIC or remove '-z nocopyreloc'" + -              getLocation(S, Sym, RelOff)); - -      addCopyRelSymbol<ELFT>(B); -    } -    IsConstant = true; -    return Expr; -  } - -  if (Sym.isFunc()) -    return getPltExpr(Sym, Expr, IsConstant); +  for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS)) +    replaceWithDefined(*Sym, Sec, 0, Sym->Size); -  errorOrWarn("symbol '" + toString(Sym) + "' defined in " + -              toString(Sym.File) + " has no type"); -  return Expr; +  InX::RelaDyn->addReloc(Target->CopyRel, Sec, 0, &SS);  }  // MIPS has an odd notion of "paired" relocations to calculate addends. @@ -728,7 +634,7 @@ static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec,      return false;    bool CanBeExternal = -      Sym.computeBinding() != STB_LOCAL && Sym.getVisibility() == STV_DEFAULT; +      Sym.computeBinding() != STB_LOCAL && Sym.Visibility == STV_DEFAULT;    if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore && CanBeExternal)      return false; @@ -756,12 +662,12 @@ static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec,  // this for the N32 ABI. Iterate over relocation with the same offset and put  // theirs types into the single bit-set.  template <class RelTy> static RelType getMipsN32RelType(RelTy *&Rel, RelTy *End) { -  RelType Type = Rel->getType(Config->IsMips64EL); +  RelType Type = 0;    uint64_t Offset = Rel->r_offset;    int N = 0; -  while (Rel + 1 != End && (Rel + 1)->r_offset == Offset) -    Type |= (++Rel)->getType(Config->IsMips64EL) << (8 * ++N); +  while (Rel != End && Rel->r_offset == Offset) +    Type |= (Rel++)->getType(Config->IsMips64EL) << (8 * N++);    return Type;  } @@ -811,16 +717,34 @@ private:  };  } // namespace +static void addRelativeReloc(InputSectionBase *IS, uint64_t OffsetInSec, +                             Symbol *Sym, int64_t Addend, RelExpr Expr, +                             RelType Type) { +  // Add a relative relocation. If RelrDyn section is enabled, and the +  // relocation offset is guaranteed to be even, add the relocation to +  // the RelrDyn section, otherwise add it to the RelaDyn section. +  // RelrDyn sections don't support odd offsets. Also, RelrDyn sections +  // don't store the addend values, so we must write it to the relocated +  // address. +  if (InX::RelrDyn && IS->Alignment >= 2 && OffsetInSec % 2 == 0) { +    IS->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym}); +    InX::RelrDyn->Relocs.push_back({IS, OffsetInSec}); +    return; +  } +  InX::RelaDyn->addReloc(Target->RelativeRel, IS, OffsetInSec, Sym, Addend, +                         Expr, Type); +} +  template <class ELFT, class GotPltSection>  static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt, -                        RelocationBaseSection *Rel, RelType Type, Symbol &Sym, -                        bool UseSymVA) { +                        RelocationBaseSection *Rel, RelType Type, Symbol &Sym) {    Plt->addEntry<ELFT>(Sym);    GotPlt->addEntry(Sym); -  Rel->addReloc({Type, GotPlt, Sym.getGotPltOffset(), UseSymVA, &Sym, 0}); +  Rel->addReloc( +      {Type, GotPlt, Sym.getGotPltOffset(), !Sym.IsPreemptible, &Sym, 0});  } -template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) { +template <class ELFT> static void addGotEntry(Symbol &Sym) {    InX::Got->addEntry(Sym);    RelExpr Expr = Sym.isTls() ? R_TLS : R_ABS; @@ -833,7 +757,8 @@ template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) {    // add a static relocation to a Relocations vector so that    // InputSection::relocate will do the work for us. We may be able    // to just write a value now, but it is a TODO.) -  bool IsLinkTimeConstant = !Preemptible && (!Config->Pic || isAbsolute(Sym)); +  bool IsLinkTimeConstant = +      !Sym.IsPreemptible && (!Config->Pic || isAbsolute(Sym));    if (IsLinkTimeConstant) {      InX::Got->Relocations.push_back({Expr, Target->GotRel, Off, 0, &Sym});      return; @@ -841,23 +766,33 @@ template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) {    // Otherwise, we emit a dynamic relocation to .rel[a].dyn so that    // the GOT slot will be fixed at load-time. -  RelType Type; -  if (Sym.isTls()) -    Type = Target->TlsGotRel; -  else if (!Preemptible && Config->Pic && !isAbsolute(Sym)) -    Type = Target->RelativeRel; -  else -    Type = Target->GotRel; -  InX::RelaDyn->addReloc({Type, InX::Got, Off, !Preemptible, &Sym, 0}); +  if (!Sym.isTls() && !Sym.IsPreemptible && Config->Pic && !isAbsolute(Sym)) { +    addRelativeReloc(InX::Got, Off, &Sym, 0, R_ABS, Target->GotRel); +    return; +  } +  InX::RelaDyn->addReloc(Sym.isTls() ? Target->TlsGotRel : Target->GotRel, +                         InX::Got, Off, &Sym, 0, +                         Sym.IsPreemptible ? R_ADDEND : R_ABS, Target->GotRel); +} -  // REL type relocations don't have addend fields unlike RELAs, and -  // their addends are stored to the section to which they are applied. -  // So, store addends if we need to. -  // -  // This is ugly -- the difference between REL and RELA should be -  // handled in a better way. It's a TODO. -  if (!Config->IsRela && !Preemptible) -    InX::Got->Relocations.push_back({R_ABS, Target->GotRel, Off, 0, &Sym}); +// Return true if we can define a symbol in the executable that +// contains the value/function of a symbol defined in a shared +// library. +static bool canDefineSymbolInExecutable(Symbol &Sym) { +  // If the symbol has default visibility the symbol defined in the +  // executable will preempt it. +  // Note that we want the visibility of the shared symbol itself, not +  // the visibility of the symbol in the output file we are producing. That is +  // why we use Sym.StOther. +  if ((Sym.StOther & 0x3) == STV_DEFAULT) +    return true; + +  // If we are allowed to break address equality of functions, defining +  // a plt entry will allow the program to call the function in the +  // .so, but the .so and the executable will no agree on the address +  // of the function. Similar logic for objects. +  return ((Sym.isFunc() && Config->IgnoreFunctionAddressEquality) || +          (Sym.isObject() && Config->IgnoreDataAddressEquality));  }  // The reason we have to do this early scan is as follows @@ -874,129 +809,23 @@ template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) {  // complicates things for the dynamic linker and means we would have to reserve  // space for the extra PT_LOAD even if we end up not using it.  template <class ELFT, class RelTy> -static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { -  OffsetGetter GetOffset(Sec); - -  // Not all relocations end up in Sec.Relocations, but a lot do. -  Sec.Relocations.reserve(Rels.size()); - -  for (auto I = Rels.begin(), End = Rels.end(); I != End; ++I) { -    const RelTy &Rel = *I; -    Symbol &Sym = Sec.getFile<ELFT>()->getRelocTargetSym(Rel); -    RelType Type = Rel.getType(Config->IsMips64EL); - -    // Deal with MIPS oddity. -    if (Config->MipsN32Abi) -      Type = getMipsN32RelType(I, End); - -    // Get an offset in an output section this relocation is applied to. -    uint64_t Offset = GetOffset.get(Rel.r_offset); -    if (Offset == uint64_t(-1)) -      continue; - -    // Skip if the target symbol is an erroneous undefined symbol. -    if (maybeReportUndefined(Sym, Sec, Rel.r_offset)) -      continue; - -    RelExpr Expr = -        Target->getRelExpr(Type, Sym, Sec.Data.begin() + Rel.r_offset); - -    // Ignore "hint" relocations because they are only markers for relaxation. -    if (isRelExprOneOf<R_HINT, R_NONE>(Expr)) -      continue; - -    // Handle yet another MIPS-ness. -    if (isMipsGprel(Type)) { -      int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal()); -      Sec.Relocations.push_back({R_MIPS_GOTREL, Type, Offset, Addend, &Sym}); -      continue; -    } - -    bool Preemptible = Sym.IsPreemptible; - -    // Strenghten or relax a PLT access. -    // -    // GNU ifunc symbols must be accessed via PLT because their addresses -    // are determined by runtime. -    // -    // On the other hand, if we know that a PLT entry will be resolved within -    // the same ELF module, we can skip PLT access and directly jump to the -    // destination function. For example, if we are linking a main exectuable, -    // all dynamic symbols that can be resolved within the executable will -    // actually be resolved that way at runtime, because the main exectuable -    // is always at the beginning of a search list. We can leverage that fact. -    if (Sym.isGnuIFunc()) -      Expr = toPlt(Expr); -    else if (!Preemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym)) -      Expr = -          Target->adjustRelaxExpr(Type, Sec.Data.data() + Rel.r_offset, Expr); -    else if (!Preemptible) -      Expr = fromPlt(Expr); - -    bool IsConstant = -        isStaticLinkTimeConstant(Expr, Type, Sym, Sec, Rel.r_offset); - -    Expr = adjustExpr<ELFT>(Sym, Expr, Type, Sec, Rel.r_offset, IsConstant); -    if (errorCount()) -      continue; - -    // This relocation does not require got entry, but it is relative to got and -    // needs it to be created. Here we request for that. -    if (isRelExprOneOf<R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_GOTREL, -                       R_GOTREL_FROM_END, R_PPC_TOC>(Expr)) -      InX::Got->HasGotOffRel = true; - -    // Read an addend. -    int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal()); - -    // Process some TLS relocations, including relaxing TLS relocations. -    // Note that this function does not handle all TLS relocations. -    if (unsigned Processed = -            handleTlsRelocation<ELFT>(Type, Sym, Sec, Offset, Addend, Expr)) { -      I += (Processed - 1); -      continue; -    } - -    // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol. -    if (needsPlt(Expr) && !Sym.isInPlt()) { -      if (Sym.isGnuIFunc() && !Preemptible) -        addPltEntry<ELFT>(InX::Iplt, InX::IgotPlt, InX::RelaIplt, -                          Target->IRelativeRel, Sym, true); -      else -        addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel, -                          Sym, !Preemptible); -    } - -    // Create a GOT slot if a relocation needs GOT. -    if (needsGot(Expr)) { -      if (Config->EMachine == EM_MIPS) { -        // MIPS ABI has special rules to process GOT entries and doesn't -        // require relocation entries for them. A special case is TLS -        // relocations. In that case dynamic loader applies dynamic -        // relocations to initialize TLS GOT entries. -        // See "Global Offset Table" in Chapter 5 in the following document -        // for detailed description: -        // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf -        InX::MipsGot->addEntry(Sym, Addend, Expr); -        if (Sym.isTls() && Sym.IsPreemptible) -          InX::RelaDyn->addReloc({Target->TlsGotRel, InX::MipsGot, -                                  Sym.getGotOffset(), false, &Sym, 0}); -      } else if (!Sym.isInGot()) { -        addGotEntry<ELFT>(Sym, Preemptible); -      } -    } - -    if (!needsPlt(Expr) && !needsGot(Expr) && Sym.IsPreemptible) { -      // We don't know anything about the finaly symbol. Just ask the dynamic -      // linker to handle the relocation for us. -      if (!Target->isPicRel(Type)) -        errorOrWarn( -            "relocation " + toString(Type) + -            " cannot be used against shared object; recompile with -fPIC" + -            getLocation(Sec, Sym, Offset)); +static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type, +                            uint64_t Offset, Symbol &Sym, const RelTy &Rel, +                            int64_t Addend) { +  if (isStaticLinkTimeConstant(Expr, Type, Sym, Sec, Offset)) { +    Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); +    return; +  } +  bool CanWrite = (Sec.Flags & SHF_WRITE) || !Config->ZText; +  if (CanWrite) { +    // R_GOT refers to a position in the got, even if the symbol is preemptible. +    bool IsPreemptibleValue = Sym.IsPreemptible && Expr != R_GOT; -      InX::RelaDyn->addReloc( -          {Target->getDynRel(Type), &Sec, Offset, false, &Sym, Addend}); +    if (!IsPreemptibleValue) { +      addRelativeReloc(&Sec, Offset, &Sym, Addend, Expr, Type); +      return; +    } else if (RelType Rel = Target->getDynRel(Type)) { +      InX::RelaDyn->addReloc(Rel, &Sec, Offset, &Sym, Addend, R_ADDEND, Type);        // MIPS ABI turns using of GOT and dynamic relocations inside out.        // While regular ABI uses dynamic relocations to fill up GOT entries @@ -1014,37 +843,210 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {        // a dynamic relocation.        // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19        if (Config->EMachine == EM_MIPS) -        InX::MipsGot->addEntry(Sym, Addend, Expr); -      continue; +        InX::MipsGot->addEntry(*Sec.File, Sym, Addend, Expr); +      return;      } +  } -    // The size is not going to change, so we fold it in here. -    if (Expr == R_SIZE) -      Addend += Sym.getSize(); +  // If the relocation is to a weak undef, and we are producing +  // executable, give up on it and produce a non preemptible 0. +  if (!Config->Shared && Sym.isUndefWeak()) { +    Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); +    return; +  } -    // If the produced value is a constant, we just remember to write it -    // when outputting this section. We also have to do it if the format -    // uses Elf_Rel, since in that case the written value is the addend. -    if (IsConstant) { -      Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); -      continue; +  if (!CanWrite && (Config->Pic && !isRelExpr(Expr))) { +    error( +        "can't create dynamic relocation " + toString(Type) + " against " + +        (Sym.getName().empty() ? "local symbol" : "symbol: " + toString(Sym)) + +        " in readonly segment; recompile object files with -fPIC " +        "or pass '-Wl,-z,notext' to allow text relocations in the output" + +        getLocation(Sec, Sym, Offset)); +    return; +  } + +  // Copy relocations are only possible if we are creating an executable. +  if (Config->Shared) { +    errorOrWarn("relocation " + toString(Type) + +                " cannot be used against symbol " + toString(Sym) + +                "; recompile with -fPIC" + getLocation(Sec, Sym, Offset)); +    return; +  } + +  // If the symbol is undefined we already reported any relevant errors. +  if (Sym.isUndefined()) +    return; + +  if (!canDefineSymbolInExecutable(Sym)) { +    error("cannot preempt symbol: " + toString(Sym) + +          getLocation(Sec, Sym, Offset)); +    return; +  } + +  if (Sym.isObject()) { +    // Produce a copy relocation. +    if (auto *SS = dyn_cast<SharedSymbol>(&Sym)) { +      if (!Config->ZCopyreloc) +        error("unresolvable relocation " + toString(Type) + +              " against symbol '" + toString(*SS) + +              "'; recompile with -fPIC or remove '-z nocopyreloc'" + +              getLocation(Sec, Sym, Offset)); +      addCopyRelSymbol<ELFT>(*SS);      } +    Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); +    return; +  } -    // If the output being produced is position independent, the final value -    // is still not known. In that case we still need some help from the -    // dynamic linker. We can however do better than just copying the incoming -    // relocation. We can process some of it and and just ask the dynamic -    // linker to add the load address. -    if (Config->IsRela) { -      InX::RelaDyn->addReloc( -          {Target->RelativeRel, &Sec, Offset, true, &Sym, Addend}); -    } else { -      // In REL, addends are stored to the target section. -      InX::RelaDyn->addReloc( -          {Target->RelativeRel, &Sec, Offset, true, &Sym, 0}); -      Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); +  if (Sym.isFunc()) { +    // This handles a non PIC program call to function in a shared library. In +    // an ideal world, we could just report an error saying the relocation can +    // overflow at runtime. In the real world with glibc, crt1.o has a +    // R_X86_64_PC32 pointing to libc.so. +    // +    // The general idea on how to handle such cases is to create a PLT entry and +    // use that as the function value. +    // +    // For the static linking part, we just return a plt expr and everything +    // else will use the PLT entry as the address. +    // +    // 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). + +    // For position independent executable on i386, the plt entry requires ebx +    // to be set. This causes two problems: +    // * If some code has a direct reference to a function, it was probably +    //   compiled without -fPIE/-fPIC and doesn't maintain ebx. +    // * If a library definition gets preempted to the executable, it will have +    //   the wrong ebx value. +    if (Config->Pie && Config->EMachine == EM_386) +      errorOrWarn("symbol '" + toString(Sym) + +                  "' cannot be preempted; recompile with -fPIE" + +                  getLocation(Sec, Sym, Offset)); +    if (!Sym.isInPlt()) +      addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel, +                        Sym); +    if (!Sym.isDefined()) +      replaceWithDefined(Sym, InX::Plt, Sym.getPltOffset(), 0); +    Sym.NeedsPltAddr = true; +    Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); +    return; +  } + +  errorOrWarn("symbol '" + toString(Sym) + "' has no type" + +              getLocation(Sec, Sym, Offset)); +} + +template <class ELFT, class RelTy> +static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I, +                      RelTy *End) { +  const RelTy &Rel = *I; +  Symbol &Sym = Sec.getFile<ELFT>()->getRelocTargetSym(Rel); +  RelType Type; + +  // Deal with MIPS oddity. +  if (Config->MipsN32Abi) { +    Type = getMipsN32RelType(I, End); +  } else { +    Type = Rel.getType(Config->IsMips64EL); +    ++I; +  } + +  // Get an offset in an output section this relocation is applied to. +  uint64_t Offset = GetOffset.get(Rel.r_offset); +  if (Offset == uint64_t(-1)) +    return; + +  // Skip if the target symbol is an erroneous undefined symbol. +  if (maybeReportUndefined(Sym, Sec, Rel.r_offset)) +    return; + +  const uint8_t *RelocatedAddr = Sec.Data.begin() + Rel.r_offset; +  RelExpr Expr = Target->getRelExpr(Type, Sym, RelocatedAddr); + +  // Ignore "hint" relocations because they are only markers for relaxation. +  if (isRelExprOneOf<R_HINT, R_NONE>(Expr)) +    return; + +  // Strenghten or relax relocations. +  // +  // GNU ifunc symbols must be accessed via PLT because their addresses +  // are determined by runtime. +  // +  // On the other hand, if we know that a PLT entry will be resolved within +  // the same ELF module, we can skip PLT access and directly jump to the +  // destination function. For example, if we are linking a main exectuable, +  // all dynamic symbols that can be resolved within the executable will +  // actually be resolved that way at runtime, because the main exectuable +  // is always at the beginning of a search list. We can leverage that fact. +  if (Sym.isGnuIFunc()) +    Expr = toPlt(Expr); +  else if (!Sym.IsPreemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym)) +    Expr = Target->adjustRelaxExpr(Type, RelocatedAddr, Expr); +  else if (!Sym.IsPreemptible) +    Expr = fromPlt(Expr); + +  // This relocation does not require got entry, but it is relative to got and +  // needs it to be created. Here we request for that. +  if (isRelExprOneOf<R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_GOTREL, +                     R_GOTREL_FROM_END, R_PPC_TOC>(Expr)) +    InX::Got->HasGotOffRel = true; + +  // Read an addend. +  int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal()); + +  // Process some TLS relocations, including relaxing TLS relocations. +  // Note that this function does not handle all TLS relocations. +  if (unsigned Processed = +          handleTlsRelocation<ELFT>(Type, Sym, Sec, Offset, Addend, Expr)) { +    I += (Processed - 1); +    return; +  } + +  // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol. +  if (needsPlt(Expr) && !Sym.isInPlt()) { +    if (Sym.isGnuIFunc() && !Sym.IsPreemptible) +      addPltEntry<ELFT>(InX::Iplt, InX::IgotPlt, InX::RelaIplt, +                        Target->IRelativeRel, Sym); +    else +      addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel, +                        Sym); +  } + +  // Create a GOT slot if a relocation needs GOT. +  if (needsGot(Expr)) { +    if (Config->EMachine == EM_MIPS) { +      // MIPS ABI has special rules to process GOT entries and doesn't +      // require relocation entries for them. A special case is TLS +      // relocations. In that case dynamic loader applies dynamic +      // relocations to initialize TLS GOT entries. +      // See "Global Offset Table" in Chapter 5 in the following document +      // for detailed description: +      // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf +      InX::MipsGot->addEntry(*Sec.File, Sym, Addend, Expr); +    } else if (!Sym.isInGot()) { +      addGotEntry<ELFT>(Sym);      }    } + +  processRelocAux<ELFT>(Sec, Expr, Type, Offset, Sym, Rel, Addend); +} + +template <class ELFT, class RelTy> +static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { +  OffsetGetter GetOffset(Sec); + +  // Not all relocations end up in Sec.Relocations, but a lot do. +  Sec.Relocations.reserve(Rels.size()); + +  for (auto I = Rels.begin(), End = Rels.end(); I != End;) +    scanReloc<ELFT>(Sec, GetOffset, I, End);  }  template <class ELFT> void elf::scanRelocations(InputSectionBase &S) { @@ -1259,17 +1261,30 @@ ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS) {  //  // We follow a simple but conservative heuristic to place ThunkSections at  // offsets that are multiples of a Target specific branch range. -// For an InputSectionRange that is smaller than the range, a single +// For an InputSectionDescription that is smaller than the range, a single  // ThunkSection at the end of the range will do. +// +// For an InputSectionDescription that is more than twice the size of the range, +// we place the last ThunkSection at range bytes from the end of the +// InputSectionDescription in order to increase the likelihood that the +// distance from a thunk to its target will be sufficiently small to +// allow for the creation of a short thunk.  void ThunkCreator::createInitialThunkSections(      ArrayRef<OutputSection *> OutputSections) {    forEachInputSectionDescription(        OutputSections, [&](OutputSection *OS, InputSectionDescription *ISD) {          if (ISD->Sections.empty())            return; +        uint32_t ISDBegin = ISD->Sections.front()->OutSecOff; +        uint32_t ISDEnd = +            ISD->Sections.back()->OutSecOff + ISD->Sections.back()->getSize(); +        uint32_t LastThunkLowerBound = -1; +        if (ISDEnd - ISDBegin > Target->ThunkSectionSpacing * 2) +          LastThunkLowerBound = ISDEnd - Target->ThunkSectionSpacing; +          uint32_t ISLimit; -        uint32_t PrevISLimit = ISD->Sections.front()->OutSecOff; -        uint32_t ThunkUpperBound = PrevISLimit + Target->ThunkSectionSpacing; +        uint32_t PrevISLimit = ISDBegin; +        uint32_t ThunkUpperBound = ISDBegin + Target->ThunkSectionSpacing;          for (const InputSection *IS : ISD->Sections) {            ISLimit = IS->OutSecOff + IS->getSize(); @@ -1277,6 +1292,8 @@ void ThunkCreator::createInitialThunkSections(              addThunkSection(OS, ISD, PrevISLimit);              ThunkUpperBound = PrevISLimit + Target->ThunkSectionSpacing;            } +          if (ISLimit > LastThunkLowerBound) +            break;            PrevISLimit = ISLimit;          }          addThunkSection(OS, ISD, ISLimit); @@ -1293,17 +1310,22 @@ ThunkSection *ThunkCreator::addThunkSection(OutputSection *OS,  std::pair<Thunk *, bool> ThunkCreator::getThunk(Symbol &Sym, RelType Type,                                                  uint64_t Src) { -  auto Res = ThunkedSymbols.insert({&Sym, std::vector<Thunk *>()}); -  if (!Res.second) { -    // Check existing Thunks for Sym to see if they can be reused -    for (Thunk *ET : Res.first->second) -      if (ET->isCompatibleWith(Type) && -          Target->inBranchRange(Type, Src, ET->ThunkSym->getVA())) -        return std::make_pair(ET, false); -  } +  std::vector<Thunk *> *ThunkVec = nullptr; +  // We use (section, offset) pair to find the thunk position if possible so +  // that we create only one thunk for aliased symbols or ICFed sections. +  if (auto *D = dyn_cast<Defined>(&Sym)) +    if (!D->isInPlt() && D->Section) +      ThunkVec = &ThunkedSymbolsBySection[{D->Section->Repl, D->Value}]; +  if (!ThunkVec) +    ThunkVec = &ThunkedSymbols[&Sym]; +  // Check existing Thunks for Sym to see if they can be reused +  for (Thunk *ET : *ThunkVec) +    if (ET->isCompatibleWith(Type) && +        Target->inBranchRange(Type, Src, ET->getThunkTargetSym()->getVA())) +      return std::make_pair(ET, false);    // No existing compatible Thunk in range, create a new one    Thunk *T = addThunk(Type, Sym); -  Res.first->second.push_back(T); +  ThunkVec->push_back(T);    return std::make_pair(T, true);  } @@ -1311,7 +1333,7 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(Symbol &Sym, RelType Type,  // InputSectionDescription::Sections.  void ThunkCreator::forEachInputSectionDescription(      ArrayRef<OutputSection *> OutputSections, -    std::function<void(OutputSection *, InputSectionDescription *)> Fn) { +    llvm::function_ref<void(OutputSection *, InputSectionDescription *)> Fn) {    for (OutputSection *OS : OutputSections) {      if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR))        continue; @@ -1379,7 +1401,7 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {        OutputSections, [&](OutputSection *OS, InputSectionDescription *ISD) {          for (InputSection *IS : ISD->Sections)            for (Relocation &Rel : IS->Relocations) { -            uint64_t Src = OS->Addr + IS->OutSecOff + Rel.Offset; +            uint64_t Src = IS->getVA(Rel.Offset);              // If we are a relocation to an existing Thunk, check if it is              // still in range. If not then Rel will be altered to point to its @@ -1394,7 +1416,6 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {              bool IsNew;              std::tie(T, IsNew) = getThunk(*Rel.Sym, Rel.Type, Src);              if (IsNew) { -              AddressesChanged = true;                // Find or create a ThunkSection for the new Thunk                ThunkSection *TS;                if (auto *TIS = T->getTargetInputSection()) @@ -1402,13 +1423,18 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {                else                  TS = getISDThunkSec(OS, IS, ISD, Rel.Type, Src);                TS->addThunk(T); -              Thunks[T->ThunkSym] = T; +              Thunks[T->getThunkTargetSym()] = T;              }              // Redirect relocation to Thunk, we never go via the PLT to a Thunk -            Rel.Sym = T->ThunkSym; +            Rel.Sym = T->getThunkTargetSym();              Rel.Expr = fromPlt(Rel.Expr);            } +        for (auto &P : ISD->ThunkSections) +          AddressesChanged |= P.first->assignOffsets();        }); +  for (auto &P : ThunkedSections) +    AddressesChanged |= P.second->assignOffsets(); +    // Merge all created synthetic ThunkSections back into OutputSection    mergeThunks(OutputSections);    ++Pass;  | 
