aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf64-ppc.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/elf64-ppc.c')
-rw-r--r--bfd/elf64-ppc.c122
1 files changed, 106 insertions, 16 deletions
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 1282b3b..3ed9042 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -92,6 +92,7 @@ static bfd_reloc_status_type ppc64_elf_unhandled_reloc
#define elf_backend_finish_dynamic_symbol ppc64_elf_finish_dynamic_symbol
#define elf_backend_reloc_type_class ppc64_elf_reloc_type_class
#define elf_backend_finish_dynamic_sections ppc64_elf_finish_dynamic_sections
+#define elf_backend_link_output_symbol_hook ppc64_elf_output_symbol_hook
#define elf_backend_special_sections ppc64_elf_special_sections
/* The name of the dynamic interpreter. This is put in the .interp
@@ -2762,6 +2763,9 @@ struct ppc_link_hash_entry
unsigned int is_func_descriptor:1;
unsigned int is_entry:1;
+ /* Whether global opd sym has been adjusted or not. */
+ unsigned int adjust_done:1;
+
/* Contexts in which symbol is used in the GOT (or TOC).
TLS_GD .. TLS_EXPLICIT bits are or'd into the mask as the
corresponding relocs are encountered during check_relocs.
@@ -2971,6 +2975,7 @@ link_hash_newfunc (struct bfd_hash_entry *entry,
eh->is_func = 0;
eh->is_func_descriptor = 0;
eh->is_entry = 0;
+ eh->adjust_done = 0;
eh->tls_mask = 0;
}
@@ -4875,10 +4880,53 @@ get_tls_mask (char **tls_maskp, unsigned long *toc_symndx,
return 1;
}
+/* Adjust all global syms defined in opd sections. In gcc generated
+ code these will already have been done, but I suppose we have to
+ cater for all sorts of hand written assembly. */
+
+static bfd_boolean
+adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
+{
+ struct ppc_link_hash_entry *eh;
+ asection *sym_sec;
+ long *opd_adjust;
+
+ if (h->root.type == bfd_link_hash_indirect)
+ return TRUE;
+
+ if (h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ if (h->root.type != bfd_link_hash_defined
+ && h->root.type != bfd_link_hash_defweak)
+ return TRUE;
+
+ eh = (struct ppc_link_hash_entry *) h;
+ if (eh->adjust_done)
+ return TRUE;
+
+ sym_sec = eh->elf.root.u.def.section;
+ if (sym_sec != NULL
+ && elf_section_data (sym_sec) != NULL
+ && (opd_adjust = ppc64_elf_section_data (sym_sec)->opd.adjust) != NULL)
+ {
+ eh->elf.root.u.def.value += opd_adjust[eh->elf.root.u.def.value / 24];
+ eh->adjust_done = 1;
+ }
+ return TRUE;
+}
+
+/* Remove unused Official Procedure Descriptor entries. Currently we
+ only remove those associated with functions in discarded link-once
+ sections, or weakly defined functions that have been overridden. It
+ would be possible to remove many more entries for statically linked
+ applications. */
+
bfd_boolean
ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
{
bfd *ibfd;
+ bfd_boolean some_edited = FALSE;
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
{
@@ -5079,22 +5127,24 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
if (h != NULL)
{
- /* Redefine the function descriptor symbol
- to this location in the opd section.
- We've checked above that opd relocs are
- ordered. */
+ /* Redefine the function descriptor symbol to
+ this location in the opd section. It is
+ necessary to update the value here rather
+ than using an array of adjustments as we do
+ for local symbols, because various places
+ in the generic ELF code use the value
+ stored in u.def.value. */
fdh->elf.root.u.def.value = wptr - sec->contents;
+ fdh->adjust_done = 1;
}
- else
- {
- /* Local syms are a bit tricky. We could
- tweak them as they can be cached, but
- we'd need to look through the local syms
- for the function descriptor sym which we
- don't have at the moment. So keep an
- array of adjustments. */
- adjust[rel->r_offset / 24] = wptr - rptr;
- }
+
+ /* Local syms are a bit tricky. We could
+ tweak them as they can be cached, but
+ we'd need to look through the local syms
+ for the function descriptor sym which we
+ don't have at the moment. So keep an
+ array of adjustments. */
+ adjust[rel->r_offset / 24] = wptr - rptr;
if (wptr != rptr)
memcpy (wptr, rptr, 24);
@@ -5153,6 +5203,7 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
elf_section_data (sec)->rel_hdr.sh_size
= sec->reloc_count * elf_section_data (sec)->rel_hdr.sh_entsize;
BFD_ASSERT (elf_section_data (sec)->rel_hdr2 == NULL);
+ some_edited = TRUE;
}
else if (elf_section_data (sec)->relocs != relstart)
free (relstart);
@@ -5167,6 +5218,9 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
}
}
+ if (some_edited)
+ elf_link_hash_traverse (elf_hash_table (info), adjust_opd_syms, NULL);
+
return TRUE;
}
@@ -5262,7 +5316,17 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
value = h->root.u.def.value;
}
else
- value = sym->st_value;
+ {
+ value = sym->st_value;
+
+ if (elf_section_data (sym_sec) != NULL)
+ {
+ long *adjust;
+ adjust = ppc64_elf_section_data (sym_sec)->opd.adjust;
+ if (adjust != NULL)
+ value += adjust[value / 24];
+ }
+ }
ok_tprel = FALSE;
is_local = FALSE;
@@ -7402,7 +7466,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
long *opd_sym_adjust;
opd_sym_adjust = ppc64_elf_section_data (sec)->opd.adjust;
- if (opd_sym_adjust != NULL && sym->st_value % 24 == 0)
+ if (opd_sym_adjust != NULL)
relocation += opd_sym_adjust[sym->st_value / 24];
}
}
@@ -8673,6 +8737,32 @@ ppc64_elf_relocate_section (bfd *output_bfd,
return ret;
}
+/* Adjust the value of any local symbols in opd sections. */
+
+static bfd_boolean
+ppc64_elf_output_symbol_hook (struct bfd_link_info *info,
+ const char *name ATTRIBUTE_UNUSED,
+ Elf_Internal_Sym *elfsym,
+ asection *input_sec,
+ struct elf_link_hash_entry *h)
+{
+ long *adjust;
+ bfd_vma value;
+
+ if (h != NULL
+ || input_sec == NULL
+ || ppc64_elf_section_data (input_sec) == NULL
+ || (adjust = ppc64_elf_section_data (input_sec)->opd.adjust) == NULL)
+ return TRUE;
+
+ value = elfsym->st_value - input_sec->output_offset;
+ if (!info->relocatable)
+ value -= input_sec->output_section->vma;
+
+ elfsym->st_value += adjust[value / 24];
+ return TRUE;
+}
+
/* Finish up dynamic symbol handling. We set the contents of various
dynamic sections here. */