return _bfd_elf_new_section_hook (abfd, sec);
}
+
+static void *
+get_opd_info (asection * sec)
+{
+ if (sec != NULL
+ && ppc64_elf_section_data (sec) != NULL
+ && ppc64_elf_section_data (sec)->opd.adjust != NULL)
+ return ppc64_elf_section_data (sec)->opd.adjust;
+ return NULL;
+}
\f
/* The following functions are specific to the ELF linker, while
functions above are used generally. Those named ppc64_elf_* are
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)
+ opd_adjust = get_opd_info (sym_sec);
+ if (opd_adjust != NULL)
{
eh->elf.root.u.def.value += opd_adjust[eh->elf.root.u.def.value / 24];
+ long adjust = opd_adjust[eh->elf.root.u.def.value / 24];
+ if (adjust == -1)
+ {
+ /* This entry has been deleted. */
+ eh->elf.root.u.def.value = 0;
+ eh->elf.root.u.def.section = &bfd_abs_section;
+ }
+ else
+ eh->elf.root.u.def.value += adjust;
eh->adjust_done = 1;
}
return TRUE;
struct elf_link_hash_entry **sym_hashes;
bfd_vma offset;
bfd_size_type amt;
- long *adjust;
+ long *opd_adjust;
bfd_boolean need_edit;
sec = bfd_get_section_by_name (ibfd, ".opd");
continue;
amt = sec->size * sizeof (long) / 24;
- adjust = ppc64_elf_section_data (sec)->opd.adjust;
- if (adjust == NULL)
+ opd_adjust = get_opd_info (sec);
+ if (opd_adjust == NULL)
{
/* Must be a ld -r link. ie. check_relocs hasn't been
called. */
- adjust = bfd_zalloc (obfd, amt);
- ppc64_elf_section_data (sec)->opd.adjust = adjust;
+ opd_adjust = bfd_zalloc (obfd, amt);
+ ppc64_elf_section_data (sec)->opd.adjust = opd_adjust;
}
- memset (adjust, 0, amt);
+ memset (opd_adjust, 0, amt);
if (sec->output_section == bfd_abs_section_ptr)
continue;
if (rel->r_offset == offset)
{
struct ppc_link_hash_entry *fdh = NULL;
- if (h != NULL)
+ if (h != NULL
+ && h->root.root.string[0] == '.')
fdh = get_fdh ((struct ppc_link_hash_entry *) h,
ppc_hash_table (info));
|| sym_sec->output_section == bfd_abs_section_ptr);
if (skip)
{
- if (h != NULL && sym_sec->owner == ibfd)
+ if (fdh != NULL && sym_sec->owner == ibfd)
{
/* Arrange for the function descriptor sym
to be dropped. */
fdh->elf.root.u.def.value = 0;
fdh->elf.root.u.def.section = sym_sec;
}
+ opd_adjust[rel->r_offset / 24] = -1;
}
else
{
/* We'll be keeping this opd entry. */
- if (h != NULL)
+ if (fdh != NULL)
{
/* Redefine the function descriptor symbol to
this location in the opd section. It is
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;
+ opd_adjust[rel->r_offset / 24] = wptr - rptr;
if (wptr != rptr)
memcpy (wptr, rptr, 24);
value = h->root.u.def.value;
}
else
- {
- 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];
- }
- }
+ /* Symbols referenced by TLS relocs must be of type
+ STT_TLS. So no need for .opd local sym adjust. */
+ value = sym->st_value;
ok_tprel = FALSE;
is_local = FALSE;
if (r_symndx < symtab_hdr->sh_info)
{
/* It's a local symbol. */
+ long *opd_adjust;
+
sym = local_syms + r_symndx;
sec = local_sections[r_symndx];
sym_name = bfd_elf_local_sym_name (input_bfd, sym);
sym_type = ELF64_ST_TYPE (sym->st_info);
relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
- if (elf_section_data (sec) != NULL)
+ opd_adjust = get_opd_info (sec);
+ if (opd_adjust != NULL)
{
- long *opd_sym_adjust;
-
- opd_sym_adjust = ppc64_elf_section_data (sec)->opd.adjust;
- if (opd_sym_adjust != NULL)
- relocation += opd_sym_adjust[sym->st_value / 24];
+ long adjust = opd_adjust[(sym->st_value + rel->r_addend) / 24];
+ if (adjust == -1)
+ relocation = 0;
+ else
+ relocation += adjust;
}
}
else
asection *input_sec,
struct elf_link_hash_entry *h)
{
- long *adjust;
+ long *opd_adjust, 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)
+ if (h != NULL)
+ return TRUE;
+
+ opd_adjust = get_opd_info (input_sec);
+ if (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];
+ adjust = opd_adjust[value / 24];
+ if (adjust == -1)
+ elfsym->st_value = 0;
+ else
+ elfsym->st_value += adjust;
return TRUE;
}