diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 1aed409983..823a31e78f 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,5 +1,21 @@ Wed Nov 22 12:02:09 1995 Ian Lance Taylor + * ecoff.c (_bfd_ecoff_new_section_hook): Handle .rconst section. + (ecoff_sec_to_styp_flags): Likewise. + (_bfd_ecoff_styp_to_sec_flags): Handle STYP_RCONST. + (ecoff_set_symbol_info): Handle scRConst. + (ecoff_slurp_reloc_table): Handle RELOC_SECTION_RCONST. + (ecoff_compute_section_file_positions): Handle .rconst section. + (_bfd_ecoff_write_object_contents): Likewise. + (ecoff_link_check_archive_element): Handle scRConst. + (ecoff_link_add_externals): Likewise. + (ecoff_link_write_external): Handle .rconst section. + (ecoff_reloc_link_order): Likewise. + * ecofflink.c (bfd_ecoff_debug_accumulate): Handle scRConst. + * coff-alpha.c (alpha_convert_external_reloc): Handle .rconst + section. + (alpha_relocate_section): Handle RELOC_SECTION_RCONST. + * sunos.c (sunos_scan_dynamic_symbol): Only set written if the DEF_DYNAMIC flag is set. diff --git a/bfd/coff-alpha.c b/bfd/coff-alpha.c index bc140a1fda..7675c56736 100644 --- a/bfd/coff-alpha.c +++ b/bfd/coff-alpha.c @@ -1309,6 +1309,8 @@ alpha_convert_external_reloc (output_bfd, info, input_bfd, ext_rel, h) case 'r': if (strcmp (name, ".rdata") == 0) r_symndx = RELOC_SECTION_RDATA; + else if (strcmp (name, ".rconst") == 0) + r_symndx = RELOC_SECTION_RCONST; break; case 's': if (strcmp (name, ".sdata") == 0) @@ -1421,6 +1423,8 @@ alpha_relocate_section (output_bfd, info, input_bfd, input_section, symndx_to_section[RELOC_SECTION_LITA] = bfd_get_section_by_name (input_bfd, ".lita"); symndx_to_section[RELOC_SECTION_ABS] = bfd_abs_section_ptr; + symndx_to_section[RELOC_SECTION_RCONST] = + bfd_get_section_by_name (input_bfd, ".rconst"); ecoff_data (input_bfd)->symndx_to_section = symndx_to_section; } @@ -1976,7 +1980,7 @@ static const struct ecoff_backend_data alpha_ecoff_backend_data = alpha_ecoff_bad_format_hook, _bfd_ecoff_set_arch_mach_hook, alpha_ecoff_mkobject_hook, _bfd_ecoff_styp_to_sec_flags, _bfd_ecoff_set_alignment_hook, _bfd_ecoff_slurp_symbol_table, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, /* Supported architecture. */ bfd_arch_alpha, @@ -2053,6 +2057,10 @@ static const struct ecoff_backend_data alpha_ecoff_backend_data = #define _bfd_ecoff_bfd_get_relocated_section_contents \ alpha_ecoff_get_relocated_section_contents +/* Handling file windows is generic. */ +#define _bfd_ecoff_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window + /* Relaxing sections is generic. */ #define _bfd_ecoff_bfd_relax_section bfd_generic_relax_section diff --git a/bfd/ecoff.c b/bfd/ecoff.c index 80291f5986..c741efe06e 100644 --- a/bfd/ecoff.c +++ b/bfd/ecoff.c @@ -163,7 +163,8 @@ _bfd_ecoff_new_section_hook (abfd, section) section->flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC; else if (strcmp (section->name, _RDATA) == 0 || strcmp (section->name, _LIT8) == 0 - || strcmp (section->name, _LIT4) == 0) + || strcmp (section->name, _LIT4) == 0 + || strcmp (section->name, _RCONST) == 0) section->flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY; else if (strcmp (section->name, _BSS) == 0 || strcmp (section->name, _SBSS) == 0) @@ -335,6 +336,8 @@ ecoff_sec_to_styp_flags (name, flags) styp = STYP_COMMENT; flags &=~ SEC_NEVER_LOAD; } + else if (strcmp (name, _RCONST) == 0) + styp = STYP_RCONST; else if (flags & SEC_CODE) styp = STYP_TEXT; else if (flags & SEC_DATA) @@ -391,14 +394,16 @@ _bfd_ecoff_styp_to_sec_flags (abfd, hdr, name) || (styp_flags & STYP_SDATA) || styp_flags == STYP_PDATA || styp_flags == STYP_XDATA - || (styp_flags & STYP_GOT)) + || (styp_flags & STYP_GOT) + || styp_flags == STYP_RCONST) { if (sec_flags & SEC_NEVER_LOAD) sec_flags |= SEC_DATA | SEC_COFF_SHARED_LIBRARY; else sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC; if ((styp_flags & STYP_RDATA) - || styp_flags == STYP_PDATA) + || styp_flags == STYP_PDATA + || styp_flags == STYP_RCONST) sec_flags |= SEC_READONLY; } else if ((styp_flags & STYP_BSS) @@ -829,6 +834,10 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, weak) asym->section = bfd_make_section_old_way (abfd, ".fini"); asym->value -= asym->section->vma; break; + case scRConst: + asym->section = bfd_make_section_old_way (abfd, ".rconst"); + asym->value -= asym->section->vma; + break; default: break; } @@ -1743,6 +1752,7 @@ ecoff_slurp_reloc_table (abfd, section, symbols) case RELOC_SECTION_PDATA: sec_name = ".pdata"; break; case RELOC_SECTION_FINI: sec_name = ".fini"; break; case RELOC_SECTION_LITA: sec_name = ".lita"; break; + case RELOC_SECTION_RCONST: sec_name = ".rconst"; break; default: abort (); } @@ -2128,11 +2138,12 @@ ecoff_compute_section_file_positions (abfd) the data. */ if ((abfd->flags & EXEC_P) != 0 && (abfd->flags & D_PAGED) != 0 - && first_data != false + && ! first_data && (current->flags & SEC_CODE) == 0 && (! ecoff_backend (abfd)->rdata_in_text || strcmp (current->name, _RDATA) != 0) - && strcmp (current->name, _PDATA) != 0) + && strcmp (current->name, _PDATA) != 0 + && strcmp (current->name, _RCONST) != 0) { sofar = (sofar + round - 1) &~ (round - 1); first_data = false; @@ -2573,7 +2584,8 @@ _bfd_ecoff_write_object_contents (abfd) || (section.s_flags & STYP_DYNSYM) != 0 || (section.s_flags & STYP_HASH) != 0 || (section.s_flags & STYP_ECOFF_INIT) != 0 - || (section.s_flags & STYP_ECOFF_FINI) != 0) + || (section.s_flags & STYP_ECOFF_FINI) != 0 + || section.s_flags == STYP_RCONST) { text_size += bfd_get_section_size_before_reloc (current); if (! set_text_start || text_start > vma) @@ -2810,6 +2822,8 @@ _bfd_ecoff_write_object_contents (abfd) in.r_symndx = RELOC_SECTION_LITA; else if (strcmp (name, "*ABS*") == 0) in.r_symndx = RELOC_SECTION_ABS; + else if (strcmp (name, ".rconst") == 0) + in.r_symndx = RELOC_SECTION_RCONST; else abort (); in.r_extern = 0; @@ -3005,7 +3019,7 @@ _bfd_ecoff_slurp_armap (abfd) /* Read in the armap. */ ardata = bfd_ardata (abfd); - mapdata = _bfd_read_ar_hdr (abfd); + mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd); if (mapdata == (struct areltdata *) NULL) return false; parsed_size = mapdata->parsed_size; @@ -3687,6 +3701,7 @@ ecoff_link_check_archive_element (abfd, info, pneeded) case scSCommon: case scInit: case scFini: + case scRConst: def = true; break; default: @@ -3948,6 +3963,10 @@ ecoff_link_add_externals (abfd, info, external_ext, ssext) section = bfd_make_section_old_way (abfd, ".fini"); value -= section->vma; break; + case scRConst: + section = bfd_make_section_old_way (abfd, ".rconst"); + value -= section->vma; + break; } if (section == (asection *) NULL) @@ -4377,6 +4396,8 @@ ecoff_link_write_external (h, data) h->esym.asym.sc = scPData; else if (strcmp (name, _XDATA) == 0) h->esym.asym.sc = scXData; + else if (strcmp (name, _RCONST) == 0) + h->esym.asym.sc = scRConst; else h->esym.asym.sc = scAbs; } @@ -4585,12 +4606,19 @@ ecoff_reloc_link_order (output_bfd, info, output_section, link_order) asection *output_section; struct bfd_link_order *link_order; { + enum bfd_link_order_type type; + asection *section; + bfd_vma addend; arelent rel; struct internal_reloc in; bfd_size_type external_reloc_size; bfd_byte *rbuf; boolean ok; + type = link_order->type; + section = NULL; + addend = link_order->u.reloc.p->addend; + /* We set up an arelent to pass to the backend adjust_reloc_out routine. */ rel.address = link_order->offset; @@ -4602,21 +4630,44 @@ ecoff_reloc_link_order (output_bfd, info, output_section, link_order) return false; } - if (link_order->type == bfd_section_reloc_link_order) - rel.sym_ptr_ptr = link_order->u.reloc.p->u.section->symbol_ptr_ptr; + if (type == bfd_section_reloc_link_order) + { + section = link_order->u.reloc.p->u.section; + rel.sym_ptr_ptr = section->symbol_ptr_ptr; + } else { - /* We can't set up a reloc against a symbol correctly, because - we have no asymbol structure. Currently no adjust_reloc_out - routine cases. */ - rel.sym_ptr_ptr = (asymbol **) NULL; + struct bfd_link_hash_entry *h; + + /* Treat a reloc against a defined symbol as though it were + actually against the section. */ + h = bfd_link_hash_lookup (info->hash, link_order->u.reloc.p->u.name, + false, false, false); + if (h != NULL + && (h->type == bfd_link_hash_defined + || h->type == bfd_link_hash_defweak)) + { + type = bfd_section_reloc_link_order; + section = h->u.def.section->output_section; + /* It seems that we ought to add the symbol value to the + addend here, but in practice it has already been added + because it was passed to constructor_callback. */ + addend += section->vma + h->u.def.section->output_offset; + } + else + { + /* We can't set up a reloc against a symbol correctly, + because we have no asymbol structure. Currently no + adjust_reloc_out routine cares. */ + rel.sym_ptr_ptr = (asymbol **) NULL; + } } /* All ECOFF relocs are in-place. Put the addend into the object file. */ BFD_ASSERT (rel.howto->partial_inplace); - if (link_order->u.reloc.p->addend != 0) + if (addend != 0) { bfd_size_type size; bfd_reloc_status_type rstat; @@ -4630,8 +4681,7 @@ ecoff_reloc_link_order (output_bfd, info, output_section, link_order) bfd_set_error (bfd_error_no_memory); return false; } - rstat = _bfd_relocate_contents (rel.howto, output_bfd, - link_order->u.reloc.p->addend, buf); + rstat = _bfd_relocate_contents (rel.howto, output_bfd, addend, buf); switch (rstat) { case bfd_reloc_ok: @@ -4643,11 +4693,10 @@ ecoff_reloc_link_order (output_bfd, info, output_section, link_order) if (! ((*info->callbacks->reloc_overflow) (info, (link_order->type == bfd_section_reloc_link_order - ? bfd_section_name (output_bfd, - link_order->u.reloc.p->u.section) + ? bfd_section_name (output_bfd, section) : link_order->u.reloc.p->u.name), - rel.howto->name, link_order->u.reloc.p->addend, - (bfd *) NULL, (asection *) NULL, (bfd_vma) 0))) + rel.howto->name, addend, (bfd *) NULL, + (asection *) NULL, (bfd_vma) 0))) { free (buf); return false; @@ -4668,7 +4717,7 @@ ecoff_reloc_link_order (output_bfd, info, output_section, link_order) + bfd_get_section_vma (output_bfd, output_section)); in.r_type = rel.howto->type; - if (link_order->type == bfd_symbol_reloc_link_order) + if (type == bfd_symbol_reloc_link_order) { struct ecoff_link_hash_entry *h; @@ -4692,8 +4741,7 @@ ecoff_reloc_link_order (output_bfd, info, output_section, link_order) { CONST char *name; - name = bfd_get_section_name (output_bfd, - link_order->u.reloc.p->u.section); + name = bfd_get_section_name (output_bfd, section); if (strcmp (name, ".text") == 0) in.r_symndx = RELOC_SECTION_TEXT; else if (strcmp (name, ".rdata") == 0) @@ -4722,6 +4770,8 @@ ecoff_reloc_link_order (output_bfd, info, output_section, link_order) in.r_symndx = RELOC_SECTION_LITA; else if (strcmp (name, "*ABS*") == 0) in.r_symndx = RELOC_SECTION_ABS; + else if (strcmp (name, ".rconst") == 0) + in.r_symndx = RELOC_SECTION_RCONST; else abort (); in.r_extern = 0; diff --git a/bfd/ecofflink.c b/bfd/ecofflink.c index 2d1f99b8c8..d527f934e4 100644 --- a/bfd/ecofflink.c +++ b/bfd/ecofflink.c @@ -16,13 +16,14 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "bfd.h" #include "sysdep.h" #include "bfdlink.h" #include "libbfd.h" #include "obstack.h" +#include "aout/stab_gnu.h" #include "coff/internal.h" #include "coff/sym.h" #include "coff/symconst.h" @@ -39,11 +40,212 @@ static void ecoff_align_debug PARAMS ((bfd *abfd, static boolean ecoff_write_symhdr PARAMS ((bfd *, struct ecoff_debug_info *, const struct ecoff_debug_swap *, file_ptr where)); +static int cmp_fdrtab_entry PARAMS ((const PTR, const PTR)); +static boolean mk_fdrtab PARAMS ((bfd *, + struct ecoff_debug_info * const, + const struct ecoff_debug_swap * const, + struct ecoff_find_line *)); +static long fdrtab_lookup PARAMS ((struct ecoff_find_line *, bfd_vma)); /* Obstack allocation and deallocation routines. */ #define obstack_chunk_alloc malloc #define obstack_chunk_free free +/* Routines to swap auxiliary information in and out. I am assuming + that the auxiliary information format is always going to be target + independent. */ + +/* Swap in a type information record. + BIGEND says whether AUX symbols are big-endian or little-endian; this + info comes from the file header record (fh-fBigendian). */ + +void +_bfd_ecoff_swap_tir_in (bigend, ext_copy, intern) + int bigend; + const struct tir_ext *ext_copy; + TIR *intern; +{ + struct tir_ext ext[1]; + + *ext = *ext_copy; /* Make it reasonable to do in-place. */ + + /* now the fun stuff... */ + if (bigend) { + intern->fBitfield = 0 != (ext->t_bits1[0] & TIR_BITS1_FBITFIELD_BIG); + intern->continued = 0 != (ext->t_bits1[0] & TIR_BITS1_CONTINUED_BIG); + intern->bt = (ext->t_bits1[0] & TIR_BITS1_BT_BIG) + >> TIR_BITS1_BT_SH_BIG; + intern->tq4 = (ext->t_tq45[0] & TIR_BITS_TQ4_BIG) + >> TIR_BITS_TQ4_SH_BIG; + intern->tq5 = (ext->t_tq45[0] & TIR_BITS_TQ5_BIG) + >> TIR_BITS_TQ5_SH_BIG; + intern->tq0 = (ext->t_tq01[0] & TIR_BITS_TQ0_BIG) + >> TIR_BITS_TQ0_SH_BIG; + intern->tq1 = (ext->t_tq01[0] & TIR_BITS_TQ1_BIG) + >> TIR_BITS_TQ1_SH_BIG; + intern->tq2 = (ext->t_tq23[0] & TIR_BITS_TQ2_BIG) + >> TIR_BITS_TQ2_SH_BIG; + intern->tq3 = (ext->t_tq23[0] & TIR_BITS_TQ3_BIG) + >> TIR_BITS_TQ3_SH_BIG; + } else { + intern->fBitfield = 0 != (ext->t_bits1[0] & TIR_BITS1_FBITFIELD_LITTLE); + intern->continued = 0 != (ext->t_bits1[0] & TIR_BITS1_CONTINUED_LITTLE); + intern->bt = (ext->t_bits1[0] & TIR_BITS1_BT_LITTLE) + >> TIR_BITS1_BT_SH_LITTLE; + intern->tq4 = (ext->t_tq45[0] & TIR_BITS_TQ4_LITTLE) + >> TIR_BITS_TQ4_SH_LITTLE; + intern->tq5 = (ext->t_tq45[0] & TIR_BITS_TQ5_LITTLE) + >> TIR_BITS_TQ5_SH_LITTLE; + intern->tq0 = (ext->t_tq01[0] & TIR_BITS_TQ0_LITTLE) + >> TIR_BITS_TQ0_SH_LITTLE; + intern->tq1 = (ext->t_tq01[0] & TIR_BITS_TQ1_LITTLE) + >> TIR_BITS_TQ1_SH_LITTLE; + intern->tq2 = (ext->t_tq23[0] & TIR_BITS_TQ2_LITTLE) + >> TIR_BITS_TQ2_SH_LITTLE; + intern->tq3 = (ext->t_tq23[0] & TIR_BITS_TQ3_LITTLE) + >> TIR_BITS_TQ3_SH_LITTLE; + } + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap out a type information record. + BIGEND says whether AUX symbols are big-endian or little-endian; this + info comes from the file header record (fh-fBigendian). */ + +void +_bfd_ecoff_swap_tir_out (bigend, intern_copy, ext) + int bigend; + const TIR *intern_copy; + struct tir_ext *ext; +{ + TIR intern[1]; + + *intern = *intern_copy; /* Make it reasonable to do in-place. */ + + /* now the fun stuff... */ + if (bigend) { + ext->t_bits1[0] = ((intern->fBitfield ? TIR_BITS1_FBITFIELD_BIG : 0) + | (intern->continued ? TIR_BITS1_CONTINUED_BIG : 0) + | ((intern->bt << TIR_BITS1_BT_SH_BIG) + & TIR_BITS1_BT_BIG)); + ext->t_tq45[0] = (((intern->tq4 << TIR_BITS_TQ4_SH_BIG) + & TIR_BITS_TQ4_BIG) + | ((intern->tq5 << TIR_BITS_TQ5_SH_BIG) + & TIR_BITS_TQ5_BIG)); + ext->t_tq01[0] = (((intern->tq0 << TIR_BITS_TQ0_SH_BIG) + & TIR_BITS_TQ0_BIG) + | ((intern->tq1 << TIR_BITS_TQ1_SH_BIG) + & TIR_BITS_TQ1_BIG)); + ext->t_tq23[0] = (((intern->tq2 << TIR_BITS_TQ2_SH_BIG) + & TIR_BITS_TQ2_BIG) + | ((intern->tq3 << TIR_BITS_TQ3_SH_BIG) + & TIR_BITS_TQ3_BIG)); + } else { + ext->t_bits1[0] = ((intern->fBitfield ? TIR_BITS1_FBITFIELD_LITTLE : 0) + | (intern->continued ? TIR_BITS1_CONTINUED_LITTLE : 0) + | ((intern->bt << TIR_BITS1_BT_SH_LITTLE) + & TIR_BITS1_BT_LITTLE)); + ext->t_tq45[0] = (((intern->tq4 << TIR_BITS_TQ4_SH_LITTLE) + & TIR_BITS_TQ4_LITTLE) + | ((intern->tq5 << TIR_BITS_TQ5_SH_LITTLE) + & TIR_BITS_TQ5_LITTLE)); + ext->t_tq01[0] = (((intern->tq0 << TIR_BITS_TQ0_SH_LITTLE) + & TIR_BITS_TQ0_LITTLE) + | ((intern->tq1 << TIR_BITS_TQ1_SH_LITTLE) + & TIR_BITS_TQ1_LITTLE)); + ext->t_tq23[0] = (((intern->tq2 << TIR_BITS_TQ2_SH_LITTLE) + & TIR_BITS_TQ2_LITTLE) + | ((intern->tq3 << TIR_BITS_TQ3_SH_LITTLE) + & TIR_BITS_TQ3_LITTLE)); + } + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap in a relative symbol record. BIGEND says whether it is in + big-endian or little-endian format.*/ + +void +_bfd_ecoff_swap_rndx_in (bigend, ext_copy, intern) + int bigend; + const struct rndx_ext *ext_copy; + RNDXR *intern; +{ + struct rndx_ext ext[1]; + + *ext = *ext_copy; /* Make it reasonable to do in-place. */ + + /* now the fun stuff... */ + if (bigend) { + intern->rfd = (ext->r_bits[0] << RNDX_BITS0_RFD_SH_LEFT_BIG) + | ((ext->r_bits[1] & RNDX_BITS1_RFD_BIG) + >> RNDX_BITS1_RFD_SH_BIG); + intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_BIG) + << RNDX_BITS1_INDEX_SH_LEFT_BIG) + | (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_BIG) + | (ext->r_bits[3] << RNDX_BITS3_INDEX_SH_LEFT_BIG); + } else { + intern->rfd = (ext->r_bits[0] << RNDX_BITS0_RFD_SH_LEFT_LITTLE) + | ((ext->r_bits[1] & RNDX_BITS1_RFD_LITTLE) + << RNDX_BITS1_RFD_SH_LEFT_LITTLE); + intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_LITTLE) + >> RNDX_BITS1_INDEX_SH_LITTLE) + | (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_LITTLE) + | ((unsigned int) ext->r_bits[3] + << RNDX_BITS3_INDEX_SH_LEFT_LITTLE); + } + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap out a relative symbol record. BIGEND says whether it is in + big-endian or little-endian format.*/ + +void +_bfd_ecoff_swap_rndx_out (bigend, intern_copy, ext) + int bigend; + const RNDXR *intern_copy; + struct rndx_ext *ext; +{ + RNDXR intern[1]; + + *intern = *intern_copy; /* Make it reasonable to do in-place. */ + + /* now the fun stuff... */ + if (bigend) { + ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_BIG; + ext->r_bits[1] = (((intern->rfd << RNDX_BITS1_RFD_SH_BIG) + & RNDX_BITS1_RFD_BIG) + | ((intern->index >> RNDX_BITS1_INDEX_SH_LEFT_BIG) + & RNDX_BITS1_INDEX_BIG)); + ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_BIG; + ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_BIG; + } else { + ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_LITTLE; + ext->r_bits[1] = (((intern->rfd >> RNDX_BITS1_RFD_SH_LEFT_LITTLE) + & RNDX_BITS1_RFD_LITTLE) + | ((intern->index << RNDX_BITS1_INDEX_SH_LITTLE) + & RNDX_BITS1_INDEX_LITTLE)); + ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_LITTLE; + ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_LITTLE; + } + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + /* The minimum amount of data to allocate. */ #define ALLOC_SIZE (4064) @@ -224,7 +426,7 @@ add_file_shuffle (ainfo, head, tail, input_bfd, offset, size) if (*tail != (struct shuffle *) NULL && (*tail)->filep && (*tail)->u.file.input_bfd == input_bfd - && (*tail)->u.file.offset + (*tail)->size == offset) + && (*tail)->u.file.offset + (*tail)->size == (unsigned long) offset) { /* Just merge this entry onto the existing one. */ (*tail)->size += size; @@ -453,6 +655,7 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, SET (".rodata", scRData); SET (".init", scInit); SET (".fini", scFini); + SET (".rconst", scRConst); #undef SET @@ -1049,7 +1252,7 @@ bfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug, if (internal_sym.iss == -1) return false; if (bfd_is_com_section ((*sym_ptr)->section) - || (*sym_ptr)->section == &bfd_und_section) + || bfd_is_und_section ((*sym_ptr)->section)) internal_sym.value = (*sym_ptr)->value; else internal_sym.value = ((*sym_ptr)->value @@ -1140,7 +1343,8 @@ bfd_ecoff_debug_externals (abfd, debug, swap, relocateable, get_extr, } if (bfd_is_com_section (sym_ptr->section) - || sym_ptr->section == &bfd_und_section) + || bfd_is_und_section (sym_ptr->section) + || sym_ptr->section->output_section == (asection *) NULL) { /* FIXME: gas does not keep the value of a small undefined symbol in the symbol itself, because of relocation @@ -1184,7 +1388,7 @@ bfd_ecoff_debug_one_external (abfd, debug, swap, name, esym) namelen = strlen (name); - if (debug->ssext_end - debug->ssext + if ((size_t) (debug->ssext_end - debug->ssext) < symhdr->issExtMax + namelen + 1) { if (ecoff_add_bytes ((char **) &debug->ssext, @@ -1193,7 +1397,8 @@ bfd_ecoff_debug_one_external (abfd, debug, swap, name, esym) == false) return false; } - if ((char *) debug->external_ext_end - (char *) debug->external_ext + if ((size_t) ((char *) debug->external_ext_end + - (char *) debug->external_ext) < (symhdr->iextMax + 1) * external_ext_size) { if (ecoff_add_bytes ((char **) &debug->external_ext, @@ -1274,7 +1479,7 @@ ecoff_align_debug (abfd, debug, swap) if (debug->external_rfd != (PTR) NULL) memset ((PTR) ((char *) debug->external_rfd + symhdr->crfd * swap->external_rfd_size), - 0, add * swap->external_rfd_size); + 0, (size_t) (add * swap->external_rfd_size)); symhdr->crfd += add; } } @@ -1359,7 +1564,7 @@ ecoff_write_symhdr (abfd, debug, swap, where) SET (cbExtOffset, iextMax, swap->external_ext_size); #undef SET - buff = (PTR) malloc (swap->external_hdr_size); + buff = (PTR) malloc ((size_t) swap->external_hdr_size); if (buff == NULL && swap->external_hdr_size != 0) { bfd_set_error (bfd_error_no_memory); @@ -1399,7 +1604,8 @@ bfd_ecoff_write_debug (abfd, debug, swap, where) return false; #define WRITE(ptr, count, size, offset) \ - BFD_ASSERT (symhdr->offset == 0 || bfd_tell (abfd) == symhdr->offset); \ + BFD_ASSERT (symhdr->offset == 0 \ + || (bfd_vma) bfd_tell (abfd) == symhdr->offset); \ if (bfd_write ((PTR) debug->ptr, size, symhdr->count, abfd) \ != size * symhdr->count) \ return false; @@ -1456,7 +1662,7 @@ ecoff_write_shuffle (abfd, swap, shuffle, space) if ((total & (swap->debug_align - 1)) != 0) { - int i; + unsigned int i; bfd_byte *s; i = swap->debug_align - (total & (swap->debug_align - 1)); @@ -1545,7 +1751,7 @@ bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where) if ((total & (swap->debug_align - 1)) != 0) { - int i; + unsigned int i; bfd_byte *s; i = swap->debug_align - (total & (swap->debug_align - 1)); @@ -1568,11 +1774,11 @@ bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where) /* The external strings and symbol are not converted over to using shuffles. FIXME: They probably should be. */ if (bfd_write (debug->ssext, 1, debug->symbolic_header.issExtMax, abfd) - != debug->symbolic_header.issExtMax) + != (bfd_size_type) debug->symbolic_header.issExtMax) goto error_return; if ((debug->symbolic_header.issExtMax & (swap->debug_align - 1)) != 0) { - int i; + unsigned int i; bfd_byte *s; i = (swap->debug_align @@ -1597,7 +1803,8 @@ bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where) goto error_return; BFD_ASSERT (debug->symbolic_header.cbExtOffset == 0 - || debug->symbolic_header.cbExtOffset == bfd_tell (abfd)); + || (debug->symbolic_header.cbExtOffset + == (bfd_vma) bfd_tell (abfd))); if (bfd_write (debug->external_ext, swap->external_ext_size, debug->symbolic_header.iextMax, abfd) @@ -1613,3 +1820,672 @@ bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where) free (space); return false; } + +/* Handle the find_nearest_line function for both ECOFF and MIPS ELF + files. */ + +/* Compare FDR entries. This is called via qsort. */ + +static int +cmp_fdrtab_entry (leftp, rightp) + const PTR leftp; + const PTR rightp; +{ + const struct ecoff_fdrtab_entry *lp = + (const struct ecoff_fdrtab_entry *) leftp; + const struct ecoff_fdrtab_entry *rp = + (const struct ecoff_fdrtab_entry *) rightp; + + if (lp->base_addr < rp->base_addr) + return -1; + if (lp->base_addr > rp->base_addr) + return 1; + return 0; +} + +/* Each file descriptor (FDR) has a memory address, to simplify + looking up an FDR by address, we build a table covering all FDRs + that have a least one procedure descriptor in them. The final + table will be sorted by address so we can look it up via binary + search. */ + +static boolean +mk_fdrtab (abfd, debug_info, debug_swap, line_info) + bfd *abfd; + struct ecoff_debug_info * const debug_info; + const struct ecoff_debug_swap * const debug_swap; + struct ecoff_find_line *line_info; +{ + struct ecoff_fdrtab_entry *tab; + FDR *fdr_ptr; + FDR *fdr_start; + FDR *fdr_end; + boolean stabs; + long len; + + fdr_start = debug_info->fdr; + fdr_end = fdr_start + debug_info->symbolic_header.ifdMax; + + /* First, let's see how long the table needs to be: */ + for (len = 0, fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++) + { + if (fdr_ptr->cpd == 0) /* skip FDRs that have no PDRs */ + continue; + ++len; + } + + /* Now, create and fill in the table: */ + + line_info->fdrtab = ((struct ecoff_fdrtab_entry*) + bfd_zalloc (abfd, + len * sizeof (struct ecoff_fdrtab_entry))); + if (line_info->fdrtab == NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + line_info->fdrtab_len = len; + + tab = line_info->fdrtab; + for (fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++) + { + if (fdr_ptr->cpd == 0) + continue; + + /* Check whether this file has stabs debugging information. In + a file with stabs debugging information, the second local + symbol is named @stabs. */ + stabs = false; + if (fdr_ptr->csym >= 2) + { + char *sym_ptr; + SYMR sym; + + sym_ptr = ((char *) debug_info->external_sym + + (fdr_ptr->isymBase + 1)*debug_swap->external_sym_size); + (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym); + if (strcmp (debug_info->ss + fdr_ptr->issBase + sym.iss, + STABS_SYMBOL) == 0) + stabs = true; + } + + if (!stabs) + { + bfd_size_type external_pdr_size; + char *pdr_ptr; + PDR pdr; + + external_pdr_size = debug_swap->external_pdr_size; + + pdr_ptr = ((char *) debug_info->external_pdr + + fdr_ptr->ipdFirst * external_pdr_size); + (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr); + /* The address of the first PDR is the offset of that + procedure relative to the beginning of file FDR. */ + tab->base_addr = fdr_ptr->adr - pdr.adr; + } + else + { + /* XXX I don't know about stabs, so this is a guess + (davidm@cs.arizona.edu): */ + tab->base_addr = fdr_ptr->adr; + } + tab->fdr = fdr_ptr; + ++tab; + } + + /* Finally, the table is sorted in increasing memory-address order. + The table is mostly sorted already, but there are cases (e.g., + static functions in include files), where this does not hold. + Use "odump -PFv" to verify... */ + qsort ((PTR) line_info->fdrtab, len, + sizeof (struct ecoff_fdrtab_entry), cmp_fdrtab_entry); + + return true; +} + +/* Return index of first FDR that covers to OFFSET. */ + +static long +fdrtab_lookup (line_info, offset) + struct ecoff_find_line *line_info; + bfd_vma offset; +{ + long low, high, len; + long mid = -1; + struct ecoff_fdrtab_entry *tab; + + len = line_info->fdrtab_len; + if (len == 0) + return -1; + + tab = line_info->fdrtab; + for (low = 0, high = len - 1 ; low != high ;) + { + mid = (high + low) / 2; + if (offset >= tab[mid].base_addr && offset < tab[mid + 1].base_addr) + goto find_min; + + if (tab[mid].base_addr > offset) + high = mid; + else + low = mid + 1; + } + ++mid; + + /* last entry is catch-all for all higher addresses: */ + if (offset < tab[mid].base_addr) + return -1; + + find_min: + + while (mid > 0 && tab[mid - 1].base_addr == tab[mid].base_addr) + --mid; + + return mid; +} + +/* Do the work of find_nearest_line. */ + +boolean +_bfd_ecoff_locate_line (abfd, section, offset, debug_info, debug_swap, + line_info, filename_ptr, functionname_ptr, retline_ptr) + bfd *abfd; + asection *section; + bfd_vma offset; + struct ecoff_debug_info * const debug_info; + const struct ecoff_debug_swap * const debug_swap; + struct ecoff_find_line *line_info; + const char **filename_ptr; + const char **functionname_ptr; + unsigned int *retline_ptr; +{ + struct ecoff_fdrtab_entry *tab; + boolean stabs; + FDR *fdr_ptr; + int i; + + offset += section->vma; + + /* Build FDR table (sorted by object file's base-address) if we + don't have it already. */ + if (line_info->fdrtab == NULL + && !mk_fdrtab (abfd, debug_info, debug_swap, line_info)) + return false; + + tab = line_info->fdrtab; + + /* find first FDR for address OFFSET */ + i = fdrtab_lookup (line_info, offset); + if (i < 0) + return false; /* no FDR, no fun... */ + fdr_ptr = tab[i].fdr; + + /* Check whether this file has stabs debugging information. In a + file with stabs debugging information, the second local symbol is + named @stabs. */ + stabs = false; + if (fdr_ptr->csym >= 2) + { + char *sym_ptr; + SYMR sym; + + sym_ptr = ((char *) debug_info->external_sym + + (fdr_ptr->isymBase + 1) * debug_swap->external_sym_size); + (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym); + if (strcmp (debug_info->ss + fdr_ptr->issBase + sym.iss, + STABS_SYMBOL) == 0) + stabs = true; + } + + if (!stabs) + { + bfd_size_type external_pdr_size; + char *pdr_ptr; + char *best_pdr = NULL; + FDR *best_fdr; + bfd_vma best_dist = ~0; + PDR pdr; + unsigned char *line_ptr; + unsigned char *line_end; + int lineno; + /* This file uses ECOFF debugging information. Each FDR has a + list of procedure descriptors (PDR). The address in the FDR + is the absolute address of the first procedure. The address + in the first PDR gives the offset of that procedure relative + to the object file's base-address. The addresses in + subsequent PDRs specify each procedure's address relative to + the object file's base-address. To make things more juicy, + whenever the PROF bit in the PDR is set, the real entry point + of the procedure may be 16 bytes below what would normally be + the procedure's entry point. Instead, DEC came up with a + wicked scheme to create profiled libraries "on the fly": + instead of shipping a regular and a profiled version of each + library, they insert 16 bytes of unused space in front of + each procedure and set the "prof" bit in the PDR to indicate + that there is a gap there (this is done automagically by "as" + when option "-pg" is specified). Thus, normally, you link + against such a library and, except for lots of 16 byte gaps + between functions, things will behave as usual. However, + when invoking "ld" with option "-pg", it will fill those gaps + with code that calls mcount(). It then moves the function's + entry point down by 16 bytes, and out pops a binary that has + all functions profiled. + + NOTE: Neither FDRs nor PDRs are strictly sorted in memory + order. For example, when including header-files that + define functions, the FDRs follow behind the including + file, even though their code may have been generated at + a lower address. File coff-alpha.c from libbfd + illustrates this (use "odump -PFv" to look at a file's + FDR/PDR). Similarly, PDRs are sometimes out of order + as well. An example of this is OSF/1 v3.0 libc's + malloc.c. I'm not sure why this happens, but it could + be due to optimizations that reorder a function's + position within an object-file. + + Strategy: + + On the first call to this function, we build a table of FDRs + that is sorted by the base-address of the object-file the FDR + is referring to. Notice that each object-file may contain + code from multiple source files (e.g., due to code defined in + include files). Thus, for any given base-address, there may + be multiple FDRs (but this case is, fortunately, uncommon). + lookup(addr) guarantees to return the first FDR that applies + to address ADDR. Thus, after invoking lookup(), we have a + list of FDRs that may contain the PDR for ADDR. Next, we + walk through the PDRs of these FDRs and locate the one that + is closest to ADDR (i.e., for which the difference between + ADDR and the PDR's entry point is positive and minimal). + Once, the right FDR and PDR are located, we simply walk + through the line-number table to lookup the line-number that + best matches ADDR. Obviously, things could be sped up by + keeping a sorted list of PDRs instead of a sorted list of + FDRs. However, this would increase space requirements + considerably, which is undesirable. */ + external_pdr_size = debug_swap->external_pdr_size; + + /* Make offset relative to object file's start-address: */ + offset -= tab[i].base_addr; + /* Search FDR list starting at tab[i] for the PDR that best matches + OFFSET. Normally, the FDR list is only one entry long. */ + best_fdr = NULL; + do + { + bfd_vma dist, min_dist = 0; + char *pdr_hold; + char *pdr_end; + + fdr_ptr = tab[i].fdr; + + pdr_ptr = ((char *) debug_info->external_pdr + + fdr_ptr->ipdFirst * external_pdr_size); + pdr_end = pdr_ptr + fdr_ptr->cpd * external_pdr_size; + (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr); + /* Find PDR that is closest to OFFSET. If pdr.prof is set, + the procedure entry-point *may* be 0x10 below pdr.adr. We + simply pretend that pdr.prof *implies* a lower entry-point. + This is safe because it just means that may identify 4 NOPs + in front of the function as belonging to the function. */ + for (pdr_hold = NULL; + pdr_ptr < pdr_end; + (pdr_ptr += external_pdr_size, + (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr))) + { + if (offset >= (pdr.adr - 0x10 * pdr.prof)) + { + dist = offset - (pdr.adr - 0x10 * pdr.prof); + if (!pdr_hold || dist < min_dist) + { + min_dist = dist; + pdr_hold = pdr_ptr; + } + } + } + + if (!best_pdr || min_dist < best_dist) + { + best_dist = min_dist; + best_fdr = fdr_ptr; + best_pdr = pdr_hold; + } + /* continue looping until base_addr of next entry is different: */ + } + while (++i < line_info->fdrtab_len + && tab[i].base_addr == tab[i - 1].base_addr); + + if (!best_fdr || !best_pdr) + return false; /* shouldn't happen... */ + + /* phew, finally we got something that we can hold onto: */ + fdr_ptr = best_fdr; + pdr_ptr = best_pdr; + (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr); + /* Now we can look for the actual line number. The line numbers + are stored in a very funky format, which I won't try to + describe. The search is bounded by the end of the FDRs line + number entries. */ + line_end = debug_info->line + fdr_ptr->cbLineOffset + fdr_ptr->cbLine; + + /* Make offset relative to procedure entry: */ + offset -= pdr.adr - 0x10 * pdr.prof; + lineno = pdr.lnLow; + line_ptr = debug_info->line + fdr_ptr->cbLineOffset + pdr.cbLineOffset; + while (line_ptr < line_end) + { + int delta; + unsigned int count; + + delta = *line_ptr >> 4; + if (delta >= 0x8) + delta -= 0x10; + count = (*line_ptr & 0xf) + 1; + ++line_ptr; + if (delta == -8) + { + delta = (((line_ptr[0]) & 0xff) << 8) + ((line_ptr[1]) & 0xff); + if (delta >= 0x8000) + delta -= 0x10000; + line_ptr += 2; + } + lineno += delta; + if (offset < count * 4) + break; + offset -= count * 4; + } + + /* If fdr_ptr->rss is -1, then this file does not have full + symbols, at least according to gdb/mipsread.c. */ + if (fdr_ptr->rss == -1) + { + *filename_ptr = NULL; + if (pdr.isym == -1) + *functionname_ptr = NULL; + else + { + EXTR proc_ext; + + (*debug_swap->swap_ext_in) + (abfd, + ((char *) debug_info->external_ext + + pdr.isym * debug_swap->external_ext_size), + &proc_ext); + *functionname_ptr = debug_info->ssext + proc_ext.asym.iss; + } + } + else + { + SYMR proc_sym; + + *filename_ptr = debug_info->ss + fdr_ptr->issBase + fdr_ptr->rss; + (*debug_swap->swap_sym_in) + (abfd, + ((char *) debug_info->external_sym + + (fdr_ptr->isymBase + pdr.isym) * debug_swap->external_sym_size), + &proc_sym); + *functionname_ptr = debug_info->ss + fdr_ptr->issBase + proc_sym.iss; + } + if (lineno == ilineNil) + lineno = 0; + *retline_ptr = lineno; + } + else + { + bfd_size_type external_sym_size; + const char *directory_name; + const char *main_file_name; + const char *current_file_name; + const char *function_name; + const char *line_file_name; + bfd_vma low_func_vma; + bfd_vma low_line_vma; + boolean past_line; + boolean past_fn; + char *sym_ptr, *sym_ptr_end; + size_t len, funclen; + char *buffer = NULL; + + /* This file uses stabs debugging information. When gcc is not + optimizing, it will put the line number information before + the function name stabs entry. When gcc is optimizing, it + will put the stabs entry for all the function first, followed + by the line number information. (This appears to happen + because of the two output files used by the -mgpopt switch, + which is implied by -O). This means that we must keep + looking through the symbols until we find both a line number + and a function name which are beyond the address we want. */ + + *filename_ptr = NULL; + *functionname_ptr = NULL; + *retline_ptr = 0; + + directory_name = NULL; + main_file_name = NULL; + current_file_name = NULL; + function_name = NULL; + line_file_name = NULL; + low_func_vma = 0; + low_line_vma = 0; + past_line = false; + past_fn = false; + + external_sym_size = debug_swap->external_sym_size; + + sym_ptr = ((char *) debug_info->external_sym + + (fdr_ptr->isymBase + 2) * external_sym_size); + sym_ptr_end = sym_ptr + (fdr_ptr->csym - 2) * external_sym_size; + for (; + sym_ptr < sym_ptr_end && (! past_line || ! past_fn); + sym_ptr += external_sym_size) + { + SYMR sym; + + (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym); + + if (ECOFF_IS_STAB (&sym)) + { + switch (ECOFF_UNMARK_STAB (sym.index)) + { + case N_SO: + main_file_name = current_file_name = + debug_info->ss + fdr_ptr->issBase + sym.iss; + + /* Check the next symbol to see if it is also an + N_SO symbol. */ + if (sym_ptr + external_sym_size < sym_ptr_end) + { + SYMR nextsym; + + (*debug_swap->swap_sym_in) (abfd, + sym_ptr + external_sym_size, + &nextsym); + if (ECOFF_IS_STAB (&nextsym) + && ECOFF_UNMARK_STAB (nextsym.index) == N_SO) + { + directory_name = current_file_name; + main_file_name = current_file_name = + debug_info->ss + fdr_ptr->issBase + nextsym.iss; + sym_ptr += external_sym_size; + } + } + break; + + case N_SOL: + current_file_name = + debug_info->ss + fdr_ptr->issBase + sym.iss; + break; + + case N_FUN: + if (sym.value > offset) + past_fn = true; + else if (sym.value >= low_func_vma) + { + low_func_vma = sym.value; + function_name = + debug_info->ss + fdr_ptr->issBase + sym.iss; + } + break; + } + } + else if (sym.st == stLabel && sym.index != indexNil) + { + if (sym.value > offset) + past_line = true; + else if (sym.value >= low_line_vma) + { + low_line_vma = sym.value; + line_file_name = current_file_name; + *retline_ptr = sym.index; + } + } + } + + if (*retline_ptr != 0) + main_file_name = line_file_name; + + /* We need to remove the stuff after the colon in the function + name. We also need to put the directory name and the file + name together. */ + if (function_name == NULL) + len = funclen = 0; + else + len = funclen = strlen (function_name) + 1; + + if (main_file_name != NULL + && directory_name != NULL + && main_file_name[0] != '/') + len += strlen (directory_name) + strlen (main_file_name) + 1; + + if (len != 0) + { + if (line_info->find_buffer != NULL) + free (line_info->find_buffer); + buffer = (char *) malloc (len); + if (buffer == NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + line_info->find_buffer = buffer; + } + + if (function_name != NULL) + { + char *colon; + + strcpy (buffer, function_name); + colon = strchr (buffer, ':'); + if (colon != NULL) + *colon = '\0'; + *functionname_ptr = buffer; + } + + if (main_file_name != NULL) + { + if (directory_name == NULL || main_file_name[0] == '/') + *filename_ptr = main_file_name; + else + { + sprintf (buffer + funclen, "%s%s", directory_name, + main_file_name); + *filename_ptr = buffer + funclen; + } + } + } + + return true; +} + +/* These routines copy symbolic information into a memory buffer. + + FIXME: The whole point of the shuffle code is to avoid storing + everything in memory, since the linker is such a memory hog. This + code makes that effort useless. It is only called by the MIPS ELF + code when generating a shared library, so it is not that big a + deal, but it should be fixed eventually. */ + +/* Collect a shuffle into a memory buffer. */ + +static boolean ecoff_collect_shuffle PARAMS ((struct shuffle *, bfd_byte *)); + +static boolean +ecoff_collect_shuffle (l, buff) + struct shuffle *l; + bfd_byte *buff; +{ + unsigned long total; + + total = 0; + for (; l != (struct shuffle *) NULL; l = l->next) + { + if (! l->filep) + memcpy (buff, l->u.memory, l->size); + else + { + if (bfd_seek (l->u.file.input_bfd, l->u.file.offset, SEEK_SET) != 0 + || bfd_read (buff, 1, l->size, l->u.file.input_bfd) != l->size) + return false; + } + total += l->size; + buff += l->size; + } + + return true; +} + +/* Copy PDR information into a memory buffer. */ + +boolean +_bfd_ecoff_get_accumulated_pdr (handle, buff) + PTR handle; + bfd_byte *buff; +{ + struct accumulate *ainfo = (struct accumulate *) handle; + + return ecoff_collect_shuffle (ainfo->pdr, buff); +} + +/* Copy symbol information into a memory buffer. */ + +boolean +_bfd_ecoff_get_accumulated_sym (handle, buff) + PTR handle; + bfd_byte *buff; +{ + struct accumulate *ainfo = (struct accumulate *) handle; + + return ecoff_collect_shuffle (ainfo->sym, buff); +} + +/* Copy the string table into a memory buffer. */ + +boolean +_bfd_ecoff_get_accumulated_ss (handle, buff) + PTR handle; + bfd_byte *buff; +{ + struct accumulate *ainfo = (struct accumulate *) handle; + struct string_hash_entry *sh; + unsigned long total; + + /* The string table is written out from the hash table if this is a + final link. */ + BFD_ASSERT (ainfo->ss == (struct shuffle *) NULL); + *buff++ = '\0'; + total = 1; + BFD_ASSERT (ainfo->ss_hash == NULL || ainfo->ss_hash->val == 1); + for (sh = ainfo->ss_hash; + sh != (struct string_hash_entry *) NULL; + sh = sh->next) + { + size_t len; + + len = strlen (sh->root.string); + memcpy (buff, (PTR) sh->root.string, len + 1); + total += len + 1; + buff += len + 1; + } + + return true; +}