+ if (opcode == 0x8b)
+ {
+ if (to_reloc_pc32)
+ {
+ /* Convert "mov foo@GOTPCREL(%rip), %reg" to
+ "lea foo(%rip), %reg". */
+ opcode = 0x8d;
+ r_type = R_X86_64_PC32;
+ }
+ else
+ {
+ /* Convert "mov foo@GOTPCREL(%rip), %reg" to
+ "mov $foo, %reg". */
+ opcode = 0xc7;
+ modrm = bfd_get_8 (abfd, contents + roff - 1);
+ modrm = 0xc0 | (modrm & 0x38) >> 3;
+ if ((rex & REX_W) != 0
+ && ABI_64_P (link_info->output_bfd))
+ {
+ /* Keep the REX_W bit in REX byte for LP64. */
+ r_type = R_X86_64_32S;
+ goto rewrite_modrm_rex;
+ }
+ else
+ {
+ /* If the REX_W bit in REX byte isn't needed,
+ use R_X86_64_32 and clear the W bit to avoid
+ sign-extend imm32 to imm64. */
+ r_type = R_X86_64_32;
+ /* Clear the W bit in REX byte. */
+ rex_mask |= REX_W;
+ goto rewrite_modrm_rex;
+ }
+ }
+ }
+ else
+ {
+ /* R_X86_64_PC32 isn't supported. */
+ if (to_reloc_pc32)
+ return TRUE;
+
+ modrm = bfd_get_8 (abfd, contents + roff - 1);
+ if (opcode == 0x85)
+ {
+ /* Convert "test %reg, foo@GOTPCREL(%rip)" to
+ "test $foo, %reg". */
+ modrm = 0xc0 | (modrm & 0x38) >> 3;
+ opcode = 0xf7;
+ }
+ else
+ {
+ /* Convert "binop foo@GOTPCREL(%rip), %reg" to
+ "binop $foo, %reg". */
+ modrm = 0xc0 | (modrm & 0x38) >> 3 | (opcode & 0x3c);
+ opcode = 0x81;
+ }
+
+ /* Use R_X86_64_32 with 32-bit operand to avoid relocation
+ overflow when sign-extending imm32 to imm64. */
+ r_type = (rex & REX_W) != 0 ? R_X86_64_32S : R_X86_64_32;
+
+rewrite_modrm_rex:
+ bfd_put_8 (abfd, modrm, contents + roff - 1);
+
+ if (rex)
+ {
+ /* Move the R bit to the B bit in REX byte. */
+ rex = (rex & ~rex_mask) | (rex & REX_R) >> 2;
+ bfd_put_8 (abfd, rex, contents + roff - 3);
+ }
+
+ /* No addend for R_X86_64_32/R_X86_64_32S relocations. */
+ irel->r_addend = 0;
+ }
+
+ bfd_put_8 (abfd, opcode, contents + roff - 2);
+ }
+
+ irel->r_info = htab->r_info (r_symndx, r_type);
+
+ *converted = TRUE;
+
+ return TRUE;
+}
+
+/* Look through the relocs for a section during the first phase, and
+ calculate needed space in the global offset table, procedure
+ linkage table, and dynamic reloc sections. */
+
+static bfd_boolean
+elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
+ asection *sec,
+ const Elf_Internal_Rela *relocs)
+{
+ struct elf_x86_64_link_hash_table *htab;
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes;
+ const Elf_Internal_Rela *rel;
+ const Elf_Internal_Rela *rel_end;
+ asection *sreloc;
+ bfd_byte *contents;
+ bfd_boolean use_plt_got;
+
+ if (bfd_link_relocatable (info))
+ return TRUE;
+
+ /* Don't do anything special with non-loaded, non-alloced sections.
+ In particular, any relocs in such sections should not affect GOT
+ and PLT reference counting (ie. we don't allow them to create GOT
+ or PLT entries), there's no possibility or desire to optimize TLS
+ relocs, and there's not much point in propagating relocs to shared
+ libs that the dynamic linker won't relocate. */
+ if ((sec->flags & SEC_ALLOC) == 0)
+ return TRUE;
+
+ BFD_ASSERT (is_x86_64_elf (abfd));
+
+ htab = elf_x86_64_hash_table (info);
+ if (htab == NULL)
+ {
+ sec->check_relocs_failed = 1;
+ return FALSE;
+ }
+
+ /* Get the section contents. */
+ if (elf_section_data (sec)->this_hdr.contents != NULL)
+ contents = elf_section_data (sec)->this_hdr.contents;
+ else if (!bfd_malloc_and_get_section (abfd, sec, &contents))
+ {
+ sec->check_relocs_failed = 1;
+ return FALSE;
+ }
+
+ use_plt_got = get_elf_x86_64_backend_data (abfd) == &elf_x86_64_arch_bed;
+
+ symtab_hdr = &elf_symtab_hdr (abfd);
+ sym_hashes = elf_sym_hashes (abfd);
+
+ sreloc = NULL;
+
+ rel_end = relocs + sec->reloc_count;
+ for (rel = relocs; rel < rel_end; rel++)
+ {
+ unsigned int r_type;
+ unsigned long r_symndx;
+ struct elf_link_hash_entry *h;
+ struct elf_x86_64_link_hash_entry *eh;
+ Elf_Internal_Sym *isym;
+ const char *name;
+ bfd_boolean size_reloc;
+
+ r_symndx = htab->r_sym (rel->r_info);
+ r_type = ELF32_R_TYPE (rel->r_info);
+
+ if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
+ {
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%B: bad symbol index: %d"),
+ abfd, r_symndx);
+ goto error_return;
+ }
+
+ if (r_symndx < symtab_hdr->sh_info)
+ {
+ /* A local symbol. */
+ isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+ abfd, r_symndx);
+ if (isym == NULL)
+ goto error_return;
+
+ /* Check relocation against local STT_GNU_IFUNC symbol. */
+ if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
+ {
+ h = elf_x86_64_get_local_sym_hash (htab, abfd, rel,
+ TRUE);
+ if (h == NULL)
+ goto error_return;
+
+ /* Fake a STT_GNU_IFUNC symbol. */
+ h->type = STT_GNU_IFUNC;
+ h->def_regular = 1;
+ h->ref_regular = 1;
+ h->forced_local = 1;
+ h->root.type = bfd_link_hash_defined;
+ }
+ else
+ h = NULL;
+ }
+ else
+ {
+ isym = NULL;
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ }
+
+ /* Check invalid x32 relocations. */
+ if (!ABI_64_P (abfd))
+ switch (r_type)
+ {
+ default:
+ break;
+
+ case R_X86_64_DTPOFF64: