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.
This commit is contained in:
H.J. Lu 2015-04-22 05:24:54 -07:00
parent 712e55b924
commit d5597ebccc
17 changed files with 277 additions and 18 deletions

View File

@ -1,3 +1,16 @@
2015-04-22 H.J. Lu <hongjiu.lu@intel.com>
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 <hongjiu.lu@intel.com>
* elf.c (assign_section_numbers): Always set up sh_name.

View File

@ -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)

View File

@ -1,3 +1,20 @@
2015-04-22 H.J. Lu <hongjiu.lu@intel.com>
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 <hongjiu.lu@intel.com>
* ld-mmix/bspec1.d: Don't hardcode offset of .shstrtab section.

View File

@ -0,0 +1 @@
int a_glob = 2;

View File

@ -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

View File

View File

@ -0,0 +1,3 @@
#...
[0-9a-f ]+R_386_COPY+[0-9a-f ]+ +a_glob
#...

View File

@ -0,0 +1,4 @@
#failif
#...
[0-9a-f ]+R_386_NONE.*
#...

View File

@ -0,0 +1 @@
/* An empty file. */

View File

@ -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" \
] \
]
}

View File

@ -0,0 +1,2 @@
PASS
PASS

View File

@ -0,0 +1,3 @@
#...
[0-9a-f ]+R_386_COPY+[0-9a-f ]+ +bar
#...

View File

@ -0,0 +1,10 @@
#include <stdio.h>
char *bar = "PASS";
extern char *bar_alias __attribute__ ((weak, alias ("bar")));
void
foo (char *x)
{
printf ("%s\n", x);
}

View File

@ -0,0 +1,6 @@
VERSION {
global:
bar_alias; bar; foo;
local:
*;
};

View File

@ -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

View File

@ -0,0 +1,3 @@
#...
[0-9a-f ]+R_386_COPY+[0-9a-f ]+ +bar@VERSION
#...

View File

@ -0,0 +1,4 @@
#failif
#...
[0-9a-f ]+R_386_NONE.*
#...