ppc64 dot symbols
Alan Modra
amodra@bigpond.net.au
Mon Aug 9 00:22:00 GMT 2004
My local PowerPC64 gcc+binutils no longer uses global "dot" symbols on
function entry points, instead the linker in now clever enough to work
out that a call to the function descriptor sym should go to the location
described therein. That change is relatively simple. More difficult is
ensuring that all combinations of dynamic and static libraries, some
using refereces to "dot" symbols and some using the new convention, all
work together nicely.
I do have some more work to do yet. For instance, objdump dissasembly
isn't very nice at the moment, since .text tends to be one big block of
code without any symbols..
Anyway, in the process of doing the linker changes, I discovered some
bugs in the existing elf64-ppc.c code, and made some cleanups. This
is the first of a number of small changes. Here I show some paranoia
about opd syms..
* elf64-ppc.c (get_opd_info): New function.
(adjust_opd_syms): Use get_opd_info. Define removed symbols as zero.
(ppc64_elf_edit_opd): Use get_opd_info. Check that sym has a dot
before calling get_fdh. Test fdh rather than h before dereferencing
fdh. Mark removed symbols in opd_adjust.
(ppc64_elf_tls_optimize): Don't bother with opd adjustment here.
(ppc64_elf_relocate_section): Use get_opd_info, and handle removed
opd symbols.
(ppc64_elf_output_symbol_hook): Likewise.
Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.149
diff -u -p -r1.149 elf64-ppc.c
--- bfd/elf64-ppc.c 27 Jul 2004 05:16:51 -0000 1.149
+++ bfd/elf64-ppc.c 8 Aug 2004 23:37:23 -0000
@@ -2492,6 +2492,16 @@ ppc64_elf_new_section_hook (bfd *abfd, a
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;
+}
/* The following functions are specific to the ELF linker, while
functions above are used generally. Those named ppc64_elf_* are
@@ -4935,11 +4945,19 @@ adjust_opd_syms (struct elf_link_hash_en
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;
@@ -4966,7 +4984,7 @@ ppc64_elf_edit_opd (bfd *obfd, struct bf
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");
@@ -4974,15 +4992,15 @@ ppc64_elf_edit_opd (bfd *obfd, struct bf
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;
@@ -5134,7 +5152,8 @@ ppc64_elf_edit_opd (bfd *obfd, struct bf
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));
@@ -5142,19 +5161,20 @@ ppc64_elf_edit_opd (bfd *obfd, struct bf
|| 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
@@ -5173,7 +5193,7 @@ ppc64_elf_edit_opd (bfd *obfd, struct bf
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);
@@ -5345,17 +5365,9 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
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;
@@ -7455,18 +7467,21 @@ ppc64_elf_relocate_section (bfd *output_
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
@@ -8745,20 +8760,25 @@ ppc64_elf_output_symbol_hook (struct bfd
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;
}
--
Alan Modra
IBM OzLabs - Linux Technology Centre
More information about the Binutils
mailing list