From 1574fd51a5280b4a29d12c75a3bb41a94f67c406 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Fri, 31 Aug 2012 20:41:40 +0000 Subject: Convert mov to lea in size_dynamic_sections bfd/ * elf32-i386.c (elf_i386_convert_mov_to_lea): New. (elf_i386_size_dynamic_sections): Use it on input sections. (elf_i386_relocate_section): Don't convert "mov foo@GOT(%reg), %reg" to "lea foo@GOTOFF(%reg), %reg" for local symbols here. * elf64-x86-64.c (elf_x86_64_convert_mov_to_lea): New. (elf_x86_64_size_dynamic_sections): Use it on input sections. (elf_x86_64_relocate_section): Don't convert "mov foo@GOTPCREL(%rip), %reg" to "lea foo@GOTOFF(%reg), %reg" for local symbols. ld/testsuite/ * ld-i386/i386.exp: Run lea1d, lea1f, lea1f. * ld-x86-64/x86-64.exp: Run lea1g, lea1h, lea1i, lea1j, lea1k, lea1l. * ld-ifunc/ifunc-13-i386.d: Remove R_386_RELATIVE entry. * ld-i386/lea1d.d: New file. * ld-i386/lea1e.d: Likewise. * ld-i386/lea1f.d: Likewise. * ld-x86-64/lea1g.d: Likewise. * ld-x86-64/lea1h.d: Likewise. * ld-x86-64/lea1i.d: Likewise. * ld-x86-64/lea1j.d: Likewise. * ld-x86-64/lea1k.d: Likewise. * ld-x86-64/lea1l.d: Likewise. --- bfd/elf32-i386.c | 165 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 147 insertions(+), 18 deletions(-) (limited to 'bfd/elf32-i386.c') diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index e67879f133..c9bc6944c4 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -2536,6 +2536,150 @@ elf_i386_readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf) return TRUE; } +/* Convert + mov foo@GOT(%reg), %reg + to + lea foo@GOTOFF(%reg), %reg + with the local symbol, foo. */ + +static bfd_boolean +elf_i386_convert_mov_to_lea (bfd *abfd, asection *sec, + struct bfd_link_info *link_info) +{ + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Rela *internal_relocs; + Elf_Internal_Rela *irel, *irelend; + bfd_byte *contents; + struct elf_i386_link_hash_table *htab; + bfd_boolean changed_contents; + bfd_boolean changed_relocs; + bfd_signed_vma *local_got_refcounts; + + /* Don't even try to convert non-ELF outputs. */ + if (!is_elf_hash_table (link_info->hash)) + return FALSE; + + /* Nothing to do if there are no codes or no relocations. */ + if ((sec->flags & (SEC_CODE | SEC_RELOC)) != (SEC_CODE | SEC_RELOC) + || sec->reloc_count == 0) + return TRUE; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + + /* Load the relocations for this section. */ + internal_relocs = (_bfd_elf_link_read_relocs + (abfd, sec, NULL, (Elf_Internal_Rela *) NULL, + link_info->keep_memory)); + if (internal_relocs == NULL) + return FALSE; + + htab = elf_i386_hash_table (link_info); + changed_contents = FALSE; + changed_relocs = FALSE; + local_got_refcounts = elf_local_got_refcounts (abfd); + + /* 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)) + goto error_return; + } + + irelend = internal_relocs + sec->reloc_count; + for (irel = internal_relocs; irel < irelend; irel++) + { + unsigned int r_type = ELF32_R_TYPE (irel->r_info); + unsigned int r_symndx = ELF32_R_SYM (irel->r_info); + unsigned int indx; + struct elf_link_hash_entry *h; + + if (r_type != R_386_GOT32) + continue; + + /* Get the symbol referred to by the reloc. */ + if (r_symndx < symtab_hdr->sh_info) + { + Elf_Internal_Sym *isym; + + isym = bfd_sym_from_r_symndx (&htab->sym_cache, + abfd, r_symndx); + + /* STT_GNU_IFUNC must keep R_386_GOT32 relocation. */ + if (ELF_ST_TYPE (isym->st_info) != STT_GNU_IFUNC + && bfd_get_8 (input_bfd, + contents + irel->r_offset - 2) == 0x8b) + { + bfd_put_8 (output_bfd, 0x8d, + contents + irel->r_offset - 2); + irel->r_info = ELF32_R_INFO (r_symndx, R_386_GOTOFF); + if (local_got_refcounts != NULL + && local_got_refcounts[r_symndx] > 0) + local_got_refcounts[r_symndx] -= 1; + changed_contents = TRUE; + changed_relocs = TRUE; + } + continue; + } + + indx = r_symndx - symtab_hdr->sh_info; + h = elf_sym_hashes (abfd)[indx]; + BFD_ASSERT (h != NULL); + + 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; + + /* STT_GNU_IFUNC must keep R_386_GOT32 relocation. */ + if (h->def_regular + && h->type != STT_GNU_IFUNC + && SYMBOL_REFERENCES_LOCAL (link_info, h) + && bfd_get_8 (input_bfd, + contents + irel->r_offset - 2) == 0x8b) + { + bfd_put_8 (output_bfd, 0x8d, + contents + irel->r_offset - 2); + irel->r_info = ELF32_R_INFO (r_symndx, R_386_GOTOFF); + if (h->got.refcount > 0) + h->got.refcount -= 1; + changed_contents = TRUE; + changed_relocs = TRUE; + } + } + + if (contents != NULL + && elf_section_data (sec)->this_hdr.contents != contents) + { + if (!changed_contents && !link_info->keep_memory) + free (contents); + else + { + /* Cache the section contents for elf_link_input_bfd. */ + elf_section_data (sec)->this_hdr.contents = contents; + } + } + + if (elf_section_data (sec)->relocs != internal_relocs) + { + if (!changed_relocs) + free (internal_relocs); + else + elf_section_data (sec)->relocs = internal_relocs; + } + + return TRUE; + + error_return: + if (contents != NULL + && elf_section_data (sec)->this_hdr.contents != contents) + free (contents); + if (internal_relocs != NULL + && elf_section_data (sec)->relocs != internal_relocs) + free (internal_relocs); + return FALSE; +} + /* Set the sizes of the dynamic sections. */ static bfd_boolean @@ -2586,6 +2730,9 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) { struct elf_dyn_relocs *p; + if (!elf_i386_convert_mov_to_lea (ibfd, s, info)) + return FALSE; + for (p = ((struct elf_dyn_relocs *) elf_section_data (s)->local_dynrel); p != NULL; @@ -3470,24 +3617,6 @@ elf_i386_relocate_section (bfd *output_bfd, if (off >= (bfd_vma) -2) abort (); - if (h != NULL - && h->def_regular - && SYMBOL_REFERENCES_LOCAL (info, h) - && bfd_get_8 (input_bfd, - contents + rel->r_offset - 2) == 0x8b) - { - /* Convert - mov foo@GOT(%reg), %reg - to - lea foo@GOTOFF(%reg), %reg - */ - bfd_put_8 (output_bfd, 0x8d, - contents + rel->r_offset - 2); - relocation -= (htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset); - break; - } - relocation = htab->elf.sgot->output_section->vma + htab->elf.sgot->output_offset + off - htab->elf.sgotplt->output_section->vma -- cgit v1.2.1