ppc64 synthetic symtab
Alan Modra
amodra@bigpond.net.au
Fri Aug 27 14:56:00 GMT 2004
A couple of minor fixes.
* elf64-ppc.c (ppc64_elf_branch_reloc): Check .opd is in a regular
object file.
(struct sfpr_def_parms): Save some space.
(sfpr_define): Here too.
And some surgery on the new code to recreate dot-symbols. The problem
I'm fixing here is that we were relying on .opd relocs to find function
entry points. That's necessary for relocatable files, but fails badly
on non-pie executables because all of the .opd relocs have been resolved.
* elf64-ppc.c (compare_symbols): Put section syms first.
(sym_exists_at): New function.
(ppc64_elf_get_synthetic_symtab): Use relocs to find code entry
points only for relocatable files. Use .opd section contents
otherwise. Generally clean up the code.
Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.167
diff -c -p -r1.167 elf64-ppc.c
*** bfd/elf64-ppc.c 27 Aug 2004 07:54:00 -0000 1.167
--- bfd/elf64-ppc.c 27 Aug 2004 14:11:30 -0000
*************** ppc64_elf_branch_reloc (bfd *abfd, arele
*** 2153,2159 ****
return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
input_section, output_bfd, error_message);
! if (strcmp (symbol->section->name, ".opd") == 0)
{
bfd_vma dest = opd_entry_value (symbol->section,
symbol->value + reloc_entry->addend,
--- 2153,2160 ----
return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
input_section, output_bfd, error_message);
! if (strcmp (symbol->section->name, ".opd") == 0
! && (symbol->section->owner->flags & DYNAMIC) == 0)
{
bfd_vma dest = opd_entry_value (symbol->section,
symbol->value + reloc_entry->addend,
*************** get_opd_info (asection * sec)
*** 2549,2555 ****
static asection *synthetic_opd;
static bfd_boolean synthetic_relocatable;
! /* Helper routine for ppc64_elf_get_synthetic_symtab. */
static int
compare_symbols (const void *ap, const void *bp)
--- 2550,2556 ----
static asection *synthetic_opd;
static bfd_boolean synthetic_relocatable;
! /* qsort comparison function for ppc64_elf_get_synthetic_symtab. */
static int
compare_symbols (const void *ap, const void *bp)
*************** compare_symbols (const void *ap, const v
*** 2557,2572 ****
const asymbol *a = * (const asymbol **) ap;
const asymbol *b = * (const asymbol **) bp;
! if ((a->flags & BSF_SECTION_SYM) == 0 && (b->flags & BSF_SECTION_SYM))
return -1;
! if ((a->flags & BSF_SECTION_SYM) && (b->flags & BSF_SECTION_SYM) == 0)
return 1;
if (a->section == synthetic_opd && b->section != synthetic_opd)
return -1;
if (a->section != synthetic_opd && b->section == synthetic_opd)
return 1;
if ((a->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
== (SEC_CODE | SEC_ALLOC)
&& (b->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
--- 2558,2576 ----
const asymbol *a = * (const asymbol **) ap;
const asymbol *b = * (const asymbol **) bp;
! /* Section symbols first. */
! if ((a->flags & BSF_SECTION_SYM) && !(b->flags & BSF_SECTION_SYM))
return -1;
! if (!(a->flags & BSF_SECTION_SYM) && (b->flags & BSF_SECTION_SYM))
return 1;
+ /* then .opd symbols. */
if (a->section == synthetic_opd && b->section != synthetic_opd)
return -1;
if (a->section != synthetic_opd && b->section == synthetic_opd)
return 1;
+ /* then other code symbols. */
if ((a->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
== (SEC_CODE | SEC_ALLOC)
&& (b->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
*************** compare_symbols (const void *ap, const v
*** 2597,2633 ****
return 0;
}
! /* Helper routine for ppc64_elf_get_synthetic_symtab. */
! static int
! compare_relocs (const void *ap, const void *bp)
{
! const arelent *a = * (const arelent **) ap;
! const arelent *b = * (const arelent **) bp;
!
! if (a->address < b->address)
! return -1;
!
! if (a->address > b->address)
! return 1;
! return 0;
}
! /* Create synthetic symbols. */
static long
ppc64_elf_get_synthetic_symtab (bfd *abfd, asymbol **relsyms, asymbol **ret)
{
asymbol *s;
! bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
! arelent **relocs, **r;
! long count, i;
! size_t size;
char *names;
asymbol **syms = NULL;
! long symcount = 0, opdsymcount, relcount;
! asection *relopd, *opd;
bfd_boolean relocatable = (abfd->flags & (EXEC_P | DYNAMIC)) == 0;
*ret = NULL;
--- 2601,2659 ----
return 0;
}
! /* Search SYMS for a symbol of the given VALUE. */
! static asymbol *
! sym_exists_at (asymbol **syms, long lo, long hi, int id, bfd_vma value)
{
! long mid;
! if (id == -1)
! {
! while (lo < hi)
! {
! mid = (lo + hi) >> 1;
! if (syms[mid]->value + syms[mid]->section->vma < value)
! lo = mid + 1;
! else if (syms[mid]->value + syms[mid]->section->vma > value)
! hi = mid;
! else
! return syms[mid];
! }
! }
! else
! {
! while (lo < hi)
! {
! mid = (lo + hi) >> 1;
! if (syms[mid]->section->id < id)
! lo = mid + 1;
! else if (syms[mid]->section->id > id)
! hi = mid;
! else if (syms[mid]->value < value)
! lo = mid + 1;
! else if (syms[mid]->value > value)
! hi = mid;
! else
! return syms[mid];
! }
! }
! return NULL;
}
! /* Create synthetic symbols, effectively restoring "dot-symbol" function
! entry syms. */
static long
ppc64_elf_get_synthetic_symtab (bfd *abfd, asymbol **relsyms, asymbol **ret)
{
asymbol *s;
! long i;
! long count;
char *names;
asymbol **syms = NULL;
! long symcount = 0, codesecsym, codesecsymend, secsymend, opdsymend;
! asection *opd;
bfd_boolean relocatable = (abfd->flags & (EXEC_P | DYNAMIC)) == 0;
*ret = NULL;
*************** ppc64_elf_get_synthetic_symtab (bfd *abf
*** 2691,2751 ****
synthetic_relocatable = relocatable;
qsort (syms, symcount, sizeof (asymbol *), compare_symbols);
! opdsymcount = symcount;
! for (i = 0; i < symcount; ++i)
! {
! if (syms[i]->flags & BSF_SECTION_SYM)
! {
! if (opdsymcount == symcount)
! opdsymcount = i;
! symcount = i;
! break;
! }
! if (syms[i]->section == opd)
! continue;
! if (opdsymcount == symcount)
! opdsymcount = i;
! if ((syms[i]->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
! != (SEC_CODE | SEC_ALLOC))
! {
! symcount = i;
! break;
! }
! }
! if (opdsymcount == 0)
{
free (syms);
return 0;
}
! slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
! if (! relocatable)
{
! relopd = bfd_get_section_by_name (abfd, ".rela.opd");
! if (relopd == NULL)
! {
! relopd = bfd_get_section_by_name (abfd, ".rela.dyn");
! if (relopd == NULL)
! {
! free (syms);
! return 0;
! }
! }
! relcount = relopd->size / 24;
! if (! relcount
! || ! (*slurp_relocs) (abfd, relopd, relsyms, TRUE))
! {
! free (syms);
! return 0;
! }
! }
! else
! {
relopd = opd;
relcount = (opd->flags & SEC_RELOC) ? opd->reloc_count : 0;
--- 2717,2766 ----
synthetic_relocatable = relocatable;
qsort (syms, symcount, sizeof (asymbol *), compare_symbols);
! i = 0;
! if (syms[i]->section == opd)
! ++i;
! codesecsym = i;
! for (; i < symcount; ++i)
! if (((syms[i]->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
! != (SEC_CODE | SEC_ALLOC))
! || (syms[i]->flags & BSF_SECTION_SYM) == 0)
! break;
! codesecsymend = i;
! for (; i < symcount; ++i)
! if ((syms[i]->flags & BSF_SECTION_SYM) == 0)
! break;
! secsymend = i;
! for (; i < symcount; ++i)
! if (syms[i]->section != opd)
! break;
! opdsymend = i;
! for (; i < symcount; ++i)
! if ((syms[i]->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
! != (SEC_CODE | SEC_ALLOC))
! break;
! symcount = i;
!
! if (opdsymend == secsymend)
{
free (syms);
return 0;
}
! count = 0;
! if (relocatable)
{
! bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
! arelent *r;
! size_t size;
! long relcount;
! asection *relopd;
! slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
relopd = opd;
relcount = (opd->flags & SEC_RELOC) ? opd->reloc_count : 0;
*************** ppc64_elf_get_synthetic_symtab (bfd *abf
*** 2755,2932 ****
free (syms);
return 0;
}
- }
! relocs = bfd_malloc (relcount * sizeof (arelent **));
! if (relocs == NULL)
! {
! free (syms);
! return 0;
! }
! for (i = 0; i < relcount; ++i)
! relocs[i] = &relopd->relocation[i];
! qsort (relocs, relcount, sizeof (*relocs), compare_relocs);
! size = 0;
! count = 0;
! for (i = 0, r = relocs; i < opdsymcount; ++i)
! {
! long lo, hi, mid;
! asymbol *sym;
! while (r < relocs + relcount
! && (*r)->address < syms[i]->value + opd->vma)
! ++r;
! if (r == relocs + relcount)
! continue;
! if ((*r)->address != syms[i]->value + opd->vma)
! continue;
! if ((*r)->howto->type != (relocatable
! ? R_PPC64_ADDR64 : R_PPC64_RELATIVE))
! continue;
! lo = opdsymcount;
! hi = symcount;
! sym = *((*r)->sym_ptr_ptr);
! if (relocatable)
! while (lo < hi)
! {
! mid = (lo + hi) >> 1;
! if (syms[mid]->section->id < sym->section->id)
! lo = mid + 1;
! else if (syms[mid]->section->id > sym->section->id)
! hi = mid;
! else if (syms[mid]->value < sym->value + (*r)->addend)
! lo = mid + 1;
! else if (syms[mid]->value > sym->value + (*r)->addend)
! hi = mid;
! else
! break;
! }
! else
! while (lo < hi)
! {
! mid = (lo + hi) >> 1;
! if (syms[mid]->value + syms[mid]->section->vma < (*r)->addend)
! lo = mid + 1;
! else if (syms[mid]->value + syms[mid]->section->vma > (*r)->addend)
! hi = mid;
! else
! break;
! }
!
! if (lo >= hi)
{
! ++count;
! size += sizeof (asymbol);
! size += strlen (syms[i]->name) + 1;
! }
! }
! s = *ret = bfd_malloc (size);
! if (s == NULL)
! {
! free (syms);
! free (relocs);
! return 0;
! }
! names = (char *) (s + count);
! for (i = 0, r = relocs; i < opdsymcount; ++i)
{
! long lo, hi, mid;
! asymbol *sym;
! while (r < relocs + relcount
! && (*r)->address < syms[i]->value + opd->vma)
! ++r;
! if (r == relocs + relcount)
! continue;
! if ((*r)->address != syms[i]->value + opd->vma)
! continue;
! if ((*r)->howto->type != (relocatable
! ? R_PPC64_ADDR64 : R_PPC64_RELATIVE))
! continue;
! lo = opdsymcount;
! hi = symcount;
! sym = *((*r)->sym_ptr_ptr);
! if (relocatable)
! while (lo < hi)
! {
! mid = (lo + hi) >> 1;
! if (syms[mid]->section->id < sym->section->id)
! lo = mid + 1;
! else if (syms[mid]->section->id > sym->section->id)
! hi = mid;
! else if (syms[mid]->value < sym->value + (*r)->addend)
! lo = mid + 1;
! else if (syms[mid]->value > sym->value + (*r)->addend)
! hi = mid;
! else
! break;
! }
! else
! while (lo < hi)
! {
! mid = (lo + hi) >> 1;
! if (syms[mid]->value + syms[mid]->section->vma < (*r)->addend)
! lo = mid + 1;
! else if (syms[mid]->value + syms[mid]->section->vma > (*r)->addend)
! hi = mid;
! else
! break;
! }
! if (lo >= hi)
{
! size_t len;
! *s = *syms[i];
!
! if (! relocatable)
{
asection *sec;
! s->section = &bfd_abs_section;
! for (sec = abfd->sections; sec; sec = sec->next)
! if ((sec->flags & (SEC_ALLOC | SEC_CODE))
! == (SEC_ALLOC | SEC_CODE)
! && (*r)->addend >= sec->vma
! && (*r)->addend < sec->vma + sec->size)
! {
! s->section = sec;
break;
! }
! s->value = (*r)->addend - sec->vma;
! }
! else
! {
! s->section = sym->section;
! s->value = sym->value + (*r)->addend;
}
- s->name = names;
- len = strlen (syms[i]->name);
- memcpy (names, syms[i]->name, len + 1);
- names += len + 1;
- s++;
}
}
free (syms);
- free (relocs);
return count;
}
-
/* The following functions are specific to the ELF linker, while
functions above are used generally. Those named ppc64_elf_* are
--- 2770,2942 ----
free (syms);
return 0;
}
! size = 0;
! for (i = secsymend, r = relopd->relocation; i < opdsymend; ++i)
! {
! asymbol *sym;
! while (r < relopd->relocation + relcount
! && r->address < syms[i]->value + opd->vma)
! ++r;
! if (r == relopd->relocation + relcount)
! break;
! if (r->address != syms[i]->value + opd->vma)
! continue;
! if (r->howto->type != R_PPC64_ADDR64)
! continue;
! sym = *r->sym_ptr_ptr;
! if (!sym_exists_at (syms, opdsymend, symcount,
! sym->section->id, sym->value + r->addend))
! {
! ++count;
! size += sizeof (asymbol);
! size += strlen (syms[i]->name) + 2;
! }
! }
! s = *ret = bfd_malloc (size);
! if (s == NULL)
! {
! free (syms);
! return 0;
! }
! names = (char *) (s + count);
! for (i = secsymend, r = relopd->relocation; i < opdsymend; ++i)
{
! asymbol *sym;
! while (r < relopd->relocation + relcount
! && r->address < syms[i]->value + opd->vma)
! ++r;
!
! if (r == relopd->relocation + relcount)
! break;
!
! if (r->address != syms[i]->value + opd->vma)
! continue;
!
! if (r->howto->type != R_PPC64_ADDR64)
! continue;
! sym = *r->sym_ptr_ptr;
! if (!sym_exists_at (syms, opdsymend, symcount,
! sym->section->id, sym->value + r->addend))
! {
! size_t len;
! *s = *syms[i];
! s->section = sym->section;
! s->value = sym->value + r->addend;
! s->name = names;
! *names++ = '.';
! len = strlen (syms[i]->name);
! memcpy (names, syms[i]->name, len + 1);
! names += len + 1;
! s++;
! }
! }
! }
! else
{
! bfd_byte *contents;
! size_t size;
! if (!bfd_malloc_and_get_section (abfd, opd, &contents))
! {
! if (contents)
! free (contents);
! free (syms);
! return 0;
! }
! size = 0;
! for (i = secsymend; i < opdsymend; ++i)
! {
! bfd_vma ent;
! ent = bfd_get_64 (abfd, contents + syms[i]->value);
! if (!sym_exists_at (syms, opdsymend, symcount, -1, ent))
! {
! ++count;
! size += sizeof (asymbol);
! size += strlen (syms[i]->name) + 2;
! }
! }
! s = *ret = bfd_malloc (size);
! if (s == NULL)
! {
! free (contents);
! free (syms);
! return 0;
! }
! names = (char *) (s + count);
! for (i = secsymend; i < opdsymend; ++i)
{
! bfd_vma ent;
! ent = bfd_get_64 (abfd, contents + syms[i]->value);
! if (!sym_exists_at (syms, opdsymend, symcount, -1, ent))
{
+ long lo, hi, mid;
+ size_t len;
asection *sec;
! *s = *syms[i];
! lo = codesecsym;
! hi = codesecsymend;
! while (lo < hi)
! {
! mid = (lo + hi) >> 1;
! if (syms[mid]->section->vma < ent)
! lo = mid + 1;
! else if (syms[mid]->section->vma > ent)
! hi = mid;
! else
break;
! }
!
! if (lo < hi)
! sec = syms[mid]->section;
! else if (lo > codesecsym)
! sec = syms[lo - 1]->section;
! else
! sec = abfd->sections;
!
! for (; sec != NULL; sec = sec->next)
! {
! if (sec->vma > ent)
! break;
! if ((sec->flags & SEC_ALLOC) == 0
! || (sec->flags & SEC_LOAD) == 0)
! break;
! if ((sec->flags & SEC_CODE) != 0)
! s->section = sec;
! }
! s->value = ent - s->section->vma;
! s->name = names;
! *names++ = '.';
! len = strlen (syms[i]->name);
! memcpy (names, syms[i]->name, len + 1);
! names += len + 1;
! s++;
}
}
+ free (contents);
}
free (syms);
return count;
}
/* The following functions are specific to the ELF linker, while
functions above are used generally. Those named ppc64_elf_* are
*************** ppc64_elf_gc_sweep_hook (bfd *abfd, stru
*** 5050,5057 ****
struct sfpr_def_parms
{
! const char *name;
! unsigned int lo, hi;
bfd_byte * (*write_ent) (bfd *, bfd_byte *, int);
bfd_byte * (*write_tail) (bfd *, bfd_byte *, int);
};
--- 5060,5067 ----
struct sfpr_def_parms
{
! const char name[12];
! unsigned char lo, hi;
bfd_byte * (*write_ent) (bfd *, bfd_byte *, int);
bfd_byte * (*write_tail) (bfd *, bfd_byte *, int);
};
*************** sfpr_define (struct bfd_link_info *info,
*** 5065,5071 ****
unsigned int i;
size_t len = strlen (parm->name);
bfd_boolean writing = FALSE;
! char sym[20];
memcpy (sym, parm->name, len);
sym[len + 2] = 0;
--- 5075,5081 ----
unsigned int i;
size_t len = strlen (parm->name);
bfd_boolean writing = FALSE;
! char sym[16];
memcpy (sym, parm->name, len);
sym[len + 2] = 0;
--
Alan Modra
IBM OzLabs - Linux Technology Centre
More information about the Binutils
mailing list