+ /* Multi-instruction sequences that access the TOC can be
+ optimized, eg. addis ra,r2,0; addi rb,ra,x;
+ to nop; addi rb,r2,x; */
+ switch (r_type)
+ {
+ default:
+ break;
+
+ case R_PPC64_GOT_TLSLD16_HI:
+ case R_PPC64_GOT_TLSGD16_HI:
+ case R_PPC64_GOT_TPREL16_HI:
+ case R_PPC64_GOT_DTPREL16_HI:
+ case R_PPC64_GOT16_HI:
+ case R_PPC64_TOC16_HI:
+ /* These relocs would only be useful if building up an
+ offset to later add to r2, perhaps in an indexed
+ addressing mode instruction. Don't try to optimize.
+ Unfortunately, the possibility of someone building up an
+ offset like this or even with the HA relocs, means that
+ we need to check the high insn when optimizing the low
+ insn. */
+ break;
+
+ case R_PPC64_GOT_TLSLD16_HA:
+ case R_PPC64_GOT_TLSGD16_HA:
+ case R_PPC64_GOT_TPREL16_HA:
+ case R_PPC64_GOT_DTPREL16_HA:
+ case R_PPC64_GOT16_HA:
+ case R_PPC64_TOC16_HA:
+ /* nop is done later. */
+ break;
+
+ case R_PPC64_GOT_TLSLD16_LO:
+ case R_PPC64_GOT_TLSGD16_LO:
+ case R_PPC64_GOT_TPREL16_LO_DS:
+ case R_PPC64_GOT_DTPREL16_LO_DS:
+ case R_PPC64_GOT16_LO:
+ case R_PPC64_GOT16_LO_DS:
+ case R_PPC64_TOC16_LO:
+ case R_PPC64_TOC16_LO_DS:
+ if (htab->do_toc_opt && relocation + addend + 0x8000 < 0x10000)
+ {
+ bfd_byte *p = contents + (rel->r_offset & ~3);
+ insn = bfd_get_32 (input_bfd, p);
+ if ((insn & (0x3f << 26)) == 14u << 26 /* addi */
+ || (insn & (0x3f << 26)) == 32u << 26 /* lwz */
+ || (insn & (0x3f << 26)) == 34u << 26 /* lbz */
+ || (insn & (0x3f << 26)) == 36u << 26 /* stw */
+ || (insn & (0x3f << 26)) == 38u << 26 /* stb */
+ || (insn & (0x3f << 26)) == 40u << 26 /* lhz */
+ || (insn & (0x3f << 26)) == 42u << 26 /* lha */
+ || (insn & (0x3f << 26)) == 44u << 26 /* sth */
+ || (insn & (0x3f << 26)) == 46u << 26 /* lmw */
+ || (insn & (0x3f << 26)) == 47u << 26 /* stmw */
+ || (insn & (0x3f << 26)) == 48u << 26 /* lfs */
+ || (insn & (0x3f << 26)) == 50u << 26 /* lfd */
+ || (insn & (0x3f << 26)) == 52u << 26 /* stfs */
+ || (insn & (0x3f << 26)) == 54u << 26 /* stfd */
+ || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */
+ && (insn & 3) != 1)
+ || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */
+ && ((insn & 3) == 0 || (insn & 3) == 3)))
+ {
+ unsigned int reg = (insn >> 16) & 0x1f;
+ const Elf_Internal_Rela *ha;
+ bfd_boolean match_addend;
+
+ match_addend = (sym != NULL
+ && ELF_ST_TYPE (sym->st_info) == STT_SECTION);
+ ha = ha_reloc_match (relocs, rel, ®, match_addend,
+ input_bfd, contents);
+ if (ha != NULL)
+ {
+ insn &= ~(0x1f << 16);
+ insn |= reg << 16;
+ bfd_put_32 (input_bfd, insn, p);
+ if (ha_opt == NULL)
+ {
+ ha_opt = bfd_zmalloc (input_section->reloc_count);
+ if (ha_opt == NULL)
+ return FALSE;
+ }
+ ha_opt[ha - relocs] = 1;
+ }
+ else
+ /* If we don't find a matching high part insn,
+ something is fishy. Refuse to nop any high
+ part insn in this section. */
+ no_ha_opt = TRUE;
+ }
+ }
+ break;
+ }
+