X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Fecoff.c;h=c7230f6aaf8f1ad9468097ae39c9b2d297156ca8;hb=86fb1dece37497b267579ed4f062d280cd5760cd;hp=68fe010fcc58f93ef3897cdff90c00b31a0d00b4;hpb=e544ed4f3d320d674bb9ca227732cb61d9d7260d;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/ecoff.c b/bfd/ecoff.c index 68fe010fcc..c7230f6aaf 100644 --- a/bfd/ecoff.c +++ b/bfd/ecoff.c @@ -1,5 +1,6 @@ /* Generic ECOFF (Extended-COFF) routines. - Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Copyright 1990, 1991, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 + Free Software Foundation, Inc. Original version by Per Bothner. Full support added by Ian Lance Taylor, ian@cygnus.com. @@ -17,14 +18,15 @@ 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 "seclet.h" #include "aout/ar.h" #include "aout/ranlib.h" +#include "aout/stab_gnu.h" /* FIXME: We need the definitions of N_SET[ADTB], but aout64.h defines some other stuff which we don't want and which conflicts with stuff @@ -44,91 +46,148 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Prototypes for static functions. */ -static void ecoff_set_symbol_info PARAMS ((bfd *abfd, SYMR *ecoff_sym, - asymbol *asym, int ext, - asymbol **indirect_ptr_ptr)); -static void ecoff_emit_aggregate PARAMS ((bfd *abfd, char *string, +static int ecoff_get_magic PARAMS ((bfd *abfd)); +static long ecoff_sec_to_styp_flags PARAMS ((const char *name, + flagword flags)); +static boolean ecoff_slurp_symbolic_header PARAMS ((bfd *abfd)); +static boolean ecoff_set_symbol_info PARAMS ((bfd *abfd, SYMR *ecoff_sym, + asymbol *asym, int ext, int weak)); +static void ecoff_emit_aggregate PARAMS ((bfd *abfd, FDR *fdr, + char *string, RNDXR *rndx, long isym, - CONST char *which)); -static char *ecoff_type_to_string PARAMS ((bfd *abfd, union aux_ext *aux_ptr, - unsigned int indx, int bigendian)); + const char *which)); +static char *ecoff_type_to_string PARAMS ((bfd *abfd, FDR *fdr, + unsigned int indx)); static boolean ecoff_slurp_reloc_table PARAMS ((bfd *abfd, asection *section, asymbol **symbols)); -static void ecoff_clear_output_flags PARAMS ((bfd *abfd)); -static boolean ecoff_rel PARAMS ((bfd *output_bfd, bfd_seclet_type *seclet, - asection *output_section, PTR data, - boolean relocateable)); -static boolean ecoff_dump_seclet PARAMS ((bfd *abfd, bfd_seclet_type *seclet, - asection *section, PTR data, - boolean relocateable)); -static long ecoff_add_string PARAMS ((bfd *output_bfd, FDR *fdr, - CONST char *string, boolean external)); -static boolean ecoff_get_debug PARAMS ((bfd *output_bfd, - bfd_seclet_type *seclet, - asection *section, - boolean relocateable)); -static void ecoff_compute_section_file_positions PARAMS ((bfd *abfd)); -static unsigned int ecoff_armap_hash PARAMS ((CONST char *s, +static int ecoff_sort_hdrs PARAMS ((const PTR, const PTR)); +static boolean ecoff_compute_section_file_positions PARAMS ((bfd *abfd)); +static bfd_size_type ecoff_compute_reloc_file_positions PARAMS ((bfd *abfd)); +static boolean ecoff_get_extr PARAMS ((asymbol *, EXTR *)); +static void ecoff_set_index PARAMS ((asymbol *, bfd_size_type)); +static unsigned int ecoff_armap_hash PARAMS ((const char *s, unsigned int *rehash, unsigned int size, unsigned int hlog)); /* This stuff is somewhat copied from coffcode.h. */ -static asection bfd_debug_section = { "*DEBUG*" }; +static asection bfd_debug_section = +{ + /* name, id, index, next, flags, user_set_vma, reloc_done, */ + "*DEBUG*", 0, 0, NULL, 0, 0, 0, + /* linker_mark, linker_has_input, gc_mark, segment_mark, */ + 0, 0, 0, 0, + /* vma, lma, _cooked_size, _raw_size, */ + 0, 0, 0, 0, + /* output_offset, output_section, alignment_power, */ + 0, NULL, 0, + /* relocation, orelocation, reloc_count, filepos, rel_filepos, */ + NULL, NULL, 0, 0, 0, + /* line_filepos, userdata, contents, lineno, lineno_count, */ + 0, NULL, NULL, NULL, 0, + /* entsize, comdat, moving_line_filepos, */ + 0, NULL, 0, + /* target_index, used_by_bfd, constructor_chain, owner, */ + 0, NULL, NULL, NULL, + /* symbol, */ + (struct symbol_cache_entry *) NULL, + /* symbol_ptr_ptr, */ + (struct symbol_cache_entry **) NULL, + /* link_order_head, link_order_tail */ + NULL, NULL +}; /* Create an ECOFF object. */ boolean -ecoff_mkobject (abfd) +_bfd_ecoff_mkobject (abfd) bfd *abfd; { - abfd->tdata.ecoff_obj_data = ((struct ecoff_tdata *) - bfd_zalloc (abfd, sizeof (ecoff_data_type))); + bfd_size_type amt = sizeof (ecoff_data_type); + abfd->tdata.ecoff_obj_data = (struct ecoff_tdata *) bfd_zalloc (abfd, amt); if (abfd->tdata.ecoff_obj_data == NULL) - { - bfd_error = no_memory; - return false; - } - - /* Always create a .scommon section for every BFD. This is a hack so - that the linker has something to attach scSCommon symbols to. */ - bfd_make_section (abfd, SCOMMON); + return false; return true; } -/* This is a hook needed by SCO COFF, but we have nothing to do. */ +/* This is a hook called by coff_real_object_p to create any backend + specific information. */ -asection * -ecoff_make_section_hook (abfd, name) +PTR +_bfd_ecoff_mkobject_hook (abfd, filehdr, aouthdr) bfd *abfd; - char *name; + PTR filehdr; + PTR aouthdr; { - return (asection *) NULL; + struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; + struct internal_aouthdr *internal_a = (struct internal_aouthdr *) aouthdr; + ecoff_data_type *ecoff; + + if (_bfd_ecoff_mkobject (abfd) == false) + return NULL; + + ecoff = ecoff_data (abfd); + ecoff->gp_size = 8; + ecoff->sym_filepos = internal_f->f_symptr; + + if (internal_a != (struct internal_aouthdr *) NULL) + { + int i; + + ecoff->text_start = internal_a->text_start; + ecoff->text_end = internal_a->text_start + internal_a->tsize; + ecoff->gp = internal_a->gp_value; + ecoff->gprmask = internal_a->gprmask; + for (i = 0; i < 4; i++) + ecoff->cprmask[i] = internal_a->cprmask[i]; + ecoff->fprmask = internal_a->fprmask; + if (internal_a->magic == ECOFF_AOUT_ZMAGIC) + abfd->flags |= D_PAGED; + else + abfd->flags &=~ D_PAGED; + } + + /* It turns out that no special action is required by the MIPS or + Alpha ECOFF backends. They have different information in the + a.out header, but we just copy it all (e.g., gprmask, cprmask and + fprmask) and let the swapping routines ensure that only relevant + information is written out. */ + + return (PTR) ecoff; } /* Initialize a new section. */ boolean -ecoff_new_section_hook (abfd, section) - bfd *abfd; +_bfd_ecoff_new_section_hook (abfd, section) + bfd *abfd ATTRIBUTE_UNUSED; asection *section; { - section->alignment_power = abfd->xvec->align_power_min; + section->alignment_power = 4; - if (strcmp (section->name, _TEXT) == 0) + if (strcmp (section->name, _TEXT) == 0 + || strcmp (section->name, _INIT) == 0 + || strcmp (section->name, _FINI) == 0) section->flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC; else if (strcmp (section->name, _DATA) == 0 || strcmp (section->name, _SDATA) == 0) 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 + || strcmp (section->name, _PDATA) == 0) section->flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY; else if (strcmp (section->name, _BSS) == 0 || strcmp (section->name, _SBSS) == 0) section->flags |= SEC_ALLOC; + else if (strcmp (section->name, _LIB) == 0) + { + /* An Irix 4 shared libary. */ + section->flags |= SEC_COFF_SHARED_LIBRARY; + } /* Probably any other section name is SEC_NEVER_LOAD, but I'm uncertain about .init on some systems and I don't know how shared @@ -137,15 +196,19 @@ ecoff_new_section_hook (abfd, section) return true; } -/* Determine the machine architecture and type. */ +/* Determine the machine architecture and type. This is called from + the generic COFF routines. It is the inverse of ecoff_get_magic, + below. This could be an ECOFF backend routine, with one version + for each target, but there aren't all that many ECOFF targets. */ boolean -ecoff_set_arch_mach_hook (abfd, filehdr) +_bfd_ecoff_set_arch_mach_hook (abfd, filehdr) bfd *abfd; PTR filehdr; { struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; enum bfd_architecture arch; + unsigned long mach; switch (internal_f->f_magic) { @@ -153,27 +216,85 @@ ecoff_set_arch_mach_hook (abfd, filehdr) case MIPS_MAGIC_LITTLE: case MIPS_MAGIC_BIG: arch = bfd_arch_mips; + mach = 3000; + break; + + case MIPS_MAGIC_LITTLE2: + case MIPS_MAGIC_BIG2: + /* MIPS ISA level 2: the r6000 */ + arch = bfd_arch_mips; + mach = 6000; + break; + + case MIPS_MAGIC_LITTLE3: + case MIPS_MAGIC_BIG3: + /* MIPS ISA level 3: the r4000 */ + arch = bfd_arch_mips; + mach = 4000; break; case ALPHA_MAGIC: arch = bfd_arch_alpha; + mach = 0; break; default: arch = bfd_arch_obscure; + mach = 0; break; } - bfd_default_set_arch_mach (abfd, arch, (unsigned long) 0); + return bfd_default_set_arch_mach (abfd, arch, mach); +} + +/* Get the magic number to use based on the architecture and machine. + This is the inverse of _bfd_ecoff_set_arch_mach_hook, above. */ - return true; +static int +ecoff_get_magic (abfd) + bfd *abfd; +{ + int big, little; + + switch (bfd_get_arch (abfd)) + { + case bfd_arch_mips: + switch (bfd_get_mach (abfd)) + { + default: + case 0: + case 3000: + big = MIPS_MAGIC_BIG; + little = MIPS_MAGIC_LITTLE; + break; + + case 6000: + big = MIPS_MAGIC_BIG2; + little = MIPS_MAGIC_LITTLE2; + break; + + case 4000: + big = MIPS_MAGIC_BIG3; + little = MIPS_MAGIC_LITTLE3; + break; + } + + return bfd_big_endian (abfd) ? big : little; + + case bfd_arch_alpha: + return ALPHA_MAGIC; + + default: + abort (); + return 0; + } } /* Get the section s_flags to use for a section. */ -long +static long ecoff_sec_to_styp_flags (name, flags) - CONST char *name; + const char *name; flagword flags; { long styp; @@ -188,6 +309,8 @@ ecoff_sec_to_styp_flags (name, flags) styp = STYP_SDATA; else if (strcmp (name, _RDATA) == 0) styp = STYP_RDATA; + else if (strcmp (name, _LITA) == 0) + styp = STYP_LITA; else if (strcmp (name, _LIT8) == 0) styp = STYP_LIT8; else if (strcmp (name, _LIT4) == 0) @@ -198,9 +321,40 @@ ecoff_sec_to_styp_flags (name, flags) styp = STYP_SBSS; else if (strcmp (name, _INIT) == 0) styp = STYP_ECOFF_INIT; - else if (flags & SEC_CODE) + else if (strcmp (name, _FINI) == 0) + styp = STYP_ECOFF_FINI; + else if (strcmp (name, _PDATA) == 0) + styp = STYP_PDATA; + else if (strcmp (name, _XDATA) == 0) + styp = STYP_XDATA; + else if (strcmp (name, _LIB) == 0) + styp = STYP_ECOFF_LIB; + else if (strcmp (name, _GOT) == 0) + styp = STYP_GOT; + else if (strcmp (name, _HASH) == 0) + styp = STYP_HASH; + else if (strcmp (name, _DYNAMIC) == 0) + styp = STYP_DYNAMIC; + else if (strcmp (name, _LIBLIST) == 0) + styp = STYP_LIBLIST; + else if (strcmp (name, _RELDYN) == 0) + styp = STYP_RELDYN; + else if (strcmp (name, _CONFLIC) == 0) + styp = STYP_CONFLIC; + else if (strcmp (name, _DYNSTR) == 0) + styp = STYP_DYNSTR; + else if (strcmp (name, _DYNSYM) == 0) + styp = STYP_DYNSYM; + else if (strcmp (name, _COMMENT) == 0) + { + 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) + else if (flags & SEC_DATA) styp = STYP_DATA; else if (flags & SEC_READONLY) styp = STYP_RDATA; @@ -217,14 +371,17 @@ ecoff_sec_to_styp_flags (name, flags) /* Get the BFD flags to use for a section. */ -flagword -ecoff_styp_to_sec_flags (abfd, hdr) - bfd *abfd; +boolean +_bfd_ecoff_styp_to_sec_flags (abfd, hdr, name, section, flags_ptr) + bfd *abfd ATTRIBUTE_UNUSED; PTR hdr; + const char *name ATTRIBUTE_UNUSED; + asection *section ATTRIBUTE_UNUSED; + flagword * flags_ptr; { struct internal_scnhdr *internal_s = (struct internal_scnhdr *) hdr; long styp_flags = internal_s->s_flags; - flagword sec_flags=0; + flagword sec_flags = 0; if (styp_flags & STYP_NOLOAD) sec_flags |= SEC_NEVER_LOAD; @@ -232,249 +389,131 @@ ecoff_styp_to_sec_flags (abfd, hdr) /* For 386 COFF, at least, an unloadable text or data section is actually a shared library section. */ if ((styp_flags & STYP_TEXT) - || (styp_flags & STYP_ECOFF_INIT)) + || (styp_flags & STYP_ECOFF_INIT) + || (styp_flags & STYP_ECOFF_FINI) + || (styp_flags & STYP_DYNAMIC) + || (styp_flags & STYP_LIBLIST) + || (styp_flags & STYP_RELDYN) + || styp_flags == STYP_CONFLIC + || (styp_flags & STYP_DYNSTR) + || (styp_flags & STYP_DYNSYM) + || (styp_flags & STYP_HASH)) { if (sec_flags & SEC_NEVER_LOAD) - sec_flags |= SEC_CODE | SEC_SHARED_LIBRARY; + sec_flags |= SEC_CODE | SEC_COFF_SHARED_LIBRARY; else sec_flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC; } else if ((styp_flags & STYP_DATA) || (styp_flags & STYP_RDATA) - || (styp_flags & STYP_SDATA)) + || (styp_flags & STYP_SDATA) + || styp_flags == STYP_PDATA + || styp_flags == STYP_XDATA + || (styp_flags & STYP_GOT) + || styp_flags == STYP_RCONST) { if (sec_flags & SEC_NEVER_LOAD) - sec_flags |= SEC_DATA | SEC_SHARED_LIBRARY; + sec_flags |= SEC_DATA | SEC_COFF_SHARED_LIBRARY; else sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC; - if (styp_flags & STYP_RDATA) + if ((styp_flags & STYP_RDATA) + || styp_flags == STYP_PDATA + || styp_flags == STYP_RCONST) sec_flags |= SEC_READONLY; } else if ((styp_flags & STYP_BSS) || (styp_flags & STYP_SBSS)) - { - sec_flags |= SEC_ALLOC; - } - else if (styp_flags & STYP_INFO) - { - sec_flags |= SEC_NEVER_LOAD; - } - else if ((styp_flags & STYP_LIT8) + sec_flags |= SEC_ALLOC; + else if ((styp_flags & STYP_INFO) || styp_flags == STYP_COMMENT) + sec_flags |= SEC_NEVER_LOAD; + else if ((styp_flags & STYP_LITA) + || (styp_flags & STYP_LIT8) || (styp_flags & STYP_LIT4)) - { - sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY; - } + sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY; + else if (styp_flags & STYP_ECOFF_LIB) + sec_flags |= SEC_COFF_SHARED_LIBRARY; else - { - sec_flags |= SEC_ALLOC | SEC_LOAD; - } + sec_flags |= SEC_ALLOC | SEC_LOAD; - return sec_flags; + * flags_ptr = sec_flags; + return true; } -/* 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). */ +/* Read in the symbolic header for an ECOFF object file. */ -void -ecoff_swap_tir_in (bigend, ext_copy, intern) - int bigend; - struct tir_ext *ext_copy; - TIR *intern; +static boolean +ecoff_slurp_symbolic_header (abfd) + bfd *abfd; { - 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). */ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + bfd_size_type external_hdr_size; + PTR raw = NULL; + HDRR *internal_symhdr; -void -ecoff_swap_tir_out (bigend, intern_copy, ext) - int bigend; - 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)); - } + /* See if we've already read it in. */ + if (ecoff_data (abfd)->debug_info.symbolic_header.magic == + backend->debug_swap.sym_magic) + return true; -#ifdef TEST - if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) - abort(); -#endif -} + /* See whether there is a symbolic header. */ + if (ecoff_data (abfd)->sym_filepos == 0) + { + bfd_get_symcount (abfd) = 0; + return true; + } -/* Swap in a relative symbol record. BIGEND says whether it is in - big-endian or little-endian format.*/ + /* At this point bfd_get_symcount (abfd) holds the number of symbols + as read from the file header, but on ECOFF this is always the + size of the symbolic information header. It would be cleaner to + handle this when we first read the file in coffgen.c. */ + external_hdr_size = backend->debug_swap.external_hdr_size; + if (bfd_get_symcount (abfd) != external_hdr_size) + { + bfd_set_error (bfd_error_bad_value); + return false; + } -void -ecoff_swap_rndx_in (bigend, ext_copy, intern) - int bigend; - 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) - | (ext->r_bits[3] << RNDX_BITS3_INDEX_SH_LEFT_LITTLE); - } + /* Read the symbolic information header. */ + raw = (PTR) bfd_malloc (external_hdr_size); + if (raw == NULL) + goto error_return; -#ifdef TEST - if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) - abort(); -#endif -} + if (bfd_seek (abfd, ecoff_data (abfd)->sym_filepos, SEEK_SET) != 0 + || bfd_bread (raw, external_hdr_size, abfd) != external_hdr_size) + goto error_return; + internal_symhdr = &ecoff_data (abfd)->debug_info.symbolic_header; + (*backend->debug_swap.swap_hdr_in) (abfd, raw, internal_symhdr); -/* Swap out a relative symbol record. BIGEND says whether it is in - big-endian or little-endian format.*/ + if (internal_symhdr->magic != backend->debug_swap.sym_magic) + { + bfd_set_error (bfd_error_bad_value); + goto error_return; + } -void -ecoff_swap_rndx_out (bigend, intern_copy, ext) - int bigend; - 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; - } + /* Now we can get the correct number of symbols. */ + bfd_get_symcount (abfd) = (internal_symhdr->isymMax + + internal_symhdr->iextMax); -#ifdef TEST - if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) - abort(); -#endif + if (raw != NULL) + free (raw); + return true; + error_return: + if (raw != NULL) + free (raw); + return false; } - + /* Read in and swap the important symbolic information for an ECOFF - object file. This is called by gdb. */ + object file. This is called by gdb via the read_debug_info entry + point in the backend structure. */ boolean -ecoff_slurp_symbolic_info (abfd) +_bfd_ecoff_slurp_symbolic_info (abfd, ignore, debug) bfd *abfd; + asection *ignore ATTRIBUTE_UNUSED; + struct ecoff_debug_info *debug; { const struct ecoff_backend_data * const backend = ecoff_backend (abfd); - bfd_size_type external_hdr_size; HDRR *internal_symhdr; bfd_size_type raw_base; bfd_size_type raw_size; @@ -483,6 +522,12 @@ ecoff_slurp_symbolic_info (abfd) char *fraw_src; char *fraw_end; struct fdr *fdr_ptr; + bfd_size_type raw_end; + bfd_size_type cb_end; + bfd_size_type amt; + file_ptr pos; + + BFD_ASSERT (debug == &ecoff_data (abfd)->debug_info); /* Check whether we've already gotten it, and whether there's any to get. */ @@ -494,66 +539,43 @@ ecoff_slurp_symbolic_info (abfd) return true; } - /* At this point bfd_get_symcount (abfd) holds the number of symbols - as read from the file header, but on ECOFF this is always the - size of the symbolic information header. It would be cleaner to - handle this when we first read the file in coffgen.c. */ - external_hdr_size = backend->external_hdr_size; - if (bfd_get_symcount (abfd) != external_hdr_size) - { - bfd_error = bad_value; - return false; - } - - /* Read the symbolic information header. */ - raw = (PTR) alloca (external_hdr_size); - if (bfd_seek (abfd, ecoff_data (abfd)->sym_filepos, SEEK_SET) == -1 - || (bfd_read (raw, external_hdr_size, 1, abfd) - != external_hdr_size)) - { - bfd_error = system_call_error; - return false; - } - internal_symhdr = &ecoff_data (abfd)->symbolic_header; - (*backend->swap_hdr_in) (abfd, raw, internal_symhdr); - - if (internal_symhdr->magic != backend->sym_magic) - { - bfd_error = bad_value; - return false; - } + if (! ecoff_slurp_symbolic_header (abfd)) + return false; - /* Now we can get the correct number of symbols. */ - bfd_get_symcount (abfd) = (internal_symhdr->isymMax - + internal_symhdr->iextMax); + internal_symhdr = &debug->symbolic_header; /* Read all the symbolic information at once. */ - raw_base = ecoff_data (abfd)->sym_filepos + external_hdr_size; - - if (internal_symhdr->cbExtOffset != 0) - raw_size = (internal_symhdr->cbExtOffset - - raw_base - + internal_symhdr->iextMax * backend->external_ext_size); - else - { - long cbline, issmax, issextmax; - - cbline = (internal_symhdr->cbLine + 3) &~ 3; - issmax = (internal_symhdr->issMax + 3) &~ 3; - issextmax = (internal_symhdr->issExtMax + 3) &~ 3; - raw_size = (cbline * sizeof (unsigned char) - + internal_symhdr->idnMax * backend->external_dnr_size - + internal_symhdr->ipdMax * backend->external_pdr_size - + internal_symhdr->isymMax * backend->external_sym_size - + internal_symhdr->ioptMax * backend->external_opt_size - + internal_symhdr->iauxMax * sizeof (union aux_ext) - + issmax * sizeof (char) - + issextmax * sizeof (char) - + internal_symhdr->ifdMax * backend->external_fdr_size - + internal_symhdr->crfd * backend->external_rfd_size - + internal_symhdr->iextMax * backend->external_ext_size); - } - + raw_base = (ecoff_data (abfd)->sym_filepos + + backend->debug_swap.external_hdr_size); + + /* Alpha ecoff makes the determination of raw_size difficult. It has + an undocumented debug data section between the symhdr and the first + documented section. And the ordering of the sections varies between + statically and dynamically linked executables. + If bfd supports SEEK_END someday, this code could be simplified. */ + + raw_end = 0; + +#define UPDATE_RAW_END(start, count, size) \ + cb_end = internal_symhdr->start + internal_symhdr->count * (size); \ + if (cb_end > raw_end) \ + raw_end = cb_end + + UPDATE_RAW_END (cbLineOffset, cbLine, sizeof (unsigned char)); + UPDATE_RAW_END (cbDnOffset, idnMax, backend->debug_swap.external_dnr_size); + UPDATE_RAW_END (cbPdOffset, ipdMax, backend->debug_swap.external_pdr_size); + UPDATE_RAW_END (cbSymOffset, isymMax, backend->debug_swap.external_sym_size); + UPDATE_RAW_END (cbOptOffset, ioptMax, backend->debug_swap.external_opt_size); + UPDATE_RAW_END (cbAuxOffset, iauxMax, sizeof (union aux_ext)); + UPDATE_RAW_END (cbSsOffset, issMax, sizeof (char)); + UPDATE_RAW_END (cbSsExtOffset, issExtMax, sizeof (char)); + UPDATE_RAW_END (cbFdOffset, ifdMax, backend->debug_swap.external_fdr_size); + UPDATE_RAW_END (cbRfdOffset, crfd, backend->debug_swap.external_rfd_size); + UPDATE_RAW_END (cbExtOffset, iextMax, backend->debug_swap.external_ext_size); + +#undef UPDATE_RAW_END + + raw_size = raw_end - raw_base; if (raw_size == 0) { ecoff_data (abfd)->sym_filepos = 0; @@ -561,28 +583,27 @@ ecoff_slurp_symbolic_info (abfd) } raw = (PTR) bfd_alloc (abfd, raw_size); if (raw == NULL) + return false; + + pos = ecoff_data (abfd)->sym_filepos; + pos += backend->debug_swap.external_hdr_size; + if (bfd_seek (abfd, pos, SEEK_SET) != 0 + || bfd_bread (raw, raw_size, abfd) != raw_size) { - bfd_error = no_memory; - return false; - } - if (bfd_read (raw, raw_size, 1, abfd) != raw_size) - { - bfd_error = system_call_error; bfd_release (abfd, raw); return false; } - ecoff_data (abfd)->raw_size = raw_size; ecoff_data (abfd)->raw_syments = raw; /* Get pointers for the numeric offsets in the HDRR structure. */ #define FIX(off1, off2, type) \ if (internal_symhdr->off1 == 0) \ - ecoff_data (abfd)->off2 = (type) NULL; \ + debug->off2 = (type) NULL; \ else \ - ecoff_data (abfd)->off2 = (type) ((char *) raw \ - + internal_symhdr->off1 \ - - raw_base) + debug->off2 = (type) ((char *) raw \ + + (internal_symhdr->off1 \ + - raw_base)) FIX (cbLineOffset, line, unsigned char *); FIX (cbDnOffset, external_dnr, PTR); FIX (cbPdOffset, external_pdr, PTR); @@ -604,21 +625,17 @@ ecoff_slurp_symbolic_info (abfd) We need to look at the fdr to deal with a lot of information in the symbols, so we swap them here. */ - ecoff_data (abfd)->fdr = - (struct fdr *) bfd_alloc (abfd, - (internal_symhdr->ifdMax * - sizeof (struct fdr))); - if (ecoff_data (abfd)->fdr == NULL) - { - bfd_error = no_memory; - return false; - } - external_fdr_size = backend->external_fdr_size; - fdr_ptr = ecoff_data (abfd)->fdr; - fraw_src = (char *) ecoff_data (abfd)->external_fdr; + amt = internal_symhdr->ifdMax; + amt *= sizeof (struct fdr); + debug->fdr = (struct fdr *) bfd_alloc (abfd, amt); + if (debug->fdr == NULL) + return false; + external_fdr_size = backend->debug_swap.external_fdr_size; + fdr_ptr = debug->fdr; + fraw_src = (char *) debug->external_fdr; fraw_end = fraw_src + internal_symhdr->ifdMax * external_fdr_size; for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++) - (*backend->swap_fdr_in) (abfd, (PTR) fraw_src, fdr_ptr); + (*backend->debug_swap.swap_fdr_in) (abfd, (PTR) fraw_src, fdr_ptr); return true; } @@ -638,18 +655,16 @@ static asymbol *ecoff_scom_symbol_ptr; /* Create an empty symbol. */ asymbol * -ecoff_make_empty_symbol (abfd) +_bfd_ecoff_make_empty_symbol (abfd) bfd *abfd; { ecoff_symbol_type *new; + bfd_size_type amt = sizeof (ecoff_symbol_type); - new = (ecoff_symbol_type *) bfd_alloc (abfd, sizeof (ecoff_symbol_type)); + new = (ecoff_symbol_type *) bfd_alloc (abfd, amt); if (new == (ecoff_symbol_type *) NULL) - { - bfd_error = no_memory; - return (asymbol *) NULL; - } - memset (new, 0, sizeof *new); + return (asymbol *) NULL; + memset ((PTR) new, 0, sizeof *new); new->symbol.section = (asection *) NULL; new->fdr = (FDR *) NULL; new->local = false; @@ -660,46 +675,18 @@ ecoff_make_empty_symbol (abfd) /* Set the BFD flags and section for an ECOFF symbol. */ -static void -ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr) +static boolean +ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, weak) bfd *abfd; SYMR *ecoff_sym; asymbol *asym; int ext; - asymbol **indirect_ptr_ptr; + int weak; { asym->the_bfd = abfd; asym->value = ecoff_sym->value; asym->section = &bfd_debug_section; - asym->udata = NULL; - - /* An indirect symbol requires two consecutive stabs symbols. */ - if (*indirect_ptr_ptr != (asymbol *) NULL) - { - BFD_ASSERT (ECOFF_IS_STAB (ecoff_sym)); - - /* @@ Stuffing pointers into integers is a no-no. - We can usually get away with it if the integer is - large enough though. */ - if (sizeof (asym) > sizeof (bfd_vma)) - abort (); - (*indirect_ptr_ptr)->value = (bfd_vma) asym; - - asym->flags = BSF_DEBUGGING; - asym->section = &bfd_und_section; - *indirect_ptr_ptr = NULL; - return; - } - - if (ECOFF_IS_STAB (ecoff_sym) - && (ECOFF_UNMARK_STAB (ecoff_sym->index) | N_EXT) == (N_INDR | N_EXT)) - { - asym->flags = BSF_DEBUGGING | BSF_INDIRECT; - asym->section = &bfd_ind_section; - /* Pass this symbol on to the next call to this function. */ - *indirect_ptr_ptr = asym; - return; - } + asym->udata.i = 0; /* Most symbol types are just for debugging. */ switch (ecoff_sym->st) @@ -714,18 +701,32 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr) if (ECOFF_IS_STAB (ecoff_sym)) { asym->flags = BSF_DEBUGGING; - return; + return true; } break; default: asym->flags = BSF_DEBUGGING; - return; + return true; } - if (ext) + if (weak) + asym->flags = BSF_EXPORT | BSF_WEAK; + else if (ext) asym->flags = BSF_EXPORT | BSF_GLOBAL; else - asym->flags = BSF_LOCAL; + { + asym->flags = BSF_LOCAL; + /* Normally, a local stProc symbol will have a corresponding + external symbol. We mark the local symbol as a debugging + symbol, in order to prevent nm from printing both out. + Similarly, we mark stLabel and stabs symbols as debugging + symbols. In both cases, we do want to set the value + correctly based on the symbol class. */ + if (ecoff_sym->st == stProc + || ecoff_sym->st == stLabel + || ECOFF_IS_STAB (ecoff_sym)) + asym->flags |= BSF_DEBUGGING; + } switch (ecoff_sym->sc) { case scNil: @@ -751,10 +752,10 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr) asym->flags = BSF_DEBUGGING; break; case scAbs: - asym->section = &bfd_abs_section; + asym->section = bfd_abs_section_ptr; break; case scUndefined: - asym->section = &bfd_und_section; + asym->section = bfd_und_section_ptr; asym->flags = 0; asym->value = 0; break; @@ -784,7 +785,7 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr) case scCommon: if (asym->value > ecoff_data (abfd)->gp_size) { - asym->section = &bfd_com_section; + asym->section = bfd_com_section_ptr; asym->flags = 0; break; } @@ -811,7 +812,7 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr) asym->flags = BSF_DEBUGGING; break; case scSUndefined: - asym->section = &bfd_und_section; + asym->section = bfd_und_section_ptr; asym->flags = 0; asym->value = 0; break; @@ -828,6 +829,10 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr) 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; } @@ -847,10 +852,15 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr) case N_SETD: case N_SETB: { + /* This code is no longer needed. It used to be used to + make the linker handle set symbols, but they are now + handled in the add_symbols routine instead. */ +#if 0 const char *name; asection *section; arelent_chain *reloc_chain; unsigned int bitsize; + bfd_size_type amt; /* Get a section with the same name as the symbol (usually __CTOR_LIST__ or __DTOR_LIST__). FIXME: gcc uses the @@ -870,14 +880,19 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr) { char *copy; - copy = (char *) bfd_alloc (abfd, strlen (name) + 1); + amt = strlen (name) + 1; + copy = (char *) bfd_alloc (abfd, amt); + if (!copy) + return false; strcpy (copy, name); section = bfd_make_section (abfd, copy); } /* Build a reloc pointing to this constructor. */ - reloc_chain = - (arelent_chain *) bfd_alloc (abfd, sizeof (arelent_chain)); + amt = sizeof (arelent_chain); + reloc_chain = (arelent_chain *) bfd_alloc (abfd, amt); + if (!reloc_chain) + return false; reloc_chain->relent.sym_ptr_ptr = bfd_get_section (asym)->symbol_ptr_ptr; reloc_chain->relent.address = section->_raw_size; @@ -902,31 +917,35 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr) section->constructor_chain = reloc_chain; section->_raw_size += bitsize / 8; +#endif /* 0 */ + /* Mark the symbol as a constructor. */ asym->flags |= BSF_CONSTRUCTOR; } break; } } + return true; } /* Read an ECOFF symbol table. */ boolean -ecoff_slurp_symbol_table (abfd) +_bfd_ecoff_slurp_symbol_table (abfd) bfd *abfd; { const struct ecoff_backend_data * const backend = ecoff_backend (abfd); - const bfd_size_type external_ext_size = backend->external_ext_size; - const bfd_size_type external_sym_size = backend->external_sym_size; + const bfd_size_type external_ext_size + = backend->debug_swap.external_ext_size; + const bfd_size_type external_sym_size + = backend->debug_swap.external_sym_size; void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *)) - = backend->swap_ext_in; + = backend->debug_swap.swap_ext_in; void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)) - = backend->swap_sym_in; + = backend->debug_swap.swap_sym_in; bfd_size_type internal_size; ecoff_symbol_type *internal; ecoff_symbol_type *internal_ptr; - asymbol *indirect_ptr; char *eraw_src; char *eraw_end; FDR *fdr_ptr; @@ -937,54 +956,54 @@ ecoff_slurp_symbol_table (abfd) return true; /* Get the symbolic information. */ - if (ecoff_slurp_symbolic_info (abfd) == false) + if (! _bfd_ecoff_slurp_symbolic_info (abfd, (asection *) NULL, + &ecoff_data (abfd)->debug_info)) return false; if (bfd_get_symcount (abfd) == 0) return true; - internal_size = bfd_get_symcount (abfd) * sizeof (ecoff_symbol_type); + internal_size = bfd_get_symcount (abfd); + internal_size *= sizeof (ecoff_symbol_type); internal = (ecoff_symbol_type *) bfd_alloc (abfd, internal_size); if (internal == NULL) - { - bfd_error = no_memory; - return false; - } + return false; internal_ptr = internal; - indirect_ptr = NULL; - eraw_src = (char *) ecoff_data (abfd)->external_ext; + eraw_src = (char *) ecoff_data (abfd)->debug_info.external_ext; eraw_end = (eraw_src - + (ecoff_data (abfd)->symbolic_header.iextMax + + (ecoff_data (abfd)->debug_info.symbolic_header.iextMax * external_ext_size)); for (; eraw_src < eraw_end; eraw_src += external_ext_size, internal_ptr++) { EXTR internal_esym; (*swap_ext_in) (abfd, (PTR) eraw_src, &internal_esym); - internal_ptr->symbol.name = (ecoff_data (abfd)->ssext + internal_ptr->symbol.name = (ecoff_data (abfd)->debug_info.ssext + internal_esym.asym.iss); - ecoff_set_symbol_info (abfd, &internal_esym.asym, - &internal_ptr->symbol, 1, &indirect_ptr); + if (!ecoff_set_symbol_info (abfd, &internal_esym.asym, + &internal_ptr->symbol, 1, + internal_esym.weakext)) + return false; /* The alpha uses a negative ifd field for section symbols. */ if (internal_esym.ifd >= 0) - internal_ptr->fdr = ecoff_data (abfd)->fdr + internal_esym.ifd; + internal_ptr->fdr = (ecoff_data (abfd)->debug_info.fdr + + internal_esym.ifd); else internal_ptr->fdr = NULL; internal_ptr->local = false; internal_ptr->native = (PTR) eraw_src; } - BFD_ASSERT (indirect_ptr == (asymbol *) NULL); /* The local symbols must be accessed via the fdr's, because the string and aux indices are relative to the fdr information. */ - fdr_ptr = ecoff_data (abfd)->fdr; - fdr_end = fdr_ptr + ecoff_data (abfd)->symbolic_header.ifdMax; + fdr_ptr = ecoff_data (abfd)->debug_info.fdr; + fdr_end = fdr_ptr + ecoff_data (abfd)->debug_info.symbolic_header.ifdMax; for (; fdr_ptr < fdr_end; fdr_ptr++) { char *lraw_src; char *lraw_end; - lraw_src = ((char *) ecoff_data (abfd)->external_sym + lraw_src = ((char *) ecoff_data (abfd)->debug_info.external_sym + fdr_ptr->isymBase * external_sym_size); lraw_end = lraw_src + fdr_ptr->csym * external_sym_size; for (; @@ -994,17 +1013,17 @@ ecoff_slurp_symbol_table (abfd) SYMR internal_sym; (*swap_sym_in) (abfd, (PTR) lraw_src, &internal_sym); - internal_ptr->symbol.name = (ecoff_data (abfd)->ss + internal_ptr->symbol.name = (ecoff_data (abfd)->debug_info.ss + fdr_ptr->issBase + internal_sym.iss); - ecoff_set_symbol_info (abfd, &internal_sym, - &internal_ptr->symbol, 0, &indirect_ptr); + if (!ecoff_set_symbol_info (abfd, &internal_sym, + &internal_ptr->symbol, 0, 0)) + return false; internal_ptr->fdr = fdr_ptr; internal_ptr->local = true; internal_ptr->native = (PTR) lraw_src; } } - BFD_ASSERT (indirect_ptr == (asymbol *) NULL); ecoff_data (abfd)->canonical_symbols = internal; @@ -1013,21 +1032,24 @@ ecoff_slurp_symbol_table (abfd) /* Return the amount of space needed for the canonical symbols. */ -unsigned int -ecoff_get_symtab_upper_bound (abfd) +long +_bfd_ecoff_get_symtab_upper_bound (abfd) bfd *abfd; { - if (ecoff_slurp_symbolic_info (abfd) == false - || bfd_get_symcount (abfd) == 0) + if (! _bfd_ecoff_slurp_symbolic_info (abfd, (asection *) NULL, + &ecoff_data (abfd)->debug_info)) + return -1; + + if (bfd_get_symcount (abfd) == 0) return 0; return (bfd_get_symcount (abfd) + 1) * (sizeof (ecoff_symbol_type *)); } -/* Get the canonicals symbols. */ +/* Get the canonical symbols. */ -unsigned int -ecoff_get_symtab (abfd, alocation) +long +_bfd_ecoff_get_symtab (abfd, alocation) bfd *abfd; asymbol **alocation; { @@ -1035,8 +1057,9 @@ ecoff_get_symtab (abfd, alocation) ecoff_symbol_type *symbase; ecoff_symbol_type **location = (ecoff_symbol_type **) alocation; - if (ecoff_slurp_symbol_table (abfd) == false - || bfd_get_symcount (abfd) == 0) + if (_bfd_ecoff_slurp_symbol_table (abfd) == false) + return -1; + if (bfd_get_symcount (abfd) == 0) return 0; symbase = ecoff_data (abfd)->canonical_symbols; @@ -1056,54 +1079,76 @@ ecoff_get_symtab (abfd, alocation) /* Write aggregate information to a string. */ static void -ecoff_emit_aggregate (abfd, string, rndx, isym, which) +ecoff_emit_aggregate (abfd, fdr, string, rndx, isym, which) bfd *abfd; + FDR *fdr; char *string; RNDXR *rndx; long isym; - CONST char *which; + const char *which; { - int ifd = rndx->rfd; - int indx = rndx->index; - int sym_base, ss_base; - CONST char *name; - + const struct ecoff_debug_swap * const debug_swap = + &ecoff_backend (abfd)->debug_swap; + struct ecoff_debug_info * const debug_info = &ecoff_data (abfd)->debug_info; + unsigned int ifd = rndx->rfd; + unsigned int indx = rndx->index; + const char *name; + if (ifd == 0xfff) ifd = isym; - sym_base = ecoff_data (abfd)->fdr[ifd].isymBase; - ss_base = ecoff_data (abfd)->fdr[ifd].issBase; - - if (indx == indexNil) - name = "/* no name */"; + /* An ifd of -1 is an opaque type. An escaped index of 0 is a + struct return type of a procedure compiled without -g. */ + if (ifd == 0xffffffff + || (rndx->rfd == 0xfff && indx == 0)) + name = ""; + else if (indx == indexNil) + name = ""; else { - const struct ecoff_backend_data * const backend = ecoff_backend (abfd); SYMR sym; - indx += sym_base; - (*backend->swap_sym_in) (abfd, - ((char *) ecoff_data (abfd)->external_sym - + indx * backend->external_sym_size), - &sym); - name = ecoff_data (abfd)->ss + ss_base + sym.iss; + if (debug_info->external_rfd == NULL) + fdr = debug_info->fdr + ifd; + else + { + RFDT rfd; + + (*debug_swap->swap_rfd_in) (abfd, + ((char *) debug_info->external_rfd + + ((fdr->rfdBase + ifd) + * debug_swap->external_rfd_size)), + &rfd); + fdr = debug_info->fdr + rfd; + } + + indx += fdr->isymBase; + + (*debug_swap->swap_sym_in) (abfd, + ((char *) debug_info->external_sym + + indx * debug_swap->external_sym_size), + &sym); + + name = debug_info->ss + fdr->issBase + sym.iss; } sprintf (string, - "%s %s { ifd = %d, index = %d }", + "%s %s { ifd = %u, index = %lu }", which, name, ifd, - indx + ecoff_data (abfd)->symbolic_header.iextMax); + ((long) indx + + debug_info->symbolic_header.iextMax)); } /* Convert the type information to string format. */ static char * -ecoff_type_to_string (abfd, aux_ptr, indx, bigendian) +ecoff_type_to_string (abfd, fdr, indx) bfd *abfd; - union aux_ext *aux_ptr; + FDR *fdr; unsigned int indx; - int bigendian; { + union aux_ext *aux_ptr; + int bigendian; AUXU u; struct qual { unsigned int type; @@ -1111,15 +1156,17 @@ ecoff_type_to_string (abfd, aux_ptr, indx, bigendian) int high_bound; int stride; } qualifiers[7]; - unsigned int basic_type; int i; - static char buffer1[1024]; + char buffer1[1024]; static char buffer2[1024]; char *p1 = buffer1; char *p2 = buffer2; RNDXR rndx; + aux_ptr = ecoff_data (abfd)->debug_info.external_aux + fdr->iauxBase; + bigendian = fdr->fBigendian; + for (i = 0; i < 7; i++) { qualifiers[i].low_bound = 0; @@ -1127,9 +1174,9 @@ ecoff_type_to_string (abfd, aux_ptr, indx, bigendian) qualifiers[i].stride = 0; } - if (AUX_GET_ISYM (bigendian, &aux_ptr[indx]) == -1) + if (AUX_GET_ISYM (bigendian, &aux_ptr[indx]) == (bfd_vma) -1) return "-1 (no type)"; - ecoff_swap_tir_in (bigendian, &aux_ptr[indx++].a_ti, &u.ti); + _bfd_ecoff_swap_tir_in (bigendian, &aux_ptr[indx++].a_ti, &u.ti); basic_type = u.ti.bt; qualifiers[0].type = u.ti.tq0; @@ -1198,9 +1245,9 @@ ecoff_type_to_string (abfd, aux_ptr, indx, bigendian) 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */ case btStruct: /* Structure (Record) */ - ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx); - ecoff_emit_aggregate (abfd, p1, &rndx, - AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]), + _bfd_ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx); + ecoff_emit_aggregate (abfd, fdr, p1, &rndx, + (long) AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]), "struct"); indx++; /* skip aux words */ break; @@ -1210,9 +1257,9 @@ ecoff_type_to_string (abfd, aux_ptr, indx, bigendian) 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */ case btUnion: /* Union */ - ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx); - ecoff_emit_aggregate (abfd, p1, &rndx, - AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]), + _bfd_ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx); + ecoff_emit_aggregate (abfd, fdr, p1, &rndx, + (long) AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]), "union"); indx++; /* skip aux words */ break; @@ -1222,9 +1269,9 @@ ecoff_type_to_string (abfd, aux_ptr, indx, bigendian) 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */ case btEnum: /* Enumeration */ - ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx); - ecoff_emit_aggregate (abfd, p1, &rndx, - AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]), + _bfd_ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx); + ecoff_emit_aggregate (abfd, fdr, p1, &rndx, + (long) AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]), "enum"); indx++; /* skip aux words */ break; @@ -1278,7 +1325,7 @@ ecoff_type_to_string (abfd, aux_ptr, indx, bigendian) break; default: - sprintf (p1, "Unknown basic type %d", (int) basic_type); + sprintf (p1, _("Unknown basic type %d"), (int) basic_type); break; } @@ -1296,7 +1343,6 @@ ecoff_type_to_string (abfd, aux_ptr, indx, bigendian) p1 += strlen (buffer1); } - /* * Deal with any qualifiers. */ @@ -1362,7 +1408,7 @@ ecoff_type_to_string (abfd, aux_ptr, indx, bigendian) int j; /* Print array bounds reversed (ie, in the order the C - programmer writes them). C is such a fun language.... */ + programmer writes them). C is such a fun language.... */ while (i < 5 && qualifiers[i+1].type == tqArray) i++; @@ -1404,24 +1450,35 @@ ecoff_type_to_string (abfd, aux_ptr, indx, bigendian) /* Return information about ECOFF symbol SYMBOL in RET. */ void -ecoff_get_symbol_info (abfd, symbol, ret) - bfd *abfd; /* Ignored. */ +_bfd_ecoff_get_symbol_info (abfd, symbol, ret) + bfd *abfd ATTRIBUTE_UNUSED; asymbol *symbol; symbol_info *ret; { bfd_symbol_info (symbol, ret); } +/* Return whether this is a local label. */ + +boolean +_bfd_ecoff_bfd_is_local_label_name (abfd, name) + bfd *abfd ATTRIBUTE_UNUSED; + const char *name; +{ + return name[0] == '$'; +} + /* Print information about an ECOFF symbol. */ void -ecoff_print_symbol (abfd, filep, symbol, how) +_bfd_ecoff_print_symbol (abfd, filep, symbol, how) bfd *abfd; PTR filep; asymbol *symbol; bfd_print_symbol_type how; { - const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + const struct ecoff_debug_swap * const debug_swap + = &ecoff_backend (abfd)->debug_swap; FILE *file = (FILE *)filep; switch (how) @@ -1433,9 +1490,9 @@ ecoff_print_symbol (abfd, filep, symbol, how) if (ecoffsymbol (symbol)->local) { SYMR ecoff_sym; - - (*backend->swap_sym_in) (abfd, ecoffsymbol (symbol)->native, - &ecoff_sym); + + (*debug_swap->swap_sym_in) (abfd, ecoffsymbol (symbol)->native, + &ecoff_sym); fprintf (file, "ecoff local "); fprintf_vma (file, (bfd_vma) ecoff_sym.value); fprintf (file, " %x %x", (unsigned) ecoff_sym.st, @@ -1445,8 +1502,8 @@ ecoff_print_symbol (abfd, filep, symbol, how) { EXTR ecoff_ext; - (*backend->swap_ext_in) (abfd, ecoffsymbol (symbol)->native, - &ecoff_ext); + (*debug_swap->swap_ext_in) (abfd, ecoffsymbol (symbol)->native, + &ecoff_ext); fprintf (file, "ecoff extern "); fprintf_vma (file, (bfd_vma) ecoff_ext.asym.value); fprintf (file, " %x %x", (unsigned) ecoff_ext.asym.st, @@ -1465,25 +1522,25 @@ ecoff_print_symbol (abfd, filep, symbol, how) if (ecoffsymbol (symbol)->local) { - (*backend->swap_sym_in) (abfd, ecoffsymbol (symbol)->native, - &ecoff_ext.asym); + (*debug_swap->swap_sym_in) (abfd, ecoffsymbol (symbol)->native, + &ecoff_ext.asym); type = 'l'; pos = ((((char *) ecoffsymbol (symbol)->native - - (char *) ecoff_data (abfd)->external_sym) - / backend->external_sym_size) - + ecoff_data (abfd)->symbolic_header.iextMax); + - (char *) ecoff_data (abfd)->debug_info.external_sym) + / debug_swap->external_sym_size) + + ecoff_data (abfd)->debug_info.symbolic_header.iextMax); jmptbl = ' '; cobol_main = ' '; weakext = ' '; } else { - (*backend->swap_ext_in) (abfd, ecoffsymbol (symbol)->native, - &ecoff_ext); + (*debug_swap->swap_ext_in) (abfd, ecoffsymbol (symbol)->native, + &ecoff_ext); type = 'e'; pos = (((char *) ecoffsymbol (symbol)->native - - (char *) ecoff_data (abfd)->external_ext) - / backend->external_ext_size); + - (char *) ecoff_data (abfd)->debug_info.external_ext) + / debug_swap->external_ext_size); jmptbl = ecoff_ext.jmptbl ? 'j' : ' '; cobol_main = ecoff_ext.cobol_main ? 'c' : ' '; weakext = ecoff_ext.weakext ? 'w' : ' '; @@ -1502,28 +1559,31 @@ ecoff_print_symbol (abfd, filep, symbol, how) if (ecoffsymbol (symbol)->fdr != NULL && ecoff_ext.asym.index != indexNil) { + FDR *fdr; unsigned int indx; int bigendian; bfd_size_type sym_base; union aux_ext *aux_base; + fdr = ecoffsymbol (symbol)->fdr; indx = ecoff_ext.asym.index; /* sym_base is used to map the fdr relative indices which appear in the file to the position number which we are using. */ - sym_base = ecoffsymbol (symbol)->fdr->isymBase; + sym_base = fdr->isymBase; if (ecoffsymbol (symbol)->local) - sym_base += ecoff_data (abfd)->symbolic_header.iextMax; + sym_base += + ecoff_data (abfd)->debug_info.symbolic_header.iextMax; /* aux_base is the start of the aux entries for this file; asym.index is an offset from this. */ - aux_base = (ecoff_data (abfd)->external_aux - + ecoffsymbol (symbol)->fdr->iauxBase); + aux_base = (ecoff_data (abfd)->debug_info.external_aux + + fdr->iauxBase); /* The aux entries are stored in host byte order; the order is indicated by a bit in the fdr. */ - bigendian = ecoffsymbol (symbol)->fdr->fBigendian; + bigendian = fdr->fBigendian; /* This switch is basically from gcc/mips-tdump.c */ switch (ecoff_ext.asym.st) @@ -1534,20 +1594,21 @@ ecoff_print_symbol (abfd, filep, symbol, how) case stFile: case stBlock: - fprintf (file, "\n End+1 symbol: %ld", + fprintf (file, _("\n End+1 symbol: %ld"), (long) (indx + sym_base)); break; case stEnd: if (ecoff_ext.asym.sc == scText || ecoff_ext.asym.sc == scInfo) - fprintf (file, "\n First symbol: %ld", + fprintf (file, _("\n First symbol: %ld"), (long) (indx + sym_base)); else - fprintf (file, "\n First symbol: %ld", - (long) (AUX_GET_ISYM (bigendian, - &aux_base[ecoff_ext.asym.index]) - + sym_base)); + fprintf (file, _("\n First symbol: %ld"), + ((long) + (AUX_GET_ISYM (bigendian, + &aux_base[ecoff_ext.asym.index]) + + sym_base))); break; case stProc: @@ -1555,24 +1616,39 @@ ecoff_print_symbol (abfd, filep, symbol, how) if (ECOFF_IS_STAB (&ecoff_ext.asym)) ; else if (ecoffsymbol (symbol)->local) - fprintf (file, "\n End+1 symbol: %-7ld Type: %s", - (long) (AUX_GET_ISYM (bigendian, - &aux_base[ecoff_ext.asym.index]) - + sym_base), - ecoff_type_to_string (abfd, aux_base, indx + 1, - bigendian)); + fprintf (file, _("\n End+1 symbol: %-7ld Type: %s"), + ((long) + (AUX_GET_ISYM (bigendian, + &aux_base[ecoff_ext.asym.index]) + + sym_base)), + ecoff_type_to_string (abfd, fdr, indx + 1)); else - fprintf (file, "\n Local symbol: %d", - (indx - + sym_base - + ecoff_data (abfd)->symbolic_header.iextMax)); + fprintf (file, _("\n Local symbol: %ld"), + ((long) indx + + (long) sym_base + + (ecoff_data (abfd) + ->debug_info.symbolic_header.iextMax))); + break; + + case stStruct: + fprintf (file, _("\n struct; End+1 symbol: %ld"), + (long) (indx + sym_base)); + break; + + case stUnion: + fprintf (file, _("\n union; End+1 symbol: %ld"), + (long) (indx + sym_base)); + break; + + case stEnum: + fprintf (file, _("\n enum; End+1 symbol: %ld"), + (long) (indx + sym_base)); break; default: if (! ECOFF_IS_STAB (&ecoff_ext.asym)) - fprintf (file, "\n Type: %s", - ecoff_type_to_string (abfd, aux_base, indx, - bigendian)); + fprintf (file, _("\n Type: %s"), + ecoff_type_to_string (abfd, fdr, indx)); break; } } @@ -1592,7 +1668,7 @@ ecoff_slurp_reloc_table (abfd, section, symbols) const struct ecoff_backend_data * const backend = ecoff_backend (abfd); arelent *internal_relocs; bfd_size_type external_reloc_size; - bfd_size_type external_relocs_size; + bfd_size_type amt; char *external_relocs; arelent *rptr; unsigned int i; @@ -1602,29 +1678,23 @@ ecoff_slurp_reloc_table (abfd, section, symbols) || (section->flags & SEC_CONSTRUCTOR) != 0) return true; - if (ecoff_slurp_symbol_table (abfd) == false) + if (_bfd_ecoff_slurp_symbol_table (abfd) == false) return false; - - internal_relocs = (arelent *) bfd_alloc (abfd, - (sizeof (arelent) - * section->reloc_count)); + + amt = section->reloc_count; + amt *= sizeof (arelent); + internal_relocs = (arelent *) bfd_alloc (abfd, amt); + external_reloc_size = backend->external_reloc_size; - external_relocs_size = external_reloc_size * section->reloc_count; - external_relocs = (char *) bfd_alloc (abfd, external_relocs_size); + amt = external_reloc_size * section->reloc_count; + external_relocs = (char *) bfd_alloc (abfd, amt); if (internal_relocs == (arelent *) NULL || external_relocs == (char *) NULL) - { - bfd_error = no_memory; - return false; - } + return false; if (bfd_seek (abfd, section->rel_filepos, SEEK_SET) != 0) return false; - if (bfd_read (external_relocs, 1, external_relocs_size, abfd) - != external_relocs_size) - { - bfd_error = system_call_error; - return false; - } + if (bfd_bread (external_relocs, amt, abfd) != amt) + return false; for (i = 0, rptr = internal_relocs; i < section->reloc_count; i++, rptr++) { @@ -1639,19 +1709,20 @@ ecoff_slurp_reloc_table (abfd, section, symbols) /* r_symndx is an index into the external symbols. */ BFD_ASSERT (intern.r_symndx >= 0 && (intern.r_symndx - < ecoff_data (abfd)->symbolic_header.iextMax)); + < (ecoff_data (abfd) + ->debug_info.symbolic_header.iextMax))); rptr->sym_ptr_ptr = symbols + intern.r_symndx; rptr->addend = 0; } else if (intern.r_symndx == RELOC_SECTION_NONE || intern.r_symndx == RELOC_SECTION_ABS) { - rptr->sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr; + rptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; rptr->addend = 0; } else { - CONST char *sec_name; + const char *sec_name; asection *sec; /* r_symndx is a section key. */ @@ -1668,7 +1739,9 @@ ecoff_slurp_reloc_table (abfd, section, symbols) case RELOC_SECTION_LIT4: sec_name = ".lit4"; break; case RELOC_SECTION_XDATA: sec_name = ".xdata"; break; 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 (); } @@ -1684,7 +1757,7 @@ ecoff_slurp_reloc_table (abfd, section, symbols) /* Let the backend select the howto field and do any other required processing. */ - (*backend->finish_reloc) (abfd, &intern, rptr); + (*backend->adjust_reloc_in) (abfd, &intern, rptr); } bfd_release (abfd, external_relocs); @@ -1696,8 +1769,8 @@ ecoff_slurp_reloc_table (abfd, section, symbols) /* Get a canonical list of relocs. */ -unsigned int -ecoff_canonicalize_reloc (abfd, section, relptr, symbols) +long +_bfd_ecoff_canonicalize_reloc (abfd, section, relptr, symbols) bfd *abfd; asection *section; arelent **relptr; @@ -1705,7 +1778,7 @@ ecoff_canonicalize_reloc (abfd, section, relptr, symbols) { unsigned int count; - if (section->flags & SEC_CONSTRUCTOR) + if (section->flags & SEC_CONSTRUCTOR) { arelent_chain *chain; @@ -1718,15 +1791,13 @@ ecoff_canonicalize_reloc (abfd, section, relptr, symbols) *relptr++ = &chain->relent; } else - { + { arelent *tblptr; if (ecoff_slurp_reloc_table (abfd, section, symbols) == false) - return 0; + return -1; tblptr = section->relocation; - if (tblptr == (arelent *) NULL) - return 0; for (count = 0; count < section->reloc_count; count++) *relptr++ = tblptr++; @@ -1742,1182 +1813,645 @@ ecoff_canonicalize_reloc (abfd, section, relptr, symbols) wanted location. */ boolean -ecoff_find_nearest_line (abfd, - section, - ignore_symbols, - offset, - filename_ptr, - functionname_ptr, - retline_ptr) +_bfd_ecoff_find_nearest_line (abfd, section, ignore_symbols, offset, + filename_ptr, functionname_ptr, retline_ptr) bfd *abfd; asection *section; - asymbol **ignore_symbols; + asymbol **ignore_symbols ATTRIBUTE_UNUSED; bfd_vma offset; - CONST char **filename_ptr; - CONST char **functionname_ptr; + const char **filename_ptr; + const char **functionname_ptr; unsigned int *retline_ptr; { - const struct ecoff_backend_data * const backend = ecoff_backend (abfd); - FDR *fdr_ptr; - FDR *fdr_start; - FDR *fdr_end; - FDR *fdr_hold; - bfd_size_type external_pdr_size; - char *pdr_ptr; - char *pdr_end; - PDR pdr; - unsigned char *line_ptr; - unsigned char *line_end; - int lineno; - - /* If we're not in the .text section, we don't have any line - numbers. */ - if (strcmp (section->name, _TEXT) != 0 - || offset < ecoff_data (abfd)->text_start - || offset >= ecoff_data (abfd)->text_end) - return false; + const struct ecoff_debug_swap * const debug_swap + = &ecoff_backend (abfd)->debug_swap; + struct ecoff_debug_info * const debug_info = &ecoff_data (abfd)->debug_info; + struct ecoff_find_line *line_info; /* Make sure we have the FDR's. */ - if (ecoff_slurp_symbolic_info (abfd) == false + if (! _bfd_ecoff_slurp_symbolic_info (abfd, (asection *) NULL, debug_info) || bfd_get_symcount (abfd) == 0) return false; - /* Each file descriptor (FDR) has a memory address. Here we track - down which FDR we want. The FDR's are stored in increasing - memory order. If speed is ever important, this can become a - binary search. We must ignore FDR's with no PDR entries; they - will have the adr of the FDR before or after them. */ - fdr_start = ecoff_data (abfd)->fdr; - fdr_end = fdr_start + ecoff_data (abfd)->symbolic_header.ifdMax; - fdr_hold = (FDR *) NULL; - for (fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++) - { - if (fdr_ptr->cpd == 0) - continue; - if (offset < fdr_ptr->adr) - break; - fdr_hold = fdr_ptr; - } - if (fdr_hold == (FDR *) NULL) - return false; - fdr_ptr = fdr_hold; - - /* Each FDR has a list of procedure descriptors (PDR). PDR's also - have an address, which is relative to the FDR address, and are - also stored in increasing memory order. */ - offset -= fdr_ptr->adr; - external_pdr_size = backend->external_pdr_size; - pdr_ptr = ((char *) ecoff_data (abfd)->external_pdr - + fdr_ptr->ipdFirst * external_pdr_size); - pdr_end = pdr_ptr + fdr_ptr->cpd * external_pdr_size; - (*backend->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr); - - /* The address of the first PDR is an offset which applies to the - addresses of all the PDR's. */ - offset += pdr.adr; - - for (pdr_ptr += external_pdr_size; - pdr_ptr < pdr_end; - pdr_ptr += external_pdr_size) - { - (*backend->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr); - if (offset < pdr.adr) - break; - } - - /* 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. - Note that right here pdr_ptr and pdr hold the PDR *after* the one - we want; we need this to compute line_end. */ - line_end = ecoff_data (abfd)->line; - if (pdr_ptr == pdr_end) - line_end += fdr_ptr->cbLineOffset + fdr_ptr->cbLine; - else - line_end += fdr_ptr->cbLineOffset + pdr.cbLineOffset; - - /* Now change pdr and pdr_ptr to the one we want. */ - pdr_ptr -= external_pdr_size; - (*backend->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr); - - offset -= pdr.adr; - lineno = pdr.lnLow; - line_ptr = (ecoff_data (abfd)->line - + fdr_ptr->cbLineOffset - + pdr.cbLineOffset); - while (line_ptr < line_end) - { - int delta; - 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) + if (ecoff_data (abfd)->find_line_info == NULL) { - *filename_ptr = NULL; - if (pdr.isym == -1) - *functionname_ptr = NULL; - else - { - EXTR proc_ext; - - (*backend->swap_ext_in) (abfd, - ((char *) ecoff_data (abfd)->external_ext - + pdr.isym * backend->external_ext_size), - &proc_ext); - *functionname_ptr = ecoff_data (abfd)->ssext + proc_ext.asym.iss; - } + bfd_size_type amt = sizeof (struct ecoff_find_line); + ecoff_data (abfd)->find_line_info + = (struct ecoff_find_line *) bfd_zalloc (abfd, amt); + if (ecoff_data (abfd)->find_line_info == NULL) + return false; } - else - { - SYMR proc_sym; - - *filename_ptr = ecoff_data (abfd)->ss + fdr_ptr->issBase + fdr_ptr->rss; - (*backend->swap_sym_in) (abfd, - ((char *) ecoff_data (abfd)->external_sym - + ((fdr_ptr->isymBase + pdr.isym) - * backend->external_sym_size)), - &proc_sym); - *functionname_ptr = (ecoff_data (abfd)->ss - + fdr_ptr->issBase - + proc_sym.iss); - } - if (lineno == ilineNil) - lineno = 0; - *retline_ptr = lineno; - return true; + line_info = ecoff_data (abfd)->find_line_info; + + return _bfd_ecoff_locate_line (abfd, section, offset, debug_info, + debug_swap, line_info, filename_ptr, + functionname_ptr, retline_ptr); } -/* We can't use the generic linking routines for ECOFF, because we - have to handle all the debugging information. The generic link - routine just works out the section contents and attaches a list of - symbols. - - We link by looping over all the seclets. We make two passes. On - the first we set the actual section contents and determine the size - of the debugging information. On the second we accumulate the - debugging information and write it out. - - This currently always accumulates the debugging information, which - is incorrect, because it ignores the -s and -S options of the - linker. The linker needs to be modified to give us that - information in a more useful format (currently it just provides a - list of symbols which should appear in the output file). */ - -/* Clear the output_has_begun flag for all the input BFD's. We use it - to avoid linking in the debugging information for a BFD more than - once. */ +/* Copy private BFD data. This is called by objcopy and strip. We + use it to copy the ECOFF debugging information from one BFD to the + other. It would be theoretically possible to represent the ECOFF + debugging information in the symbol table. However, it would be a + lot of work, and there would be little gain (gas, gdb, and ld + already access the ECOFF debugging information via the + ecoff_debug_info structure, and that structure would have to be + retained in order to support ECOFF debugging in MIPS ELF). + + The debugging information for the ECOFF external symbols comes from + the symbol table, so this function only handles the other debugging + information. */ -static void -ecoff_clear_output_flags (abfd) - bfd *abfd; +boolean +_bfd_ecoff_bfd_copy_private_bfd_data (ibfd, obfd) + bfd *ibfd; + bfd *obfd; { - register asection *o; - register bfd_seclet_type *p; + struct ecoff_debug_info *iinfo = &ecoff_data (ibfd)->debug_info; + struct ecoff_debug_info *oinfo = &ecoff_data (obfd)->debug_info; + register int i; + asymbol **sym_ptr_ptr; + size_t c; + boolean local; - for (o = abfd->sections; o != (asection *) NULL; o = o->next) - for (p = o->seclets_head; - p != (bfd_seclet_type *) NULL; - p = p->next) - if (p->type == bfd_indirect_seclet) - p->u.indirect.section->owner->output_has_begun = false; -} + /* We only want to copy information over if both BFD's use ECOFF + format. */ + if (bfd_get_flavour (ibfd) != bfd_target_ecoff_flavour + || bfd_get_flavour (obfd) != bfd_target_ecoff_flavour) + return true; -/* Handle an indirect seclet on the first pass. Set the contents of - the output section, and accumulate the debugging information if - any. */ + /* Copy the GP value and the register masks. */ + ecoff_data (obfd)->gp = ecoff_data (ibfd)->gp; + ecoff_data (obfd)->gprmask = ecoff_data (ibfd)->gprmask; + ecoff_data (obfd)->fprmask = ecoff_data (ibfd)->fprmask; + for (i = 0; i < 3; i++) + ecoff_data (obfd)->cprmask[i] = ecoff_data (ibfd)->cprmask[i]; -static boolean -ecoff_rel (output_bfd, seclet, output_section, data, relocateable) - bfd *output_bfd; - bfd_seclet_type *seclet; - asection *output_section; - PTR data; - boolean relocateable; -{ - bfd *input_bfd; - HDRR *output_symhdr; - HDRR *input_symhdr; - - if ((output_section->flags & SEC_HAS_CONTENTS) - && !(output_section->flags & SEC_NEVER_LOAD) - && (output_section->flags & SEC_LOAD) - && seclet->size) - { - data = (PTR) bfd_get_relocated_section_contents (output_bfd, - seclet, - data, - relocateable); - if (bfd_set_section_contents (output_bfd, - output_section, - data, - seclet->offset, - seclet->size) - == false) + /* Copy the version stamp. */ + oinfo->symbolic_header.vstamp = iinfo->symbolic_header.vstamp; + + /* If there are no symbols, don't copy any debugging information. */ + c = bfd_get_symcount (obfd); + sym_ptr_ptr = bfd_get_outsymbols (obfd); + if (c == 0 || sym_ptr_ptr == (asymbol **) NULL) + return true; + + /* See if there are any local symbols. */ + local = false; + for (; c > 0; c--, sym_ptr_ptr++) + { + if (ecoffsymbol (*sym_ptr_ptr)->local) { - abort(); + local = true; + break; } } - input_bfd = seclet->u.indirect.section->owner; + if (local) + { + /* There are some local symbols. We just bring over all the + debugging information. FIXME: This is not quite the right + thing to do. If the user has asked us to discard all + debugging information, then we are probably going to wind up + keeping it because there will probably be some local symbol + which objcopy did not discard. We should actually break + apart the debugging information and only keep that which + applies to the symbols we want to keep. */ + oinfo->symbolic_header.ilineMax = iinfo->symbolic_header.ilineMax; + oinfo->symbolic_header.cbLine = iinfo->symbolic_header.cbLine; + oinfo->line = iinfo->line; - /* We want to figure out how much space will be required to - incorporate all the debugging information from input_bfd. We use - the output_has_begun field to avoid adding it in more than once. - The actual incorporation is done in the second pass, in - ecoff_get_debug. The code has to parallel that code in its - manipulations of output_symhdr. */ + oinfo->symbolic_header.idnMax = iinfo->symbolic_header.idnMax; + oinfo->external_dnr = iinfo->external_dnr; - if (input_bfd->output_has_begun) - return true; - input_bfd->output_has_begun = true; + oinfo->symbolic_header.ipdMax = iinfo->symbolic_header.ipdMax; + oinfo->external_pdr = iinfo->external_pdr; - output_symhdr = &ecoff_data (output_bfd)->symbolic_header; + oinfo->symbolic_header.isymMax = iinfo->symbolic_header.isymMax; + oinfo->external_sym = iinfo->external_sym; - if (input_bfd->xvec->flavour != bfd_target_ecoff_flavour) - { - asymbol **symbols; - asymbol **sym_ptr; - asymbol **sym_end; + oinfo->symbolic_header.ioptMax = iinfo->symbolic_header.ioptMax; + oinfo->external_opt = iinfo->external_opt; - /* We just accumulate local symbols from a non-ECOFF BFD. The - external symbols are handled separately. */ + oinfo->symbolic_header.iauxMax = iinfo->symbolic_header.iauxMax; + oinfo->external_aux = iinfo->external_aux; - symbols = (asymbol **) bfd_alloc (output_bfd, - get_symtab_upper_bound (input_bfd)); - if (symbols == (asymbol **) NULL) - { - bfd_error = no_memory; - return false; - } - sym_end = symbols + bfd_canonicalize_symtab (input_bfd, symbols); + oinfo->symbolic_header.issMax = iinfo->symbolic_header.issMax; + oinfo->ss = iinfo->ss; + + oinfo->symbolic_header.ifdMax = iinfo->symbolic_header.ifdMax; + oinfo->external_fdr = iinfo->external_fdr; - for (sym_ptr = symbols; sym_ptr < sym_end; sym_ptr++) + oinfo->symbolic_header.crfd = iinfo->symbolic_header.crfd; + oinfo->external_rfd = iinfo->external_rfd; + } + else + { + /* We are discarding all the local symbol information. Look + through the external symbols and remove all references to FDR + or aux information. */ + c = bfd_get_symcount (obfd); + sym_ptr_ptr = bfd_get_outsymbols (obfd); + for (; c > 0; c--, sym_ptr_ptr++) { - size_t len; + EXTR esym; - len = strlen ((*sym_ptr)->name); - if (((*sym_ptr)->flags & BSF_EXPORT) == 0) - { - ++output_symhdr->isymMax; - output_symhdr->issMax += len + 1; - } + (*(ecoff_backend (obfd)->debug_swap.swap_ext_in)) + (obfd, ecoffsymbol (*sym_ptr_ptr)->native, &esym); + esym.ifd = ifdNil; + esym.asym.index = indexNil; + (*(ecoff_backend (obfd)->debug_swap.swap_ext_out)) + (obfd, &esym, ecoffsymbol (*sym_ptr_ptr)->native); } + } - bfd_release (output_bfd, (PTR) symbols); + return true; +} + +/* Set the architecture. The supported architecture is stored in the + backend pointer. We always set the architecture anyhow, since many + callers ignore the return value. */ - ++output_symhdr->ifdMax; +boolean +_bfd_ecoff_set_arch_mach (abfd, arch, machine) + bfd *abfd; + enum bfd_architecture arch; + unsigned long machine; +{ + bfd_default_set_arch_mach (abfd, arch, machine); + return arch == ecoff_backend (abfd)->arch; +} - return true; - } +/* Get the size of the section headers. */ - /* We simply add in the information from another ECOFF BFD. First - we make sure we have the symbolic information. */ - if (ecoff_slurp_symbol_table (input_bfd) == false) - return false; - if (bfd_get_symcount (input_bfd) == 0) - return true; +int +_bfd_ecoff_sizeof_headers (abfd, reloc) + bfd *abfd; + boolean reloc ATTRIBUTE_UNUSED; +{ + asection *current; + int c; + int ret; - input_symhdr = &ecoff_data (input_bfd)->symbolic_header; - - /* Figure out how much information we are going to be putting in. - The external symbols are handled separately. */ - output_symhdr->ilineMax += input_symhdr->ilineMax; - output_symhdr->cbLine += input_symhdr->cbLine; - output_symhdr->idnMax += input_symhdr->idnMax; - output_symhdr->ipdMax += input_symhdr->ipdMax; - output_symhdr->isymMax += input_symhdr->isymMax; - output_symhdr->ioptMax += input_symhdr->ioptMax; - output_symhdr->iauxMax += input_symhdr->iauxMax; - output_symhdr->issMax += input_symhdr->issMax; - output_symhdr->ifdMax += input_symhdr->ifdMax; - - /* The RFD's are special, since we create them if needed. */ - if (input_symhdr->crfd > 0) - output_symhdr->crfd += input_symhdr->crfd; - else - output_symhdr->crfd += input_symhdr->ifdMax; + c = 0; + for (current = abfd->sections; + current != (asection *)NULL; + current = current->next) + ++c; - return true; + ret = (bfd_coff_filhsz (abfd) + + bfd_coff_aoutsz (abfd) + + c * bfd_coff_scnhsz (abfd)); + return BFD_ALIGN (ret, 16); } -/* Handle an arbitrary seclet on the first pass. */ +/* Get the contents of a section. */ -static boolean -ecoff_dump_seclet (abfd, seclet, section, data, relocateable) +boolean +_bfd_ecoff_get_section_contents (abfd, section, location, offset, count) bfd *abfd; - bfd_seclet_type *seclet; asection *section; - PTR data; - boolean relocateable; + PTR location; + file_ptr offset; + bfd_size_type count; { - switch (seclet->type) - { - case bfd_indirect_seclet: - /* The contents of this section come from another one somewhere - else. */ - return ecoff_rel (abfd, seclet, section, data, relocateable); - - case bfd_fill_seclet: - /* Fill in the section with fill.value. This is used to pad out - sections, but we must avoid padding the .bss section. */ - if ((section->flags & SEC_HAS_CONTENTS) == 0) - { - if (seclet->u.fill.value != 0) - abort (); - } - else - { - char *d = (char *) bfd_alloc (abfd, seclet->size); - unsigned int i; - boolean ret; - - for (i = 0; i < seclet->size; i+=2) - d[i] = seclet->u.fill.value >> 8; - for (i = 1; i < seclet->size; i+=2) - d[i] = seclet->u.fill.value; - ret = bfd_set_section_contents (abfd, section, d, seclet->offset, - seclet->size); - bfd_release (abfd, (PTR) d); - return ret; - } - break; - - default: - abort(); - } - - return true; + return _bfd_generic_get_section_contents (abfd, section, location, + offset, count); } -/* Add a string to the debugging information we are accumulating for a - file. Return the offset from the fdr string base or from the - external string base. */ +/* Sort sections by VMA, but put SEC_ALLOC sections first. This is + called via qsort. */ -static long -ecoff_add_string (output_bfd, fdr, string, external) - bfd *output_bfd; - FDR *fdr; - CONST char *string; - boolean external; +static int +ecoff_sort_hdrs (arg1, arg2) + const PTR arg1; + const PTR arg2; { - HDRR *symhdr; - size_t len; - long ret; + const asection *hdr1 = *(const asection **) arg1; + const asection *hdr2 = *(const asection **) arg2; - symhdr = &ecoff_data (output_bfd)->symbolic_header; - len = strlen (string); - if (external) + if ((hdr1->flags & SEC_ALLOC) != 0) { - strcpy (ecoff_data (output_bfd)->ssext + symhdr->issExtMax, string); - ret = symhdr->issExtMax; - symhdr->issExtMax += len + 1; + if ((hdr2->flags & SEC_ALLOC) == 0) + return -1; } else { - strcpy (ecoff_data (output_bfd)->ss + symhdr->issMax, string); - ret = fdr->cbSs; - symhdr->issMax += len + 1; - fdr->cbSs += len + 1; + if ((hdr2->flags & SEC_ALLOC) != 0) + return 1; } - return ret; + if (hdr1->vma < hdr2->vma) + return -1; + else if (hdr1->vma > hdr2->vma) + return 1; + else + return 0; } -/* Accumulate the debugging information from an input section. */ +/* Calculate the file position for each section, and set + reloc_filepos. */ static boolean -ecoff_get_debug (output_bfd, seclet, section, relocateable) - bfd *output_bfd; - bfd_seclet_type *seclet; - asection *section; - boolean relocateable; +ecoff_compute_section_file_positions (abfd) + bfd *abfd; { - const struct ecoff_backend_data * const backend = ecoff_backend (output_bfd); - const bfd_size_type external_sym_size = backend->external_sym_size; - const bfd_size_type external_pdr_size = backend->external_pdr_size; - const bfd_size_type external_fdr_size = backend->external_fdr_size; - const bfd_size_type external_rfd_size = backend->external_rfd_size; - void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)) - = backend->swap_sym_in; - void (* const swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR)) - = backend->swap_sym_out; - void (* const swap_pdr_in) PARAMS ((bfd *, PTR, PDR *)) - = backend->swap_pdr_in; - void (* const swap_fdr_out) PARAMS ((bfd *, const FDR *, PTR)) - = backend->swap_fdr_out; - void (* const swap_rfd_out) PARAMS ((bfd *, const RFDT *, PTR)) - = backend->swap_rfd_out; - bfd *input_bfd; - HDRR *output_symhdr; - HDRR *input_symhdr; - ecoff_data_type *output_ecoff; - ecoff_data_type *input_ecoff; - unsigned int count; - char *sym_out; - ecoff_symbol_type *esym_ptr; - ecoff_symbol_type *esym_end; - FDR *fdr_ptr; - FDR *fdr_end; - char *fdr_out; - - input_bfd = seclet->u.indirect.section->owner; - - /* Don't get the information more than once. */ - if (input_bfd->output_has_begun) - return true; - input_bfd->output_has_begun = true; - - output_ecoff = ecoff_data (output_bfd); - output_symhdr = &output_ecoff->symbolic_header; + file_ptr sofar, file_sofar; + asection **sorted_hdrs; + asection *current; + unsigned int i; + file_ptr old_sofar; + boolean rdata_in_text; + boolean first_data, first_nonalloc; + const bfd_vma round = ecoff_backend (abfd)->round; + bfd_size_type amt; + + sofar = _bfd_ecoff_sizeof_headers (abfd, false); + file_sofar = sofar; + + /* Sort the sections by VMA. */ + amt = abfd->section_count; + amt *= sizeof (asection *); + sorted_hdrs = (asection **) bfd_malloc (amt); + if (sorted_hdrs == NULL) + return false; + for (current = abfd->sections, i = 0; + current != NULL; + current = current->next, i++) + sorted_hdrs[i] = current; + BFD_ASSERT (i == abfd->section_count); + + qsort (sorted_hdrs, abfd->section_count, sizeof (asection *), + ecoff_sort_hdrs); + + /* Some versions of the OSF linker put the .rdata section in the + text segment, and some do not. */ + rdata_in_text = ecoff_backend (abfd)->rdata_in_text; + if (rdata_in_text) + { + for (i = 0; i < abfd->section_count; i++) + { + current = sorted_hdrs[i]; + if (strcmp (current->name, _RDATA) == 0) + break; + if ((current->flags & SEC_CODE) == 0 + && strcmp (current->name, _PDATA) != 0 + && strcmp (current->name, _RCONST) != 0) + { + rdata_in_text = false; + break; + } + } + } + ecoff_data (abfd)->rdata_in_text = rdata_in_text; - if (input_bfd->xvec->flavour != bfd_target_ecoff_flavour) + first_data = true; + first_nonalloc = true; + for (i = 0; i < abfd->section_count; i++) { - FDR fdr; - asymbol **symbols; - asymbol **sym_ptr; - asymbol **sym_end; + unsigned int alignment_power; - /* This is not an ECOFF BFD. Just gather the symbols. */ + current = sorted_hdrs[i]; - memset (&fdr, 0, sizeof fdr); + /* For the Alpha ECOFF .pdata section the lnnoptr field is + supposed to indicate the number of .pdata entries that are + really in the section. Each entry is 8 bytes. We store this + away in line_filepos before increasing the section size. */ + if (strcmp (current->name, _PDATA) == 0) + current->line_filepos = current->_raw_size / 8; - fdr.adr = bfd_get_section_vma (output_bfd, section) + seclet->offset; - fdr.issBase = output_symhdr->issMax; - fdr.cbSs = 0; - fdr.rss = ecoff_add_string (output_bfd, - &fdr, - bfd_get_filename (input_bfd), - false); - fdr.isymBase = output_symhdr->isymMax; + alignment_power = current->alignment_power; - /* Get the local symbols from the input BFD. */ - symbols = (asymbol **) bfd_alloc (output_bfd, - get_symtab_upper_bound (input_bfd)); - if (symbols == (asymbol **) NULL) + /* On Ultrix, the data sections in an executable file must be + aligned to a page boundary within the file. This does not + affect the section size, though. FIXME: Does this work for + other platforms? It requires some modification for the + Alpha, because .rdata on the Alpha goes with the text, not + the data. */ + if ((abfd->flags & EXEC_P) != 0 + && (abfd->flags & D_PAGED) != 0 + && ! first_data + && (current->flags & SEC_CODE) == 0 + && (! rdata_in_text + || strcmp (current->name, _RDATA) != 0) + && strcmp (current->name, _PDATA) != 0 + && strcmp (current->name, _RCONST) != 0) { - bfd_error = no_memory; - return false; + sofar = (sofar + round - 1) &~ (round - 1); + file_sofar = (file_sofar + round - 1) &~ (round - 1); + first_data = false; } - sym_end = symbols + bfd_canonicalize_symtab (input_bfd, symbols); + else if (strcmp (current->name, _LIB) == 0) + { + /* On Irix 4, the location of contents of the .lib section + from a shared library section is also rounded up to a + page boundary. */ - /* Handle the local symbols. Any external symbols are handled - separately. */ - fdr.csym = 0; - for (sym_ptr = symbols; sym_ptr != sym_end; sym_ptr++) + sofar = (sofar + round - 1) &~ (round - 1); + file_sofar = (file_sofar + round - 1) &~ (round - 1); + } + else if (first_nonalloc + && (current->flags & SEC_ALLOC) == 0 + && (abfd->flags & D_PAGED) != 0) { - SYMR internal_sym; + /* Skip up to the next page for an unallocated section, such + as the .comment section on the Alpha. This leaves room + for the .bss section. */ + first_nonalloc = false; + sofar = (sofar + round - 1) &~ (round - 1); + file_sofar = (file_sofar + round - 1) &~ (round - 1); + } - if (((*sym_ptr)->flags & BSF_EXPORT) != 0) - continue; - memset (&internal_sym, 0, sizeof internal_sym); - internal_sym.iss = ecoff_add_string (output_bfd, - &fdr, - (*sym_ptr)->name, - false); - - if (bfd_is_com_section ((*sym_ptr)->section) - || (*sym_ptr)->section == &bfd_und_section) - internal_sym.value = (*sym_ptr)->value; - else - internal_sym.value = ((*sym_ptr)->value - + (*sym_ptr)->section->output_offset - + (*sym_ptr)->section->output_section->vma); - internal_sym.st = stNil; - internal_sym.sc = scUndefined; - internal_sym.index = indexNil; - (*swap_sym_out) (output_bfd, &internal_sym, - ((char *) output_ecoff->external_sym - + output_symhdr->isymMax * external_sym_size)); - ++fdr.csym; - ++output_symhdr->isymMax; + /* Align the sections in the file to the same boundary on + which they are aligned in virtual memory. */ + sofar = BFD_ALIGN (sofar, 1 << alignment_power); + if ((current->flags & SEC_HAS_CONTENTS) != 0) + file_sofar = BFD_ALIGN (file_sofar, 1 << alignment_power); + + if ((abfd->flags & D_PAGED) != 0 + && (current->flags & SEC_ALLOC) != 0) + { + sofar += (current->vma - sofar) % round; + if ((current->flags & SEC_HAS_CONTENTS) != 0) + file_sofar += (current->vma - file_sofar) % round; } - bfd_release (output_bfd, (PTR) symbols); + if ((current->flags & (SEC_HAS_CONTENTS | SEC_LOAD)) != 0) + current->filepos = file_sofar; - /* Leave everything else in the FDR zeroed out. This will cause - the lang field to be langC. The fBigendian field will - indicate little endian format, but it doesn't matter because - it only applies to aux fields and there are none. */ + sofar += current->_raw_size; + if ((current->flags & SEC_HAS_CONTENTS) != 0) + file_sofar += current->_raw_size; - (*swap_fdr_out) (output_bfd, &fdr, - ((char *) output_ecoff->external_fdr - + output_symhdr->ifdMax * external_fdr_size)); - ++output_symhdr->ifdMax; - return true; + /* make sure that this section is of the right size too */ + old_sofar = sofar; + sofar = BFD_ALIGN (sofar, 1 << alignment_power); + if ((current->flags & SEC_HAS_CONTENTS) != 0) + file_sofar = BFD_ALIGN (file_sofar, 1 << alignment_power); + current->_raw_size += sofar - old_sofar; } - /* This is an ECOFF BFD. We want to grab the information from - input_bfd and attach it to output_bfd. */ - count = bfd_get_symcount (input_bfd); - if (count == 0) - return true; - input_ecoff = ecoff_data (input_bfd); - input_symhdr = &input_ecoff->symbolic_header; - - /* I think that it is more efficient to simply copy the debugging - information from the input BFD to the output BFD. Because ECOFF - uses relative pointers for most of the debugging information, - only a little of it has to be changed at all. */ + free (sorted_hdrs); + sorted_hdrs = NULL; - /* Swap in the local symbols, adjust their values, and swap them out - again. The external symbols are handled separately. */ - sym_out = ((char *) output_ecoff->external_sym - + output_symhdr->isymMax * external_sym_size); + ecoff_data (abfd)->reloc_filepos = file_sofar; - esym_ptr = ecoff_data (input_bfd)->canonical_symbols; - esym_end = esym_ptr + count; - for (; esym_ptr < esym_end; esym_ptr++) - { - if (esym_ptr->local) - { - SYMR sym; + return true; +} - (*swap_sym_in) (input_bfd, esym_ptr->native, &sym); +/* Determine the location of the relocs for all the sections in the + output file, as well as the location of the symbolic debugging + information. */ - /* If we're producing an executable, move common symbols - into bss. */ - if (relocateable == false) - { - if (sym.sc == scCommon) - sym.sc = scBss; - else if (sym.sc == scSCommon) - sym.sc = scSBss; - } +static bfd_size_type +ecoff_compute_reloc_file_positions (abfd) + bfd *abfd; +{ + const bfd_size_type external_reloc_size = + ecoff_backend (abfd)->external_reloc_size; + file_ptr reloc_base; + bfd_size_type reloc_size; + asection *current; + file_ptr sym_base; - if (! bfd_is_com_section (esym_ptr->symbol.section) - && (esym_ptr->symbol.flags & BSF_DEBUGGING) == 0 - && esym_ptr->symbol.section != &bfd_und_section) - sym.value = (esym_ptr->symbol.value - + esym_ptr->symbol.section->output_offset - + esym_ptr->symbol.section->output_section->vma); - (*swap_sym_out) (output_bfd, &sym, sym_out); - sym_out += external_sym_size; - } + if (! abfd->output_has_begun) + { + if (! ecoff_compute_section_file_positions (abfd)) + abort (); + abfd->output_has_begun = true; } - /* That should have accounted for all the local symbols in - input_bfd. */ - - /* Copy the information that does not need swapping. */ - memcpy (output_ecoff->line + output_symhdr->cbLine, - input_ecoff->line, - input_symhdr->cbLine * sizeof (unsigned char)); - memcpy (output_ecoff->external_aux + output_symhdr->iauxMax, - input_ecoff->external_aux, - input_symhdr->iauxMax * sizeof (union aux_ext)); - memcpy (output_ecoff->ss + output_symhdr->issMax, - input_ecoff->ss, - input_symhdr->issMax * sizeof (char)); - - /* Some of the information may need to be swapped. */ - if (output_bfd->xvec->header_byteorder_big_p - == input_bfd->xvec->header_byteorder_big_p) - { - /* The two BFD's have the same endianness, so memcpy will - suffice. */ - if (input_symhdr->idnMax > 0) - memcpy (((char *) output_ecoff->external_dnr - + output_symhdr->idnMax * backend->external_dnr_size), - input_ecoff->external_dnr, - input_symhdr->idnMax * backend->external_dnr_size); - if (input_symhdr->ipdMax > 0) - memcpy (((char *) output_ecoff->external_pdr - + output_symhdr->ipdMax * external_pdr_size), - input_ecoff->external_pdr, - input_symhdr->ipdMax * external_pdr_size); - if (input_symhdr->ioptMax > 0) - memcpy (((char *) output_ecoff->external_opt - + output_symhdr->ioptMax * backend->external_opt_size), - input_ecoff->external_opt, - input_symhdr->ioptMax * backend->external_opt_size); - } - else + reloc_base = ecoff_data (abfd)->reloc_filepos; + + reloc_size = 0; + for (current = abfd->sections; + current != (asection *)NULL; + current = current->next) { - bfd_size_type sz; - char *in; - char *end; - char *out; - - /* The two BFD's have different endianness, so we must swap - everything in and out. This code would always work, but it - would be slow in the normal case. */ - sz = backend->external_dnr_size; - in = (char *) input_ecoff->external_dnr; - end = in + input_symhdr->idnMax * sz; - out = (char *) output_ecoff->external_dnr + output_symhdr->idnMax * sz; - for (; in < end; in += sz, out += sz) + if (current->reloc_count == 0) + current->rel_filepos = 0; + else { - DNR dnr; + bfd_size_type relsize; - (*backend->swap_dnr_in) (input_bfd, in, &dnr); - (*backend->swap_dnr_out) (output_bfd, &dnr, out); + current->rel_filepos = reloc_base; + relsize = current->reloc_count * external_reloc_size; + reloc_size += relsize; + reloc_base += relsize; } + } - sz = external_pdr_size; - in = (char *) input_ecoff->external_pdr; - end = in + input_symhdr->ipdMax * sz; - out = (char *) output_ecoff->external_pdr + output_symhdr->ipdMax * sz; - for (; in < end; in += sz, out += sz) - { - PDR pdr; + sym_base = ecoff_data (abfd)->reloc_filepos + reloc_size; - (*swap_pdr_in) (input_bfd, in, &pdr); - (*backend->swap_pdr_out) (output_bfd, &pdr, out); - } + /* At least on Ultrix, the symbol table of an executable file must + be aligned to a page boundary. FIXME: Is this true on other + platforms? */ + if ((abfd->flags & EXEC_P) != 0 + && (abfd->flags & D_PAGED) != 0) + sym_base = ((sym_base + ecoff_backend (abfd)->round - 1) + &~ (ecoff_backend (abfd)->round - 1)); - sz = backend->external_opt_size; - in = (char *) input_ecoff->external_opt; - end = in + input_symhdr->ioptMax * sz; - out = (char *) output_ecoff->external_opt + output_symhdr->ioptMax * sz; - for (; in < end; in += sz, out += sz) - { - OPTR opt; + ecoff_data (abfd)->sym_filepos = sym_base; - (*backend->swap_opt_in) (input_bfd, in, &opt); - (*backend->swap_opt_out) (output_bfd, &opt, out); - } - } + return reloc_size; +} - /* Set ifdbase so that the external symbols know how to adjust their - ifd values. */ - input_ecoff->ifdbase = output_symhdr->ifdMax; +/* Set the contents of a section. */ + +boolean +_bfd_ecoff_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + asection *section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + file_ptr pos; - fdr_ptr = input_ecoff->fdr; - fdr_end = fdr_ptr + input_symhdr->ifdMax; - fdr_out = ((char *) output_ecoff->external_fdr - + output_symhdr->ifdMax * external_fdr_size); - for (; fdr_ptr < fdr_end; fdr_ptr++, fdr_out += external_fdr_size) + /* This must be done first, because bfd_set_section_contents is + going to set output_has_begun to true. */ + if (abfd->output_has_begun == false) { - FDR fdr; - unsigned long pdr_off; + if (! ecoff_compute_section_file_positions (abfd)) + return false; + } - fdr = *fdr_ptr; + /* Handle the .lib section specially so that Irix 4 shared libraries + work out. See coff_set_section_contents in coffcode.h. */ + if (strcmp (section->name, _LIB) == 0) + { + bfd_byte *rec, *recend; - /* The memory address for this fdr is the address for the seclet - plus the offset to this fdr within input_bfd. For some - reason the offset of the first procedure pointer is also - added in. */ - if (fdr.cpd == 0) - pdr_off = 0; - else + rec = (bfd_byte *) location; + recend = rec + count; + while (rec < recend) { - PDR pdr; - - (*swap_pdr_in) (input_bfd, - ((char *) input_ecoff->external_pdr - + fdr.ipdFirst * external_pdr_size), - &pdr); - pdr_off = pdr.adr; + ++section->lma; + rec += bfd_get_32 (abfd, rec) * 4; } - fdr.adr = (bfd_get_section_vma (output_bfd, section) - + seclet->offset - + (fdr_ptr->adr - input_ecoff->fdr->adr) - + pdr_off); - - fdr.issBase += output_symhdr->issMax; - fdr.isymBase += output_symhdr->isymMax; - fdr.ilineBase += output_symhdr->ilineMax; - fdr.ioptBase += output_symhdr->ioptMax; - fdr.ipdFirst += output_symhdr->ipdMax; - fdr.iauxBase += output_symhdr->iauxMax; - fdr.rfdBase += output_symhdr->crfd; - - /* If there are no RFD's, we are going to add some. We don't - want to adjust irfd for this, so that all the FDR's can share - the RFD's. */ - if (input_symhdr->crfd == 0) - fdr.crfd = input_symhdr->ifdMax; - - if (fdr.cbLine != 0) - fdr.cbLineOffset += output_symhdr->cbLine; - - (*swap_fdr_out) (output_bfd, &fdr, fdr_out); - } - - if (input_symhdr->crfd > 0) - { - void (* const swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *)) - = backend->swap_rfd_in; - char *rfd_in; - char *rfd_end; - char *rfd_out; - - /* Swap and adjust the RFD's. RFD's are only created by the - linker, so this will only be necessary if one of the input - files is the result of a partial link. Presumably all - necessary RFD's are present. */ - rfd_in = (char *) input_ecoff->external_rfd; - rfd_end = rfd_in + input_symhdr->crfd * external_rfd_size; - rfd_out = ((char *) output_ecoff->external_rfd - + output_symhdr->crfd * external_rfd_size); - for (; - rfd_in < rfd_end; - rfd_in += external_rfd_size, rfd_out += external_rfd_size) - { - RFDT rfd; - (*swap_rfd_in) (input_bfd, rfd_in, &rfd); - rfd += output_symhdr->ifdMax; - (*swap_rfd_out) (output_bfd, &rfd, rfd_out); - } - output_symhdr->crfd += input_symhdr->crfd; + BFD_ASSERT (rec == recend); } - else - { - char *rfd_out; - char *rfd_end; - RFDT rfd; - - /* Create RFD's. Some of the debugging information includes - relative file indices. These indices are taken as indices to - the RFD table if there is one, or to the global table if - there is not. If we did not create RFD's, we would have to - parse and adjust all the debugging information which contains - file indices. */ - rfd = output_symhdr->ifdMax; - rfd_out = ((char *) output_ecoff->external_rfd - + output_symhdr->crfd * external_rfd_size); - rfd_end = rfd_out + input_symhdr->ifdMax * external_rfd_size; - for (; rfd_out < rfd_end; rfd_out += external_rfd_size, rfd++) - (*swap_rfd_out) (output_bfd, &rfd, rfd_out); - output_symhdr->crfd += input_symhdr->ifdMax; - } - - /* Combine the register masks. Not all of these are used on all - targets, but that's OK because only the relevant ones will be - swapped in and out. */ - { - int i; - output_ecoff->gprmask |= input_ecoff->gprmask; - output_ecoff->fprmask |= input_ecoff->fprmask; - for (i = 0; i < 4; i++) - output_ecoff->cprmask[i] |= input_ecoff->cprmask[i]; - } + if (count == 0) + return true; - /* Update the counts. */ - output_symhdr->ilineMax += input_symhdr->ilineMax; - output_symhdr->cbLine += input_symhdr->cbLine; - output_symhdr->idnMax += input_symhdr->idnMax; - output_symhdr->ipdMax += input_symhdr->ipdMax; - output_symhdr->isymMax += input_symhdr->isymMax; - output_symhdr->ioptMax += input_symhdr->ioptMax; - output_symhdr->iauxMax += input_symhdr->iauxMax; - output_symhdr->issMax += input_symhdr->issMax; - output_symhdr->ifdMax += input_symhdr->ifdMax; + pos = section->filepos + offset; + if (bfd_seek (abfd, pos, SEEK_SET) != 0 + || bfd_bwrite (location, count, abfd) != count) + return false; return true; } -/* This is the actual link routine. It makes two passes over all the - seclets. */ +/* Get the GP value for an ECOFF file. This is a hook used by + nlmconv. */ -boolean -ecoff_bfd_seclet_link (abfd, data, relocateable) +bfd_vma +bfd_ecoff_get_gp_value (abfd) bfd *abfd; - PTR data; - boolean relocateable; { - const struct ecoff_backend_data * const backend = ecoff_backend (abfd); - HDRR *symhdr; - int ipass; - register asection *o; - register bfd_seclet_type *p; - asymbol **sym_ptr_ptr; - bfd_size_type debug_align; - bfd_size_type size; - char *raw; + if (bfd_get_flavour (abfd) != bfd_target_ecoff_flavour + || bfd_get_format (abfd) != bfd_object) + { + bfd_set_error (bfd_error_invalid_operation); + return 0; + } - /* We accumulate the debugging information counts in the symbolic - header. */ - symhdr = &ecoff_data (abfd)->symbolic_header; - symhdr->magic = backend->sym_magic; - /* FIXME: What should the version stamp be? */ - symhdr->vstamp = 0; - symhdr->ilineMax = 0; - symhdr->cbLine = 0; - symhdr->idnMax = 0; - symhdr->ipdMax = 0; - symhdr->isymMax = 0; - symhdr->ioptMax = 0; - symhdr->iauxMax = 0; - symhdr->issMax = 0; - symhdr->issExtMax = 0; - symhdr->ifdMax = 0; - symhdr->crfd = 0; - symhdr->iextMax = 0; + return ecoff_data (abfd)->gp; +} + +/* Set the GP value for an ECOFF file. This is a hook used by the + assembler. */ - /* We need to copy over the debugging symbols from each input BFD. - When we do this copying, we have to adjust the text address in - the FDR structures, so we have to know the text address used for - the input BFD. Since we only want to copy the symbols once per - input BFD, but we are going to look at each input BFD multiple - times (once for each section it provides), we arrange to always - look at the text section first. That means that when we copy the - debugging information, we always know the text address. So we - actually do each pass in two sub passes; first the text sections, - then the non-text sections. We use the output_has_begun flag to - determine whether we have copied over the debugging information - yet. */ - - /* Do the first pass: set the output section contents and count the - debugging information. */ - ecoff_clear_output_flags (abfd); - for (ipass = 0; ipass < 2; ipass++) +boolean +bfd_ecoff_set_gp_value (abfd, gp_value) + bfd *abfd; + bfd_vma gp_value; +{ + if (bfd_get_flavour (abfd) != bfd_target_ecoff_flavour + || bfd_get_format (abfd) != bfd_object) { - for (o = abfd->sections; o != (asection *) NULL; o = o->next) - { - /* For SEC_CODE sections, (flags & SEC_CODE) == 0 is false, - so they are done on pass 0. For other sections the - expression is true, so they are done on pass 1. */ - if (((o->flags & SEC_CODE) == 0) != ipass) - continue; + bfd_set_error (bfd_error_invalid_operation); + return false; + } - for (p = o->seclets_head; - p != (bfd_seclet_type *) NULL; - p = p->next) - { - if (ecoff_dump_seclet (abfd, p, o, data, relocateable) - == false) - return false; - } - } + ecoff_data (abfd)->gp = gp_value; + + return true; +} + +/* Set the register masks for an ECOFF file. This is a hook used by + the assembler. */ + +boolean +bfd_ecoff_set_regmasks (abfd, gprmask, fprmask, cprmask) + bfd *abfd; + unsigned long gprmask; + unsigned long fprmask; + unsigned long *cprmask; +{ + ecoff_data_type *tdata; + + if (bfd_get_flavour (abfd) != bfd_target_ecoff_flavour + || bfd_get_format (abfd) != bfd_object) + { + bfd_set_error (bfd_error_invalid_operation); + return false; } - /* We handle the external symbols differently. We use the ones - attached to the output_bfd. The linker will have already - determined which symbols are to be attached. Here we just - determine how much space we will need for them. */ - sym_ptr_ptr = bfd_get_outsymbols (abfd); - if (sym_ptr_ptr != NULL) + tdata = ecoff_data (abfd); + tdata->gprmask = gprmask; + tdata->fprmask = fprmask; + if (cprmask != (unsigned long *) NULL) { - asymbol **sym_end; + register int i; - sym_end = sym_ptr_ptr + bfd_get_symcount (abfd); - for (; sym_ptr_ptr < sym_end; sym_ptr_ptr++) - { - if (((*sym_ptr_ptr)->flags & BSF_DEBUGGING) == 0 - && ((*sym_ptr_ptr)->flags & BSF_LOCAL) == 0) - { - ++symhdr->iextMax; - symhdr->issExtMax += strlen ((*sym_ptr_ptr)->name) + 1; - } - } + for (i = 0; i < 3; i++) + tdata->cprmask[i] = cprmask[i]; } - /* Adjust the counts so that structures are longword aligned. */ - debug_align = backend->debug_align; - --debug_align; - symhdr->cbLine = (symhdr->cbLine + debug_align) &~ debug_align; - symhdr->issMax = (symhdr->issMax + debug_align) &~ debug_align; - symhdr->issExtMax = (symhdr->issExtMax + debug_align) &~ debug_align; - - /* Now the counts in symhdr are the correct size for the debugging - information. We allocate the right amount of space, and reset - the counts so that the second pass can use them as indices. It - would be possible to output the debugging information directly to - the file in pass 2, rather than to build it in memory and then - write it out. Outputting to the file would require a lot of - seeks and small writes, though, and I think this approach is - faster. */ - size = (symhdr->cbLine * sizeof (unsigned char) - + symhdr->idnMax * backend->external_dnr_size - + symhdr->ipdMax * backend->external_pdr_size - + symhdr->isymMax * backend->external_sym_size - + symhdr->ioptMax * backend->external_opt_size - + symhdr->iauxMax * sizeof (union aux_ext) - + symhdr->issMax * sizeof (char) - + symhdr->issExtMax * sizeof (char) - + symhdr->ifdMax * backend->external_fdr_size - + symhdr->crfd * backend->external_rfd_size - + symhdr->iextMax * backend->external_ext_size); - raw = (char *) bfd_alloc (abfd, size); - if (raw == (char *) NULL) - { - bfd_error = no_memory; - return false; - } - ecoff_data (abfd)->raw_size = size; - ecoff_data (abfd)->raw_syments = (PTR) raw; - - /* Initialize the raw pointers. */ -#define SET(field, count, type, size) \ - ecoff_data (abfd)->field = (type) raw; \ - raw += symhdr->count * size - - SET (line, cbLine, unsigned char *, sizeof (unsigned char)); - SET (external_dnr, idnMax, PTR, backend->external_dnr_size); - SET (external_pdr, ipdMax, PTR, backend->external_pdr_size); - SET (external_sym, isymMax, PTR, backend->external_sym_size); - SET (external_opt, ioptMax, PTR, backend->external_opt_size); - SET (external_aux, iauxMax, union aux_ext *, sizeof (union aux_ext)); - SET (ss, issMax, char *, sizeof (char)); - SET (ssext, issExtMax, char *, sizeof (char)); - SET (external_fdr, ifdMax, PTR, backend->external_fdr_size); - SET (external_rfd, crfd, PTR, backend->external_rfd_size); - SET (external_ext, iextMax, PTR, backend->external_ext_size); -#undef SET - - /* Reset the counts so the second pass can use them to know how far - it has gotten. */ - symhdr->ilineMax = 0; - symhdr->cbLine = 0; - symhdr->idnMax = 0; - symhdr->ipdMax = 0; - symhdr->isymMax = 0; - symhdr->ioptMax = 0; - symhdr->iauxMax = 0; - symhdr->issMax = 0; - symhdr->issExtMax = 0; - symhdr->ifdMax = 0; - symhdr->crfd = 0; - symhdr->iextMax = 0; - - /* Do the second pass: accumulate the debugging information. */ - ecoff_clear_output_flags (abfd); - for (ipass = 0; ipass < 2; ipass++) - { - for (o = abfd->sections; o != (asection *) NULL; o = o->next) - { - if (((o->flags & SEC_CODE) == 0) != ipass) - continue; - for (p = o->seclets_head; - p != (bfd_seclet_type *) NULL; - p = p->next) - { - if (p->type == bfd_indirect_seclet) - { - if (ecoff_get_debug (abfd, p, o, relocateable) == false) - return false; - } - } - } - } - - /* Put in the external symbols. */ - sym_ptr_ptr = bfd_get_outsymbols (abfd); - if (sym_ptr_ptr != NULL) - { - const bfd_size_type external_ext_size = backend->external_ext_size; - void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *)) - = backend->swap_ext_in; - void (* const swap_ext_out) PARAMS ((bfd *, const EXTR *, PTR)) - = backend->swap_ext_out; - char *ssext; - char *external_ext; - - ssext = ecoff_data (abfd)->ssext; - external_ext = (char *) ecoff_data (abfd)->external_ext; - for (; *sym_ptr_ptr != NULL; sym_ptr_ptr++) - { - asymbol *sym_ptr; - EXTR esym; - - sym_ptr = *sym_ptr_ptr; - - if ((sym_ptr->flags & BSF_DEBUGGING) != 0 - || (sym_ptr->flags & BSF_LOCAL) != 0) - continue; - - /* The native pointer can be NULL for a symbol created by - the linker via ecoff_make_empty_symbol. */ - if (bfd_asymbol_flavour (sym_ptr) != bfd_target_ecoff_flavour - || ecoffsymbol (sym_ptr)->native == NULL) - { - esym.jmptbl = 0; - esym.cobol_main = 0; - esym.weakext = 0; - esym.reserved = 0; - esym.ifd = ifdNil; - /* FIXME: we can do better than this for st and sc. */ - esym.asym.st = stGlobal; - esym.asym.sc = scAbs; - esym.asym.reserved = 0; - esym.asym.index = indexNil; - } - else - { - ecoff_symbol_type *ecoff_sym_ptr; - - ecoff_sym_ptr = ecoffsymbol (sym_ptr); - if (ecoff_sym_ptr->local) - abort (); - (*swap_ext_in) (abfd, ecoff_sym_ptr->native, &esym); - - /* If we're producing an executable, move common symbols - into bss. */ - if (relocateable == false) - { - if (esym.asym.sc == scCommon) - esym.asym.sc = scBss; - else if (esym.asym.sc == scSCommon) - esym.asym.sc = scSBss; - } - - /* Adjust the FDR index for the symbol by that used for - the input BFD. */ - esym.ifd += ecoff_data (bfd_asymbol_bfd (sym_ptr))->ifdbase; - } - - esym.asym.iss = symhdr->issExtMax; - - if (bfd_is_com_section (sym_ptr->section) - || sym_ptr->section == &bfd_und_section) - esym.asym.value = sym_ptr->value; - else - esym.asym.value = (sym_ptr->value - + sym_ptr->section->output_offset - + sym_ptr->section->output_section->vma); - - (*swap_ext_out) (abfd, &esym, external_ext); - - ecoff_set_sym_index (sym_ptr, symhdr->iextMax); - - external_ext += external_ext_size; - ++symhdr->iextMax; - - strcpy (ssext + symhdr->issExtMax, sym_ptr->name); - symhdr->issExtMax += strlen (sym_ptr->name) + 1; - } - } - - /* Adjust the counts so that structures are longword aligned. */ - symhdr->cbLine = (symhdr->cbLine + debug_align) &~ debug_align; - symhdr->issMax = (symhdr->issMax + debug_align) &~ debug_align; - symhdr->issExtMax = (symhdr->issExtMax + debug_align) &~ debug_align; - return true; } - -/* Set the architecture. The supported architecture is stored in the - backend pointer. We always set the architecture anyhow, since many - callers ignore the return value. */ - -boolean -ecoff_set_arch_mach (abfd, arch, machine) - bfd *abfd; - enum bfd_architecture arch; - unsigned long machine; -{ - bfd_default_set_arch_mach (abfd, arch, machine); - return arch == ecoff_backend (abfd)->arch; -} - -/* Get the size of the section headers. We do not output the .scommon - section which we created in ecoff_mkobject. */ - -int -ecoff_sizeof_headers (abfd, reloc) - bfd *abfd; - boolean reloc; -{ - return (bfd_coff_filhsz (abfd) - + bfd_coff_aoutsz (abfd) - + (abfd->section_count - 1) * bfd_coff_scnhsz (abfd)); -} -/* Calculate the file position for each section, and set - reloc_filepos. */ +/* Get ECOFF EXTR information for an external symbol. This function + is passed to bfd_ecoff_debug_externals. */ -static void -ecoff_compute_section_file_positions (abfd) - bfd *abfd; +static boolean +ecoff_get_extr (sym, esym) + asymbol *sym; + EXTR *esym; { - asection *current; - file_ptr sofar; - file_ptr old_sofar; - boolean first_data; - - if (bfd_get_start_address (abfd)) - abfd->flags |= EXEC_P; - - sofar = ecoff_sizeof_headers (abfd, false); + ecoff_symbol_type *ecoff_sym_ptr; + bfd *input_bfd; - first_data = true; - for (current = abfd->sections; - current != (asection *) NULL; - current = current->next) + if (bfd_asymbol_flavour (sym) != bfd_target_ecoff_flavour + || ecoffsymbol (sym)->native == NULL) { - /* Only deal with sections which have contents */ - if ((current->flags & (SEC_HAS_CONTENTS | SEC_LOAD)) == 0 - || strcmp (current->name, SCOMMON) == 0) - continue; - - /* On Ultrix, the data sections in an executable file must be - aligned to a page boundary within the file. This does not - affect the section size, though. FIXME: Does this work for - other platforms? */ - if ((abfd->flags & EXEC_P) != 0 - && (abfd->flags & D_PAGED) != 0 - && first_data != false - && (current->flags & SEC_CODE) == 0) - { - const bfd_vma round = ecoff_backend (abfd)->round; + /* Don't include debugging, local, or section symbols. */ + if ((sym->flags & BSF_DEBUGGING) != 0 + || (sym->flags & BSF_LOCAL) != 0 + || (sym->flags & BSF_SECTION_SYM) != 0) + return false; - sofar = (sofar + round - 1) &~ (round - 1); - first_data = false; - } + esym->jmptbl = 0; + esym->cobol_main = 0; + esym->weakext = (sym->flags & BSF_WEAK) != 0; + esym->reserved = 0; + esym->ifd = ifdNil; + /* FIXME: we can do better than this for st and sc. */ + esym->asym.st = stGlobal; + esym->asym.sc = scAbs; + esym->asym.reserved = 0; + esym->asym.index = indexNil; + return true; + } - /* Align the sections in the file to the same boundary on - which they are aligned in virtual memory. */ - old_sofar = sofar; - sofar = BFD_ALIGN (sofar, 1 << current->alignment_power); + ecoff_sym_ptr = ecoffsymbol (sym); - current->filepos = sofar; + if (ecoff_sym_ptr->local) + return false; - sofar += current->_raw_size; + input_bfd = bfd_asymbol_bfd (sym); + (*(ecoff_backend (input_bfd)->debug_swap.swap_ext_in)) + (input_bfd, ecoff_sym_ptr->native, esym); + + /* If the symbol was defined by the linker, then esym will be + undefined but sym will not be. Get a better class for such a + symbol. */ + if ((esym->asym.sc == scUndefined + || esym->asym.sc == scSUndefined) + && ! bfd_is_und_section (bfd_get_section (sym))) + esym->asym.sc = scAbs; + + /* Adjust the FDR index for the symbol by that used for the input + BFD. */ + if (esym->ifd != -1) + { + struct ecoff_debug_info *input_debug; - /* make sure that this section is of the right size too */ - old_sofar = sofar; - sofar = BFD_ALIGN (sofar, 1 << current->alignment_power); - current->_raw_size += sofar - old_sofar; + input_debug = &ecoff_data (input_bfd)->debug_info; + BFD_ASSERT (esym->ifd < input_debug->symbolic_header.ifdMax); + if (input_debug->ifdmap != (RFDT *) NULL) + esym->ifd = input_debug->ifdmap[esym->ifd]; } - ecoff_data (abfd)->reloc_filepos = sofar; + return true; } -/* Set the contents of a section. */ +/* Set the external symbol index. This routine is passed to + bfd_ecoff_debug_externals. */ -boolean -ecoff_set_section_contents (abfd, section, location, offset, count) - bfd *abfd; - asection *section; - PTR location; - file_ptr offset; - bfd_size_type count; +static void +ecoff_set_index (sym, indx) + asymbol *sym; + bfd_size_type indx; { - if (abfd->output_has_begun == false) - ecoff_compute_section_file_positions (abfd); - - bfd_seek (abfd, (file_ptr) (section->filepos + offset), SEEK_SET); - - if (count != 0) - return (bfd_write (location, 1, count, abfd) == count) ? true : false; - - return true; + ecoff_set_sym_index (sym, indx); } /* Write out an ECOFF file. */ boolean -ecoff_write_object_contents (abfd) +_bfd_ecoff_write_object_contents (abfd) bfd *abfd; { const struct ecoff_backend_data * const backend = ecoff_backend (abfd); @@ -2925,88 +2459,78 @@ ecoff_write_object_contents (abfd) const bfd_size_type filhsz = bfd_coff_filhsz (abfd); const bfd_size_type aoutsz = bfd_coff_aoutsz (abfd); const bfd_size_type scnhsz = bfd_coff_scnhsz (abfd); - const bfd_size_type external_hdr_size = backend->external_hdr_size; + const bfd_size_type external_hdr_size + = backend->debug_swap.external_hdr_size; const bfd_size_type external_reloc_size = backend->external_reloc_size; + void (* const adjust_reloc_out) PARAMS ((bfd *, + const arelent *, + struct internal_reloc *)) + = backend->adjust_reloc_out; void (* const swap_reloc_out) PARAMS ((bfd *, const struct internal_reloc *, PTR)) = backend->swap_reloc_out; + struct ecoff_debug_info * const debug = &ecoff_data (abfd)->debug_info; + HDRR * const symhdr = &debug->symbolic_header; asection *current; unsigned int count; - file_ptr scn_base; - file_ptr reloc_base; - file_ptr sym_base; - unsigned long reloc_size; - unsigned long text_size; - unsigned long text_start; - unsigned long data_size; - unsigned long data_start; - unsigned long bss_size; - PTR buff; + bfd_size_type reloc_size; + bfd_size_type text_size; + bfd_vma text_start; + boolean set_text_start; + bfd_size_type data_size; + bfd_vma data_start; + boolean set_data_start; + bfd_size_type bss_size; + PTR buff = NULL; + PTR reloc_buff = NULL; struct internal_filehdr internal_f; struct internal_aouthdr internal_a; int i; - bfd_error = system_call_error; - - if(abfd->output_has_begun == false) - ecoff_compute_section_file_positions(abfd); - - if (abfd->sections != (asection *) NULL) - scn_base = abfd->sections->filepos; - else - scn_base = 0; - reloc_base = ecoff_data (abfd)->reloc_filepos; + /* Determine where the sections and relocs will go in the output + file. */ + reloc_size = ecoff_compute_reloc_file_positions (abfd); count = 1; - reloc_size = 0; for (current = abfd->sections; - current != (asection *)NULL; - current = current->next) + current != (asection *)NULL; + current = current->next) { - if (strcmp (current->name, SCOMMON) == 0) - continue; current->target_index = count; ++count; - if (current->reloc_count != 0) - { - bfd_size_type relsize; - - current->rel_filepos = reloc_base; - relsize = current->reloc_count * external_reloc_size; - reloc_size += relsize; - reloc_base += relsize; - } - else - current->rel_filepos = 0; } - sym_base = reloc_base + reloc_size; - - /* At least on Ultrix, the symbol table of an executable file must - be aligned to a page boundary. FIXME: Is this true on other - platforms? */ - if ((abfd->flags & EXEC_P) != 0 - && (abfd->flags & D_PAGED) != 0) - sym_base = (sym_base + round - 1) &~ (round - 1); - - ecoff_data (abfd)->sym_filepos = sym_base; - if ((abfd->flags & D_PAGED) != 0) - text_size = ecoff_sizeof_headers (abfd, false); + text_size = _bfd_ecoff_sizeof_headers (abfd, false); else text_size = 0; text_start = 0; + set_text_start = false; data_size = 0; data_start = 0; + set_data_start = false; bss_size = 0; /* Write section headers to the file. */ - buff = (PTR) alloca (scnhsz); + /* Allocate buff big enough to hold a section header, + file header, or a.out header. */ + { + bfd_size_type siz; + siz = scnhsz; + if (siz < filhsz) + siz = filhsz; + if (siz < aoutsz) + siz = aoutsz; + buff = (PTR) bfd_malloc (siz); + if (buff == NULL) + goto error_return; + } + internal_f.f_nscns = 0; if (bfd_seek (abfd, (file_ptr) (filhsz + aoutsz), SEEK_SET) != 0) - return false; + goto error_return; for (current = abfd->sections; current != (asection *) NULL; current = current->next) @@ -3014,26 +2538,18 @@ ecoff_write_object_contents (abfd) struct internal_scnhdr section; bfd_vma vma; - if (strcmp (current->name, SCOMMON) == 0) - { - BFD_ASSERT (bfd_get_section_size_before_reloc (current) == 0 - && current->reloc_count == 0); - continue; - } - ++internal_f.f_nscns; strncpy (section.s_name, current->name, sizeof section.s_name); - /* FIXME: is this correct for shared libraries? I think it is - but I have no platform to check. Ian Lance Taylor. */ + /* This seems to be correct for Irix 4 shared libraries. */ vma = bfd_get_section_vma (abfd, current); if (strcmp (current->name, _LIB) == 0) section.s_vaddr = 0; else section.s_vaddr = vma; - section.s_paddr = vma; + section.s_paddr = current->lma; section.s_size = bfd_get_section_size_before_reloc (current); /* If this section is unloadable then the scnptr will be 0. */ @@ -3050,44 +2566,78 @@ ecoff_write_object_contents (abfd) want the linker to compute the best size to use, or something. I don't know what happens if the information is not present. */ - section.s_lnnoptr = 0; + if (strcmp (current->name, _PDATA) != 0) + section.s_lnnoptr = 0; + else + { + /* The Alpha ECOFF .pdata section uses the lnnoptr field to + hold the number of entries in the section (each entry is + 8 bytes). We stored this in the line_filepos field in + ecoff_compute_section_file_positions. */ + section.s_lnnoptr = current->line_filepos; + } section.s_nreloc = current->reloc_count; section.s_nlnno = 0; section.s_flags = ecoff_sec_to_styp_flags (current->name, current->flags); - bfd_coff_swap_scnhdr_out (abfd, (PTR) §ion, buff); - if (bfd_write (buff, 1, scnhsz, abfd) != scnhsz) - return false; - - if ((section.s_flags & STYP_TEXT) != 0) + if (bfd_coff_swap_scnhdr_out (abfd, (PTR) §ion, buff) == 0 + || bfd_bwrite (buff, scnhsz, abfd) != scnhsz) + goto error_return; + + if ((section.s_flags & STYP_TEXT) != 0 + || ((section.s_flags & STYP_RDATA) != 0 + && ecoff_data (abfd)->rdata_in_text) + || section.s_flags == STYP_PDATA + || (section.s_flags & STYP_DYNAMIC) != 0 + || (section.s_flags & STYP_LIBLIST) != 0 + || (section.s_flags & STYP_RELDYN) != 0 + || section.s_flags == STYP_CONFLIC + || (section.s_flags & STYP_DYNSTR) != 0 + || (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_RCONST) { text_size += bfd_get_section_size_before_reloc (current); - if (text_start == 0 || text_start > vma) - text_start = vma; + if (! set_text_start || text_start > vma) + { + text_start = vma; + set_text_start = true; + } } else if ((section.s_flags & STYP_RDATA) != 0 || (section.s_flags & STYP_DATA) != 0 + || (section.s_flags & STYP_LITA) != 0 || (section.s_flags & STYP_LIT8) != 0 || (section.s_flags & STYP_LIT4) != 0 - || (section.s_flags & STYP_SDATA) != 0) + || (section.s_flags & STYP_SDATA) != 0 + || section.s_flags == STYP_XDATA + || (section.s_flags & STYP_GOT) != 0) { data_size += bfd_get_section_size_before_reloc (current); - if (data_start == 0 || data_start > vma) - data_start = vma; + if (! set_data_start || data_start > vma) + { + data_start = vma; + set_data_start = true; + } } else if ((section.s_flags & STYP_BSS) != 0 || (section.s_flags & STYP_SBSS) != 0) bss_size += bfd_get_section_size_before_reloc (current); - } + else if (section.s_flags == 0 + || (section.s_flags & STYP_ECOFF_LIB) != 0 + || section.s_flags == STYP_COMMENT) + /* Do nothing */ ; + else + abort (); + } /* Set up the file header. */ - if (abfd->xvec->header_byteorder_big_p != false) - internal_f.f_magic = backend->big_magic; - else - internal_f.f_magic = backend->little_magic; + internal_f.f_magic = ecoff_get_magic (abfd); /* We will NOT put a fucking timestamp in the header here. Every time you put it back, I will come in and take it out again. I'm @@ -3101,7 +2651,7 @@ ecoff_write_object_contents (abfd) /* The ECOFF f_nsyms field is not actually the number of symbols, it's the size of symbolic information header. */ internal_f.f_nsyms = external_hdr_size; - internal_f.f_symptr = sym_base; + internal_f.f_symptr = ecoff_data (abfd)->sym_filepos; } else { @@ -3119,7 +2669,7 @@ ecoff_write_object_contents (abfd) if (abfd->flags & EXEC_P) internal_f.f_flags |= F_EXEC; - if (! abfd->xvec->byteorder_big_p) + if (bfd_little_endian (abfd)) internal_f.f_flags |= F_AR32WR; else internal_f.f_flags |= F_AR32W; @@ -3130,9 +2680,8 @@ ecoff_write_object_contents (abfd) else internal_a.magic = ECOFF_AOUT_OMAGIC; - /* FIXME: This is what Ultrix puts in, and it makes the Ultrix - linker happy. But, is it right? */ - internal_a.vstamp = 0x20a; + /* FIXME: Is this really correct? */ + internal_a.vstamp = symhdr->vstamp; /* At least on Ultrix, these have to be rounded to page boundaries. FIXME: Is this true on other platforms? */ @@ -3172,174 +2721,191 @@ ecoff_write_object_contents (abfd) for (i = 0; i < 4; i++) internal_a.cprmask[i] = ecoff_data (abfd)->cprmask[i]; + /* Let the backend adjust the headers if necessary. */ + if (backend->adjust_headers) + { + if (! (*backend->adjust_headers) (abfd, &internal_f, &internal_a)) + goto error_return; + } + /* Write out the file header and the optional header. */ if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) - return false; + goto error_return; - buff = (PTR) alloca (filhsz); bfd_coff_swap_filehdr_out (abfd, (PTR) &internal_f, buff); - if (bfd_write (buff, 1, filhsz, abfd) != filhsz) - return false; + if (bfd_bwrite (buff, filhsz, abfd) != filhsz) + goto error_return; - buff = (PTR) alloca (aoutsz); bfd_coff_swap_aouthdr_out (abfd, (PTR) &internal_a, buff); - if (bfd_write (buff, 1, aoutsz, abfd) != aoutsz) - return false; - - /* Write out the relocs. */ - for (current = abfd->sections; - current != (asection *) NULL; - current = current->next) + if (bfd_bwrite (buff, aoutsz, abfd) != aoutsz) + goto error_return; + + /* Build the external symbol information. This must be done before + writing out the relocs so that we know the symbol indices. We + don't do this if this BFD was created by the backend linker, + since it will have already handled the symbols and relocs. */ + if (! ecoff_data (abfd)->linker) { - arelent **reloc_ptr_ptr; - arelent **reloc_end; - char *out_ptr; - - if (current->reloc_count == 0) - continue; + symhdr->iextMax = 0; + symhdr->issExtMax = 0; + debug->external_ext = debug->external_ext_end = NULL; + debug->ssext = debug->ssext_end = NULL; + if (bfd_ecoff_debug_externals (abfd, debug, &backend->debug_swap, + (((abfd->flags & EXEC_P) == 0) + ? true : false), + ecoff_get_extr, ecoff_set_index) + == false) + goto error_return; - buff = bfd_alloc (abfd, current->reloc_count * external_reloc_size); - if (buff == NULL) + /* Write out the relocs. */ + for (current = abfd->sections; + current != (asection *) NULL; + current = current->next) { - bfd_error = no_memory; - return false; - } + arelent **reloc_ptr_ptr; + arelent **reloc_end; + char *out_ptr; + bfd_size_type amt; - reloc_ptr_ptr = current->orelocation; - reloc_end = reloc_ptr_ptr + current->reloc_count; - out_ptr = (char *) buff; - for (; - reloc_ptr_ptr < reloc_end; - reloc_ptr_ptr++, out_ptr += external_reloc_size) - { - arelent *reloc; - asymbol *sym; - struct internal_reloc in; - - memset (&in, 0, sizeof in); + if (current->reloc_count == 0) + continue; - reloc = *reloc_ptr_ptr; - sym = *reloc->sym_ptr_ptr; + amt = current->reloc_count * external_reloc_size; + reloc_buff = bfd_alloc (abfd, amt); + if (reloc_buff == NULL) + goto error_return; + + reloc_ptr_ptr = current->orelocation; + reloc_end = reloc_ptr_ptr + current->reloc_count; + out_ptr = (char *) reloc_buff; + for (; + reloc_ptr_ptr < reloc_end; + reloc_ptr_ptr++, out_ptr += external_reloc_size) + { + arelent *reloc; + asymbol *sym; + struct internal_reloc in; - in.r_vaddr = reloc->address + bfd_get_section_vma (abfd, current); - in.r_type = reloc->howto->type; + memset ((PTR) &in, 0, sizeof in); - if ((sym->flags & BSF_SECTION_SYM) == 0) - { - in.r_symndx = ecoff_get_sym_index (*reloc->sym_ptr_ptr); - in.r_extern = 1; - } - else - { - CONST char *name; - - name = bfd_get_section_name (abfd, bfd_get_section (sym)); - if (strcmp (name, ".text") == 0) - in.r_symndx = RELOC_SECTION_TEXT; - else if (strcmp (name, ".rdata") == 0) - in.r_symndx = RELOC_SECTION_RDATA; - else if (strcmp (name, ".data") == 0) - in.r_symndx = RELOC_SECTION_DATA; - else if (strcmp (name, ".sdata") == 0) - in.r_symndx = RELOC_SECTION_SDATA; - else if (strcmp (name, ".sbss") == 0) - in.r_symndx = RELOC_SECTION_SBSS; - else if (strcmp (name, ".bss") == 0) - in.r_symndx = RELOC_SECTION_BSS; - else if (strcmp (name, ".init") == 0) - in.r_symndx = RELOC_SECTION_INIT; - else if (strcmp (name, ".lit8") == 0) - in.r_symndx = RELOC_SECTION_LIT8; - else if (strcmp (name, ".lit4") == 0) - in.r_symndx = RELOC_SECTION_LIT4; + reloc = *reloc_ptr_ptr; + sym = *reloc->sym_ptr_ptr; + + in.r_vaddr = (reloc->address + + bfd_get_section_vma (abfd, current)); + in.r_type = reloc->howto->type; + + if ((sym->flags & BSF_SECTION_SYM) == 0) + { + in.r_symndx = ecoff_get_sym_index (*reloc->sym_ptr_ptr); + in.r_extern = 1; + } else - abort (); - in.r_extern = 0; + { + const char *name; + + name = bfd_get_section_name (abfd, bfd_get_section (sym)); + if (strcmp (name, ".text") == 0) + in.r_symndx = RELOC_SECTION_TEXT; + else if (strcmp (name, ".rdata") == 0) + in.r_symndx = RELOC_SECTION_RDATA; + else if (strcmp (name, ".data") == 0) + in.r_symndx = RELOC_SECTION_DATA; + else if (strcmp (name, ".sdata") == 0) + in.r_symndx = RELOC_SECTION_SDATA; + else if (strcmp (name, ".sbss") == 0) + in.r_symndx = RELOC_SECTION_SBSS; + else if (strcmp (name, ".bss") == 0) + in.r_symndx = RELOC_SECTION_BSS; + else if (strcmp (name, ".init") == 0) + in.r_symndx = RELOC_SECTION_INIT; + else if (strcmp (name, ".lit8") == 0) + in.r_symndx = RELOC_SECTION_LIT8; + else if (strcmp (name, ".lit4") == 0) + in.r_symndx = RELOC_SECTION_LIT4; + else if (strcmp (name, ".xdata") == 0) + in.r_symndx = RELOC_SECTION_XDATA; + else if (strcmp (name, ".pdata") == 0) + in.r_symndx = RELOC_SECTION_PDATA; + else if (strcmp (name, ".fini") == 0) + in.r_symndx = RELOC_SECTION_FINI; + else if (strcmp (name, ".lita") == 0) + 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; + } + + (*adjust_reloc_out) (abfd, reloc, &in); + + (*swap_reloc_out) (abfd, &in, (PTR) out_ptr); } - (*swap_reloc_out) (abfd, &in, (PTR) out_ptr); + if (bfd_seek (abfd, current->rel_filepos, SEEK_SET) != 0) + goto error_return; + amt = current->reloc_count * external_reloc_size; + if (bfd_bwrite (reloc_buff, amt, abfd) != amt) + goto error_return; + bfd_release (abfd, reloc_buff); + reloc_buff = NULL; } - if (bfd_seek (abfd, current->rel_filepos, SEEK_SET) != 0) - return false; - if (bfd_write (buff, external_reloc_size, current->reloc_count, abfd) - != external_reloc_size * current->reloc_count) - return false; - bfd_release (abfd, buff); + /* Write out the symbolic debugging information. */ + if (bfd_get_symcount (abfd) > 0) + { + /* Write out the debugging information. */ + if (bfd_ecoff_write_debug (abfd, debug, &backend->debug_swap, + ecoff_data (abfd)->sym_filepos) + == false) + goto error_return; + } } - /* Write out the symbolic debugging information. */ - if (bfd_get_symcount (abfd) > 0) - { - HDRR *symhdr; - unsigned long sym_offset; - - /* Set up the offsets in the symbolic header. */ - symhdr = &ecoff_data (abfd)->symbolic_header; - sym_offset = ecoff_data (abfd)->sym_filepos + external_hdr_size; - -#define SET(offset, size, ptr) \ - if (symhdr->size == 0) \ - symhdr->offset = 0; \ - else \ - symhdr->offset = (((char *) ecoff_data (abfd)->ptr \ - - (char *) ecoff_data (abfd)->raw_syments) \ - + sym_offset); - - SET (cbLineOffset, cbLine, line); - SET (cbDnOffset, idnMax, external_dnr); - SET (cbPdOffset, ipdMax, external_pdr); - SET (cbSymOffset, isymMax, external_sym); - SET (cbOptOffset, ioptMax, external_opt); - SET (cbAuxOffset, iauxMax, external_aux); - SET (cbSsOffset, issMax, ss); - SET (cbSsExtOffset, issExtMax, ssext); - SET (cbFdOffset, ifdMax, external_fdr); - SET (cbRfdOffset, crfd, external_rfd); - SET (cbExtOffset, iextMax, external_ext); -#undef SET - - if (bfd_seek (abfd, (file_ptr) ecoff_data (abfd)->sym_filepos, - SEEK_SET) != 0) - return false; - buff = (PTR) alloca (external_hdr_size); - (*backend->swap_hdr_out) (abfd, &ecoff_data (abfd)->symbolic_header, - buff); - if (bfd_write (buff, 1, external_hdr_size, abfd) != external_hdr_size) - return false; - if (bfd_write ((PTR) ecoff_data (abfd)->raw_syments, 1, - ecoff_data (abfd)->raw_size, abfd) - != ecoff_data (abfd)->raw_size) - return false; - } - else if ((abfd->flags & EXEC_P) != 0 - && (abfd->flags & D_PAGED) != 0) + /* The .bss section of a demand paged executable must receive an + entire page. If there are symbols, the symbols will start on the + next page. If there are no symbols, we must fill out the page by + hand. */ + if (bfd_get_symcount (abfd) == 0 + && (abfd->flags & EXEC_P) != 0 + && (abfd->flags & D_PAGED) != 0) { char c; - /* A demand paged executable must occupy an even number of - pages. */ if (bfd_seek (abfd, (file_ptr) ecoff_data (abfd)->sym_filepos - 1, SEEK_SET) != 0) - return false; - if (bfd_read (&c, 1, 1, abfd) == 0) + goto error_return; + if (bfd_bread (&c, (bfd_size_type) 1, abfd) == 0) c = 0; if (bfd_seek (abfd, (file_ptr) ecoff_data (abfd)->sym_filepos - 1, SEEK_SET) != 0) - return false; - if (bfd_write (&c, 1, 1, abfd) != 1) - return false; + goto error_return; + if (bfd_bwrite (&c, (bfd_size_type) 1, abfd) != 1) + goto error_return; } + if (reloc_buff != NULL) + bfd_release (abfd, reloc_buff); + if (buff != NULL) + free (buff); return true; + error_return: + if (reloc_buff != NULL) + bfd_release (abfd, reloc_buff); + if (buff != NULL) + free (buff); + return false; } /* Archive handling. ECOFF uses what appears to be a unique type of - archive header (which I call an armap). The byte ordering of the - armap and the contents are encoded in the name of the armap itself. - At least for now, we only support archives with the same byte - ordering in the armap and the contents. + archive header (armap). The byte ordering of the armap and the + contents are encoded in the name of the armap itself. At least for + now, we only support archives with the same byte ordering in the + armap and the contents. The first four bytes in the armap are the number of symbol definitions. This is always a power of two. @@ -3355,10 +2921,6 @@ ecoff_write_object_contents (abfd) The symbols are hashed into the armap with a closed hashing scheme. See the functions below for the details of the algorithm. - We could use the hash table when looking up symbols in a library. - This would require a new BFD target entry point to replace the - bfd_get_next_mapent function used by the linker. - After the symbol definitions comes four bytes holding the size of the string table, followed by the string table itself. */ @@ -3390,13 +2952,15 @@ ecoff_write_object_contents (abfd) static unsigned int ecoff_armap_hash (s, rehash, size, hlog) - CONST char *s; + const char *s; unsigned int *rehash; unsigned int size; unsigned int hlog; { unsigned int hash; + if (hlog == 0) + return 0; hash = *s++; while (*s != '\0') hash = ((hash >> 27) | (hash << 5)) + *s++; @@ -3408,7 +2972,7 @@ ecoff_armap_hash (s, rehash, size, hlog) /* Read in the armap. */ boolean -ecoff_slurp_armap (abfd) +_bfd_ecoff_slurp_armap (abfd) bfd *abfd; { char nextname[17]; @@ -3421,15 +2985,17 @@ ecoff_slurp_armap (abfd) char *raw_ptr; struct symdef *symdef_ptr; char *stringbase; - + bfd_size_type amt; + /* Get the name of the first element. */ - i = bfd_read ((PTR) nextname, 1, 16, abfd); + i = bfd_bread ((PTR) nextname, (bfd_size_type) 16, abfd); if (i == 0) return true; if (i != 16) return false; - bfd_seek (abfd, (file_ptr) -16, SEEK_CUR); + if (bfd_seek (abfd, (file_ptr) -16, SEEK_CUR) != 0) + return false; /* Irix 4.0.5F apparently can use either an ECOFF armap or a standard COFF armap. We could move the ECOFF armap stuff into @@ -3457,37 +3023,37 @@ ecoff_slurp_armap (abfd) /* Make sure we have the right byte ordering. */ if (((nextname[ARMAP_HEADER_ENDIAN_INDEX] == ARMAP_BIG_ENDIAN) - ^ (abfd->xvec->header_byteorder_big_p != false)) + ^ (bfd_header_big_endian (abfd))) || ((nextname[ARMAP_OBJECT_ENDIAN_INDEX] == ARMAP_BIG_ENDIAN) - ^ (abfd->xvec->byteorder_big_p != false))) + ^ (bfd_big_endian (abfd)))) { - bfd_error = wrong_format; + bfd_set_error (bfd_error_wrong_format); return false; } /* Read in the armap. */ ardata = bfd_ardata (abfd); - mapdata = snarf_ar_hdr (abfd); + mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd); if (mapdata == (struct areltdata *) NULL) return false; parsed_size = mapdata->parsed_size; bfd_release (abfd, (PTR) mapdata); - + raw_armap = (char *) bfd_alloc (abfd, parsed_size); if (raw_armap == (char *) NULL) + return false; + + if (bfd_bread ((PTR) raw_armap, parsed_size, abfd) != parsed_size) { - bfd_error = no_memory; - return false; - } - - if (bfd_read ((PTR) raw_armap, 1, parsed_size, abfd) != parsed_size) - { - bfd_error = malformed_archive; + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_malformed_archive); bfd_release (abfd, (PTR) raw_armap); return false; } - - count = bfd_h_get_32 (abfd, (PTR) raw_armap); + + ardata->tdata = (PTR) raw_armap; + + count = H_GET_32 (abfd, raw_armap); ardata->symdef_count = 0; ardata->cache = (struct ar_cache *) NULL; @@ -3513,9 +3079,9 @@ ecoff_slurp_armap (abfd) { unsigned int name_offset, file_offset; unsigned int hash, rehash, srch; - - name_offset = bfd_h_get_32 (abfd, (PTR) raw_ptr); - file_offset = bfd_h_get_32 (abfd, (PTR) (raw_ptr + 4)); + + name_offset = H_GET_32 (abfd, raw_ptr); + file_offset = H_GET_32 (abfd, (raw_ptr + 4)); if (file_offset == 0) continue; hash = ecoff_armap_hash (stringbase + name_offset, &rehash, count, @@ -3527,8 +3093,7 @@ ecoff_slurp_armap (abfd) for (srch = (hash + rehash) & (count - 1); srch != hash && srch != i; srch = (srch + rehash) & (count - 1)) - BFD_ASSERT (bfd_h_get_32 (abfd, (PTR) (raw_armap + 8 + srch * 8)) - != 0); + BFD_ASSERT (H_GET_32 (abfd, (raw_armap + 8 + srch * 8)) != 0); BFD_ASSERT (srch == i); } } @@ -3537,12 +3102,15 @@ ecoff_slurp_armap (abfd) raw_ptr = raw_armap + 4; for (i = 0; i < count; i++, raw_ptr += 8) - if (bfd_h_get_32 (abfd, (PTR) (raw_ptr + 4)) != 0) + if (H_GET_32 (abfd, (raw_ptr + 4)) != 0) ++ardata->symdef_count; - symdef_ptr = ((struct symdef *) - bfd_alloc (abfd, - ardata->symdef_count * sizeof (struct symdef))); + amt = ardata->symdef_count; + amt *= sizeof (struct symdef); + symdef_ptr = (struct symdef *) bfd_alloc (abfd, amt); + if (!symdef_ptr) + return false; + ardata->symdefs = (carsym *) symdef_ptr; raw_ptr = raw_armap + 4; @@ -3550,10 +3118,10 @@ ecoff_slurp_armap (abfd) { unsigned int name_offset, file_offset; - file_offset = bfd_h_get_32 (abfd, (PTR) (raw_ptr + 4)); + file_offset = H_GET_32 (abfd, (raw_ptr + 4)); if (file_offset == 0) continue; - name_offset = bfd_h_get_32 (abfd, (PTR) raw_ptr); + name_offset = H_GET_32 (abfd, raw_ptr); symdef_ptr->s.name = stringbase + name_offset; symdef_ptr->file_offset = file_offset; ++symdef_ptr; @@ -3571,7 +3139,7 @@ ecoff_slurp_armap (abfd) /* Write out an armap. */ boolean -ecoff_write_armap (abfd, elength, map, orl_count, stridx) +_bfd_ecoff_write_armap (abfd, elength, map, orl_count, stridx) bfd *abfd; unsigned int elength; struct orl *map; @@ -3579,7 +3147,7 @@ ecoff_write_armap (abfd, elength, map, orl_count, stridx) int stridx; { unsigned int hashsize, hashlog; - unsigned int symdefsize; + bfd_size_type symdefsize; int padit; unsigned int stringsize; unsigned int mapsize; @@ -3594,7 +3162,7 @@ ecoff_write_armap (abfd, elength, map, orl_count, stridx) /* Ultrix appears to use as a hash table size the least power of two greater than twice the number of entries. */ - for (hashlog = 0; (1 << hashlog) <= 2 * orl_count; hashlog++) + for (hashlog = 0; ((unsigned int) 1 << hashlog) <= 2 * orl_count; hashlog++) ; hashsize = 1 << hashlog; @@ -3602,7 +3170,7 @@ ecoff_write_armap (abfd, elength, map, orl_count, stridx) padit = stridx % 2; stringsize = stridx + padit; - /* Include 8 bytes to store symdefsize and stringsize in output. */ + /* Include 8 bytes to store symdefsize and stringsize in output. */ mapsize = symdefsize + stringsize + 8; firstreal = SARMAG + sizeof (struct ar_hdr) + mapsize + elength; @@ -3613,12 +3181,12 @@ ecoff_write_armap (abfd, elength, map, orl_count, stridx) strcpy (hdr.ar_name, ecoff_backend (abfd)->armap_start); hdr.ar_name[ARMAP_HEADER_MARKER_INDEX] = ARMAP_MARKER; hdr.ar_name[ARMAP_HEADER_ENDIAN_INDEX] = - (abfd->xvec->header_byteorder_big_p + (bfd_header_big_endian (abfd) ? ARMAP_BIG_ENDIAN : ARMAP_LITTLE_ENDIAN); hdr.ar_name[ARMAP_OBJECT_MARKER_INDEX] = ARMAP_MARKER; hdr.ar_name[ARMAP_OBJECT_ENDIAN_INDEX] = - abfd->xvec->byteorder_big_p ? ARMAP_BIG_ENDIAN : ARMAP_LITTLE_ENDIAN; + bfd_big_endian (abfd) ? ARMAP_BIG_ENDIAN : ARMAP_LITTLE_ENDIAN; memcpy (hdr.ar_name + ARMAP_END_INDEX, ARMAP_END, sizeof ARMAP_END - 1); /* Write the timestamp of the archive header to be just a little bit @@ -3633,27 +3201,36 @@ ecoff_write_armap (abfd, elength, map, orl_count, stridx) armap. */ hdr.ar_uid[0] = '0'; hdr.ar_gid[0] = '0'; +#if 0 hdr.ar_mode[0] = '0'; +#else + /* Building gcc ends up extracting the armap as a file - twice. */ + hdr.ar_mode[0] = '6'; + hdr.ar_mode[1] = '4'; + hdr.ar_mode[2] = '4'; +#endif sprintf (hdr.ar_size, "%-10d", (int) mapsize); hdr.ar_fmag[0] = '`'; - hdr.ar_fmag[1] = '\n'; + hdr.ar_fmag[1] = '\012'; /* Turn all null bytes in the header into spaces. */ for (i = 0; i < sizeof (struct ar_hdr); i++) - if (((char *)(&hdr))[i] == '\0') - (((char *)(&hdr))[i]) = ' '; + if (((char *) (&hdr))[i] == '\0') + (((char *) (&hdr))[i]) = ' '; - if (bfd_write ((PTR) &hdr, 1, sizeof (struct ar_hdr), abfd) + if (bfd_bwrite ((PTR) &hdr, (bfd_size_type) sizeof (struct ar_hdr), abfd) != sizeof (struct ar_hdr)) return false; - bfd_h_put_32 (abfd, hashsize, temp); - if (bfd_write (temp, 1, 4, abfd) != 4) + H_PUT_32 (abfd, hashsize, temp); + if (bfd_bwrite ((PTR) temp, (bfd_size_type) 4, abfd) != 4) return false; - + hashtable = (bfd_byte *) bfd_zalloc (abfd, symdefsize); + if (!hashtable) + return false; current = abfd->archive_head; last_elt = current; @@ -3663,7 +3240,7 @@ ecoff_write_armap (abfd, elength, map, orl_count, stridx) /* Advance firstreal to the file position of this archive element. */ - if (((bfd *) map[i].pos) != last_elt) + if (map[i].u.abfd != last_elt) { do { @@ -3671,13 +3248,13 @@ ecoff_write_armap (abfd, elength, map, orl_count, stridx) firstreal += firstreal % 2; current = current->next; } - while (current != (bfd *) map[i].pos); + while (current != map[i].u.abfd); } last_elt = current; hash = ecoff_armap_hash (*map[i].name, &rehash, hashsize, hashlog); - if (bfd_h_get_32 (abfd, (PTR) (hashtable + (hash * 8) + 4)) != 0) + if (H_GET_32 (abfd, (hashtable + (hash * 8) + 4)) != 0) { unsigned int srch; @@ -3685,33 +3262,33 @@ ecoff_write_armap (abfd, elength, map, orl_count, stridx) for (srch = (hash + rehash) & (hashsize - 1); srch != hash; srch = (srch + rehash) & (hashsize - 1)) - if (bfd_h_get_32 (abfd, (PTR) (hashtable + (srch * 8) + 4)) == 0) + if (H_GET_32 (abfd, (hashtable + (srch * 8) + 4)) == 0) break; BFD_ASSERT (srch != hash); hash = srch; } - - bfd_h_put_32 (abfd, map[i].namidx, (PTR) (hashtable + hash * 8)); - bfd_h_put_32 (abfd, firstreal, (PTR) (hashtable + hash * 8 + 4)); + + H_PUT_32 (abfd, map[i].namidx, (hashtable + hash * 8)); + H_PUT_32 (abfd, firstreal, (hashtable + hash * 8 + 4)); } - if (bfd_write (hashtable, 1, symdefsize, abfd) != symdefsize) + if (bfd_bwrite ((PTR) hashtable, symdefsize, abfd) != symdefsize) return false; bfd_release (abfd, hashtable); /* Now write the strings. */ - bfd_h_put_32 (abfd, stringsize, temp); - if (bfd_write (temp, 1, 4, abfd) != 4) + H_PUT_32 (abfd, stringsize, temp); + if (bfd_bwrite ((PTR) temp, (bfd_size_type) 4, abfd) != 4) return false; for (i = 0; i < orl_count; i++) { bfd_size_type len; len = strlen (*map[i].name) + 1; - if (bfd_write ((PTR) (*map[i].name), 1, len, abfd) != len) + if (bfd_bwrite ((PTR) (*map[i].name), len, abfd) != len) return false; } @@ -3719,7 +3296,7 @@ ecoff_write_armap (abfd, elength, map, orl_count, stridx) bug-compatible for DECstation ar we use a null. */ if (padit) { - if (bfd_write ("\0", 1, 1, abfd) != 1) + if (bfd_bwrite ("", (bfd_size_type) 1, abfd) != 1) return false; } @@ -3729,40 +3306,1552 @@ ecoff_write_armap (abfd, elength, map, orl_count, stridx) /* See whether this BFD is an archive. If it is, read in the armap and the extended name table. */ -bfd_target * -ecoff_archive_p (abfd) +const bfd_target * +_bfd_ecoff_archive_p (abfd) bfd *abfd; { + struct artdata *tdata_hold; char armag[SARMAG + 1]; + bfd_size_type amt; + + tdata_hold = abfd->tdata.aout_ar_data; + + if (bfd_bread ((PTR) armag, (bfd_size_type) SARMAG, abfd) != SARMAG) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return (const bfd_target *) NULL; + } - if (bfd_read ((PTR) armag, 1, SARMAG, abfd) != SARMAG - || strncmp (armag, ARMAG, SARMAG) != 0) + if (strncmp (armag, ARMAG, SARMAG) != 0) { - bfd_error = wrong_format; - return (bfd_target *) NULL; + bfd_set_error (bfd_error_wrong_format); + return NULL; } /* We are setting bfd_ardata(abfd) here, but since bfd_ardata involves a cast, we can't do it as the left operand of assignment. */ - abfd->tdata.aout_ar_data = - (struct artdata *) bfd_zalloc (abfd, sizeof (struct artdata)); + amt = sizeof (struct artdata); + abfd->tdata.aout_ar_data = (struct artdata *) bfd_zalloc (abfd, amt); if (bfd_ardata (abfd) == (struct artdata *) NULL) { - bfd_error = no_memory; - return (bfd_target *) NULL; + abfd->tdata.aout_ar_data = tdata_hold; + return (const bfd_target *) NULL; } bfd_ardata (abfd)->first_file_filepos = SARMAG; - - if (ecoff_slurp_armap (abfd) == false - || ecoff_slurp_extended_name_table (abfd) == false) + bfd_ardata (abfd)->cache = NULL; + bfd_ardata (abfd)->archive_head = NULL; + bfd_ardata (abfd)->symdefs = NULL; + bfd_ardata (abfd)->extended_names = NULL; + bfd_ardata (abfd)->tdata = NULL; + + if (_bfd_ecoff_slurp_armap (abfd) == false + || _bfd_ecoff_slurp_extended_name_table (abfd) == false) { bfd_release (abfd, bfd_ardata (abfd)); - abfd->tdata.aout_ar_data = (struct artdata *) NULL; - return (bfd_target *) NULL; + abfd->tdata.aout_ar_data = tdata_hold; + return (const bfd_target *) NULL; } - + + if (bfd_has_map (abfd)) + { + bfd *first; + + /* This archive has a map, so we may presume that the contents + are object files. Make sure that if the first file in the + archive can be recognized as an object file, it is for this + target. If not, assume that this is the wrong format. If + the first file is not an object file, somebody is doing + something weird, and we permit it so that ar -t will work. */ + + first = bfd_openr_next_archived_file (abfd, (bfd *) NULL); + if (first != NULL) + { + boolean fail; + + first->target_defaulted = false; + fail = false; + if (bfd_check_format (first, bfd_object) + && first->xvec != abfd->xvec) + { + (void) bfd_close (first); + bfd_release (abfd, bfd_ardata (abfd)); + abfd->tdata.aout_ar_data = tdata_hold; + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + /* We ought to close first here, but we can't, because we + have no way to remove it from the archive cache. FIXME. */ + } + } + return abfd->xvec; } + +/* ECOFF linker code. */ + +static struct bfd_hash_entry *ecoff_link_hash_newfunc + PARAMS ((struct bfd_hash_entry *entry, + struct bfd_hash_table *table, + const char *string)); +static boolean ecoff_link_add_archive_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean ecoff_link_check_archive_element + PARAMS ((bfd *, struct bfd_link_info *, boolean *pneeded)); +static boolean ecoff_link_add_object_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean ecoff_link_add_externals + PARAMS ((bfd *, struct bfd_link_info *, PTR, char *)); + +/* Routine to create an entry in an ECOFF link hash table. */ + +static struct bfd_hash_entry * +ecoff_link_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct ecoff_link_hash_entry *ret = (struct ecoff_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct ecoff_link_hash_entry *) NULL) + ret = ((struct ecoff_link_hash_entry *) + bfd_hash_allocate (table, sizeof (struct ecoff_link_hash_entry))); + if (ret == (struct ecoff_link_hash_entry *) NULL) + return NULL; + + /* Call the allocation method of the superclass. */ + ret = ((struct ecoff_link_hash_entry *) + _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret, + table, string)); + + if (ret) + { + /* Set local fields. */ + ret->indx = -1; + ret->abfd = NULL; + ret->written = 0; + ret->small = 0; + } + memset ((PTR) &ret->esym, 0, sizeof ret->esym); + + return (struct bfd_hash_entry *) ret; +} + +/* Create an ECOFF link hash table. */ + +struct bfd_link_hash_table * +_bfd_ecoff_bfd_link_hash_table_create (abfd) + bfd *abfd; +{ + struct ecoff_link_hash_table *ret; + bfd_size_type amt = sizeof (struct ecoff_link_hash_table); + + ret = (struct ecoff_link_hash_table *) bfd_malloc (amt); + if (ret == NULL) + return NULL; + if (! _bfd_link_hash_table_init (&ret->root, abfd, + ecoff_link_hash_newfunc)) + { + free (ret); + return (struct bfd_link_hash_table *) NULL; + } + return &ret->root; +} + +/* Look up an entry in an ECOFF link hash table. */ + +#define ecoff_link_hash_lookup(table, string, create, copy, follow) \ + ((struct ecoff_link_hash_entry *) \ + bfd_link_hash_lookup (&(table)->root, (string), (create), (copy), (follow))) + +/* Traverse an ECOFF link hash table. */ + +#define ecoff_link_hash_traverse(table, func, info) \ + (bfd_link_hash_traverse \ + (&(table)->root, \ + (boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \ + (info))) + +/* Get the ECOFF link hash table from the info structure. This is + just a cast. */ + +#define ecoff_hash_table(p) ((struct ecoff_link_hash_table *) ((p)->hash)) + +/* Given an ECOFF BFD, add symbols to the global hash table as + appropriate. */ + +boolean +_bfd_ecoff_bfd_link_add_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + switch (bfd_get_format (abfd)) + { + case bfd_object: + return ecoff_link_add_object_symbols (abfd, info); + case bfd_archive: + return ecoff_link_add_archive_symbols (abfd, info); + default: + bfd_set_error (bfd_error_wrong_format); + return false; + } +} + +/* Add the symbols from an archive file to the global hash table. + This looks through the undefined symbols, looks each one up in the + archive hash table, and adds any associated object file. We do not + use _bfd_generic_link_add_archive_symbols because ECOFF archives + already have a hash table, so there is no reason to construct + another one. */ + +static boolean +ecoff_link_add_archive_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + const bfd_byte *raw_armap; + struct bfd_link_hash_entry **pundef; + unsigned int armap_count; + unsigned int armap_log; + unsigned int i; + const bfd_byte *hashtable; + const char *stringbase; + + if (! bfd_has_map (abfd)) + { + /* An empty archive is a special case. */ + if (bfd_openr_next_archived_file (abfd, (bfd *) NULL) == NULL) + return true; + bfd_set_error (bfd_error_no_armap); + return false; + } + + /* If we don't have any raw data for this archive, as can happen on + Irix 4.0.5F, we call the generic routine. + FIXME: We should be more clever about this, since someday tdata + may get to something for a generic archive. */ + raw_armap = (const bfd_byte *) bfd_ardata (abfd)->tdata; + if (raw_armap == (bfd_byte *) NULL) + return (_bfd_generic_link_add_archive_symbols + (abfd, info, ecoff_link_check_archive_element)); + + armap_count = H_GET_32 (abfd, raw_armap); + + armap_log = 0; + for (i = 1; i < armap_count; i <<= 1) + armap_log++; + BFD_ASSERT (i == armap_count); + + hashtable = raw_armap + 4; + stringbase = (const char *) raw_armap + armap_count * 8 + 8; + + /* Look through the list of undefined symbols. */ + pundef = &info->hash->undefs; + while (*pundef != (struct bfd_link_hash_entry *) NULL) + { + struct bfd_link_hash_entry *h; + unsigned int hash, rehash; + unsigned int file_offset; + const char *name; + bfd *element; + + h = *pundef; + + /* When a symbol is defined, it is not necessarily removed from + the list. */ + if (h->type != bfd_link_hash_undefined + && h->type != bfd_link_hash_common) + { + /* Remove this entry from the list, for general cleanliness + and because we are going to look through the list again + if we search any more libraries. We can't remove the + entry if it is the tail, because that would lose any + entries we add to the list later on. */ + if (*pundef != info->hash->undefs_tail) + *pundef = (*pundef)->next; + else + pundef = &(*pundef)->next; + continue; + } + + /* Native ECOFF linkers do not pull in archive elements merely + to satisfy common definitions, so neither do we. We leave + them on the list, though, in case we are linking against some + other object format. */ + if (h->type != bfd_link_hash_undefined) + { + pundef = &(*pundef)->next; + continue; + } + + /* Look for this symbol in the archive hash table. */ + hash = ecoff_armap_hash (h->root.string, &rehash, armap_count, + armap_log); + + file_offset = H_GET_32 (abfd, hashtable + (hash * 8) + 4); + if (file_offset == 0) + { + /* Nothing in this slot. */ + pundef = &(*pundef)->next; + continue; + } + + name = stringbase + H_GET_32 (abfd, hashtable + (hash * 8)); + if (name[0] != h->root.string[0] + || strcmp (name, h->root.string) != 0) + { + unsigned int srch; + boolean found; + + /* That was the wrong symbol. Try rehashing. */ + found = false; + for (srch = (hash + rehash) & (armap_count - 1); + srch != hash; + srch = (srch + rehash) & (armap_count - 1)) + { + file_offset = H_GET_32 (abfd, hashtable + (srch * 8) + 4); + if (file_offset == 0) + break; + name = stringbase + H_GET_32 (abfd, hashtable + (srch * 8)); + if (name[0] == h->root.string[0] + && strcmp (name, h->root.string) == 0) + { + found = true; + break; + } + } + + if (! found) + { + pundef = &(*pundef)->next; + continue; + } + + hash = srch; + } + + element = (*backend->get_elt_at_filepos) (abfd, (file_ptr) file_offset); + if (element == (bfd *) NULL) + return false; + + if (! bfd_check_format (element, bfd_object)) + return false; + + /* Unlike the generic linker, we know that this element provides + a definition for an undefined symbol and we know that we want + to include it. We don't need to check anything. */ + if (! (*info->callbacks->add_archive_element) (info, element, name)) + return false; + if (! ecoff_link_add_object_symbols (element, info)) + return false; + + pundef = &(*pundef)->next; + } + + return true; +} + +/* This is called if we used _bfd_generic_link_add_archive_symbols + because we were not dealing with an ECOFF archive. */ + +static boolean +ecoff_link_check_archive_element (abfd, info, pneeded) + bfd *abfd; + struct bfd_link_info *info; + boolean *pneeded; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *)) + = backend->debug_swap.swap_ext_in; + HDRR *symhdr; + bfd_size_type external_ext_size; + PTR external_ext = NULL; + bfd_size_type esize; + char *ssext = NULL; + char *ext_ptr; + char *ext_end; + + *pneeded = false; + + if (! ecoff_slurp_symbolic_header (abfd)) + goto error_return; + + /* If there are no symbols, we don't want it. */ + if (bfd_get_symcount (abfd) == 0) + goto successful_return; + + symhdr = &ecoff_data (abfd)->debug_info.symbolic_header; + + /* Read in the external symbols and external strings. */ + external_ext_size = backend->debug_swap.external_ext_size; + esize = symhdr->iextMax * external_ext_size; + external_ext = (PTR) bfd_malloc (esize); + if (external_ext == NULL && esize != 0) + goto error_return; + + if (bfd_seek (abfd, (file_ptr) symhdr->cbExtOffset, SEEK_SET) != 0 + || bfd_bread (external_ext, esize, abfd) != esize) + goto error_return; + + ssext = (char *) bfd_malloc ((bfd_size_type) symhdr->issExtMax); + if (ssext == NULL && symhdr->issExtMax != 0) + goto error_return; + + if (bfd_seek (abfd, (file_ptr) symhdr->cbSsExtOffset, SEEK_SET) != 0 + || (bfd_bread (ssext, (bfd_size_type) symhdr->issExtMax, abfd) + != (bfd_size_type) symhdr->issExtMax)) + goto error_return; + + /* Look through the external symbols to see if they define some + symbol that is currently undefined. */ + ext_ptr = (char *) external_ext; + ext_end = ext_ptr + esize; + for (; ext_ptr < ext_end; ext_ptr += external_ext_size) + { + EXTR esym; + boolean def; + const char *name; + struct bfd_link_hash_entry *h; + + (*swap_ext_in) (abfd, (PTR) ext_ptr, &esym); + + /* See if this symbol defines something. */ + if (esym.asym.st != stGlobal + && esym.asym.st != stLabel + && esym.asym.st != stProc) + continue; + + switch (esym.asym.sc) + { + case scText: + case scData: + case scBss: + case scAbs: + case scSData: + case scSBss: + case scRData: + case scCommon: + case scSCommon: + case scInit: + case scFini: + case scRConst: + def = true; + break; + default: + def = false; + break; + } + + if (! def) + continue; + + name = ssext + esym.asym.iss; + h = bfd_link_hash_lookup (info->hash, name, false, false, true); + + /* Unlike the generic linker, we do not pull in elements because + of common symbols. */ + if (h == (struct bfd_link_hash_entry *) NULL + || h->type != bfd_link_hash_undefined) + continue; + + /* Include this element. */ + if (! (*info->callbacks->add_archive_element) (info, abfd, name)) + goto error_return; + if (! ecoff_link_add_externals (abfd, info, external_ext, ssext)) + goto error_return; + + *pneeded = true; + goto successful_return; + } + + successful_return: + if (external_ext != NULL) + free (external_ext); + if (ssext != NULL) + free (ssext); + return true; + error_return: + if (external_ext != NULL) + free (external_ext); + if (ssext != NULL) + free (ssext); + return false; +} + +/* Add symbols from an ECOFF object file to the global linker hash + table. */ + +static boolean +ecoff_link_add_object_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + HDRR *symhdr; + bfd_size_type external_ext_size; + PTR external_ext = NULL; + bfd_size_type esize; + char *ssext = NULL; + boolean result; + + if (! ecoff_slurp_symbolic_header (abfd)) + return false; + + /* If there are no symbols, we don't want it. */ + if (bfd_get_symcount (abfd) == 0) + return true; + + symhdr = &ecoff_data (abfd)->debug_info.symbolic_header; + + /* Read in the external symbols and external strings. */ + external_ext_size = ecoff_backend (abfd)->debug_swap.external_ext_size; + esize = symhdr->iextMax * external_ext_size; + external_ext = (PTR) bfd_malloc (esize); + if (external_ext == NULL && esize != 0) + goto error_return; + + if (bfd_seek (abfd, (file_ptr) symhdr->cbExtOffset, SEEK_SET) != 0 + || bfd_bread (external_ext, esize, abfd) != esize) + goto error_return; + + ssext = (char *) bfd_malloc ((bfd_size_type) symhdr->issExtMax); + if (ssext == NULL && symhdr->issExtMax != 0) + goto error_return; + + if (bfd_seek (abfd, (file_ptr) symhdr->cbSsExtOffset, SEEK_SET) != 0 + || (bfd_bread (ssext, (bfd_size_type) symhdr->issExtMax, abfd) + != (bfd_size_type) symhdr->issExtMax)) + goto error_return; + + result = ecoff_link_add_externals (abfd, info, external_ext, ssext); + + if (ssext != NULL) + free (ssext); + if (external_ext != NULL) + free (external_ext); + return result; + + error_return: + if (ssext != NULL) + free (ssext); + if (external_ext != NULL) + free (external_ext); + return false; +} + +/* Add the external symbols of an object file to the global linker + hash table. The external symbols and strings we are passed are + just allocated on the stack, and will be discarded. We must + explicitly save any information we may need later on in the link. + We do not want to read the external symbol information again. */ + +static boolean +ecoff_link_add_externals (abfd, info, external_ext, ssext) + bfd *abfd; + struct bfd_link_info *info; + PTR external_ext; + char *ssext; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *)) + = backend->debug_swap.swap_ext_in; + bfd_size_type external_ext_size = backend->debug_swap.external_ext_size; + unsigned long ext_count; + struct ecoff_link_hash_entry **sym_hash; + char *ext_ptr; + char *ext_end; + bfd_size_type amt; + + ext_count = ecoff_data (abfd)->debug_info.symbolic_header.iextMax; + + amt = ext_count; + amt *= sizeof (struct bfd_link_hash_entry *); + sym_hash = (struct ecoff_link_hash_entry **) bfd_alloc (abfd, amt); + if (!sym_hash) + return false; + ecoff_data (abfd)->sym_hashes = sym_hash; + + ext_ptr = (char *) external_ext; + ext_end = ext_ptr + ext_count * external_ext_size; + for (; ext_ptr < ext_end; ext_ptr += external_ext_size, sym_hash++) + { + EXTR esym; + boolean skip; + bfd_vma value; + asection *section; + const char *name; + struct ecoff_link_hash_entry *h; + + *sym_hash = NULL; + + (*swap_ext_in) (abfd, (PTR) ext_ptr, &esym); + + /* Skip debugging symbols. */ + skip = false; + switch (esym.asym.st) + { + case stGlobal: + case stStatic: + case stLabel: + case stProc: + case stStaticProc: + break; + default: + skip = true; + break; + } + + if (skip) + continue; + + /* Get the information for this symbol. */ + value = esym.asym.value; + switch (esym.asym.sc) + { + default: + case scNil: + case scRegister: + case scCdbLocal: + case scBits: + case scCdbSystem: + case scRegImage: + case scInfo: + case scUserStruct: + case scVar: + case scVarRegister: + case scVariant: + case scBasedVar: + case scXData: + case scPData: + section = NULL; + break; + case scText: + section = bfd_make_section_old_way (abfd, ".text"); + value -= section->vma; + break; + case scData: + section = bfd_make_section_old_way (abfd, ".data"); + value -= section->vma; + break; + case scBss: + section = bfd_make_section_old_way (abfd, ".bss"); + value -= section->vma; + break; + case scAbs: + section = bfd_abs_section_ptr; + break; + case scUndefined: + section = bfd_und_section_ptr; + break; + case scSData: + section = bfd_make_section_old_way (abfd, ".sdata"); + value -= section->vma; + break; + case scSBss: + section = bfd_make_section_old_way (abfd, ".sbss"); + value -= section->vma; + break; + case scRData: + section = bfd_make_section_old_way (abfd, ".rdata"); + value -= section->vma; + break; + case scCommon: + if (value > ecoff_data (abfd)->gp_size) + { + section = bfd_com_section_ptr; + break; + } + /* Fall through. */ + case scSCommon: + if (ecoff_scom_section.name == NULL) + { + /* Initialize the small common section. */ + ecoff_scom_section.name = SCOMMON; + ecoff_scom_section.flags = SEC_IS_COMMON; + ecoff_scom_section.output_section = &ecoff_scom_section; + ecoff_scom_section.symbol = &ecoff_scom_symbol; + ecoff_scom_section.symbol_ptr_ptr = &ecoff_scom_symbol_ptr; + ecoff_scom_symbol.name = SCOMMON; + ecoff_scom_symbol.flags = BSF_SECTION_SYM; + ecoff_scom_symbol.section = &ecoff_scom_section; + ecoff_scom_symbol_ptr = &ecoff_scom_symbol; + } + section = &ecoff_scom_section; + break; + case scSUndefined: + section = bfd_und_section_ptr; + break; + case scInit: + section = bfd_make_section_old_way (abfd, ".init"); + value -= section->vma; + break; + case scFini: + 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) + continue; + + name = ssext + esym.asym.iss; + + h = NULL; + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, name, + (flagword) (esym.weakext ? BSF_WEAK : BSF_GLOBAL), + section, value, (const char *) NULL, true, true, + (struct bfd_link_hash_entry **) &h))) + return false; + + *sym_hash = h; + + /* If we are building an ECOFF hash table, save the external + symbol information. */ + if (info->hash->creator->flavour == bfd_get_flavour (abfd)) + { + if (h->abfd == (bfd *) NULL + || (! bfd_is_und_section (section) + && (! bfd_is_com_section (section) + || (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak)))) + { + h->abfd = abfd; + h->esym = esym; + } + + /* Remember whether this symbol was small undefined. */ + if (esym.asym.sc == scSUndefined) + h->small = 1; + + /* If this symbol was ever small undefined, it needs to wind + up in a GP relative section. We can't control the + section of a defined symbol, but we can control the + section of a common symbol. This case is actually needed + on Ultrix 4.2 to handle the symbol cred in -lckrb. */ + if (h->small + && h->root.type == bfd_link_hash_common + && strcmp (h->root.u.c.p->section->name, SCOMMON) != 0) + { + h->root.u.c.p->section = bfd_make_section_old_way (abfd, + SCOMMON); + h->root.u.c.p->section->flags = SEC_ALLOC; + if (h->esym.asym.sc == scCommon) + h->esym.asym.sc = scSCommon; + } + } + } + + return true; +} + +/* ECOFF final link routines. */ + +static boolean ecoff_final_link_debug_accumulate + PARAMS ((bfd *output_bfd, bfd *input_bfd, struct bfd_link_info *, + PTR handle)); +static boolean ecoff_link_write_external + PARAMS ((struct ecoff_link_hash_entry *, PTR)); +static boolean ecoff_indirect_link_order + PARAMS ((bfd *, struct bfd_link_info *, asection *, + struct bfd_link_order *)); +static boolean ecoff_reloc_link_order + PARAMS ((bfd *, struct bfd_link_info *, asection *, + struct bfd_link_order *)); + +/* Structure used to pass information to ecoff_link_write_external. */ + +struct extsym_info +{ + bfd *abfd; + struct bfd_link_info *info; +}; + +/* ECOFF final link routine. This looks through all the input BFDs + and gathers together all the debugging information, and then + processes all the link order information. This may cause it to + close and reopen some input BFDs; I'll see how bad this is. */ + +boolean +_bfd_ecoff_bfd_final_link (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + struct ecoff_debug_info * const debug = &ecoff_data (abfd)->debug_info; + HDRR *symhdr; + PTR handle; + register bfd *input_bfd; + asection *o; + struct bfd_link_order *p; + struct extsym_info einfo; + + /* We accumulate the debugging information counts in the symbolic + header. */ + symhdr = &debug->symbolic_header; + symhdr->vstamp = 0; + symhdr->ilineMax = 0; + symhdr->cbLine = 0; + symhdr->idnMax = 0; + symhdr->ipdMax = 0; + symhdr->isymMax = 0; + symhdr->ioptMax = 0; + symhdr->iauxMax = 0; + symhdr->issMax = 0; + symhdr->issExtMax = 0; + symhdr->ifdMax = 0; + symhdr->crfd = 0; + symhdr->iextMax = 0; + + /* We accumulate the debugging information itself in the debug_info + structure. */ + debug->line = NULL; + debug->external_dnr = NULL; + debug->external_pdr = NULL; + debug->external_sym = NULL; + debug->external_opt = NULL; + debug->external_aux = NULL; + debug->ss = NULL; + debug->ssext = debug->ssext_end = NULL; + debug->external_fdr = NULL; + debug->external_rfd = NULL; + debug->external_ext = debug->external_ext_end = NULL; + + handle = bfd_ecoff_debug_init (abfd, debug, &backend->debug_swap, info); + if (handle == (PTR) NULL) + return false; + + /* Accumulate the debugging symbols from each input BFD. */ + for (input_bfd = info->input_bfds; + input_bfd != (bfd *) NULL; + input_bfd = input_bfd->link_next) + { + boolean ret; + + if (bfd_get_flavour (input_bfd) == bfd_target_ecoff_flavour) + { + /* Abitrarily set the symbolic header vstamp to the vstamp + of the first object file in the link. */ + if (symhdr->vstamp == 0) + symhdr->vstamp + = ecoff_data (input_bfd)->debug_info.symbolic_header.vstamp; + ret = ecoff_final_link_debug_accumulate (abfd, input_bfd, info, + handle); + } + else + ret = bfd_ecoff_debug_accumulate_other (handle, abfd, + debug, &backend->debug_swap, + input_bfd, info); + if (! ret) + return false; + + /* Combine the register masks. */ + ecoff_data (abfd)->gprmask |= ecoff_data (input_bfd)->gprmask; + ecoff_data (abfd)->fprmask |= ecoff_data (input_bfd)->fprmask; + ecoff_data (abfd)->cprmask[0] |= ecoff_data (input_bfd)->cprmask[0]; + ecoff_data (abfd)->cprmask[1] |= ecoff_data (input_bfd)->cprmask[1]; + ecoff_data (abfd)->cprmask[2] |= ecoff_data (input_bfd)->cprmask[2]; + ecoff_data (abfd)->cprmask[3] |= ecoff_data (input_bfd)->cprmask[3]; + } + + /* Write out the external symbols. */ + einfo.abfd = abfd; + einfo.info = info; + ecoff_link_hash_traverse (ecoff_hash_table (info), + ecoff_link_write_external, + (PTR) &einfo); + + if (info->relocateable) + { + /* We need to make a pass over the link_orders to count up the + number of relocations we will need to output, so that we know + how much space they will take up. */ + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + { + o->reloc_count = 0; + for (p = o->link_order_head; + p != (struct bfd_link_order *) NULL; + p = p->next) + if (p->type == bfd_indirect_link_order) + o->reloc_count += p->u.indirect.section->reloc_count; + else if (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order) + ++o->reloc_count; + } + } + + /* Compute the reloc and symbol file positions. */ + ecoff_compute_reloc_file_positions (abfd); + + /* Write out the debugging information. */ + if (! bfd_ecoff_write_accumulated_debug (handle, abfd, debug, + &backend->debug_swap, info, + ecoff_data (abfd)->sym_filepos)) + return false; + + bfd_ecoff_debug_free (handle, abfd, debug, &backend->debug_swap, info); + + if (info->relocateable) + { + /* Now reset the reloc_count field of the sections in the output + BFD to 0, so that we can use them to keep track of how many + relocs we have output thus far. */ + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + o->reloc_count = 0; + } + + /* Get a value for the GP register. */ + if (ecoff_data (abfd)->gp == 0) + { + struct bfd_link_hash_entry *h; + + h = bfd_link_hash_lookup (info->hash, "_gp", false, false, true); + if (h != (struct bfd_link_hash_entry *) NULL + && h->type == bfd_link_hash_defined) + ecoff_data (abfd)->gp = (h->u.def.value + + h->u.def.section->output_section->vma + + h->u.def.section->output_offset); + else if (info->relocateable) + { + bfd_vma lo; + + /* Make up a value. */ + lo = (bfd_vma) -1; + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + { + if (o->vma < lo + && (strcmp (o->name, _SBSS) == 0 + || strcmp (o->name, _SDATA) == 0 + || strcmp (o->name, _LIT4) == 0 + || strcmp (o->name, _LIT8) == 0 + || strcmp (o->name, _LITA) == 0)) + lo = o->vma; + } + ecoff_data (abfd)->gp = lo + 0x8000; + } + else + { + /* If the relocate_section function needs to do a reloc + involving the GP value, it should make a reloc_dangerous + callback to warn that GP is not defined. */ + } + } + + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + { + for (p = o->link_order_head; + p != (struct bfd_link_order *) NULL; + p = p->next) + { + if (p->type == bfd_indirect_link_order + && (bfd_get_flavour (p->u.indirect.section->owner) + == bfd_target_ecoff_flavour)) + { + if (! ecoff_indirect_link_order (abfd, info, o, p)) + return false; + } + else if (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order) + { + if (! ecoff_reloc_link_order (abfd, info, o, p)) + return false; + } + else + { + if (! _bfd_default_link_order (abfd, info, o, p)) + return false; + } + } + } + + bfd_get_symcount (abfd) = symhdr->iextMax + symhdr->isymMax; + + ecoff_data (abfd)->linker = true; + + return true; +} + +/* Accumulate the debugging information for an input BFD into the + output BFD. This must read in the symbolic information of the + input BFD. */ + +static boolean +ecoff_final_link_debug_accumulate (output_bfd, input_bfd, info, handle) + bfd *output_bfd; + bfd *input_bfd; + struct bfd_link_info *info; + PTR handle; +{ + struct ecoff_debug_info * const debug = &ecoff_data (input_bfd)->debug_info; + const struct ecoff_debug_swap * const swap = + &ecoff_backend (input_bfd)->debug_swap; + HDRR *symhdr = &debug->symbolic_header; + boolean ret; + +#define READ(ptr, offset, count, size, type) \ + if (symhdr->count == 0) \ + debug->ptr = NULL; \ + else \ + { \ + bfd_size_type amt = (bfd_size_type) size * symhdr->count; \ + debug->ptr = (type) bfd_malloc (amt); \ + if (debug->ptr == NULL) \ + { \ + ret = false; \ + goto return_something; \ + } \ + if (bfd_seek (input_bfd, (file_ptr) symhdr->offset, SEEK_SET) != 0 \ + || bfd_bread (debug->ptr, amt, input_bfd) != amt) \ + { \ + ret = false; \ + goto return_something; \ + } \ + } + + /* If raw_syments is not NULL, then the data was already by read by + _bfd_ecoff_slurp_symbolic_info. */ + if (ecoff_data (input_bfd)->raw_syments == NULL) + { + READ (line, cbLineOffset, cbLine, sizeof (unsigned char), + unsigned char *); + READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, PTR); + READ (external_pdr, cbPdOffset, ipdMax, swap->external_pdr_size, PTR); + READ (external_sym, cbSymOffset, isymMax, swap->external_sym_size, PTR); + READ (external_opt, cbOptOffset, ioptMax, swap->external_opt_size, PTR); + READ (external_aux, cbAuxOffset, iauxMax, sizeof (union aux_ext), + union aux_ext *); + READ (ss, cbSsOffset, issMax, sizeof (char), char *); + READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size, PTR); + READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, PTR); + } +#undef READ + + /* We do not read the external strings or the external symbols. */ + + ret = (bfd_ecoff_debug_accumulate + (handle, output_bfd, &ecoff_data (output_bfd)->debug_info, + &ecoff_backend (output_bfd)->debug_swap, + input_bfd, debug, swap, info)); + + return_something: + if (ecoff_data (input_bfd)->raw_syments == NULL) + { + if (debug->line != NULL) + free (debug->line); + if (debug->external_dnr != NULL) + free (debug->external_dnr); + if (debug->external_pdr != NULL) + free (debug->external_pdr); + if (debug->external_sym != NULL) + free (debug->external_sym); + if (debug->external_opt != NULL) + free (debug->external_opt); + if (debug->external_aux != NULL) + free (debug->external_aux); + if (debug->ss != NULL) + free (debug->ss); + if (debug->external_fdr != NULL) + free (debug->external_fdr); + if (debug->external_rfd != NULL) + free (debug->external_rfd); + + /* Make sure we don't accidentally follow one of these pointers + into freed memory. */ + debug->line = NULL; + debug->external_dnr = NULL; + debug->external_pdr = NULL; + debug->external_sym = NULL; + debug->external_opt = NULL; + debug->external_aux = NULL; + debug->ss = NULL; + debug->external_fdr = NULL; + debug->external_rfd = NULL; + } + + return ret; +} + +/* Put out information for an external symbol. These come only from + the hash table. */ + +static boolean +ecoff_link_write_external (h, data) + struct ecoff_link_hash_entry *h; + PTR data; +{ + struct extsym_info *einfo = (struct extsym_info *) data; + bfd *output_bfd = einfo->abfd; + boolean strip; + + if (h->root.type == bfd_link_hash_warning) + { + h = (struct ecoff_link_hash_entry *) h->root.u.i.link; + if (h->root.type == bfd_link_hash_new) + return true; + } + + /* We need to check if this symbol is being stripped. */ + if (h->root.type == bfd_link_hash_undefined + || h->root.type == bfd_link_hash_undefweak) + strip = false; + else if (einfo->info->strip == strip_all + || (einfo->info->strip == strip_some + && bfd_hash_lookup (einfo->info->keep_hash, + h->root.root.string, + false, false) == NULL)) + strip = true; + else + strip = false; + + if (strip || h->written) + return true; + + if (h->abfd == (bfd *) NULL) + { + h->esym.jmptbl = 0; + h->esym.cobol_main = 0; + h->esym.weakext = 0; + h->esym.reserved = 0; + h->esym.ifd = ifdNil; + h->esym.asym.value = 0; + h->esym.asym.st = stGlobal; + + if (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak) + h->esym.asym.sc = scAbs; + else + { + asection *output_section; + const char *name; + + output_section = h->root.u.def.section->output_section; + name = bfd_section_name (output_section->owner, output_section); + + if (strcmp (name, _TEXT) == 0) + h->esym.asym.sc = scText; + else if (strcmp (name, _DATA) == 0) + h->esym.asym.sc = scData; + else if (strcmp (name, _SDATA) == 0) + h->esym.asym.sc = scSData; + else if (strcmp (name, _RDATA) == 0) + h->esym.asym.sc = scRData; + else if (strcmp (name, _BSS) == 0) + h->esym.asym.sc = scBss; + else if (strcmp (name, _SBSS) == 0) + h->esym.asym.sc = scSBss; + else if (strcmp (name, _INIT) == 0) + h->esym.asym.sc = scInit; + else if (strcmp (name, _FINI) == 0) + h->esym.asym.sc = scFini; + else if (strcmp (name, _PDATA) == 0) + 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; + } + + h->esym.asym.reserved = 0; + h->esym.asym.index = indexNil; + } + else if (h->esym.ifd != -1) + { + struct ecoff_debug_info *debug; + + /* Adjust the FDR index for the symbol by that used for the + input BFD. */ + debug = &ecoff_data (h->abfd)->debug_info; + BFD_ASSERT (h->esym.ifd >= 0 + && h->esym.ifd < debug->symbolic_header.ifdMax); + h->esym.ifd = debug->ifdmap[h->esym.ifd]; + } + + switch (h->root.type) + { + default: + case bfd_link_hash_warning: + case bfd_link_hash_new: + abort (); + case bfd_link_hash_undefined: + case bfd_link_hash_undefweak: + if (h->esym.asym.sc != scUndefined + && h->esym.asym.sc != scSUndefined) + h->esym.asym.sc = scUndefined; + break; + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + if (h->esym.asym.sc == scUndefined + || h->esym.asym.sc == scSUndefined) + h->esym.asym.sc = scAbs; + else if (h->esym.asym.sc == scCommon) + h->esym.asym.sc = scBss; + else if (h->esym.asym.sc == scSCommon) + h->esym.asym.sc = scSBss; + h->esym.asym.value = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + break; + case bfd_link_hash_common: + if (h->esym.asym.sc != scCommon + && h->esym.asym.sc != scSCommon) + h->esym.asym.sc = scCommon; + h->esym.asym.value = h->root.u.c.size; + break; + case bfd_link_hash_indirect: + /* We ignore these symbols, since the indirected symbol is + already in the hash table. */ + return true; + } + + /* bfd_ecoff_debug_one_external uses iextMax to keep track of the + symbol number. */ + h->indx = ecoff_data (output_bfd)->debug_info.symbolic_header.iextMax; + h->written = 1; + + return (bfd_ecoff_debug_one_external + (output_bfd, &ecoff_data (output_bfd)->debug_info, + &ecoff_backend (output_bfd)->debug_swap, h->root.root.string, + &h->esym)); +} + +/* Relocate and write an ECOFF section into an ECOFF output file. */ + +static boolean +ecoff_indirect_link_order (output_bfd, info, output_section, link_order) + bfd *output_bfd; + struct bfd_link_info *info; + asection *output_section; + struct bfd_link_order *link_order; +{ + asection *input_section; + bfd *input_bfd; + struct ecoff_section_tdata *section_tdata; + bfd_size_type raw_size; + bfd_size_type cooked_size; + bfd_byte *contents = NULL; + bfd_size_type external_reloc_size; + bfd_size_type external_relocs_size; + PTR external_relocs = NULL; + bfd_size_type amt; + + BFD_ASSERT ((output_section->flags & SEC_HAS_CONTENTS) != 0); + + if (link_order->size == 0) + return true; + + input_section = link_order->u.indirect.section; + input_bfd = input_section->owner; + section_tdata = ecoff_section_data (input_bfd, input_section); + + raw_size = input_section->_raw_size; + cooked_size = input_section->_cooked_size; + if (cooked_size == 0) + cooked_size = raw_size; + + BFD_ASSERT (input_section->output_section == output_section); + BFD_ASSERT (input_section->output_offset == link_order->offset); + BFD_ASSERT (cooked_size == link_order->size); + + /* Get the section contents. We allocate memory for the larger of + the size before relocating and the size after relocating. */ + amt = raw_size >= cooked_size ? raw_size : cooked_size; + contents = (bfd_byte *) bfd_malloc (amt); + if (contents == NULL && amt != 0) + goto error_return; + + /* If we are relaxing, the contents may have already been read into + memory, in which case we copy them into our new buffer. We don't + simply reuse the old buffer in case cooked_size > raw_size. */ + if (section_tdata != (struct ecoff_section_tdata *) NULL + && section_tdata->contents != (bfd_byte *) NULL) + memcpy (contents, section_tdata->contents, (size_t) raw_size); + else + { + if (! bfd_get_section_contents (input_bfd, input_section, + (PTR) contents, + (file_ptr) 0, raw_size)) + goto error_return; + } + + /* Get the relocs. If we are relaxing MIPS code, they will already + have been read in. Otherwise, we read them in now. */ + external_reloc_size = ecoff_backend (input_bfd)->external_reloc_size; + external_relocs_size = external_reloc_size * input_section->reloc_count; + + if (section_tdata != (struct ecoff_section_tdata *) NULL + && section_tdata->external_relocs != NULL) + external_relocs = section_tdata->external_relocs; + else + { + external_relocs = (PTR) bfd_malloc (external_relocs_size); + if (external_relocs == NULL && external_relocs_size != 0) + goto error_return; + + if (bfd_seek (input_bfd, input_section->rel_filepos, SEEK_SET) != 0 + || (bfd_bread (external_relocs, external_relocs_size, input_bfd) + != external_relocs_size)) + goto error_return; + } + + /* Relocate the section contents. */ + if (! ((*ecoff_backend (input_bfd)->relocate_section) + (output_bfd, info, input_bfd, input_section, contents, + external_relocs))) + goto error_return; + + /* Write out the relocated section. */ + if (! bfd_set_section_contents (output_bfd, + output_section, + (PTR) contents, + (file_ptr) input_section->output_offset, + cooked_size)) + goto error_return; + + /* If we are producing relocateable output, the relocs were + modified, and we write them out now. We use the reloc_count + field of output_section to keep track of the number of relocs we + have output so far. */ + if (info->relocateable) + { + file_ptr pos = (output_section->rel_filepos + + output_section->reloc_count * external_reloc_size); + if (bfd_seek (output_bfd, pos, SEEK_SET) != 0 + || (bfd_bwrite (external_relocs, external_relocs_size, output_bfd) + != external_relocs_size)) + goto error_return; + output_section->reloc_count += input_section->reloc_count; + } + + if (contents != NULL) + free (contents); + if (external_relocs != NULL && section_tdata == NULL) + free (external_relocs); + return true; + + error_return: + if (contents != NULL) + free (contents); + if (external_relocs != NULL && section_tdata == NULL) + free (external_relocs); + return false; +} + +/* Generate a reloc when linking an ECOFF file. This is a reloc + requested by the linker, and does come from any input file. This + is used to build constructor and destructor tables when linking + with -Ur. */ + +static boolean +ecoff_reloc_link_order (output_bfd, info, output_section, link_order) + bfd *output_bfd; + struct bfd_link_info *info; + 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; + file_ptr pos; + + 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; + + rel.howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc); + if (rel.howto == 0) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + if (type == bfd_section_reloc_link_order) + { + section = link_order->u.reloc.p->u.section; + rel.sym_ptr_ptr = section->symbol_ptr_ptr; + } + else + { + struct bfd_link_hash_entry *h; + + /* Treat a reloc against a defined symbol as though it were + actually against the section. */ + h = bfd_wrapped_link_hash_lookup (output_bfd, info, + 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 (addend != 0) + { + bfd_size_type size; + bfd_reloc_status_type rstat; + bfd_byte *buf; + + size = bfd_get_reloc_size (rel.howto); + buf = (bfd_byte *) bfd_zmalloc (size); + if (buf == (bfd_byte *) NULL) + return false; + rstat = _bfd_relocate_contents (rel.howto, output_bfd, + (bfd_vma) addend, buf); + switch (rstat) + { + case bfd_reloc_ok: + break; + default: + case bfd_reloc_outofrange: + abort (); + case bfd_reloc_overflow: + if (! ((*info->callbacks->reloc_overflow) + (info, + (link_order->type == bfd_section_reloc_link_order + ? bfd_section_name (output_bfd, section) + : link_order->u.reloc.p->u.name), + rel.howto->name, addend, (bfd *) NULL, + (asection *) NULL, (bfd_vma) 0))) + { + free (buf); + return false; + } + break; + } + ok = bfd_set_section_contents (output_bfd, output_section, (PTR) buf, + (file_ptr) link_order->offset, size); + free (buf); + if (! ok) + return false; + } + + rel.addend = 0; + + /* Move the information into an internal_reloc structure. */ + in.r_vaddr = (rel.address + + bfd_get_section_vma (output_bfd, output_section)); + in.r_type = rel.howto->type; + + if (type == bfd_symbol_reloc_link_order) + { + struct ecoff_link_hash_entry *h; + + h = ((struct ecoff_link_hash_entry *) + bfd_wrapped_link_hash_lookup (output_bfd, info, + link_order->u.reloc.p->u.name, + false, false, true)); + if (h != (struct ecoff_link_hash_entry *) NULL + && h->indx != -1) + in.r_symndx = h->indx; + else + { + if (! ((*info->callbacks->unattached_reloc) + (info, link_order->u.reloc.p->u.name, (bfd *) NULL, + (asection *) NULL, (bfd_vma) 0))) + return false; + in.r_symndx = 0; + } + in.r_extern = 1; + } + else + { + const char *name; + + 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) + in.r_symndx = RELOC_SECTION_RDATA; + else if (strcmp (name, ".data") == 0) + in.r_symndx = RELOC_SECTION_DATA; + else if (strcmp (name, ".sdata") == 0) + in.r_symndx = RELOC_SECTION_SDATA; + else if (strcmp (name, ".sbss") == 0) + in.r_symndx = RELOC_SECTION_SBSS; + else if (strcmp (name, ".bss") == 0) + in.r_symndx = RELOC_SECTION_BSS; + else if (strcmp (name, ".init") == 0) + in.r_symndx = RELOC_SECTION_INIT; + else if (strcmp (name, ".lit8") == 0) + in.r_symndx = RELOC_SECTION_LIT8; + else if (strcmp (name, ".lit4") == 0) + in.r_symndx = RELOC_SECTION_LIT4; + else if (strcmp (name, ".xdata") == 0) + in.r_symndx = RELOC_SECTION_XDATA; + else if (strcmp (name, ".pdata") == 0) + in.r_symndx = RELOC_SECTION_PDATA; + else if (strcmp (name, ".fini") == 0) + in.r_symndx = RELOC_SECTION_FINI; + else if (strcmp (name, ".lita") == 0) + 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; + } + + /* Let the BFD backend adjust the reloc. */ + (*ecoff_backend (output_bfd)->adjust_reloc_out) (output_bfd, &rel, &in); + + /* Get some memory and swap out the reloc. */ + external_reloc_size = ecoff_backend (output_bfd)->external_reloc_size; + rbuf = (bfd_byte *) bfd_malloc (external_reloc_size); + if (rbuf == (bfd_byte *) NULL) + return false; + + (*ecoff_backend (output_bfd)->swap_reloc_out) (output_bfd, &in, (PTR) rbuf); + + pos = (output_section->rel_filepos + + output_section->reloc_count * external_reloc_size); + ok = (bfd_seek (output_bfd, pos, SEEK_SET) == 0 + && (bfd_bwrite ((PTR) rbuf, external_reloc_size, output_bfd) + == external_reloc_size)); + + if (ok) + ++output_section->reloc_count; + + free (rbuf); + + return ok; +}