toolchain/binutils: backport stable patches
[openwrt/staging/dedeckeh.git] / toolchain / binutils / patches / 2.39 / 009-PR29462-internal-error-in-relocate-at-powerpc.cc-107.patch
diff --git a/toolchain/binutils/patches/2.39/009-PR29462-internal-error-in-relocate-at-powerpc.cc-107.patch b/toolchain/binutils/patches/2.39/009-PR29462-internal-error-in-relocate-at-powerpc.cc-107.patch
new file mode 100644 (file)
index 0000000..e325d3b
--- /dev/null
@@ -0,0 +1,270 @@
+From e3b5d935247084dca057dea72be61b063fe2357a Mon Sep 17 00:00:00 2001
+From: Alan Modra <amodra@gmail.com>
+Date: Wed, 10 Aug 2022 10:38:52 +0930
+Subject: [PATCH 009/160] PR29462, internal error in relocate, at
+ powerpc.cc:10796
+
+Prior to the inline plt call support (commit 08be322439), the only
+local syms with plt entries were local ifunc symbols.  There shouldn't
+be stubs for other local symbols so don't look for them.  The patch
+also fixes minor bugs in get_reference_flags; Many relocs are valid
+only for ppc64 and a couple only for ppc32.
+
+       PR 29462
+       * powerpc.cc (Target_powerpc::Relocate::relocate): Rename
+       use_plt_offset to pltcal_to_direct, invert logic.  For relocs
+       not used with inline plt sequences against local symbols, only
+       look for stubs when the symbol is an ifunc.
+       (Target_powerpc::Scan::get_reference_flags): Correct reloc
+       handling for relocs not valid for both 32-bit and 64-bit.
+
+(cherry picked from commit 6158b25f77db11712b84e6a4609898f2615ac749)
+---
+ gold/powerpc.cc | 129 ++++++++++++++++++++++++++++--------------------
+ 1 file changed, 75 insertions(+), 54 deletions(-)
+
+--- a/gold/powerpc.cc
++++ b/gold/powerpc.cc
+@@ -7675,22 +7675,18 @@ Target_powerpc<size, big_endian>::Scan::
+   switch (r_type)
+     {
++    case elfcpp::R_PPC64_TOC:
++      if (size != 64)
++      break;
++      // Fall through.
+     case elfcpp::R_POWERPC_NONE:
+     case elfcpp::R_POWERPC_GNU_VTINHERIT:
+     case elfcpp::R_POWERPC_GNU_VTENTRY:
+-    case elfcpp::R_PPC64_TOC:
+       // No symbol reference.
+       break;
+     case elfcpp::R_PPC64_ADDR64:
+     case elfcpp::R_PPC64_UADDR64:
+-    case elfcpp::R_POWERPC_ADDR32:
+-    case elfcpp::R_POWERPC_UADDR32:
+-    case elfcpp::R_POWERPC_ADDR16:
+-    case elfcpp::R_POWERPC_UADDR16:
+-    case elfcpp::R_POWERPC_ADDR16_LO:
+-    case elfcpp::R_POWERPC_ADDR16_HI:
+-    case elfcpp::R_POWERPC_ADDR16_HA:
+     case elfcpp::R_PPC64_ADDR16_HIGHER34:
+     case elfcpp::R_PPC64_ADDR16_HIGHERA34:
+     case elfcpp::R_PPC64_ADDR16_HIGHEST34:
+@@ -7700,6 +7696,16 @@ Target_powerpc<size, big_endian>::Scan::
+     case elfcpp::R_PPC64_D34_HI30:
+     case elfcpp::R_PPC64_D34_HA30:
+     case elfcpp::R_PPC64_D28:
++      if (size != 64)
++      break;
++      // Fall through.
++    case elfcpp::R_POWERPC_ADDR32:
++    case elfcpp::R_POWERPC_UADDR32:
++    case elfcpp::R_POWERPC_ADDR16:
++    case elfcpp::R_POWERPC_UADDR16:
++    case elfcpp::R_POWERPC_ADDR16_LO:
++    case elfcpp::R_POWERPC_ADDR16_HI:
++    case elfcpp::R_POWERPC_ADDR16_HA:
+       ref = Symbol::ABSOLUTE_REF;
+       break;
+@@ -7710,13 +7716,14 @@ Target_powerpc<size, big_endian>::Scan::
+       ref = Symbol::FUNCTION_CALL | Symbol::ABSOLUTE_REF;
+       break;
+-    case elfcpp::R_PPC64_REL64:
+-    case elfcpp::R_POWERPC_REL32:
+     case elfcpp::R_PPC_LOCAL24PC:
+-    case elfcpp::R_POWERPC_REL16:
+-    case elfcpp::R_POWERPC_REL16_LO:
+-    case elfcpp::R_POWERPC_REL16_HI:
+-    case elfcpp::R_POWERPC_REL16_HA:
++      if (size != 32)
++      break;
++      // Fall through.
++      ref = Symbol::RELATIVE_REF;
++      break;
++
++    case elfcpp::R_PPC64_REL64:
+     case elfcpp::R_PPC64_REL16_HIGH:
+     case elfcpp::R_PPC64_REL16_HIGHA:
+     case elfcpp::R_PPC64_REL16_HIGHER:
+@@ -7729,36 +7736,45 @@ Target_powerpc<size, big_endian>::Scan::
+     case elfcpp::R_PPC64_REL16_HIGHEST34:
+     case elfcpp::R_PPC64_REL16_HIGHESTA34:
+     case elfcpp::R_PPC64_PCREL28:
++      if (size != 64)
++      break;
++      // Fall through.
++    case elfcpp::R_POWERPC_REL32:
++    case elfcpp::R_POWERPC_REL16:
++    case elfcpp::R_POWERPC_REL16_LO:
++    case elfcpp::R_POWERPC_REL16_HI:
++    case elfcpp::R_POWERPC_REL16_HA:
+       ref = Symbol::RELATIVE_REF;
+       break;
++    case elfcpp::R_PPC_PLTREL24:
++      if (size != 32)
++      break;
++      ref = Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF;
++      break;
++
+     case elfcpp::R_PPC64_REL24_NOTOC:
+-      if (size == 32)
++    case elfcpp::R_PPC64_REL24_P9NOTOC:
++    case elfcpp::R_PPC64_PLT16_LO_DS:
++    case elfcpp::R_PPC64_PLTSEQ_NOTOC:
++    case elfcpp::R_PPC64_PLTCALL_NOTOC:
++    case elfcpp::R_PPC64_PLT_PCREL34:
++    case elfcpp::R_PPC64_PLT_PCREL34_NOTOC:
++      if (size != 64)
+       break;
+       // Fall through.
+-    case elfcpp::R_PPC64_REL24_P9NOTOC:
+     case elfcpp::R_POWERPC_REL24:
+-    case elfcpp::R_PPC_PLTREL24:
+     case elfcpp::R_POWERPC_REL14:
+     case elfcpp::R_POWERPC_REL14_BRTAKEN:
+     case elfcpp::R_POWERPC_REL14_BRNTAKEN:
+     case elfcpp::R_POWERPC_PLT16_LO:
+     case elfcpp::R_POWERPC_PLT16_HI:
+     case elfcpp::R_POWERPC_PLT16_HA:
+-    case elfcpp::R_PPC64_PLT16_LO_DS:
+     case elfcpp::R_POWERPC_PLTSEQ:
+-    case elfcpp::R_PPC64_PLTSEQ_NOTOC:
+     case elfcpp::R_POWERPC_PLTCALL:
+-    case elfcpp::R_PPC64_PLTCALL_NOTOC:
+-    case elfcpp::R_PPC64_PLT_PCREL34:
+-    case elfcpp::R_PPC64_PLT_PCREL34_NOTOC:
+       ref = Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF;
+       break;
+-    case elfcpp::R_POWERPC_GOT16:
+-    case elfcpp::R_POWERPC_GOT16_LO:
+-    case elfcpp::R_POWERPC_GOT16_HI:
+-    case elfcpp::R_POWERPC_GOT16_HA:
+     case elfcpp::R_PPC64_GOT16_DS:
+     case elfcpp::R_PPC64_GOT16_LO_DS:
+     case elfcpp::R_PPC64_GOT_PCREL34:
+@@ -7768,11 +7784,16 @@ Target_powerpc<size, big_endian>::Scan::
+     case elfcpp::R_PPC64_TOC16_HA:
+     case elfcpp::R_PPC64_TOC16_DS:
+     case elfcpp::R_PPC64_TOC16_LO_DS:
++      if (size != 64)
++      break;
++      // Fall through.
++    case elfcpp::R_POWERPC_GOT16:
++    case elfcpp::R_POWERPC_GOT16_LO:
++    case elfcpp::R_POWERPC_GOT16_HI:
++    case elfcpp::R_POWERPC_GOT16_HA:
+       ref = Symbol::RELATIVE_REF;
+       break;
+-    case elfcpp::R_POWERPC_GOT_TPREL16:
+-    case elfcpp::R_POWERPC_TLS:
+     case elfcpp::R_PPC64_TLSGD:
+     case elfcpp::R_PPC64_TLSLD:
+     case elfcpp::R_PPC64_TPREL34:
+@@ -7781,6 +7802,11 @@ Target_powerpc<size, big_endian>::Scan::
+     case elfcpp::R_PPC64_GOT_TLSLD_PCREL34:
+     case elfcpp::R_PPC64_GOT_TPREL_PCREL34:
+     case elfcpp::R_PPC64_GOT_DTPREL_PCREL34:
++      if (size != 64)
++      break;
++      // Fall through.
++    case elfcpp::R_POWERPC_GOT_TPREL16:
++    case elfcpp::R_POWERPC_TLS:
+       ref = Symbol::TLS_REF;
+       break;
+@@ -10671,10 +10697,8 @@ Target_powerpc<size, big_endian>::Reloca
+   bool has_stub_value = false;
+   bool localentry0 = false;
+   unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+-  bool use_plt_offset
+-    = (gsym != NULL
+-       ? gsym->use_plt_offset(Scan::get_reference_flags(r_type, target))
+-       : object->local_has_plt_offset(r_sym));
++  bool pltcall_to_direct = false;
++
+   if (is_plt16_reloc<size>(r_type)
+       || r_type == elfcpp::R_PPC64_PLT_PCREL34
+       || r_type == elfcpp::R_PPC64_PLT_PCREL34_NOTOC
+@@ -10688,21 +10712,18 @@ Target_powerpc<size, big_endian>::Reloca
+       // that the decision depends on the PLTCALL reloc, and we don't
+       // know the address of that instruction when processing others
+       // in the sequence.  So the decision needs to be made in
+-      // do_relax().  For now, don't optimise inline plt calls.
+-      if (gsym)
+-      use_plt_offset = gsym->has_plt_offset();
+-    }
+-  if (use_plt_offset
+-      && !is_got_reloc(r_type)
+-      && !is_plt16_reloc<size>(r_type)
+-      && r_type != elfcpp::R_PPC64_PLT_PCREL34
+-      && r_type != elfcpp::R_PPC64_PLT_PCREL34_NOTOC
+-      && r_type != elfcpp::R_POWERPC_PLTSEQ
+-      && r_type != elfcpp::R_POWERPC_PLTCALL
+-      && r_type != elfcpp::R_PPC64_PLTSEQ_NOTOC
+-      && r_type != elfcpp::R_PPC64_PLTCALL_NOTOC
+-      && (!psymval->is_ifunc_symbol()
+-        || Scan::reloc_needs_plt_for_ifunc(target, object, r_type, false)))
++      // do_relax().
++      pltcall_to_direct = !(gsym != NULL
++                          ? gsym->has_plt_offset()
++                          : object->local_has_plt_offset(r_sym));
++    }
++  else if ((gsym != NULL
++          ? gsym->use_plt_offset(Scan::get_reference_flags(r_type, target))
++          : psymval->is_ifunc_symbol() && object->local_has_plt_offset(r_sym))
++         && !is_got_reloc(r_type)
++         && (!psymval->is_ifunc_symbol()
++             || Scan::reloc_needs_plt_for_ifunc(target, object, r_type,
++                                                false)))
+     {
+       if (size == 64
+         && gsym != NULL
+@@ -10796,9 +10817,9 @@ Target_powerpc<size, big_endian>::Reloca
+       gold_assert(has_stub_value || !(os->flags() & elfcpp::SHF_ALLOC));
+     }
+-  if (use_plt_offset && (is_plt16_reloc<size>(r_type)
+-                       || r_type == elfcpp::R_PPC64_PLT_PCREL34
+-                       || r_type == elfcpp::R_PPC64_PLT_PCREL34_NOTOC))
++  if (!pltcall_to_direct && (is_plt16_reloc<size>(r_type)
++                           || r_type == elfcpp::R_PPC64_PLT_PCREL34
++                           || r_type == elfcpp::R_PPC64_PLT_PCREL34_NOTOC))
+     {
+       const Output_data_plt_powerpc<size, big_endian>* plt;
+       if (gsym)
+@@ -10826,7 +10847,7 @@ Target_powerpc<size, big_endian>::Reloca
+           value -= target->toc_pointer();
+       }
+     }
+-  else if (!use_plt_offset
++  else if (pltcall_to_direct
+          && (is_plt16_reloc<size>(r_type)
+              || r_type == elfcpp::R_POWERPC_PLTSEQ
+              || r_type == elfcpp::R_PPC64_PLTSEQ_NOTOC))
+@@ -10835,7 +10856,7 @@ Target_powerpc<size, big_endian>::Reloca
+       elfcpp::Swap<32, big_endian>::writeval(iview, nop);
+       r_type = elfcpp::R_POWERPC_NONE;
+     }
+-  else if (!use_plt_offset
++  else if (pltcall_to_direct
+          && (r_type == elfcpp::R_PPC64_PLT_PCREL34
+              || r_type == elfcpp::R_PPC64_PLT_PCREL34_NOTOC))
+     {
+@@ -11316,8 +11337,8 @@ Target_powerpc<size, big_endian>::Reloca
+     }
+   else if (!has_stub_value)
+     {
+-      if (!use_plt_offset && (r_type == elfcpp::R_POWERPC_PLTCALL
+-                            || r_type == elfcpp::R_PPC64_PLTCALL_NOTOC))
++      if (pltcall_to_direct && (r_type == elfcpp::R_POWERPC_PLTCALL
++                              || r_type == elfcpp::R_PPC64_PLTCALL_NOTOC))
+       {
+         // PLTCALL without plt entry => convert to direct call
+         Insn* iview = reinterpret_cast<Insn*>(view);