diff options
-rw-r--r-- | bfd/ChangeLog | 14 | ||||
-rw-r--r-- | bfd/bfd-in2.h | 4 | ||||
-rw-r--r-- | bfd/bfd.c | 4 | ||||
-rw-r--r-- | bfd/elf.c | 7 | ||||
-rw-r--r-- | bfd/elf64-ppc.c | 384 | ||||
-rw-r--r-- | bfd/elfxx-target.h | 2 | ||||
-rw-r--r-- | binutils/ChangeLog | 5 | ||||
-rw-r--r-- | binutils/objdump.c | 14 |
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)) @@ -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)) @@ -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; } |