aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog14
-rw-r--r--bfd/bfd-in2.h4
-rw-r--r--bfd/bfd.c4
-rw-r--r--bfd/elf.c7
-rw-r--r--bfd/elf64-ppc.c384
-rw-r--r--bfd/elfxx-target.h2
-rw-r--r--binutils/ChangeLog5
-rw-r--r--binutils/objdump.c14
8 files changed, 426 insertions, 8 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index fc164dc..e4f0e7a 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,17 @@
+2004-08-17 Jakub Jelinek <jakub@redhat.com>
+
+ * elfxx-target.h (bfd_elfNN_get_synthetic_symtab): Only define
+ if not yet defined.
+ * elf64-ppc.c (bfd_elf64_get_synthetic_symtab): Define.
+ (synthetic_opd, synthetic_relocatable): New variables.
+ (compare_symbols, compare_relocs): New helper routines.
+ (ppc64_elf_get_synthetic_symtab): New function.
+ * bfd.c (bfd_get_synthetic_symtab): Rename dynsyms argument
+ to relsyms.
+ * bfd-in2.h: Regenerated.
+ * elf.c (_bfd_elf_get_synthetic_symtab): Rename dynsyms argument
+ to relsyms. Return 0 if abfd is relocatable.
+
2004-08-17 Alan Modra <amodra@bigpond.net.au>
* elflink.h (elf_gc_sweep): Keep non-alloc, non-load sections.
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 20b7b83..01d6331 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -4109,8 +4109,8 @@ bfd_boolean bfd_set_private_flags (bfd *abfd, flagword flags);
#define bfd_canonicalize_dynamic_symtab(abfd, asymbols) \
BFD_SEND (abfd, _bfd_canonicalize_dynamic_symtab, (abfd, asymbols))
-#define bfd_get_synthetic_symtab(abfd, dynsyms, ret) \
- BFD_SEND (abfd, _bfd_get_synthetic_symtab, (abfd, dynsyms, ret))
+#define bfd_get_synthetic_symtab(abfd, relsyms, ret) \
+ BFD_SEND (abfd, _bfd_get_synthetic_symtab, (abfd, relsyms, ret))
#define bfd_get_dynamic_reloc_upper_bound(abfd) \
BFD_SEND (abfd, _bfd_get_dynamic_reloc_upper_bound, (abfd))
diff --git a/bfd/bfd.c b/bfd/bfd.c
index d888eb1..dc30cfe 100644
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -1218,8 +1218,8 @@ DESCRIPTION
.#define bfd_canonicalize_dynamic_symtab(abfd, asymbols) \
. BFD_SEND (abfd, _bfd_canonicalize_dynamic_symtab, (abfd, asymbols))
.
-.#define bfd_get_synthetic_symtab(abfd, dynsyms, ret) \
-. BFD_SEND (abfd, _bfd_get_synthetic_symtab, (abfd, dynsyms, ret))
+.#define bfd_get_synthetic_symtab(abfd, relsyms, ret) \
+. BFD_SEND (abfd, _bfd_get_synthetic_symtab, (abfd, relsyms, ret))
.
.#define bfd_get_dynamic_reloc_upper_bound(abfd) \
. BFD_SEND (abfd, _bfd_get_dynamic_reloc_upper_bound, (abfd))
diff --git a/bfd/elf.c b/bfd/elf.c
index 387f719..d1fa2c0 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -7744,7 +7744,7 @@ bfd_elf_bfd_from_remote_memory
}
long
-_bfd_elf_get_synthetic_symtab (bfd *abfd, asymbol **dynsyms, asymbol **ret)
+_bfd_elf_get_synthetic_symtab (bfd *abfd, asymbol **relsyms, asymbol **ret)
{
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
asection *relplt;
@@ -7758,6 +7758,9 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd, asymbol **dynsyms, asymbol **ret)
char *names;
asection *plt;
+ if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0)
+ return 0;
+
*ret = NULL;
if (!bed->plt_sym_val)
return 0;
@@ -7779,7 +7782,7 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd, asymbol **dynsyms, asymbol **ret)
return 0;
slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
- if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE))
+ if (! (*slurp_relocs) (abfd, relplt, relsyms, TRUE))
return -1;
count = relplt->size / hdr->sh_entsize;
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 7f89359..ed679c2 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -79,6 +79,7 @@ static bfd_vma opd_entry_value
#define bfd_elf64_new_section_hook ppc64_elf_new_section_hook
#define bfd_elf64_bfd_link_hash_table_create ppc64_elf_link_hash_table_create
#define bfd_elf64_bfd_link_hash_table_free ppc64_elf_link_hash_table_free
+#define bfd_elf64_get_synthetic_symtab ppc64_elf_get_synthetic_symtab
#define elf_backend_object_p ppc64_elf_object_p
#define elf_backend_grok_prstatus ppc64_elf_grok_prstatus
@@ -2536,6 +2537,389 @@ get_opd_info (asection * sec)
return NULL;
}
+/* Parameters for the qsort hook. */
+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)
+{
+ 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))
+ != (SEC_CODE | SEC_ALLOC))
+ 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))
+ == (SEC_CODE | SEC_ALLOC))
+ return 1;
+
+ if (synthetic_relocatable)
+ {
+ if (a->section->id < b->section->id)
+ return -1;
+
+ if (a->section->id > b->section->id)
+ return 1;
+ }
+
+ if (a->value + a->section->vma < b->value + b->section->vma)
+ return -1;
+
+ if (a->value + a->section->vma > b->value + b->section->vma)
+ return 1;
+
+ 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;
+
+ opd = bfd_get_section_by_name (abfd, ".opd");
+ if (opd == NULL)
+ return 0;
+
+ if ((bfd_get_file_flags (abfd) & HAS_SYMS))
+ {
+ long storage;
+ storage = bfd_get_symtab_upper_bound (abfd);
+ if (storage < 0)
+ return 0;
+
+ if (storage)
+ {
+ syms = bfd_malloc (storage);
+ if (syms == NULL)
+ return 0;
+ }
+
+ symcount = bfd_canonicalize_symtab (abfd, syms);
+ if (symcount < 0)
+ {
+ free (syms);
+ return 0;
+ }
+
+ if (symcount == 0)
+ {
+ free (syms);
+ syms = NULL;
+ }
+ }
+
+ if (symcount == 0)
+ {
+ long storage;
+
+ storage = bfd_get_dynamic_symtab_upper_bound (abfd);
+ if (storage < 0)
+ return 0;
+
+ if (storage)
+ {
+ syms = bfd_malloc (storage);
+ if (syms == NULL)
+ return 0;
+ }
+
+ symcount = bfd_canonicalize_dynamic_symtab (abfd, syms);
+ if (symcount < 0)
+ {
+ free (syms);
+ return 0;
+ }
+ }
+
+ synthetic_opd = opd;
+ 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;
+
+ if (! relcount
+ || ! (*slurp_relocs) (abfd, relopd, relsyms, FALSE))
+ {
+ 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
called by the main ELF linker code. They appear in this file more
diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
index b086112..572e8e8 100644
--- a/bfd/elfxx-target.h
+++ b/bfd/elfxx-target.h
@@ -34,8 +34,10 @@
#define bfd_elfNN_canonicalize_dynamic_symtab \
_bfd_elf_canonicalize_dynamic_symtab
+#ifndef bfd_elfNN_get_synthetic_symtab
#define bfd_elfNN_get_synthetic_symtab \
_bfd_elf_get_synthetic_symtab
+#endif
#ifndef bfd_elfNN_canonicalize_reloc
#define bfd_elfNN_canonicalize_reloc _bfd_elf_canonicalize_reloc
#endif
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index e00ad96..958a26a 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,8 @@
+2004-08-17 Jakub Jelinek <jakub@redhat.com>
+
+ * objdump.c (dump_bfd): For relocatable objects, pass syms instead
+ of dynsyms to bfd_get_synthetic_symtab.
+
2004-08-16 Alan Modra <amodra@bigpond.net.au>
* readelf.c (debug_apply_rela_addends): New function, extracted from..
diff --git a/binutils/objdump.c b/binutils/objdump.c
index 7cc9640..af04b70 100644
--- a/binutils/objdump.c
+++ b/binutils/objdump.c
@@ -2564,9 +2564,19 @@ dump_bfd (bfd *abfd)
if (dump_dynamic_symtab || dump_dynamic_reloc_info
|| (disassemble && bfd_get_dynamic_symtab_upper_bound (abfd) > 0))
dynsyms = slurp_dynamic_symtab (abfd);
- if (disassemble && dynsymcount > 0)
+ if (disassemble)
{
- synthcount = bfd_get_synthetic_symtab (abfd, dynsyms, &synthsyms);
+ synthcount = 0;
+ if (bfd_get_file_flags (abfd) & (DYNAMIC | EXEC_P))
+ {
+ if (dynsymcount > 0)
+ synthcount = bfd_get_synthetic_symtab (abfd, dynsyms, &synthsyms);
+ }
+ else
+ {
+ if (symcount > 0)
+ synthcount = bfd_get_synthetic_symtab (abfd, syms, &synthsyms);
+ }
if (synthcount < 0) synthcount = 0;
}