* 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. * 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.
This commit is contained in:
parent
4b6f5fd267
commit
699733f62e
|
@ -1,3 +1,16 @@
|
|||
2004-08-28 Alan Modra <amodra@bigpond.net.au>
|
||||
|
||||
* 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.
|
||||
|
||||
* 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.
|
||||
|
||||
2004-08-27 Alan Modra <amodra@bigpond.net.au>
|
||||
|
||||
* elf64-ppc.c (STD_R0_0R1, STD_R0_0R12, LD_R0_0R1, LD_R0_0R12,
|
||||
|
|
396
bfd/elf64-ppc.c
396
bfd/elf64-ppc.c
|
@ -2153,7 +2153,8 @@ ppc64_elf_branch_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
|
|||
return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
|
||||
input_section, output_bfd, error_message);
|
||||
|
||||
if (strcmp (symbol->section->name, ".opd") == 0)
|
||||
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,
|
||||
|
@ -2549,7 +2550,7 @@ get_opd_info (asection * sec)
|
|||
static asection *synthetic_opd;
|
||||
static bfd_boolean synthetic_relocatable;
|
||||
|
||||
/* Helper routine for ppc64_elf_get_synthetic_symtab. */
|
||||
/* qsort comparison function for ppc64_elf_get_synthetic_symtab. */
|
||||
|
||||
static int
|
||||
compare_symbols (const void *ap, const void *bp)
|
||||
|
@ -2557,16 +2558,19 @@ compare_symbols (const void *ap, const void *bp)
|
|||
const asymbol *a = * (const asymbol **) ap;
|
||||
const asymbol *b = * (const asymbol **) bp;
|
||||
|
||||
if ((a->flags & BSF_SECTION_SYM) == 0 && (b->flags & BSF_SECTION_SYM))
|
||||
/* 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) == 0)
|
||||
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))
|
||||
|
@ -2597,37 +2601,59 @@ compare_symbols (const void *ap, const void *bp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Helper routine for ppc64_elf_get_synthetic_symtab. */
|
||||
/* Search SYMS for a symbol of the given VALUE. */
|
||||
|
||||
static int
|
||||
compare_relocs (const void *ap, const void *bp)
|
||||
static asymbol *
|
||||
sym_exists_at (asymbol **syms, long lo, long hi, int id, bfd_vma value)
|
||||
{
|
||||
const arelent *a = * (const arelent **) ap;
|
||||
const arelent *b = * (const arelent **) bp;
|
||||
long mid;
|
||||
|
||||
if (a->address < b->address)
|
||||
return -1;
|
||||
|
||||
if (a->address > b->address)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
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. */
|
||||
/* 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;
|
||||
bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
|
||||
arelent **relocs, **r;
|
||||
long count, i;
|
||||
size_t size;
|
||||
long i;
|
||||
long count;
|
||||
char *names;
|
||||
asymbol **syms = NULL;
|
||||
long symcount = 0, opdsymcount, relcount;
|
||||
asection *relopd, *opd;
|
||||
long symcount = 0, codesecsym, codesecsymend, secsymend, opdsymend;
|
||||
asection *opd;
|
||||
bfd_boolean relocatable = (abfd->flags & (EXEC_P | DYNAMIC)) == 0;
|
||||
|
||||
*ret = NULL;
|
||||
|
@ -2691,61 +2717,50 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd, asymbol **relsyms, asymbol **ret)
|
|||
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;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
if (syms[i]->section == opd)
|
||||
continue;
|
||||
++i;
|
||||
codesecsym = i;
|
||||
|
||||
if (opdsymcount == symcount)
|
||||
opdsymcount = 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))
|
||||
{
|
||||
symcount = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
symcount = i;
|
||||
|
||||
if (opdsymcount == 0)
|
||||
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;
|
||||
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;
|
||||
|
||||
|
@ -2755,76 +2770,32 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd, asymbol **relsyms, asymbol **ret)
|
|||
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)
|
||||
for (i = secsymend, r = relopd->relocation; i < opdsymend; ++i)
|
||||
{
|
||||
long lo, hi, mid;
|
||||
asymbol *sym;
|
||||
|
||||
while (r < relocs + relcount
|
||||
&& (*r)->address < syms[i]->value + opd->vma)
|
||||
while (r < relopd->relocation + 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
|
||||
if (r == relopd->relocation + relcount)
|
||||
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)
|
||||
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) + 1;
|
||||
size += strlen (syms[i]->name) + 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2832,101 +2803,140 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd, asymbol **relsyms, asymbol **ret)
|
|||
if (s == NULL)
|
||||
{
|
||||
free (syms);
|
||||
free (relocs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
names = (char *) (s + count);
|
||||
|
||||
for (i = 0, r = relocs; i < opdsymcount; ++i)
|
||||
for (i = secsymend, r = relopd->relocation; i < opdsymend; ++i)
|
||||
{
|
||||
long lo, hi, mid;
|
||||
asymbol *sym;
|
||||
|
||||
while (r < relocs + relcount
|
||||
&& (*r)->address < syms[i]->value + opd->vma)
|
||||
while (r < relopd->relocation + 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
|
||||
if (r == relopd->relocation + relcount)
|
||||
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)
|
||||
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];
|
||||
|
||||
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->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);
|
||||
free (relocs);
|
||||
return count;
|
||||
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
|
||||
|
@ -5050,8 +5060,8 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
|
|||
|
||||
struct sfpr_def_parms
|
||||
{
|
||||
const char *name;
|
||||
unsigned int lo, hi;
|
||||
const char name[12];
|
||||
unsigned char lo, hi;
|
||||
bfd_byte * (*write_ent) (bfd *, bfd_byte *, int);
|
||||
bfd_byte * (*write_tail) (bfd *, bfd_byte *, int);
|
||||
};
|
||||
|
@ -5065,7 +5075,7 @@ sfpr_define (struct bfd_link_info *info, const struct sfpr_def_parms *parm)
|
|||
unsigned int i;
|
||||
size_t len = strlen (parm->name);
|
||||
bfd_boolean writing = FALSE;
|
||||
char sym[20];
|
||||
char sym[16];
|
||||
|
||||
memcpy (sym, parm->name, len);
|
||||
sym[len + 2] = 0;
|
||||
|
|
Loading…
Reference in New Issue