+ /* We use section_count + 1, rather than section_count, because
+ the target_index fields are 1 based. */
+ amt = abfd->section_count + 1;
+ amt *= sizeof (struct coff_link_section_info);
+ finfo.section_info = (struct coff_link_section_info *) bfd_malloc (amt);
+
+ if (finfo.section_info == NULL)
+ goto error_return;
+
+ for (i = 0; i <= abfd->section_count; i++)
+ {
+ finfo.section_info[i].relocs = NULL;
+ finfo.section_info[i].rel_hashes = NULL;
+ }
+ }
+
+ /* We now know the size of the relocs, so we can determine the file
+ positions of the line numbers. */
+ line_filepos = rel_filepos;
+ linesz = bfd_coff_linesz (abfd);
+ max_output_reloc_count = 0;
+
+ for (o = abfd->sections; o != NULL; o = o->next)
+ {
+ if (o->lineno_count == 0)
+ o->line_filepos = 0;
+ else
+ {
+ o->line_filepos = line_filepos;
+ line_filepos += o->lineno_count * linesz;
+ }
+
+ if (o->reloc_count != 0)
+ {
+ /* We don't know the indices of global symbols until we have
+ written out all the local symbols. For each section in
+ the output file, we keep an array of pointers to hash
+ table entries. Each entry in the array corresponds to a
+ reloc. When we find a reloc against a global symbol, we
+ set the corresponding entry in this array so that we can
+ fix up the symbol index after we have written out all the
+ local symbols.
+
+ Because of this problem, we also keep the relocs in
+ memory until the end of the link. This wastes memory,
+ but only when doing a relocatable link, which is not the
+ common case. */
+ BFD_ASSERT (info->relocatable);
+ amt = o->reloc_count;
+ amt *= sizeof (struct internal_reloc);
+ finfo.section_info[o->target_index].relocs =
+ (struct internal_reloc *) bfd_malloc (amt);
+ amt = o->reloc_count;
+ amt *= sizeof (struct coff_link_hash_entry *);
+ finfo.section_info[o->target_index].rel_hashes =
+ (struct coff_link_hash_entry **) bfd_malloc (amt);
+ if (finfo.section_info[o->target_index].relocs == NULL
+ || finfo.section_info[o->target_index].rel_hashes == NULL)
+ goto error_return;
+
+ if (o->reloc_count > max_output_reloc_count)
+ max_output_reloc_count = o->reloc_count;
+ }
+
+ /* Reset the reloc and lineno counts, so that we can use them to
+ count the number of entries we have output so far. */
+ o->reloc_count = 0;
+ o->lineno_count = 0;
+ }
+
+ obj_sym_filepos (abfd) = line_filepos;
+
+ /* Figure out the largest number of symbols in an input BFD. Take
+ the opportunity to clear the output_has_begun fields of all the
+ input BFD's. */
+ max_sym_count = 0;
+ for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+ {
+ bfd_size_type sz;
+
+ sub->output_has_begun = FALSE;
+ sz = obj_raw_syment_count (sub);
+ if (sz > max_sym_count)
+ max_sym_count = sz;
+ }
+
+ /* Allocate some buffers used while linking. */
+ amt = max_sym_count * sizeof (struct internal_syment);
+ finfo.internal_syms = (struct internal_syment *) bfd_malloc (amt);
+ amt = max_sym_count * sizeof (asection *);
+ finfo.sec_ptrs = (asection **) bfd_malloc (amt);
+ amt = max_sym_count * sizeof (long);
+ finfo.sym_indices = (long *) bfd_malloc (amt);
+ amt = (max_sym_count + 1) * symesz;
+ finfo.outsyms = (bfd_byte *) bfd_malloc (amt);
+ amt = max_lineno_count * bfd_coff_linesz (abfd);
+ finfo.linenos = (bfd_byte *) bfd_malloc (amt);
+ finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size);
+ finfo.external_relocs = (bfd_byte *) bfd_malloc (max_reloc_count * relsz);
+ if (! info->relocatable)
+ {
+ amt = max_reloc_count * sizeof (struct internal_reloc);
+ finfo.internal_relocs = (struct internal_reloc *) bfd_malloc (amt);
+ }
+ if ((finfo.internal_syms == NULL && max_sym_count > 0)
+ || (finfo.sec_ptrs == NULL && max_sym_count > 0)
+ || (finfo.sym_indices == NULL && max_sym_count > 0)
+ || finfo.outsyms == NULL
+ || (finfo.linenos == NULL && max_lineno_count > 0)
+ || (finfo.contents == NULL && max_contents_size > 0)
+ || (finfo.external_relocs == NULL && max_reloc_count > 0)
+ || (! info->relocatable
+ && finfo.internal_relocs == NULL
+ && max_reloc_count > 0))
+ goto error_return;
+
+ /* We now know the position of everything in the file, except that
+ we don't know the size of the symbol table and therefore we don't
+ know where the string table starts. We just build the string
+ table in memory as we go along. We process all the relocations
+ for a single input file at once. */
+ obj_raw_syment_count (abfd) = 0;
+
+ if (coff_backend_info (abfd)->_bfd_coff_start_final_link)
+ {
+ if (! bfd_coff_start_final_link (abfd, info))
+ goto error_return;
+ }
+
+ for (o = abfd->sections; o != NULL; o = o->next)
+ {
+ for (p = o->link_order_head; p != NULL; p = p->next)
+ {
+ if (p->type == bfd_indirect_link_order
+ && (bfd_get_flavour (p->u.indirect.section->owner)
+ == bfd_target_coff_flavour))
+ {
+ sub = p->u.indirect.section->owner;
+#ifdef POWERPC_LE_PE
+ if (! sub->output_has_begun && !ppc_do_last(sub))
+#else
+ if (! sub->output_has_begun)
+#endif
+ {
+ if (! _bfd_coff_link_input_bfd (&finfo, sub))
+ goto error_return;
+ sub->output_has_begun = TRUE;
+ }
+ }
+ else if (p->type == bfd_section_reloc_link_order
+ || p->type == bfd_symbol_reloc_link_order)
+ {
+ if (! _bfd_coff_reloc_link_order (abfd, &finfo, o, p))
+ goto error_return;
+ }
+ else
+ {
+ if (! _bfd_default_link_order (abfd, info, o, p))
+ goto error_return;
+ }
+ }
+ }
+
+#ifdef POWERPC_LE_PE
+ {
+ bfd* last_one = ppc_get_last();
+ if (last_one)
+ {
+ if (! _bfd_coff_link_input_bfd (&finfo, last_one))
+ goto error_return;
+ }
+ last_one->output_has_begun = TRUE;
+ }
+#endif
+
+ /* Free up the buffers used by _bfd_coff_link_input_bfd. */
+ coff_debug_merge_hash_table_free (&finfo.debug_merge);
+ debug_merge_allocated = FALSE;
+
+ if (finfo.internal_syms != NULL)
+ {
+ free (finfo.internal_syms);
+ finfo.internal_syms = NULL;
+ }
+ if (finfo.sec_ptrs != NULL)
+ {
+ free (finfo.sec_ptrs);
+ finfo.sec_ptrs = NULL;
+ }
+ if (finfo.sym_indices != NULL)
+ {
+ free (finfo.sym_indices);
+ finfo.sym_indices = NULL;
+ }
+ if (finfo.linenos != NULL)
+ {
+ free (finfo.linenos);
+ finfo.linenos = NULL;
+ }
+ if (finfo.contents != NULL)
+ {
+ free (finfo.contents);
+ finfo.contents = NULL;
+ }
+ if (finfo.external_relocs != NULL)
+ {
+ free (finfo.external_relocs);
+ finfo.external_relocs = NULL;
+ }
+ if (finfo.internal_relocs != NULL)
+ {
+ free (finfo.internal_relocs);
+ finfo.internal_relocs = NULL;
+ }
+
+ /* The value of the last C_FILE symbol is supposed to be the symbol
+ index of the first external symbol. Write it out again if
+ necessary. */
+ if (finfo.last_file_index != -1
+ && (unsigned int) finfo.last_file.n_value != obj_raw_syment_count (abfd))
+ {
+ file_ptr pos;
+
+ finfo.last_file.n_value = obj_raw_syment_count (abfd);
+ bfd_coff_swap_sym_out (abfd, (PTR) &finfo.last_file,
+ (PTR) finfo.outsyms);
+ pos = obj_sym_filepos (abfd) + finfo.last_file_index * symesz;
+ if (bfd_seek (abfd, pos, SEEK_SET) != 0
+ || bfd_bwrite (finfo.outsyms, symesz, abfd) != symesz)
+ return FALSE;
+ }
+
+ /* Write out the global symbols. */
+ finfo.failed = FALSE;
+ coff_link_hash_traverse (coff_hash_table (info), _bfd_coff_write_global_sym,
+ (PTR) &finfo);
+ if (finfo.failed)
+ goto error_return;
+
+ /* The outsyms buffer is used by _bfd_coff_write_global_sym. */
+ if (finfo.outsyms != NULL)
+ {
+ free (finfo.outsyms);
+ finfo.outsyms = NULL;
+ }
+
+ if (info->relocatable)
+ {
+ /* Now that we have written out all the global symbols, we know
+ the symbol indices to use for relocs against them, and we can
+ finally write out the relocs. */
+ amt = max_output_reloc_count * relsz;
+ external_relocs = (bfd_byte *) bfd_malloc (amt);
+ if (external_relocs == NULL)
+ goto error_return;
+
+ for (o = abfd->sections; o != NULL; o = o->next)
+ {
+ struct internal_reloc *irel;
+ struct internal_reloc *irelend;
+ struct coff_link_hash_entry **rel_hash;
+ bfd_byte *erel;
+
+ if (o->reloc_count == 0)
+ continue;
+
+ irel = finfo.section_info[o->target_index].relocs;
+ irelend = irel + o->reloc_count;
+ rel_hash = finfo.section_info[o->target_index].rel_hashes;
+ erel = external_relocs;
+ for (; irel < irelend; irel++, rel_hash++, erel += relsz)
+ {
+ if (*rel_hash != NULL)
+ {
+ BFD_ASSERT ((*rel_hash)->indx >= 0);
+ irel->r_symndx = (*rel_hash)->indx;
+ }
+ bfd_coff_swap_reloc_out (abfd, (PTR) irel, (PTR) erel);
+ }
+
+ amt = relsz * o->reloc_count;
+ if (bfd_seek (abfd, o->rel_filepos, SEEK_SET) != 0
+ || bfd_bwrite ((PTR) external_relocs, amt, abfd) != amt)
+ goto error_return;
+ }
+
+ free (external_relocs);
+ external_relocs = NULL;
+ }
+
+ /* Free up the section information. */
+ if (finfo.section_info != NULL)
+ {
+ unsigned int i;
+
+ for (i = 0; i < abfd->section_count; i++)
+ {
+ if (finfo.section_info[i].relocs != NULL)
+ free (finfo.section_info[i].relocs);
+ if (finfo.section_info[i].rel_hashes != NULL)
+ free (finfo.section_info[i].rel_hashes);
+ }
+ free (finfo.section_info);
+ finfo.section_info = NULL;
+ }
+
+ /* If we have optimized stabs strings, output them. */
+ if (coff_hash_table (info)->stab_info != NULL)
+ {
+ if (! _bfd_write_stab_strings (abfd, &coff_hash_table (info)->stab_info))
+ return FALSE;
+ }
+
+ /* Write out the string table. */
+ if (obj_raw_syment_count (abfd) != 0)
+ {
+ file_ptr pos;
+
+ pos = obj_sym_filepos (abfd) + obj_raw_syment_count (abfd) * symesz;
+ if (bfd_seek (abfd, pos, SEEK_SET) != 0)
+ return FALSE;
+
+#if STRING_SIZE_SIZE == 4
+ H_PUT_32 (abfd,
+ _bfd_stringtab_size (finfo.strtab) + STRING_SIZE_SIZE,
+ strbuf);
+#else
+ #error Change H_PUT_32 above
+#endif
+
+ if (bfd_bwrite (strbuf, (bfd_size_type) STRING_SIZE_SIZE, abfd)
+ != STRING_SIZE_SIZE)
+ return FALSE;
+
+ if (! _bfd_stringtab_emit (abfd, finfo.strtab))
+ return FALSE;
+ }
+
+ _bfd_stringtab_free (finfo.strtab);
+
+ /* Setting bfd_get_symcount to 0 will cause write_object_contents to
+ not try to write out the symbols. */
+ bfd_get_symcount (abfd) = 0;
+
+ return TRUE;
+
+ error_return:
+ if (debug_merge_allocated)
+ coff_debug_merge_hash_table_free (&finfo.debug_merge);
+ if (finfo.strtab != NULL)
+ _bfd_stringtab_free (finfo.strtab);
+ if (finfo.section_info != NULL)
+ {
+ unsigned int i;
+
+ for (i = 0; i < abfd->section_count; i++)
+ {
+ if (finfo.section_info[i].relocs != NULL)
+ free (finfo.section_info[i].relocs);
+ if (finfo.section_info[i].rel_hashes != NULL)
+ free (finfo.section_info[i].rel_hashes);
+ }
+ free (finfo.section_info);
+ }
+ if (finfo.internal_syms != NULL)
+ free (finfo.internal_syms);
+ if (finfo.sec_ptrs != NULL)
+ free (finfo.sec_ptrs);
+ if (finfo.sym_indices != NULL)
+ free (finfo.sym_indices);
+ if (finfo.outsyms != NULL)
+ free (finfo.outsyms);
+ if (finfo.linenos != NULL)
+ free (finfo.linenos);
+ if (finfo.contents != NULL)
+ free (finfo.contents);
+ if (finfo.external_relocs != NULL)
+ free (finfo.external_relocs);
+ if (finfo.internal_relocs != NULL)
+ free (finfo.internal_relocs);
+ if (external_relocs != NULL)
+ free (external_relocs);
+ return FALSE;
+}
+#endif