diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2016-02-26 09:38:08 -0800 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2016-02-26 09:39:24 -0800 |
commit | bae420ef26f4331415b0503141c5931318025906 (patch) | |
tree | 997f55c531ebd08c7220d5fe523d3df00b709f87 /bfd/elf32-i386.c | |
parent | fc5a9bd57cbb974b8fc3aeb9a15d644cd9103451 (diff) | |
download | gdb-bae420ef26f4331415b0503141c5931318025906.zip gdb-bae420ef26f4331415b0503141c5931318025906.tar.gz gdb-bae420ef26f4331415b0503141c5931318025906.tar.bz2 |
Optimize x86 GOT32X/GOTPCRELX relocations
R_386_GOT32X, R_X86_64_GOTPCRELX and R_X86_64_REX_GOTPCRELX relocations
retrieve the symbol address via its GOT slot. If the symbol address is
known at the link-time, we can use it directly by changing instruction
encoding. Indirect branch can only be converted to PC relative direct
branch. MOV can be changed to LEA or encoded differently with signed
address. The subset of binary operations can be encoded only with
signed address.
If undefined weak symbol is resolved to zero link-time, we can use it
as address. Zero addresss can't used with PC relative direct branch
when PIC is true since the current PC is unknown. In 64-bit, 32-bit
relocation for PC relatiave direct branch to zero may also overflow.
If this optimization causes relocation overflow, --no-relax can be used
to work around it.
bfd/
PR ld/19609
* elf32-i386.c (elf_i386_convert_load): Convert to R_386_32 for
load with locally bound symbols if PIC is false or there is no
base register. Optimize branch to 0 if PIC is false.
(elf_i386_relocate_section): Don't generate dynamic relocations
against undefined weak symbols if PIC is false.
* elf64-x86-64.c (elf_x86_64_convert_load): Disable optimization
if we can't estimate relocation overflow with --no-relax.
Convert to R_X86_64_32S/R_X86_64_32 for load with locally bound
symbols if PIC is false. Optimize branch to 0 if PIC is false.
(elf_x86_64_relocate_section): Don't generate dynamic relocations
against undefined weak symbols if PIC is false.
ld/
PR ld/19609
* testsuite/ld-i386/got1.dd: Updated.
* testsuite/ld-i386/lea1c.d: Likewise.
* testsuite/ld-i386/load1-nacl.d: Likewise.
* testsuite/ld-i386/load1.d: Likewise.
* testsuite/ld-i386/load4b.d: Likewise.
* testsuite/ld-i386/load5b.d: Likewise.
* testsuite/ld-i386/mov1b.d: Likewise.
* testsuite/ld-x86-64/mov1b.d: Likewise.
* testsuite/ld-x86-64/mov1d.d: Likewise.
* testsuite/ld-ifunc/ifunc-21-i386.d: Likewise.
* testsuite/ld-ifunc/ifunc-21-x86-64.d: Likewise.
* testsuite/ld-ifunc/ifunc-22-i386.d: Likewise.
* testsuite/ld-ifunc/ifunc-22-x86-64.d: Likewise.
* testsuite/ld-x86-64/gotpcrel1.dd: Likewise.
* testsuite/ld-x86-64/lea1a.d: Likewise.
* testsuite/ld-x86-64/lea1b.d: Likewise.
* testsuite/ld-x86-64/lea1c.d: Likewise.
* testsuite/ld-x86-64/lea1d.d: Likewise.
* testsuite/ld-x86-64/lea1e.d: Likewise.
* testsuite/ld-x86-64/lea1f.d: Likewise.
* testsuite/ld-x86-64/mov1b.d: Likewise.
* testsuite/ld-x86-64/mov1d.d: Likewise.
* testsuite/ld-x86-64/pr13082-3b.d: Likewise.
* testsuite/ld-x86-64/pr13082-4b.d: Likewise.
* testsuite/ld-x86-64/lea1.s: Add tests for 32-bit registers.
* testsuite/ld-i386/pr19609-1.s: New file.
* testsuite/ld-i386/pr19609-1a.d: Likewise.
* testsuite/ld-i386/pr19609-1b.d: Likewise.
* testsuite/ld-i386/pr19609-1c.d: Likewise.
* testsuite/ld-i386/pr19609-1d.d: Likewise.
* testsuite/ld-i386/pr19609-1e.d: Likewise.
* testsuite/ld-i386/pr19609-1f.d: Likewise.
* testsuite/ld-i386/pr19609-1g.d: Likewise.
* testsuite/ld-i386/pr19609-1h.d: Likewise.
* testsuite/ld-i386/pr19609-1i.d: Likewise.
* testsuite/ld-i386/pr19609-2.s: Likewise.
* testsuite/ld-i386/pr19609-2a.d: Likewise.
* testsuite/ld-i386/pr19609-2b.d: Likewise.
* testsuite/ld-i386/pr19609-2c.d: Likewise.
* testsuite/ld-i386/undefweak.s: Likewise.
* testsuite/ld-i386/undefweaka.d: Likewise.
* testsuite/ld-i386/undefweakb.d: Likewise.
* testsuite/ld-x86-64/pr13082-3c.d: Likewise.
* testsuite/ld-x86-64/pr13082-3d.d: Likewise.
* testsuite/ld-x86-64/pr19609-1.s: Likewise.
* testsuite/ld-x86-64/pr19609-1a.d: Likewise.
* testsuite/ld-x86-64/pr19609-1b.d: Likewise.
* testsuite/ld-x86-64/pr19609-1c.d: Likewise.
* testsuite/ld-x86-64/pr19609-1d.d: Likewise.
* testsuite/ld-x86-64/pr19609-1e.d: Likewise.
* testsuite/ld-x86-64/pr19609-1f.d: Likewise.
* testsuite/ld-x86-64/pr19609-1g.d: Likewise.
* testsuite/ld-x86-64/pr19609-1h.d: Likewise.
* testsuite/ld-x86-64/pr19609-1i.d: Likewise.
* testsuite/ld-x86-64/pr19609-1j.d: Likewise.
* testsuite/ld-x86-64/pr19609-1k.d: Likewise.
* testsuite/ld-x86-64/pr19609-1l.d: Likewise.
* testsuite/ld-x86-64/pr19609-1m.d: Likewise.
* testsuite/ld-x86-64/pr19609-2.s: Likewise.
* testsuite/ld-x86-64/pr19609-2a.d: Likewise.
* testsuite/ld-x86-64/pr19609-2b.d: Likewise.
* testsuite/ld-x86-64/pr19609-2c.d: Likewise.
* testsuite/ld-x86-64/pr19609-2d.d: Likewise.
* testsuite/ld-x86-64/pr19609-3.s: Likewise.
* testsuite/ld-x86-64/pr19609-3a.d: Likewise.
* testsuite/ld-x86-64/pr19609-3b.d: Likewise.
* testsuite/ld-x86-64/pr19609-4.s: Likewise.
* testsuite/ld-x86-64/pr19609-4a.d: Likewise.
* testsuite/ld-x86-64/pr19609-4b.d: Likewise.
* testsuite/ld-x86-64/pr19609-4c.d: Likewise.
* testsuite/ld-x86-64/pr19609-4d.d: Likewise.
* testsuite/ld-x86-64/pr19609-4e.d: Likewise.
* testsuite/ld-x86-64/pr19609-5.s: Likewise.
* testsuite/ld-x86-64/pr19609-5a.d: Likewise.
* testsuite/ld-x86-64/pr19609-5b.d: Likewise.
* testsuite/ld-x86-64/pr19609-5c.d: Likewise.
* testsuite/ld-x86-64/pr19609-5d.d: Likewise.
* testsuite/ld-x86-64/pr19609-5e.d: Likewise.
* testsuite/ld-x86-64/pr19609-6.s: Likewise.
* testsuite/ld-x86-64/pr19609-6a.d: Likewise.
* testsuite/ld-x86-64/pr19609-6b.d: Likewise.
* testsuite/ld-x86-64/pr19609-6c.d: Likewise.
* testsuite/ld-x86-64/pr19609-6d.d: Likewise.
* testsuite/ld-x86-64/pr19609-7.s: Likewise.
* testsuite/ld-x86-64/pr19609-7a.d: Likewise.
* testsuite/ld-x86-64/pr19609-7b.d: Likewise.
* testsuite/ld-x86-64/pr19609-7c.d: Likewise.
* testsuite/ld-x86-64/pr19609-7d.d: Likewise.
* testsuite/ld-i386/i386.exp: Run undefweak tests and tests for
PR ld/19609.
* testsuite/ld-x86-64/x86-64.exp: Run pr13082-3c, pr13082-3d
and tests for PR ld/19609.
Diffstat (limited to 'bfd/elf32-i386.c')
-rw-r--r-- | bfd/elf32-i386.c | 79 |
1 files changed, 51 insertions, 28 deletions
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 2ae5e44..ab3945d 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -2863,6 +2863,7 @@ elf_i386_convert_load (bfd *abfd, asection *sec, struct elf_i386_link_hash_table *htab; bfd_boolean changed_contents; bfd_boolean changed_relocs; + bfd_boolean is_pic; bfd_signed_vma *local_got_refcounts; /* Don't even try to convert non-ELF outputs. */ @@ -2889,6 +2890,8 @@ elf_i386_convert_load (bfd *abfd, asection *sec, changed_relocs = FALSE; local_got_refcounts = elf_local_got_refcounts (abfd); + is_pic = bfd_link_pic (link_info); + /* Get the section contents. */ if (elf_section_data (sec)->this_hdr.contents != NULL) contents = elf_section_data (sec)->this_hdr.contents; @@ -2913,6 +2916,7 @@ elf_i386_convert_load (bfd *abfd, asection *sec, unsigned int addend; unsigned int nop; bfd_vma nop_offset; + bfd_boolean to_reloc_32; if (r_type != R_386_GOT32 && r_type != R_386_GOT32X) continue; @@ -2929,9 +2933,7 @@ elf_i386_convert_load (bfd *abfd, asection *sec, modrm = bfd_get_8 (abfd, contents + roff - 1); baseless = (modrm & 0xc7) == 0x5; - if (r_type == R_386_GOT32X - && baseless - && bfd_link_pic (link_info)) + if (r_type == R_386_GOT32X && baseless && is_pic) { /* For PIC, disallow R_386_GOT32X without a base register since we don't know what the GOT base is. Allow @@ -2960,7 +2962,7 @@ elf_i386_convert_load (bfd *abfd, asection *sec, opcode = bfd_get_8 (abfd, contents + roff - 2); - /* It is OK to convert mov to lea. */ + /* Convert mov to lea since it has been done for a while. */ if (opcode != 0x8b) { /* Only convert R_386_GOT32X relocation for call, jmp or @@ -2968,14 +2970,12 @@ elf_i386_convert_load (bfd *abfd, asection *sec, instructions. */ if (r_type != R_386_GOT32X) continue; - - /* It is OK to convert indirect branch to direct branch. It - is OK to convert adc, add, and, cmp, or, sbb, sub, test, - xor only when PIC is false. */ - if (opcode != 0xff && bfd_link_pic (link_info)) - continue; } + /* Convert to R_386_32 if PIC is false or there is no base + register. */ + to_reloc_32 = !is_pic || baseless; + /* Try to convert R_386_GOT32 and R_386_GOT32X. Get the symbol referred to by the reloc. */ if (r_symndx < symtab_hdr->sh_info) @@ -3010,6 +3010,27 @@ elf_i386_convert_load (bfd *abfd, asection *sec, if (h->type == STT_GNU_IFUNC) continue; + /* Undefined weak symbol is only bound locally in executable + and its reference is resolved as 0. */ + if (UNDEFINED_WEAK_RESOLVED_TO_ZERO (link_info, + elf_i386_hash_entry (h))) + { + if (opcode == 0xff) + { + /* No direct branch to 0 for PIC. */ + if (is_pic) + continue; + else + goto convert_branch; + } + else + { + /* We can convert load of address 0 to R_386_32. */ + to_reloc_32 = TRUE; + goto convert_load; + } + } + if (opcode == 0xff) { /* We have "call/jmp *foo@GOT[(%reg)]". */ @@ -3087,27 +3108,29 @@ convert_branch: convert_load: if (opcode == 0x8b) { - /* Convert "mov foo@GOT(%reg1), %reg2" to - "lea foo@GOTOFF(%reg1), %reg2". */ - if (r_type == R_386_GOT32X - && (baseless || !bfd_link_pic (link_info))) + if (to_reloc_32) { + /* Convert "mov foo@GOT[(%reg1)], %reg2" to + "mov $foo, %reg2" with R_386_32. */ r_type = R_386_32; - /* For R_386_32, convert - "lea foo@GOTOFF(%reg1), %reg2" to - "lea foo@GOT, %reg2". */ - if (!baseless) - { - modrm = 0x5 | (modrm & 0x38); - bfd_put_8 (abfd, modrm, contents + roff - 1); - } + modrm = 0xc0 | (modrm & 0x38) >> 3; + bfd_put_8 (abfd, modrm, contents + roff - 1); + opcode = 0xc7; } else - r_type = R_386_GOTOFF; - opcode = 0x8d; + { + /* Convert "mov foo@GOT(%reg1), %reg2" to + "lea foo@GOTOFF(%reg1), %reg2". */ + r_type = R_386_GOTOFF; + opcode = 0x8d; + } } else { + /* Only R_386_32 is supported. */ + if (!to_reloc_32) + continue; + if (opcode == 0x85) { /* Convert "test %reg1, foo@GOT(%reg2)" to @@ -4369,10 +4392,10 @@ r_386_got32: || eh->func_pointer_refcount > 0 || (h->root.type == bfd_link_hash_undefweak && !resolved_to_zero)) - && ((h->def_dynamic - && !h->def_regular) - || h->root.type == bfd_link_hash_undefweak - || h->root.type == bfd_link_hash_undefined))) + && ((h->def_dynamic && !h->def_regular) + /* Undefined weak symbol is bound locally when + PIC is false. */ + || h->root.type == bfd_link_hash_undefweak))) { Elf_Internal_Rela outrel; bfd_boolean skip, relocate; |