From: H.J. Lu Date: Wed, 22 Apr 2015 12:24:54 +0000 (-0700) Subject: i386: Allow copy relocs for building PIE X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=d5597ebccca6761fb641b7fc99b6e8b56fbac6e2;p=binutils-gdb.git i386: Allow copy relocs for building PIE This patch allows copy relocs for R_386_GOTOFF relocations in PIE. For extern int glob_a; int foo () { return glob_a; } compiler now can optimize it from call __x86.get_pc_thunk.ax addl $_GLOBAL_OFFSET_TABLE_, %eax movl glob_a@GOT(%eax), %eax movl (%eax), %eax ret to call __x86.get_pc_thunk.ax addl $_GLOBAL_OFFSET_TABLE_, %eax movl glob_a@GOTOFF(%eax), %eax ret bfd/ PR ld/18289 * elf32-i386.c (elf_i386_link_hash_entry): Add gotoff_ref. (elf_i386_link_hash_newfunc): Initialize gotoff_ref to 0. (elf_i386_create_dynamic_sections): Always allow copy relocs for building executables. (elf_i386_copy_indirect_symbol): Also copy gotoff_ref. (elf_i386_check_relocs): Set gotoff_ref for R_386_GOTOFF. (elf_i386_adjust_dynamic_symbol): Also allocate copy relocs for PIE and R_386_GOTOFF. (elf_i386_relocate_section): Allow R_386_GOTOFF in executable. ld/testsuite/ PR ld/18289 * ld-i386/copyreloc-lib.c: New file. * ld-i386/copyreloc-main.S: Likewise. * ld-i386/copyreloc-main.out: Likewise. * ld-i386/copyreloc-main1.rd: Likewise. * ld-i386/copyreloc-main2.rd: Likewise. * ld-i386/dummy.c: Likewise. * ld-i386/pr17689.out: Likewise. * ld-i386/pr17689.rd: Likewise. * ld-i386/pr17689a.c: Likewise. * ld-i386/pr17689b.S: Likewise. * ld-i386/pr17827.rd: Likewise. * ld-i386/pr17827ver.rd: Likewise. * ld-i386/i386.exp: Run copyreloc tests. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 1f95fd54c33..94aca528246 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,16 @@ +2015-04-22 H.J. Lu + + PR ld/18289 + * elf32-i386.c (elf_i386_link_hash_entry): Add gotoff_ref. + (elf_i386_link_hash_newfunc): Initialize gotoff_ref to 0. + (elf_i386_create_dynamic_sections): Always allow copy relocs for + building executables. + (elf_i386_copy_indirect_symbol): Also copy gotoff_ref. + (elf_i386_check_relocs): Set gotoff_ref for R_386_GOTOFF. + (elf_i386_adjust_dynamic_symbol): Also allocate copy relocs for + PIE and R_386_GOTOFF. + (elf_i386_relocate_section): Allow R_386_GOTOFF in executable. + 2015-04-20 H.J. Lu * elf.c (assign_section_numbers): Always set up sh_name. diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index f71bce12243..d76addbeb32 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -756,6 +756,9 @@ struct elf_i386_link_hash_entry (GOT_TLS_GD_P (type) || GOT_TLS_GDESC_P (type)) unsigned char tls_type; + /* Symbol is referenced by R_386_GOTOFF relocation. */ + unsigned int gotoff_ref : 1; + /* Information about the GOT PLT entry. Filled when there are both GOT and PLT relocations against the same function. */ union gotplt_union plt_got; @@ -879,6 +882,7 @@ elf_i386_link_hash_newfunc (struct bfd_hash_entry *entry, eh = (struct elf_i386_link_hash_entry *) entry; eh->dyn_relocs = NULL; eh->tls_type = GOT_UNKNOWN; + eh->gotoff_ref = 0; eh->plt_got.offset = (bfd_vma) -1; eh->tlsdesc_got = (bfd_vma) -1; } @@ -1022,13 +1026,28 @@ elf_i386_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) return FALSE; htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss"); - if (!info->shared) - htab->srelbss = bfd_get_linker_section (dynobj, ".rel.bss"); - - if (!htab->sdynbss - || (!info->shared && !htab->srelbss)) + if (!htab->sdynbss) abort (); + if (info->executable) + { + /* Always allow copy relocs for building executables. */ + asection *s = bfd_get_linker_section (dynobj, ".rel.bss"); + if (s == NULL) + { + const struct elf_backend_data *bed = get_elf_backend_data (dynobj); + s = bfd_make_section_anyway_with_flags (dynobj, + ".rel.bss", + (bed->dynamic_sec_flags + | SEC_READONLY)); + if (s == NULL + || ! bfd_set_section_alignment (dynobj, s, + bed->s->log_file_align)) + return FALSE; + } + htab->srelbss = s; + } + if (get_elf_i386_backend_data (dynobj)->is_vxworks && !elf_vxworks_create_dynamic_sections (dynobj, info, &htab->srelplt2)) @@ -1101,6 +1120,10 @@ elf_i386_copy_indirect_symbol (struct bfd_link_info *info, eind->tls_type = GOT_UNKNOWN; } + /* Copy gotoff_ref so that elf_i386_adjust_dynamic_symbol will + generate a R_386_COPY reloc. */ + edir->gotoff_ref |= eind->gotoff_ref; + if (ELIMINATE_COPY_RELOCS && ind->root.type != bfd_link_hash_indirect && dir->dynamic_adjusted) @@ -1475,6 +1498,7 @@ elf_i386_check_relocs (bfd *abfd, unsigned int r_type; unsigned long r_symndx; struct elf_link_hash_entry *h; + struct elf_i386_link_hash_entry *eh; Elf_Internal_Sym *isym; const char *name; bfd_boolean size_reloc; @@ -1524,6 +1548,7 @@ elf_i386_check_relocs (bfd *abfd, h = (struct elf_link_hash_entry *) h->root.u.i.link; } + eh = (struct elf_i386_link_hash_entry *) h; if (h != NULL) { /* Create the ifunc sections for static executables. If we @@ -1535,11 +1560,12 @@ elf_i386_check_relocs (bfd *abfd, default: break; + case R_386_GOTOFF: + eh->gotoff_ref = 1; case R_386_32: case R_386_PC32: case R_386_PLT32: case R_386_GOT32: - case R_386_GOTOFF: if (htab->elf.dynobj == NULL) htab->elf.dynobj = abfd; if (!_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info)) @@ -1791,7 +1817,7 @@ do_size: relocations we need for this symbol. */ if (h != NULL) { - head = &((struct elf_i386_link_hash_entry *) h)->dyn_relocs; + head = &eh->dyn_relocs; } else { @@ -2175,12 +2201,14 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, only references to the symbol are via the global offset table. For such cases we need not do anything here; the relocations will be handled correctly by relocate_section. */ - if (info->shared) + if (!info->executable) return TRUE; /* If there are no references to this symbol that do not use the - GOT, we don't need to generate a copy reloc. */ - if (!h->non_got_ref) + GOT nor R_386_GOTOFF relocation, we don't need to generate a copy + reloc. */ + eh = (struct elf_i386_link_hash_entry *) h; + if (!h->non_got_ref && !eh->gotoff_ref) return TRUE; /* If -z nocopyreloc was given, we won't generate them either. */ @@ -2194,14 +2222,15 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, if (htab == NULL) return FALSE; - /* If there aren't any dynamic relocs in read-only sections, then - we can keep the dynamic relocs and avoid the copy reloc. This - doesn't work on VxWorks, where we can not have dynamic relocations - (other than copy and jump slot relocations) in an executable. */ + /* If there aren't any dynamic relocs in read-only sections nor + R_386_GOTOFF relocation, then we can keep the dynamic relocs and + avoid the copy reloc. This doesn't work on VxWorks, where we can + not have dynamic relocations (other than copy and jump slot + relocations) in an executable. */ if (ELIMINATE_COPY_RELOCS + && !eh->gotoff_ref && !get_elf_i386_backend_data (info->output_bfd)->is_vxworks) { - eh = (struct elf_i386_link_hash_entry *) h; for (p = eh->dyn_relocs; p != NULL; p = p->next) { s = p->sec->output_section; @@ -3718,7 +3747,7 @@ elf_i386_relocate_section (bfd *output_bfd, symbol for shared library since it may not be local when used as function address or with copy relocation. We also need to make sure that a symbol is referenced locally. */ - if (info->shared && h) + if (!info->executable && h) { if (!h->def_regular) { @@ -3746,8 +3775,7 @@ elf_i386_relocate_section (bfd *output_bfd, bfd_set_error (bfd_error_bad_value); return FALSE; } - else if (!info->executable - && !SYMBOL_REFERENCES_LOCAL (info, h) + else if (!SYMBOL_REFERENCES_LOCAL (info, h) && (h->type == STT_FUNC || h->type == STT_OBJECT) && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED) diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index 240a4444195..ea6a86326be 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,20 @@ +2015-04-22 H.J. Lu + + PR ld/18289 + * ld-i386/copyreloc-lib.c: New file. + * ld-i386/copyreloc-main.S: Likewise. + * ld-i386/copyreloc-main.out: Likewise. + * ld-i386/copyreloc-main1.rd: Likewise. + * ld-i386/copyreloc-main2.rd: Likewise. + * ld-i386/dummy.c: Likewise. + * ld-i386/pr17689.out: Likewise. + * ld-i386/pr17689.rd: Likewise. + * ld-i386/pr17689a.c: Likewise. + * ld-i386/pr17689b.S: Likewise. + * ld-i386/pr17827.rd: Likewise. + * ld-i386/pr17827ver.rd: Likewise. + * ld-i386/i386.exp: Run copyreloc tests. + 2015-04-20 H.J. Lu * ld-mmix/bspec1.d: Don't hardcode offset of .shstrtab section. diff --git a/ld/testsuite/ld-i386/copyreloc-lib.c b/ld/testsuite/ld-i386/copyreloc-lib.c new file mode 100644 index 00000000000..cbbc5e245eb --- /dev/null +++ b/ld/testsuite/ld-i386/copyreloc-lib.c @@ -0,0 +1 @@ +int a_glob = 2; diff --git a/ld/testsuite/ld-i386/copyreloc-main.S b/ld/testsuite/ld-i386/copyreloc-main.S new file mode 100644 index 00000000000..98aef839e07 --- /dev/null +++ b/ld/testsuite/ld-i386/copyreloc-main.S @@ -0,0 +1,24 @@ + .section .text.startup,"ax",@progbits + .p2align 4,,15 + .globl main + .type main, @function +main: + .cfi_startproc + call __x86.get_pc_thunk.ax + addl $_GLOBAL_OFFSET_TABLE_, %eax + cmpl $2, a_glob@GOTOFF(%eax) + setne %al + movzbl %al, %eax + ret + .cfi_endproc + .size main, .-main + .section .text.__x86.get_pc_thunk.ax,"axG",@progbits,__x86.get_pc_thunk.ax,comdat + .globl __x86.get_pc_thunk.ax + .hidden __x86.get_pc_thunk.ax + .type __x86.get_pc_thunk.ax, @function +__x86.get_pc_thunk.ax: + .cfi_startproc + movl (%esp), %eax + ret + .cfi_endproc + .section .note.GNU-stack,"",@progbits diff --git a/ld/testsuite/ld-i386/copyreloc-main.out b/ld/testsuite/ld-i386/copyreloc-main.out new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ld/testsuite/ld-i386/copyreloc-main1.rd b/ld/testsuite/ld-i386/copyreloc-main1.rd new file mode 100644 index 00000000000..a6bd67c7442 --- /dev/null +++ b/ld/testsuite/ld-i386/copyreloc-main1.rd @@ -0,0 +1,3 @@ +#... +[0-9a-f ]+R_386_COPY+[0-9a-f ]+ +a_glob +#... diff --git a/ld/testsuite/ld-i386/copyreloc-main2.rd b/ld/testsuite/ld-i386/copyreloc-main2.rd new file mode 100644 index 00000000000..ed61aa1927f --- /dev/null +++ b/ld/testsuite/ld-i386/copyreloc-main2.rd @@ -0,0 +1,4 @@ +#failif +#... +[0-9a-f ]+R_386_NONE.* +#... diff --git a/ld/testsuite/ld-i386/dummy.c b/ld/testsuite/ld-i386/dummy.c new file mode 100644 index 00000000000..5c0328739c6 --- /dev/null +++ b/ld/testsuite/ld-i386/dummy.c @@ -0,0 +1 @@ +/* An empty file. */ diff --git a/ld/testsuite/ld-i386/i386.exp b/ld/testsuite/ld-i386/i386.exp index f214d896ecc..8399cbcdde1 100644 --- a/ld/testsuite/ld-i386/i386.exp +++ b/ld/testsuite/ld-i386/i386.exp @@ -335,6 +335,78 @@ if { [isnative] {{readelf {-Wr} plt-main.rd}} \ "plt-main" \ ] \ + [list \ + "Build copyreloc-lib.so" \ + "-shared" \ + "-fPIC" \ + { copyreloc-lib.c } \ + {} \ + "copyreloc-lib.so" \ + ] \ + [list \ + "Build copyreloc-main with PIE and GOTOFF (1)" \ + "tmpdir/copyreloc-lib.so -pie" \ + "" \ + { copyreloc-main.S } \ + {{readelf {-Wr} copyreloc-main1.rd}} \ + "copyreloc-main" \ + ] \ + [list \ + "Build copyreloc-main with PIE and GOTOFF (2)" \ + "tmpdir/copyreloc-lib.so -pie" \ + "" \ + { copyreloc-main.S } \ + {{readelf {-Wr} copyreloc-main2.rd}} \ + "copyreloc-main" \ + ] \ + [list \ + "Build pr17689.so" \ + "-shared" \ + "-fPIC" \ + { pr17689a.c } \ + {} \ + "pr17689.so" \ + ] \ + [list \ + "Build pr17689ver.so" \ + "-shared -Wl,--version-script,pr17689a.t" \ + "-fPIC" \ + { pr17689a.c } \ + {} \ + "pr17689ver.so" \ + ] \ + [list \ + "Build pr17689.a" \ + "" \ + "" \ + { pr17689b.S } \ + {} \ + "pr17689.a" \ + ] \ + [list \ + "Build pr17689 with PIE and GOTOFF" \ + "tmpdir/pr17689b.o tmpdir/pr17689.so -pie" \ + "" \ + { dummy.c } \ + {{readelf {-Wr} pr17689.rd}} \ + "pr17689" \ + ] \ + [list \ + "Build pr17689ver with PIE and GOTOFF" \ + "tmpdir/pr17689b.o tmpdir/pr17689ver.so -pie" \ + "" \ + { dummy.c } \ + {{readelf {-Wr} pr17689ver.rd}} \ + "pr17689ver" \ + ] \ + [list \ + "Build pr17827 with PIE and GOTOFF" \ + "tmpdir/pr17689b.o tmpdir/pr17689.so -pie" \ + "" \ + { dummy.c } \ + {{readelf {-Wr} pr17827.rd}} \ + "pr17827" \ + ] \ ] run_ld_link_exec_tests [] [list \ @@ -357,5 +429,29 @@ if { [isnative] "plt-main.out" \ "-fPIC" \ ] \ + [list \ + "Run copyreloc-main with PIE and GOTOFF" \ + "tmpdir/copyreloc-lib.so -pie" \ + "" \ + { copyreloc-main.S } \ + "copyreloc-main" \ + "copyreloc-main.out" \ + ] \ + [list \ + "Run pr17689 with PIE and GOTOFF" \ + "tmpdir/pr17689b.o tmpdir/pr17689.so -pie" \ + "" \ + { dummy.c } \ + "pr17689" \ + "pr17689.out" \ + ] \ + [list \ + "Run pr17689ver with PIE and GOTOFF" \ + "tmpdir/pr17689b.o tmpdir/pr17689ver.so -pie" \ + "" \ + { dummy.c } \ + "pr17689ver" \ + "pr17689.out" \ + ] \ ] } diff --git a/ld/testsuite/ld-i386/pr17689.out b/ld/testsuite/ld-i386/pr17689.out new file mode 100644 index 00000000000..38e03525155 --- /dev/null +++ b/ld/testsuite/ld-i386/pr17689.out @@ -0,0 +1,2 @@ +PASS +PASS diff --git a/ld/testsuite/ld-i386/pr17689.rd b/ld/testsuite/ld-i386/pr17689.rd new file mode 100644 index 00000000000..dda18509c0b --- /dev/null +++ b/ld/testsuite/ld-i386/pr17689.rd @@ -0,0 +1,3 @@ +#... +[0-9a-f ]+R_386_COPY+[0-9a-f ]+ +bar +#... diff --git a/ld/testsuite/ld-i386/pr17689a.c b/ld/testsuite/ld-i386/pr17689a.c new file mode 100644 index 00000000000..5317668876e --- /dev/null +++ b/ld/testsuite/ld-i386/pr17689a.c @@ -0,0 +1,10 @@ +#include + +char *bar = "PASS"; +extern char *bar_alias __attribute__ ((weak, alias ("bar"))); + +void +foo (char *x) +{ + printf ("%s\n", x); +} diff --git a/ld/testsuite/ld-i386/pr17689a.t b/ld/testsuite/ld-i386/pr17689a.t new file mode 100644 index 00000000000..7f0efef7b42 --- /dev/null +++ b/ld/testsuite/ld-i386/pr17689a.t @@ -0,0 +1,6 @@ +VERSION { + global: + bar_alias; bar; foo; + local: + *; +}; diff --git a/ld/testsuite/ld-i386/pr17689b.S b/ld/testsuite/ld-i386/pr17689b.S new file mode 100644 index 00000000000..24daf36308d --- /dev/null +++ b/ld/testsuite/ld-i386/pr17689b.S @@ -0,0 +1,44 @@ + .text + .globl main + .type main, @function +main: + leal 4(%esp), %ecx + andl $-16, %esp + pushl -4(%ecx) + pushl %ebp + movl %esp, %ebp + pushl %ebx + pushl %ecx + call __x86.get_pc_thunk.bx + addl $_GLOBAL_OFFSET_TABLE_, %ebx + subl $12, %esp + pushl bar_alias@GOTOFF(%ebx) + call foo@PLT + popl %eax + movl ptr@GOTOFF(%ebx), %eax + pushl (%eax) + call foo@PLT + addl $16, %esp + leal -8(%ebp), %esp + xorl %eax, %eax + popl %ecx + popl %ebx + popl %ebp + leal -4(%ecx), %esp + ret + .size main, .-main + .globl ptr + .section .data.rel.local,"aw",@progbits + .align 4 + .type ptr, @object + .size ptr, 4 +ptr: + .long bar_alias + .section .text.__x86.get_pc_thunk.bx,"axG",@progbits,__x86.get_pc_thunk.bx,comdat + .globl __x86.get_pc_thunk.bx + .hidden __x86.get_pc_thunk.bx + .type __x86.get_pc_thunk.bx, @function +__x86.get_pc_thunk.bx: + movl (%esp), %ebx + ret + .section .note.GNU-stack,"",@progbits diff --git a/ld/testsuite/ld-i386/pr17689ver.rd b/ld/testsuite/ld-i386/pr17689ver.rd new file mode 100644 index 00000000000..6cebe73e29d --- /dev/null +++ b/ld/testsuite/ld-i386/pr17689ver.rd @@ -0,0 +1,3 @@ +#... +[0-9a-f ]+R_386_COPY+[0-9a-f ]+ +bar@VERSION +#... diff --git a/ld/testsuite/ld-i386/pr17827.rd b/ld/testsuite/ld-i386/pr17827.rd new file mode 100644 index 00000000000..ed61aa1927f --- /dev/null +++ b/ld/testsuite/ld-i386/pr17827.rd @@ -0,0 +1,4 @@ +#failif +#... +[0-9a-f ]+R_386_NONE.* +#...