#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
pointers must reference the descriptor. Thus, a function pointer
initialized to the address of a function in a shared library will
either require a copy reloc, or a dynamic reloc. Using a copy reloc
- redefines the function desctriptor symbol to point to the copy. This
+ redefines the function descriptor symbol to point to the copy. This
presents a problem as a plt entry for that function is also
initialized from the function descriptor symbol and the copy reloc
may not be initialized first. */
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.
eh->is_func = 0;
eh->is_func_descriptor = 0;
eh->is_entry = 0;
+ eh->adjust_done = 0;
eh->tls_mask = 0;
}
if (info->relocatable)
return TRUE;
+ /* Don't do anything special with non-loaded, non-alloced sections.
+ In particular, any relocs in such sections should not affect GOT
+ and PLT reference counting (ie. we don't allow them to create GOT
+ or PLT entries), there's no possibility or desire to optimize TLS
+ relocs, and there's not much point in propagating relocs to shared
+ libs that the dynamic linker won't relocate. */
+ if ((sec->flags & SEC_ALLOC) == 0)
+ return TRUE;
+
htab = ppc_hash_table (info);
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
if (NO_OPD_RELOCS && opd_sym_map != NULL)
break;
- /* Don't propagate relocs that the dynamic linker won't relocate. */
- if ((sec->flags & SEC_ALLOC) == 0)
- break;
-
/* If we are creating a shared library, and this is a reloc
against a global symbol, or a non PC relative reloc
against a local symbol, then we need to copy the reloc
struct got_entry **local_got_ents;
const Elf_Internal_Rela *rel, *relend;
+ if ((sec->flags & SEC_ALLOC) == 0)
+ return TRUE;
+
elf_section_data (sec)->local_dynrel = NULL;
htab = ppc_hash_table (info);
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)
{
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);
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);
}
}
+ if (some_edited)
+ elf_link_hash_traverse (elf_hash_table (info), adjust_opd_syms, NULL);
+
return TRUE;
}
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;
}
/* .plt is in the bss section. We don't initialise it. */
- if ((s->flags & SEC_LOAD) == 0)
+ if (s == htab->plt)
continue;
/* Allocate memory for the section contents. We use bfd_zalloc
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];
}
}
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. */