aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf64-x86-64.c
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2016-02-26 04:16:15 -0800
committerH.J. Lu <hjl.tools@gmail.com>2016-02-26 04:55:57 -0800
commitaec6b87e0b66d707ead62ca40d220ee78b4cf5a5 (patch)
tree17d41e8d0d0e4a083d0fc0316c0dc56b29b42e75 /bfd/elf64-x86-64.c
parentb32547cd11bec3baf53e0dedf3c733cd3e0839f6 (diff)
downloadgdb-aec6b87e0b66d707ead62ca40d220ee78b4cf5a5.zip
gdb-aec6b87e0b66d707ead62ca40d220ee78b4cf5a5.tar.gz
gdb-aec6b87e0b66d707ead62ca40d220ee78b4cf5a5.tar.bz2
[x86] Resolve non-PIC undefweak symbols in executable
For i386 and x86-64, non-PIC references to undefined weak symbols are resolved without dynamic relocation when creating executable. Resolved undefined weak symbols are removed from the dynamic symbol table in executable. One exception is on i386, we need resolved undefined weak symbols in the dynamic symbol table in PIE if input relocatable files contain branchs without PLT so that we can branch to 0 with dynamic relocation in text section. This makes behaviors of dynamic executable and position independent executable predictable with mixed PIC and non-PIC references to undefined weak symbols. If all references to undefined weak symbols are PIC, dynamic relocations against undefined weak symbols will be generated in executable unless -z nodynamic-undefined-weak is passed to linker. bfd/ PR ld/19636 PR ld/19704 PR ld/19719 * elf32-i386.c (UNDEFINED_WEAK_RESOLVED_TO_ZERO): New. (elf_i386_link_hash_entry): Add has_got_reloc and has_non_got_reloc. (elf_i386_link_hash_table): Add interp. (elf_i386_link_hash_newfunc): Initialize has_got_reloc and has_non_got_reloc. (elf_i386_copy_indirect_symbol): Copy has_got_reloc and has_non_got_reloc. (elf_i386_check_relocs): Set has_got_reloc and has_non_got_reloc. (elf_i386_fixup_symbol): New function. (elf_i386_pie_finish_undefweak_symbol): Likewise. (elf_i386_allocate_dynrelocs): Don't allocate space for dynamic relocations and discard relocations against resolved undefined weak symbols in executable. Don't make resolved undefined weak symbols in executable dynamic. Keep dynamic non-GOT/non-PLT relocation against undefined weak symbols in PIE. (elf_i386_size_dynamic_sections): Set interp to .interp section. (elf_i386_relocate_section): Don't generate dynamic relocations against resolved undefined weak symbols in PIE, except for R_386_PC32. (elf_i386_finish_dynamic_symbol): Keep PLT/GOT entries without dynamic PLT/GOT relocations for resolved undefined weak symbols. Don't generate dynamic relocation against resolved undefined weak symbol in executable. (elf_i386_finish_dynamic_sections): Call elf_i386_pie_finish_undefweak_symbol on all symbols in PIE. (elf_backend_fixup_symbol): New. * elf64-x86-64.c (UNDEFINED_WEAK_RESOLVED_TO_ZERO): New. (elf_x86_64_link_hash_entry): Add has_got_reloc and has_non_got_reloc. (elf_x86_64_link_hash_table): Add interp. (elf_x86_64_link_hash_newfunc): Initialize has_got_reloc and has_non_got_reloc. (elf_x86_64_copy_indirect_symbol): Copy has_got_reloc and has_non_got_reloc. (elf_x86_64_check_relocs): Set has_got_reloc and has_non_got_reloc. (elf_x86_64_fixup_symbol): New function. (elf_x86_64_pie_finish_undefweak_symbol): Likewise. (elf_x86_64_allocate_dynrelocs): Don't allocate space for dynamic relocations and discard relocations against resolved undefined weak symbols in executable. Don't make resolved undefined weak symbols in executable dynamic. (elf_x86_64_size_dynamic_sections): Set interp to .interp section. (elf_x86_64_relocate_section): Check relocation overflow for dynamic relocations against unresolved weak undefined symbols. Don't generate dynamic relocations against resolved weak undefined symbols in PIE. (elf_x86_64_finish_dynamic_symbol): Keep PLT/GOT entries without dynamic PLT/GOT relocations for resolved undefined weak symbols. Don't generate dynamic relocation against resolved undefined weak symbol in executable. (elf_x86_64_finish_dynamic_sections): Call elf_x86_64_pie_finish_undefweak_symbol on all symbols in PIE. (elf_backend_fixup_symbol): New. include/ PR ld/19636 PR ld/19704 PR ld/19719 * bfdlink.h (bfd_link_info): Add dynamic_undefined_weak. ld/ PR ld/19636 PR ld/19704 PR ld/19719 * Makefile.am (ELF_X86_DEPS): Add dynamic_undefined_weak.sh. * Makefile.in: Regenerated. * NEWS: Mention -z nodynamic-undefined-weak. * ld.texinfo: Document -z nodynamic-undefined-weak. * ldmain.c (main): Initialize dynamic_undefined_weak to -1. * emulparams/dynamic_undefined_weak.sh: New file. * emulparams/elf32_x86_64.sh: Source dynamic_undefined_weak.sh. * emulparams/elf_i386.sh: Likewise. * emulparams/elf_i386_be.sh: Likewise. * emulparams/elf_i386_chaos.sh: Likewise. * emulparams/elf_i386_ldso.sh: Likewise. * emulparams/elf_i386_vxworks.sh: Likewise. * emulparams/elf_iamcu.sh: Likewise. * emulparams/elf_k1om.sh: Likewise. * emulparams/elf_l1om.sh: Likewise. * emulparams/elf_x86_64.sh: Likewise. * emulparams/extern_protected_data.sh (PARSE_AND_LIST_OPTIONS): Append. (PARSE_AND_LIST_ARGS_CASE_Z): Likewise. * testsuite/ld-elf/pr19719a.c: New file. * testsuite/ld-elf/pr19719b.c: Likewise. * testsuite/ld-elf/pr19719c.c: Likewise. * testsuite/ld-elf/pr19719d.c: Likewise. * testsuite/ld-i386/pr19636-1.s: Likewise. * testsuite/ld-i386/pr19636-1a.d: Likewise. * testsuite/ld-i386/pr19636-1b.d: Likewise. * testsuite/ld-i386/pr19636-1c.d: Likewise. * testsuite/ld-i386/pr19636-1d-nacl.d: Likewise. * testsuite/ld-i386/pr19636-1d.d: Likewise. * testsuite/ld-i386/pr19636-1e.d: Likewise. * testsuite/ld-i386/pr19636-1f.d: Likewise. * testsuite/ld-i386/pr19636-1g.d: Likewise. * testsuite/ld-i386/pr19636-1h.d: Likewise. * testsuite/ld-i386/pr19636-1i.d: Likewise. * testsuite/ld-i386/pr19636-2.s: Likewise. * testsuite/ld-i386/pr19636-2a.d: Likewise. * testsuite/ld-i386/pr19636-2b.d: Likewise. * testsuite/ld-i386/pr19636-2c-nacl.d: Likewise. * testsuite/ld-i386/pr19636-2c.d: Likewise. * testsuite/ld-i386/pr19636-2d-nacl.d: Likewise. * testsuite/ld-i386/pr19636-2d.d: Likewise. * testsuite/ld-i386/pr19636-2e-nacl.d: Likewise. * testsuite/ld-i386/pr19636-2e.d: Likewise. * testsuite/ld-i386/pr19636-3.s: Likewise. * testsuite/ld-i386/pr19636-3a.d: Likewise. * testsuite/ld-i386/pr19636-3b.d: Likewise. * testsuite/ld-i386/pr19636-3c.d: Likewise. * testsuite/ld-i386/pr19636-3d.d: Likewise. * testsuite/ld-i386/pr19636-3e.d: Likewise. * testsuite/ld-i386/pr19636-3f.d: Likewise. * testsuite/ld-i386/pr19636-3g.d: Likewise. * testsuite/ld-i386/pr19636-4.s: Likewise. * testsuite/ld-i386/pr19636-4a.d: Likewise. * testsuite/ld-i386/pr19636-4b.d: Likewise. * testsuite/ld-i386/pr19636-4c.d: Likewise. * testsuite/ld-i386/pr19636-4d.d: Likewise. * testsuite/ld-i386/pr19704.out: Likewise. * testsuite/ld-i386/pr19704a.c: Likewise. * testsuite/ld-i386/pr19704b.c: Likewise. * testsuite/ld-x86-64/pr19636-1.s: Likewise. * testsuite/ld-x86-64/pr19636-1a.d: Likewise. * testsuite/ld-x86-64/pr19636-1b.d: Likewise. * testsuite/ld-x86-64/pr19636-1c.d: Likewise. * testsuite/ld-x86-64/pr19636-1d.d: Likewise. * testsuite/ld-x86-64/pr19636-1e.d: Likewise. * testsuite/ld-x86-64/pr19636-1f.d: Likewise. * testsuite/ld-x86-64/pr19636-1g.d: Likewise. * testsuite/ld-x86-64/pr19636-2.s: Likewise. * testsuite/ld-x86-64/pr19636-2a.d: Likewise. * testsuite/ld-x86-64/pr19636-2b.d: Likewise. * testsuite/ld-x86-64/pr19636-2c.d: Likewise. * testsuite/ld-x86-64/pr19636-2d-nacl.d: Likewise. * testsuite/ld-x86-64/pr19636-2d.d: Likewise. * testsuite/ld-x86-64/pr19636-2e.d: Likewise. * testsuite/ld-x86-64/pr19636-2f.d: Likewise. * testsuite/ld-x86-64/pr19636-2g.d: Likewise. * testsuite/ld-x86-64/pr19636-2h.d: Likewise. * testsuite/ld-x86-64/pr19636-2i.d: Likewise. * testsuite/ld-x86-64/pr19636-3.s: Likewise. * testsuite/ld-x86-64/pr19636-3a.d: Likewise. * testsuite/ld-x86-64/pr19636-3b.d: Likewise. * testsuite/ld-x86-64/pr19636-3c.d: Likewise. * testsuite/ld-x86-64/pr19636-3d.d: Likewise. * testsuite/ld-x86-64/pr19704.out: Likewise. * testsuite/ld-x86-64/pr19704a.c: Likewise. * testsuite/ld-x86-64/pr19704b.c: Likewise. * testsuite/ld-elf/shared.exp (mix_pic_and_non_pic): New. Run mix_pic_and_non_pic. * testsuite/ld-i386/i386.exp (undefined_weak): New. Run undefined_weak and PR ld/19636 tests. * testsuite/ld-x86-64/x86-64.exp: Likewise. * testsuite/ld-x86-64/pr13082-3b.d: Updated. * testsuite/ld-x86-64/pr13082-4b.d: Likewise.
Diffstat (limited to 'bfd/elf64-x86-64.c')
-rw-r--r--bfd/elf64-x86-64.c311
1 files changed, 220 insertions, 91 deletions
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 48d263e..6ca3b2e 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -742,6 +742,20 @@ static const struct elf_x86_64_backend_data elf_x86_64_bnd_arch_bed =
#define elf_backend_arch_data &elf_x86_64_arch_bed
+/* Is a undefined weak symbol which is resolved to 0. Reference to an
+ undefined weak symbol is resolved to 0 when building executable if
+ it isn't dynamic and
+ 1. Has non-GOT/non-PLT relocations in text section. Or
+ 2. Has no GOT/PLT relocation.
+ */
+#define UNDEFINED_WEAK_RESOLVED_TO_ZERO(INFO, EH) \
+ ((EH)->elf.root.type == bfd_link_hash_undefweak \
+ && bfd_link_executable (INFO) \
+ && (elf_x86_64_hash_table (INFO)->interp == NULL \
+ || !(EH)->has_got_reloc \
+ || (EH)->has_non_got_reloc \
+ || !(INFO)->dynamic_undefined_weak))
+
/* x86-64 ELF linker hash entry. */
struct elf_x86_64_link_hash_entry
@@ -776,6 +790,12 @@ struct elf_x86_64_link_hash_entry
/* TRUE if symbol has at least one BND relocation. */
unsigned int has_bnd_reloc : 1;
+ /* TRUE if symbol has GOT or PLT relocations. */
+ unsigned int has_got_reloc : 1;
+
+ /* TRUE if symbol has non-GOT/non-PLT relocations in text sections. */
+ unsigned int has_non_got_reloc : 1;
+
/* Reference count of C/C++ function pointer relocations in read-write
section which can be resolved at run-time. */
bfd_signed_vma func_pointer_refcount;
@@ -835,6 +855,7 @@ struct elf_x86_64_link_hash_table
struct elf_link_hash_table elf;
/* Short-cuts to get to dynamic linker sections. */
+ asection *interp;
asection *sdynbss;
asection *srelbss;
asection *plt_eh_frame;
@@ -919,6 +940,8 @@ elf_x86_64_link_hash_newfunc (struct bfd_hash_entry *entry,
eh->tls_type = GOT_UNKNOWN;
eh->needs_copy = 0;
eh->has_bnd_reloc = 0;
+ eh->has_got_reloc = 0;
+ eh->has_non_got_reloc = 0;
eh->func_pointer_refcount = 0;
eh->plt_bnd.offset = (bfd_vma) -1;
eh->plt_got.offset = (bfd_vma) -1;
@@ -1136,6 +1159,12 @@ elf_x86_64_copy_indirect_symbol (struct bfd_link_info *info,
if (!edir->has_bnd_reloc)
edir->has_bnd_reloc = eind->has_bnd_reloc;
+ if (!edir->has_got_reloc)
+ edir->has_got_reloc = eind->has_got_reloc;
+
+ if (!edir->has_non_got_reloc)
+ edir->has_non_got_reloc = eind->has_non_got_reloc;
+
if (eind->dyn_relocs != NULL)
{
if (edir->dyn_relocs != NULL)
@@ -1595,6 +1624,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
unsigned int r_type;
unsigned long r_symndx;
struct elf_link_hash_entry *h;
+ struct elf_x86_64_link_hash_entry *eh;
Elf_Internal_Sym *isym;
const char *name;
bfd_boolean size_reloc;
@@ -1760,6 +1790,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
rel, rel_end, h, r_symndx))
return FALSE;
+ eh = (struct elf_x86_64_link_hash_entry *) h;
switch (r_type)
{
case R_X86_64_TLSLD:
@@ -1781,6 +1812,8 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
+ if (eh != NULL)
+ eh->has_got_reloc = 1;
break;
case R_X86_64_GOTTPOFF:
@@ -1815,7 +1848,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
if (h != NULL)
{
h->got.refcount += 1;
- old_tls_type = elf_x86_64_hash_entry (h)->tls_type;
+ old_tls_type = eh->tls_type;
}
else
{
@@ -1873,8 +1906,8 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
if (old_tls_type != tls_type)
{
- if (h != NULL)
- elf_x86_64_hash_entry (h)->tls_type = tls_type;
+ if (eh != NULL)
+ eh->tls_type = tls_type;
else
elf_x86_64_local_got_tls_type (abfd) [r_symndx] = tls_type;
}
@@ -1885,6 +1918,8 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_X86_64_GOTPC32:
case R_X86_64_GOTPC64:
create_got:
+ if (eh != NULL)
+ eh->has_got_reloc = 1;
if (htab->elf.sgot == NULL)
{
if (htab->elf.dynobj == NULL)
@@ -1909,6 +1944,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
if (h == NULL)
continue;
+ eh->has_got_reloc = 1;
h->needs_plt = 1;
h->plt.refcount += 1;
break;
@@ -1961,6 +1997,8 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_X86_64_PC64:
case R_X86_64_64:
pointer:
+ if (eh != NULL && (sec->flags & SEC_CODE) != 0)
+ eh->has_non_got_reloc = 1;
if (h != NULL && bfd_link_executable (info))
{
/* If this reloc is in a read-only section, we might
@@ -1994,11 +2032,7 @@ pointer:
|| (!ABI_64_P (abfd)
&& (r_type == R_X86_64_32
|| r_type == R_X86_64_32S))))
- {
- struct elf_x86_64_link_hash_entry *eh
- = (struct elf_x86_64_link_hash_entry *) h;
- eh->func_pointer_refcount += 1;
- }
+ eh->func_pointer_refcount += 1;
}
}
@@ -2061,9 +2095,7 @@ do_size:
/* If this is a global symbol, we count the number of
relocations we need for this symbol. */
if (h != NULL)
- {
- head = &((struct elf_x86_64_link_hash_entry *) h)->dyn_relocs;
- }
+ head = &eh->dyn_relocs;
else
{
/* Track dynamic relocs needed for local syms too.
@@ -2363,6 +2395,24 @@ pointer:
return TRUE;
}
+/* Remove undefined weak symbol from the dynamic symbol table if it
+ is resolved to 0. */
+
+static bfd_boolean
+elf_x86_64_fixup_symbol (struct bfd_link_info *info,
+ struct elf_link_hash_entry *h)
+{
+ if (h->dynindx != -1
+ && UNDEFINED_WEAK_RESOLVED_TO_ZERO (info,
+ elf_x86_64_hash_entry (h)))
+ {
+ h->dynindx = -1;
+ _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+ h->dynstr_index);
+ }
+ return TRUE;
+}
+
/* Adjust a symbol defined by a dynamic object and referenced by a
regular object. The current definition is in some section of the
dynamic object, but we're not including those sections. We have to
@@ -2552,6 +2602,7 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
struct elf_dyn_relocs *p;
const struct elf_backend_data *bed;
unsigned int plt_entry_size;
+ bfd_boolean resolved_to_zero;
if (h->root.type == bfd_link_hash_indirect)
return TRUE;
@@ -2565,6 +2616,8 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
bed = get_elf_backend_data (info->output_bfd);
plt_entry_size = GET_PLT_ENTRY_SIZE (info->output_bfd);
+ resolved_to_zero = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, eh);
+
/* We can't use the GOT PLT if pointer equality is needed since
finish_dynamic_symbol won't clear symbol value and the dynamic
linker won't update the GOT slot. We will get into an infinite
@@ -2641,7 +2694,8 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
/* Make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic. */
if (h->dynindx == -1
- && !h->forced_local)
+ && !h->forced_local
+ && !resolved_to_zero)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
@@ -2715,10 +2769,15 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
script. */
htab->elf.sgotplt->size += GOT_ENTRY_SIZE;
- /* We also need to make an entry in the .rela.plt
- section. */
- htab->elf.srelplt->size += bed->s->sizeof_rela;
- htab->elf.srelplt->reloc_count++;
+ /* There should be no PLT relocation against resolved
+ undefined weak symbol in executable. */
+ if (!resolved_to_zero)
+ {
+ /* We also need to make an entry in the .rela.plt
+ section. */
+ htab->elf.srelplt->size += bed->s->sizeof_rela;
+ htab->elf.srelplt->reloc_count++;
+ }
}
}
else
@@ -2755,7 +2814,8 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
/* Make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic. */
if (h->dynindx == -1
- && !h->forced_local)
+ && !h->forced_local
+ && !resolved_to_zero)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
@@ -2779,15 +2839,17 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
}
dyn = htab->elf.dynamic_sections_created;
/* R_X86_64_TLSGD needs one dynamic relocation if local symbol
- and two if global.
- R_X86_64_GOTTPOFF needs one dynamic relocation. */
+ and two if global. R_X86_64_GOTTPOFF needs one dynamic
+ relocation. No dynamic relocation against resolved undefined
+ weak symbol in executable. */
if ((GOT_TLS_GD_P (tls_type) && h->dynindx == -1)
|| tls_type == GOT_TLS_IE)
htab->elf.srelgot->size += bed->s->sizeof_rela;
else if (GOT_TLS_GD_P (tls_type))
htab->elf.srelgot->size += 2 * bed->s->sizeof_rela;
else if (! GOT_TLS_GDESC_P (tls_type)
- && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ && ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ && !resolved_to_zero)
|| h->root.type != bfd_link_hash_undefweak)
&& (bfd_link_pic (info)
|| WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
@@ -2834,16 +2896,16 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
}
/* Also discard relocs on undefined weak syms with non-default
- visibility. */
+ visibility or in PIE. */
if (eh->dyn_relocs != NULL)
{
if (h->root.type == bfd_link_hash_undefweak)
{
- if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+ /* Undefined weak symbol is never bound locally in shared
+ library. */
+ if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+ || resolved_to_zero)
eh->dyn_relocs = NULL;
-
- /* Make sure undefined weak symbols are output as a dynamic
- symbol in PIEs. */
else if (h->dynindx == -1
&& ! h->forced_local
&& ! bfd_elf_link_record_dynamic_symbol (info, h))
@@ -2875,7 +2937,10 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
dynamic. Keep dynamic relocations for run-time function
pointer initialization. */
- if ((!h->non_got_ref || eh->func_pointer_refcount > 0)
+ if ((!h->non_got_ref
+ || eh->func_pointer_refcount > 0
+ || (h->root.type == bfd_link_hash_undefweak
+ && !resolved_to_zero))
&& ((h->def_dynamic
&& !h->def_regular)
|| (htab->elf.dynamic_sections_created
@@ -2886,6 +2951,7 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
Undefined weak syms won't yet be marked as dynamic. */
if (h->dynindx == -1
&& ! h->forced_local
+ && ! resolved_to_zero
&& ! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
@@ -3398,6 +3464,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
abort ();
s->size = htab->dynamic_interpreter_size;
s->contents = (unsigned char *) htab->dynamic_interpreter;
+ htab->interp = s;
}
}
@@ -3949,6 +4016,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
int tls_type;
asection *base_got, *resolved_plt;
bfd_vma st_size;
+ bfd_boolean resolved_to_zero;
r_type = ELF32_R_TYPE (rel->r_info);
if (r_type == (int) R_X86_64_GNU_VTINHERIT
@@ -4259,6 +4327,9 @@ elf_x86_64_relocate_section (bfd *output_bfd,
}
}
+ resolved_to_zero = (eh != NULL
+ && UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, eh));
+
/* When generating a shared object, the relocations handled here are
copied into the output file to be resolved at run time. */
switch (r_type)
@@ -4539,13 +4610,16 @@ elf_x86_64_relocate_section (bfd *output_bfd,
case R_X86_64_PC32:
case R_X86_64_PC32_BND:
/* Don't complain about -fPIC if the symbol is undefined when
- building executable. */
- if (bfd_link_pic (info)
- && (input_section->flags & SEC_ALLOC) != 0
+ building executable unless it is unresolved weak symbol. */
+ if ((input_section->flags & SEC_ALLOC) != 0
&& (input_section->flags & SEC_READONLY) != 0
&& h != NULL
- && !(bfd_link_executable (info)
- && h->root.type == bfd_link_hash_undefined))
+ && ((bfd_link_executable (info)
+ && h->root.type == bfd_link_hash_undefweak
+ && !resolved_to_zero)
+ || (bfd_link_pic (info)
+ && !(bfd_link_pie (info)
+ && h->root.type == bfd_link_hash_undefined))))
{
bfd_boolean fail = FALSE;
bfd_boolean branch
@@ -4559,7 +4633,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
defined locally or for a branch. */
fail = !h->def_regular && !branch;
}
- else if (!(bfd_link_executable (info)
+ else if (!(bfd_link_pie (info)
&& (h->needs_copy || eh->needs_copy)))
{
/* Symbol doesn't need copy reloc and isn't referenced
@@ -4589,17 +4663,19 @@ direct:
/* Don't copy a pc-relative relocation into the output file
if the symbol needs copy reloc or the symbol is undefined
when building executable. Copy dynamic function pointer
- relocations. */
+ relocations. Don't generate dynamic relocations against
+ resolved undefined weak symbols in PIE. */
if ((bfd_link_pic (info)
- && !(bfd_link_executable (info)
+ && !(bfd_link_pie (info)
&& h != NULL
&& (h->needs_copy
|| eh->needs_copy
|| h->root.type == bfd_link_hash_undefined)
&& IS_X86_64_PCREL_TYPE (r_type))
&& (h == NULL
- || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
- || h->root.type != bfd_link_hash_undefweak)
+ || ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ && !resolved_to_zero)
+ || h->root.type != bfd_link_hash_undefweak))
&& ((! IS_X86_64_PCREL_TYPE (r_type)
&& r_type != R_X86_64_SIZE32
&& r_type != R_X86_64_SIZE64)
@@ -4608,7 +4684,10 @@ direct:
&& !bfd_link_pic (info)
&& h != NULL
&& h->dynindx != -1
- && (!h->non_got_ref || eh->func_pointer_refcount > 0)
+ && (!h->non_got_ref
+ || 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
@@ -4647,6 +4726,11 @@ direct:
|| ! SYMBOLIC_BIND (info, h)
|| ! h->def_regular))
{
+ if ((r_type != R_X86_64_PC64 && r_type != R_X86_64_64)
+ && bfd_link_executable (info)
+ && h->root.type == bfd_link_hash_undefweak
+ && !resolved_to_zero)
+ return elf_x86_64_need_pic (input_bfd, h, howto);
outrel.r_info = htab->r_info (h->dynindx, r_type);
outrel.r_addend = rel->r_addend;
}
@@ -5340,12 +5424,13 @@ static bfd_boolean
elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
struct bfd_link_info *info,
struct elf_link_hash_entry *h,
- Elf_Internal_Sym *sym ATTRIBUTE_UNUSED)
+ Elf_Internal_Sym *sym)
{
struct elf_x86_64_link_hash_table *htab;
const struct elf_x86_64_backend_data *abed;
bfd_boolean use_plt_bnd;
struct elf_x86_64_link_hash_entry *eh;
+ bfd_boolean local_undefweak;
htab = elf_x86_64_hash_table (info);
if (htab == NULL)
@@ -5360,6 +5445,11 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
eh = (struct elf_x86_64_link_hash_entry *) h;
+ /* We keep PLT/GOT entries without dynamic PLT/GOT relocations for
+ resolved undefined weak symbols in executable so that their
+ references have value 0 at run-time. */
+ local_undefweak = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, eh);
+
if (h->plt.offset != (bfd_vma) -1)
{
bfd_vma plt_index;
@@ -5389,6 +5479,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
/* This symbol has an entry in the procedure linkage table. Set
it up. */
if ((h->dynindx == -1
+ && !local_undefweak
&& !((h->forced_local || bfd_link_executable (info))
&& h->def_regular
&& h->type == STT_GNU_IFUNC))
@@ -5489,60 +5580,67 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
resolved_plt->contents + plt_offset + plt_got_offset);
/* Fill in the entry in the global offset table, initially this
- points to the second part of the PLT entry. */
- bfd_put_64 (output_bfd, (plt->output_section->vma
- + plt->output_offset
- + h->plt.offset + abed->plt_lazy_offset),
- gotplt->contents + got_offset);
-
- /* Fill in the entry in the .rela.plt section. */
- rela.r_offset = (gotplt->output_section->vma
- + gotplt->output_offset
- + got_offset);
- if (h->dynindx == -1
- || ((bfd_link_executable (info)
- || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
- && h->def_regular
- && h->type == STT_GNU_IFUNC))
+ points to the second part of the PLT entry. Leave the entry
+ as zero for undefined weak symbol in PIE. No PLT relocation
+ against undefined weak symbol in PIE. */
+ if (!local_undefweak)
{
- /* If an STT_GNU_IFUNC symbol is locally defined, generate
- R_X86_64_IRELATIVE instead of R_X86_64_JUMP_SLOT. */
- rela.r_info = htab->r_info (0, R_X86_64_IRELATIVE);
- rela.r_addend = (h->root.u.def.value
- + h->root.u.def.section->output_section->vma
- + h->root.u.def.section->output_offset);
- /* R_X86_64_IRELATIVE comes last. */
- plt_index = htab->next_irelative_index--;
- }
- else
- {
- rela.r_info = htab->r_info (h->dynindx, R_X86_64_JUMP_SLOT);
- rela.r_addend = 0;
- plt_index = htab->next_jump_slot_index++;
- }
+ bfd_put_64 (output_bfd, (plt->output_section->vma
+ + plt->output_offset
+ + h->plt.offset
+ + abed->plt_lazy_offset),
+ gotplt->contents + got_offset);
+
+ /* Fill in the entry in the .rela.plt section. */
+ rela.r_offset = (gotplt->output_section->vma
+ + gotplt->output_offset
+ + got_offset);
+ if (h->dynindx == -1
+ || ((bfd_link_executable (info)
+ || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+ && h->def_regular
+ && h->type == STT_GNU_IFUNC))
+ {
+ /* If an STT_GNU_IFUNC symbol is locally defined, generate
+ R_X86_64_IRELATIVE instead of R_X86_64_JUMP_SLOT. */
+ rela.r_info = htab->r_info (0, R_X86_64_IRELATIVE);
+ rela.r_addend = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ /* R_X86_64_IRELATIVE comes last. */
+ plt_index = htab->next_irelative_index--;
+ }
+ else
+ {
+ rela.r_info = htab->r_info (h->dynindx, R_X86_64_JUMP_SLOT);
+ rela.r_addend = 0;
+ plt_index = htab->next_jump_slot_index++;
+ }
- /* Don't fill PLT entry for static executables. */
- if (plt == htab->elf.splt)
- {
- bfd_vma plt0_offset = h->plt.offset + plt_plt_insn_end;
-
- /* Put relocation index. */
- bfd_put_32 (output_bfd, plt_index,
- plt->contents + h->plt.offset + abed->plt_reloc_offset);
-
- /* Put offset for jmp .PLT0 and check for overflow. We don't
- check relocation index for overflow since branch displacement
- will overflow first. */
- if (plt0_offset > 0x80000000)
- info->callbacks->einfo (_("%F%B: branch displacement overflow in PLT entry for `%s'\n"),
- output_bfd, h->root.root.string);
- bfd_put_32 (output_bfd, - plt0_offset,
- plt->contents + h->plt.offset + plt_plt_offset);
- }
+ /* Don't fill PLT entry for static executables. */
+ if (plt == htab->elf.splt)
+ {
+ bfd_vma plt0_offset = h->plt.offset + plt_plt_insn_end;
+
+ /* Put relocation index. */
+ bfd_put_32 (output_bfd, plt_index,
+ (plt->contents + h->plt.offset
+ + abed->plt_reloc_offset));
+
+ /* Put offset for jmp .PLT0 and check for overflow. We don't
+ check relocation index for overflow since branch displacement
+ will overflow first. */
+ if (plt0_offset > 0x80000000)
+ info->callbacks->einfo (_("%F%B: branch displacement overflow in PLT entry for `%s'\n"),
+ output_bfd, h->root.root.string);
+ bfd_put_32 (output_bfd, - plt0_offset,
+ plt->contents + h->plt.offset + plt_plt_offset);
+ }
- bed = get_elf_backend_data (output_bfd);
- loc = relplt->contents + plt_index * bed->s->sizeof_rela;
- bed->s->swap_reloca_out (output_bfd, &rela, loc);
+ bed = get_elf_backend_data (output_bfd);
+ loc = relplt->contents + plt_index * bed->s->sizeof_rela;
+ bed->s->swap_reloca_out (output_bfd, &rela, loc);
+ }
}
else if (eh->plt_got.offset != (bfd_vma) -1)
{
@@ -5604,7 +5702,8 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
plt->contents + plt_offset + plt_got_offset);
}
- if (!h->def_regular
+ if (!local_undefweak
+ && !h->def_regular
&& (h->plt.offset != (bfd_vma) -1
|| eh->plt_got.offset != (bfd_vma) -1))
{
@@ -5621,9 +5720,12 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
sym->st_value = 0;
}
+ /* Don't generate dynamic GOT relocation against undefined weak
+ symbol in executable. */
if (h->got.offset != (bfd_vma) -1
&& ! GOT_TLS_GD_ANY_P (elf_x86_64_hash_entry (h)->tls_type)
- && elf_x86_64_hash_entry (h)->tls_type != GOT_TLS_IE)
+ && elf_x86_64_hash_entry (h)->tls_type != GOT_TLS_IE
+ && !local_undefweak)
{
Elf_Internal_Rela rela;
@@ -5729,6 +5831,25 @@ elf_x86_64_finish_local_dynamic_symbol (void **slot, void *inf)
info, h, NULL);
}
+/* Finish up undefined weak symbol handling in PIE. Fill its PLT entry
+ here since undefined weak symbol may not be dynamic and may not be
+ called for elf_x86_64_finish_dynamic_symbol. */
+
+static bfd_boolean
+elf_x86_64_pie_finish_undefweak_symbol (struct bfd_hash_entry *bh,
+ void *inf)
+{
+ struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) bh;
+ struct bfd_link_info *info = (struct bfd_link_info *) inf;
+
+ if (h->root.type != bfd_link_hash_undefweak
+ || h->dynindx != -1)
+ return TRUE;
+
+ return elf_x86_64_finish_dynamic_symbol (info->output_bfd,
+ info, h, NULL);
+}
+
/* Used to decide how to sort relocs in an optimal manner for the
dynamic linker, before writing them out. */
@@ -6002,6 +6123,12 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd,
elf_x86_64_finish_local_dynamic_symbol,
info);
+ /* Fill PLT entries for undefined weak symbols in PIE. */
+ if (bfd_link_pie (info))
+ bfd_hash_traverse (&info->hash->table,
+ elf_x86_64_pie_finish_undefweak_symbol,
+ info);
+
return TRUE;
}
@@ -6413,6 +6540,8 @@ static const struct bfd_elf_special_section
elf_x86_64_hash_symbol
#define elf_backend_omit_section_dynsym \
((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
+#define elf_backend_fixup_symbol \
+ elf_x86_64_fixup_symbol
#include "elf64-target.h"