From daa67607072dd28275d2a54d6fba1623094905e8 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Fri, 31 Aug 2012 20:41:41 +0000 Subject: [PATCH] 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/ChangeLog | 14 +++ bfd/elf32-i386.c | 165 ++++++++++++++++++++++++++++++---- bfd/elf64-x86-64.c | 163 +++++++++++++++++++++++++++++---- ld/testsuite/ChangeLog | 18 ++++ ld/testsuite/ld-i386/i386.exp | 3 + ld/testsuite/ld-i386/lea1d.d | 9 ++ ld/testsuite/ld-i386/lea1e.d | 9 ++ ld/testsuite/ld-i386/lea1f.d | 9 ++ ld/testsuite/ld-ifunc/ifunc-13-i386.d | 4 - ld/testsuite/ld-x86-64/lea1g.d | 9 ++ ld/testsuite/ld-x86-64/lea1h.d | 9 ++ ld/testsuite/ld-x86-64/lea1i.d | 9 ++ ld/testsuite/ld-x86-64/lea1j.d | 9 ++ ld/testsuite/ld-x86-64/lea1k.d | 9 ++ ld/testsuite/ld-x86-64/lea1l.d | 9 ++ ld/testsuite/ld-x86-64/x86-64.exp | 6 ++ 16 files changed, 416 insertions(+), 38 deletions(-) create mode 100644 ld/testsuite/ld-i386/lea1d.d create mode 100644 ld/testsuite/ld-i386/lea1e.d create mode 100644 ld/testsuite/ld-i386/lea1f.d create mode 100644 ld/testsuite/ld-x86-64/lea1g.d create mode 100644 ld/testsuite/ld-x86-64/lea1h.d create mode 100644 ld/testsuite/ld-x86-64/lea1i.d create mode 100644 ld/testsuite/ld-x86-64/lea1j.d create mode 100644 ld/testsuite/ld-x86-64/lea1k.d create mode 100644 ld/testsuite/ld-x86-64/lea1l.d diff --git a/bfd/ChangeLog b/bfd/ChangeLog index c6f424a..71933e6 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,17 @@ +2012-08-31 H.J. Lu + + * 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(%rip), %reg" + for local symbols here. + 2012-08-30 H.J. Lu * elf32-i386.c (elf_i386_relocate_section): Convert diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index e67879f..c9bc694 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 diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index cc40404..0c37cd3 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -2572,6 +2572,150 @@ elf_x86_64_readonly_dynrelocs (struct elf_link_hash_entry *h, return TRUE; } +/* Convert + mov foo@GOTPCREL(%rip), %reg + to + lea foo(%rip), %reg + with the local symbol, foo. */ + +static bfd_boolean +elf_x86_64_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_x86_64_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_x86_64_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 = htab->r_sym (irel->r_info); + unsigned int indx; + struct elf_link_hash_entry *h; + + if (r_type != R_X86_64_GOTPCREL) + 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_X86_64_GOTPCREL 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 = htab->r_info (r_symndx, R_X86_64_PC32); + 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_X86_64_GOTPCREL 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 = htab->r_info (r_symndx, R_X86_64_PC32); + 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 @@ -2626,6 +2770,9 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, { struct elf_dyn_relocs *p; + if (!elf_x86_64_convert_mov_to_lea (ibfd, s, info)) + return FALSE; + for (p = (struct elf_dyn_relocs *) (elf_section_data (s)->local_dynrel); p != NULL; @@ -3460,22 +3607,6 @@ elf_x86_64_relocate_section (bfd *output_bfd, if (off >= (bfd_vma) -2) abort (); - if (r_type == R_X86_64_GOTPCREL - && h->def_regular - && SYMBOL_REFERENCES_LOCAL (info, h) - && bfd_get_8 (input_bfd, - contents + rel->r_offset - 2) == 0x8b) - { - /* Convert - mov foo@GOTPCREL(%rip), %reg - to - lea foo(%rip), %reg - */ - bfd_put_8 (output_bfd, 0x8d, - contents + rel->r_offset - 2); - break; - } - relocation = base_got->output_section->vma + base_got->output_offset + off; if (r_type != R_X86_64_GOTPCREL && r_type != R_X86_64_GOTPCREL64) diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index bab65e4..35740cc 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,21 @@ +2012-08-31 H.J. Lu + + * 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. + 2012-08-30 H.J. Lu * ld-i386/i386.exp: Run lea1a, lea1b, lea1c. diff --git a/ld/testsuite/ld-i386/i386.exp b/ld/testsuite/ld-i386/i386.exp index b7e8042..adb852e 100644 --- a/ld/testsuite/ld-i386/i386.exp +++ b/ld/testsuite/ld-i386/i386.exp @@ -236,6 +236,9 @@ run_dump_test "pr12570b" run_dump_test "lea1a" run_dump_test "lea1b" run_dump_test "lea1c" +run_dump_test "lea1d" +run_dump_test "lea1e" +run_dump_test "lea1f" if { !([istarget "i?86-*-linux*"] || [istarget "i?86-*-gnu*"] diff --git a/ld/testsuite/ld-i386/lea1d.d b/ld/testsuite/ld-i386/lea1d.d new file mode 100644 index 0000000..7deab26 --- /dev/null +++ b/ld/testsuite/ld-i386/lea1d.d @@ -0,0 +1,9 @@ +#source: lea1.s +#as: --32 +#ld: -Bsymbolic -shared -melf_i386 +#readelf: -Sw + +#failif +#... +[ ]*\[.*\][ ]+.*\.got .* +#... diff --git a/ld/testsuite/ld-i386/lea1e.d b/ld/testsuite/ld-i386/lea1e.d new file mode 100644 index 0000000..ae66958 --- /dev/null +++ b/ld/testsuite/ld-i386/lea1e.d @@ -0,0 +1,9 @@ +#source: lea1.s +#as: --32 +#ld: -pie -melf_i386 +#readelf: -Sw + +#failif +#... +[ ]*\[.*\][ ]+.*\.got .* +#... diff --git a/ld/testsuite/ld-i386/lea1f.d b/ld/testsuite/ld-i386/lea1f.d new file mode 100644 index 0000000..3c16996 --- /dev/null +++ b/ld/testsuite/ld-i386/lea1f.d @@ -0,0 +1,9 @@ +#source: lea1.s +#as: --32 +#ld: -melf_i386 +#readelf: -Sw + +#failif +#... +[ ]*\[.*\][ ]+.*\.got .* +#... diff --git a/ld/testsuite/ld-ifunc/ifunc-13-i386.d b/ld/testsuite/ld-ifunc/ifunc-13-i386.d index 55cca22..746945b 100644 --- a/ld/testsuite/ld-ifunc/ifunc-13-i386.d +++ b/ld/testsuite/ld-ifunc/ifunc-13-i386.d @@ -5,10 +5,6 @@ #readelf: -r --wide #target: x86_64-*-* i?86-*-* -Relocation section '.rel.got' at offset 0x[0-9a-f]+ contains 1 entries: -[ ]+Offset[ ]+Info[ ]+Type[ ]+.* -[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_386_RELATIVE[ ]+ - Relocation section '.rel.ifunc' at offset 0x[0-9a-f]+ contains 1 entries: [ ]+Offset[ ]+Info[ ]+Type[ ]+.* [0-9a-f]+[ ]+[0-9a-f]+[ ]+R_386_32[ ]+ifunc\(\)[ ]+ifunc diff --git a/ld/testsuite/ld-x86-64/lea1g.d b/ld/testsuite/ld-x86-64/lea1g.d new file mode 100644 index 0000000..df0abd8 --- /dev/null +++ b/ld/testsuite/ld-x86-64/lea1g.d @@ -0,0 +1,9 @@ +#source: lea1.s +#as: --64 +#ld: -Bsymbolic -shared -melf_x86_64 +#readelf: -Sw + +#failif +#... +[ ]*\[.*\][ ]+.*\.got .* +#... diff --git a/ld/testsuite/ld-x86-64/lea1h.d b/ld/testsuite/ld-x86-64/lea1h.d new file mode 100644 index 0000000..3c9860b --- /dev/null +++ b/ld/testsuite/ld-x86-64/lea1h.d @@ -0,0 +1,9 @@ +#source: lea1.s +#as: --64 +#ld: -pie -melf_x86_64 +#readelf: -Sw + +#failif +#... +[ ]*\[.*\][ ]+.*\.got .* +#... diff --git a/ld/testsuite/ld-x86-64/lea1i.d b/ld/testsuite/ld-x86-64/lea1i.d new file mode 100644 index 0000000..9a91a10 --- /dev/null +++ b/ld/testsuite/ld-x86-64/lea1i.d @@ -0,0 +1,9 @@ +#source: lea1.s +#as: --64 +#ld: -melf_x86_64 +#readelf: -Sw + +#failif +#... +[ ]*\[.*\][ ]+.*\.got .* +#... diff --git a/ld/testsuite/ld-x86-64/lea1j.d b/ld/testsuite/ld-x86-64/lea1j.d new file mode 100644 index 0000000..a8cfc19 --- /dev/null +++ b/ld/testsuite/ld-x86-64/lea1j.d @@ -0,0 +1,9 @@ +#source: lea1.s +#as: --x32 +#ld: -Bsymbolic -shared -melf32_x86_64 +#readelf: -Sw + +#failif +#... +[ ]*\[.*\][ ]+.*\.got .* +#... diff --git a/ld/testsuite/ld-x86-64/lea1k.d b/ld/testsuite/ld-x86-64/lea1k.d new file mode 100644 index 0000000..bb02506 --- /dev/null +++ b/ld/testsuite/ld-x86-64/lea1k.d @@ -0,0 +1,9 @@ +#source: lea1.s +#as: --x32 +#ld: -pie -melf32_x86_64 +#readelf: -Sw + +#failif +#... +[ ]*\[.*\][ ]+.*\.got .* +#... diff --git a/ld/testsuite/ld-x86-64/lea1l.d b/ld/testsuite/ld-x86-64/lea1l.d new file mode 100644 index 0000000..1df2bc1 --- /dev/null +++ b/ld/testsuite/ld-x86-64/lea1l.d @@ -0,0 +1,9 @@ +#source: lea1.s +#as: --x32 +#ld: -melf32_x86_64 +#readelf: -Sw + +#failif +#... +[ ]*\[.*\][ ]+.*\.got .* +#... diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp index 1db81c8..7eabf39 100644 --- a/ld/testsuite/ld-x86-64/x86-64.exp +++ b/ld/testsuite/ld-x86-64/x86-64.exp @@ -282,6 +282,12 @@ run_dump_test "lea1c" run_dump_test "lea1d" run_dump_test "lea1e" run_dump_test "lea1f" +run_dump_test "lea1g" +run_dump_test "lea1h" +run_dump_test "lea1i" +run_dump_test "lea1j" +run_dump_test "lea1k" +run_dump_test "lea1l" # Must be native with the C compiler if { [isnative] && [which $CC] != 0 } { -- 2.7.4