+/* Set section VMAs and GP values before reloc processing. */
+
+void
+ecoff_frob_file_before_fix (void)
+{
+ bfd_vma addr;
+ asection *sec;
+
+ /* Set the section VMA values. We force the .sdata and .sbss
+ sections to the end to ensure that their VMA addresses are close
+ together so that the GP register can address both of them. We
+ put the .bss section after the .sbss section.
+
+ Also, for the Alpha, we must sort the sections, to make sure they
+ appear in the output file in the correct order. (Actually, maybe
+ this is a job for BFD. But the VMAs computed would be out of
+ whack if we computed them given our initial, random ordering.
+ It's possible that that wouldn't break things; I could do some
+ experimenting sometime and find out.
+
+ This output ordering of sections is magic, on the Alpha, at
+ least. The .lita section must come before .lit8 and .lit4,
+ otherwise the OSF/1 linker may silently trash the .lit{4,8}
+ section contents. Also, .text must preceed .rdata. These differ
+ from the order described in some parts of the DEC OSF/1 Assembly
+ Language Programmer's Guide, but that order doesn't seem to work
+ with their linker.
+
+ I don't know if section ordering on the MIPS is important. */
+
+ static const char *const names[] =
+ {
+ /* text segment */
+ ".text", ".rdata", ".init", ".fini",
+ /* data segment */
+ ".data", ".lita", ".lit8", ".lit4", ".sdata", ".got",
+ /* bss segment */
+ ".sbss", ".bss",
+ };
+#define n_names ((int) (sizeof (names) / sizeof (names[0])))
+
+ /* Sections that match names, order to be straightened out later. */
+ asection *secs[n_names];
+ int i;
+
+ addr = 0;
+ for (i = 0; i < n_names; i++)
+ secs[i] = NULL;
+
+ for (sec = stdoutput->sections; sec != NULL; sec = sec->next)
+ {
+ for (i = 0; i < n_names; i++)
+ if (!strcmp (sec->name, names[i]))
+ {
+ secs[i] = sec;
+ bfd_section_list_remove (stdoutput, sec);
+ break;
+ }
+ if (i == n_names)
+ {
+ bfd_set_section_vma (stdoutput, sec, addr);
+ addr += bfd_section_size (stdoutput, sec);
+ }
+ }
+ for (i = 0; i < n_names; i++)
+ if (secs[i])
+ {
+ bfd_set_section_vma (stdoutput, secs[i], addr);
+ addr += bfd_section_size (stdoutput, secs[i]);
+ }
+ for (i = n_names - 1; i >= 0; i--)
+ if (secs[i])
+ bfd_section_list_prepend (stdoutput, secs[i]);
+
+ /* Fill in the register masks. */
+ {
+ unsigned long gprmask = 0;
+ unsigned long fprmask = 0;
+ unsigned long *cprmask = NULL;
+
+#ifdef TC_MIPS
+ /* Fill in the MIPS register masks. It's probably not worth
+ setting up a generic interface for this. */
+ gprmask = mips_gprmask;
+ cprmask = mips_cprmask;
+#endif
+
+#ifdef TC_ALPHA
+ alpha_frob_ecoff_data ();
+
+ if (! bfd_ecoff_set_gp_value (stdoutput, alpha_gp_value))
+ as_fatal (_("Can't set GP value"));
+
+ gprmask = alpha_gprmask;
+ fprmask = alpha_fprmask;
+#endif
+
+ if (! bfd_ecoff_set_regmasks (stdoutput, gprmask, fprmask, cprmask))
+ as_fatal (_("Can't set register masks"));
+ }
+}
+
+/* Swap out the symbols and debugging information for BFD. */
+
+void
+ecoff_frob_file (void)
+{
+ const struct ecoff_debug_swap * const debug_swap
+ = &ecoff_backend (stdoutput)->debug_swap;
+ bfd_vma addr ATTRIBUTE_UNUSED;
+ HDRR *hdr;
+ char *buf;
+ char *set;
+
+ /* Build the ECOFF debugging information. */
+ gas_assert (ecoff_data (stdoutput) != 0);
+ hdr = &ecoff_data (stdoutput)->debug_info.symbolic_header;
+ ecoff_build_debug (hdr, &buf, debug_swap);
+
+ /* Finish up the ecoff_tdata structure. */
+ set = buf;
+#define SET(ptr, count, type, size) \
+ if (hdr->count == 0) \
+ ecoff_data (stdoutput)->debug_info.ptr = NULL; \
+ else \
+ { \
+ ecoff_data (stdoutput)->debug_info.ptr = (type) set; \
+ set += hdr->count * size; \
+ }
+
+ SET (line, cbLine, unsigned char *, sizeof (unsigned char));
+ SET (external_dnr, idnMax, void *, debug_swap->external_dnr_size);
+ SET (external_pdr, ipdMax, void *, debug_swap->external_pdr_size);
+ SET (external_sym, isymMax, void *, debug_swap->external_sym_size);
+ SET (external_opt, ioptMax, void *, debug_swap->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_rfd, crfd, void *, debug_swap->external_rfd_size);
+ SET (external_fdr, ifdMax, void *, debug_swap->external_fdr_size);
+ SET (external_ext, iextMax, void *, debug_swap->external_ext_size);
+#undef SET
+}
+
+/* This is called by the ECOFF code to set the external information
+ for a symbol. We just pass it on to BFD, which expects the swapped
+ information to be stored in the native field of the symbol. */
+
+void
+obj_ecoff_set_ext (symbolS *sym, EXTR *ext)
+{
+ const struct ecoff_debug_swap * const debug_swap
+ = &ecoff_backend (stdoutput)->debug_swap;
+ ecoff_symbol_type *esym;
+
+ know (bfd_asymbol_flavour (symbol_get_bfdsym (sym))
+ == bfd_target_ecoff_flavour);
+ esym = ecoffsymbol (symbol_get_bfdsym (sym));
+ esym->local = FALSE;
+ esym->native = xmalloc (debug_swap->external_ext_size);
+ (*debug_swap->swap_ext_out) (stdoutput, ext, esym->native);
+}
+
+static int
+ecoff_sec_sym_ok_for_reloc (asection *sec ATTRIBUTE_UNUSED)
+{
+ return 1;
+}
+
+static void
+obj_ecoff_frob_symbol (symbolS *sym, int *puntp ATTRIBUTE_UNUSED)
+{
+ ecoff_frob_symbol (sym);
+}
+
+static void
+ecoff_pop_insert (void)
+{
+ pop_insert (obj_pseudo_table);
+}
+
+static int
+ecoff_separate_stab_sections (void)
+{
+ return 0;
+}
+