- xcoff_data (abfd)->coff.link_info = info;
-
- finfo.strtab = _bfd_stringtab_init ();
- if (finfo.strtab == NULL)
- goto error_return;
-
- /* Count the line number and relocation entries required for the
- output file. Determine a few maximum sizes. */
- max_contents_size = 0;
- max_lineno_count = 0;
- max_reloc_count = 0;
- for (o = abfd->sections; o != NULL; o = o->next)
- {
- o->reloc_count = 0;
- o->lineno_count = 0;
- for (p = o->link_order_head; p != NULL; p = p->next)
- {
- if (p->type == bfd_indirect_link_order)
- {
- asection *sec;
-
- sec = p->u.indirect.section;
-
- /* Mark all sections which are to be included in the
- link. This will normally be every section. We need
- to do this so that we can identify any sections which
- the linker has decided to not include. */
- sec->linker_mark = true;
-
- if (info->strip == strip_none
- || info->strip == strip_some)
- o->lineno_count += sec->lineno_count;
-
- o->reloc_count += sec->reloc_count;
-
- if (sec->_raw_size > max_contents_size)
- max_contents_size = sec->_raw_size;
- if (sec->lineno_count > max_lineno_count)
- max_lineno_count = sec->lineno_count;
- if (coff_section_data (sec->owner, sec) != NULL
- && xcoff_section_data (sec->owner, sec) != NULL
- && (xcoff_section_data (sec->owner, sec)->lineno_count
- > max_lineno_count))
- max_lineno_count =
- xcoff_section_data (sec->owner, sec)->lineno_count;
- if (sec->reloc_count > max_reloc_count)
- max_reloc_count = sec->reloc_count;
- }
- else if (p->type == bfd_section_reloc_link_order
- || p->type == bfd_symbol_reloc_link_order)
- ++o->reloc_count;
- }
- }
-
- /* Compute the file positions for all the sections. */
- if (abfd->output_has_begun)
- {
- if (xcoff_hash_table (info)->file_align != 0)
- abort ();
- }
- else
- {
- bfd_vma file_align;
-
- file_align = xcoff_hash_table (info)->file_align;
- if (file_align != 0)
- {
- boolean saw_contents;
- int indx;
- asection **op;
- file_ptr sofar;
-
- /* Insert .pad sections before every section which has
- contents and is loaded, if it is preceded by some other
- section which has contents and is loaded. */
- saw_contents = true;
- for (op = &abfd->sections; *op != NULL; op = &(*op)->next)
- {
- (*op)->target_index = indx;
- if (strcmp ((*op)->name, ".pad") == 0)
- saw_contents = false;
- else if (((*op)->flags & SEC_HAS_CONTENTS) != 0
- && ((*op)->flags & SEC_LOAD) != 0)
- {
- if (! saw_contents)
- saw_contents = true;
- else
- {
- asection *n, *hold;
-
- hold = *op;
- *op = NULL;
- n = bfd_make_section_anyway (abfd, ".pad");
- BFD_ASSERT (*op == n);
- n->next = hold;
- n->flags = SEC_HAS_CONTENTS;
- n->alignment_power = 0;
- saw_contents = false;
- }
- }
- }
-
- /* Reset the section indices after inserting the new
- sections. */
- indx = 0;
- for (o = abfd->sections; o != NULL; o = o->next)
- {
- ++indx;
- o->target_index = indx;
- }
- BFD_ASSERT ((unsigned int) indx == abfd->section_count);
-
- /* Work out appropriate sizes for the .pad sections to force
- each section to land on a page boundary. This bit of
- code knows what compute_section_file_positions is going
- to do. */
- sofar = bfd_coff_filhsz (abfd);
- sofar += bfd_coff_aoutsz (abfd);
- sofar += abfd->section_count * bfd_coff_scnhsz (abfd);
- for (o = abfd->sections; o != NULL; o = o->next)
- if (o->reloc_count >= 0xffff || o->lineno_count >= 0xffff)
- sofar += bfd_coff_scnhsz (abfd);
-
- for (o = abfd->sections; o != NULL; o = o->next)
- {
- if (strcmp (o->name, ".pad") == 0)
- {
- bfd_vma pageoff;
-
- BFD_ASSERT (o->_raw_size == 0);
- pageoff = sofar & (file_align - 1);
- if (pageoff != 0)
- {
- o->_raw_size = file_align - pageoff;
- sofar += file_align - pageoff;
- o->flags |= SEC_HAS_CONTENTS;
- }
- }
- else
- {
- if ((o->flags & SEC_HAS_CONTENTS) != 0)
- sofar += BFD_ALIGN (o->_raw_size,
- 1 << o->alignment_power);
- }
- }
- }
-
- bfd_coff_compute_section_file_positions (abfd);
- }
-
- /* Allocate space for the pointers we need to keep for the relocs. */
- {
- unsigned int i;
-
- /* We use section_count + 1, rather than section_count, because
- the target_index fields are 1 based. */
- finfo.section_info =
- ((struct xcoff_link_section_info *)
- bfd_malloc ((abfd->section_count + 1)
- * sizeof (struct xcoff_link_section_info)));
- 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;
- finfo.section_info[i].toc_rel_hashes = NULL;
- }
- }
-
- /* Set the file positions for the relocs. */
- rel_filepos = obj_relocbase (abfd);
- relsz = bfd_coff_relsz (abfd);
- max_output_reloc_count = 0;
- for (o = abfd->sections; o != NULL; o = o->next)
- {
- if (o->reloc_count == 0)
- o->rel_filepos = 0;
- else
- {
- o->flags |= SEC_RELOC;
- o->rel_filepos = rel_filepos;
- rel_filepos += o->reloc_count * relsz;
-
- /* 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.
- We could backpatch the file later, I suppose, although it
- would be slow. */
- finfo.section_info[o->target_index].relocs =
- ((struct internal_reloc *)
- bfd_malloc (o->reloc_count * sizeof (struct internal_reloc)));
- finfo.section_info[o->target_index].rel_hashes =
- ((struct xcoff_link_hash_entry **)
- bfd_malloc (o->reloc_count
- * sizeof (struct xcoff_link_hash_entry *)));
- 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;
- }
- }
-
- /* We now know the size of the relocs, so we can determine the file
- positions of the line numbers. */
- line_filepos = rel_filepos;
- finfo.line_filepos = line_filepos;
- linesz = bfd_coff_linesz (abfd);
- 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;
- }
-
- /* 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. We want at least 4 symbols, since that is the
- number which xcoff_write_global_symbol may need. */
- max_sym_count = 4;
- for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
- {
- size_t 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. */
- finfo.internal_syms = ((struct internal_syment *)
- bfd_malloc (max_sym_count
- * sizeof (struct internal_syment)));
- finfo.sym_indices = (long *) bfd_malloc (max_sym_count * sizeof (long));
- finfo.outsyms = ((bfd_byte *)
- bfd_malloc ((size_t) ((max_sym_count + 1) * symesz)));
- finfo.linenos = (bfd_byte *) bfd_malloc (max_lineno_count
- * bfd_coff_linesz (abfd));
- finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size);
- finfo.external_relocs = (bfd_byte *) bfd_malloc (max_reloc_count * relsz);
- if ((finfo.internal_syms == 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))
- goto error_return;
-
- obj_raw_syment_count (abfd) = 0;
- xcoff_data (abfd)->toc = (bfd_vma) -1;
-
- /* 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. */
- 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
- && p->u.indirect.section->owner->xvec == abfd->xvec)
- {
- sub = p->u.indirect.section->owner;
- if (! sub->output_has_begun)
- {
- if (! xcoff_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 (! xcoff_reloc_link_order (abfd, &finfo, o, p))
- goto error_return;
- }
- else
- {
- if (! _bfd_default_link_order (abfd, info, o, p))
- goto error_return;
- }
- }
- }
-
- /* Free up the buffers used by xcoff_link_input_bfd. */
-
- if (finfo.internal_syms != NULL)
- {
- free (finfo.internal_syms);
- finfo.internal_syms = 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;
- }
-
- /* The value of the last C_FILE symbol is supposed to be -1. Write
- it out again. */
- if (finfo.last_file_index != -1)
- {
- finfo.last_file.n_value = -1;
- bfd_coff_swap_sym_out (abfd, (PTR) &finfo.last_file,
- (PTR) finfo.outsyms);
- if (bfd_seek (abfd,
- (obj_sym_filepos (abfd)
- + finfo.last_file_index * symesz),
- SEEK_SET) != 0
- || bfd_write (finfo.outsyms, symesz, 1, abfd) != symesz)
- goto error_return;
- }
-
- /* Write out all the global symbols which do not come from XCOFF
- input files. */
- xcoff_link_hash_traverse (xcoff_hash_table (info),
- xcoff_write_global_symbol,
- (PTR) &finfo);
-
- if (finfo.outsyms != NULL)
- {
- free (finfo.outsyms);
- finfo.outsyms = NULL;
- }
-
- /* 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. */
- external_relocs = (bfd_byte *) malloc (max_output_reloc_count * relsz);
- if (external_relocs == NULL && max_output_reloc_count != 0)
- {
- bfd_set_error (bfd_error_no_memory);
- goto error_return;
- }
-
- for (o = abfd->sections; o != NULL; o = o->next)
- {
- struct internal_reloc *irel;
- struct internal_reloc *irelend;
- struct xcoff_link_hash_entry **rel_hash;
- struct xcoff_toc_rel_hash *toc_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;
- for (; irel < irelend; irel++, rel_hash++, erel += relsz)
- {
- if (*rel_hash != NULL)
- {
- if ((*rel_hash)->indx < 0)
- {
- if (! ((*info->callbacks->unattached_reloc)
- (info, (*rel_hash)->root.root.string,
- (bfd *) NULL, o, irel->r_vaddr)))
- goto error_return;
- (*rel_hash)->indx = 0;
- }
- irel->r_symndx = (*rel_hash)->indx;
- }
- }
-
- for (toc_rel_hash = finfo.section_info[o->target_index].toc_rel_hashes;
- toc_rel_hash != NULL;
- toc_rel_hash = toc_rel_hash->next)
- {
- if (toc_rel_hash->h->u.toc_indx < 0)
- {
- if (! ((*info->callbacks->unattached_reloc)
- (info, toc_rel_hash->h->root.root.string,
- (bfd *) NULL, o, toc_rel_hash->rel->r_vaddr)))
- goto error_return;
- toc_rel_hash->h->u.toc_indx = 0;
- }
- toc_rel_hash->rel->r_symndx = toc_rel_hash->h->u.toc_indx;
- }
-
- /* XCOFF requires that the relocs be sorted by address. We tend
- to produce them in the order in which their containing csects
- appear in the symbol table, which is not necessarily by
- address. So we sort them here. There may be a better way to
- do this. */
- qsort ((PTR) finfo.section_info[o->target_index].relocs,
- o->reloc_count, sizeof (struct internal_reloc),
- xcoff_sort_relocs);
-
- irel = finfo.section_info[o->target_index].relocs;
- irelend = irel + o->reloc_count;
- erel = external_relocs;
- for (; irel < irelend; irel++, rel_hash++, erel += relsz)
- bfd_coff_swap_reloc_out (abfd, (PTR) irel, (PTR) erel);
-
- if (bfd_seek (abfd, o->rel_filepos, SEEK_SET) != 0
- || bfd_write ((PTR) external_relocs, relsz, o->reloc_count,
- abfd) != relsz * o->reloc_count)
- goto error_return;
- }
-
- if (external_relocs != NULL)
- {
- 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;
- }
-
- /* Write out the loader section contents. */
- BFD_ASSERT ((bfd_byte *) finfo.ldrel
- == (xcoff_hash_table (info)->loader_section->contents
- + xcoff_hash_table (info)->ldhdr.l_impoff));
- o = xcoff_hash_table (info)->loader_section;
- if (! bfd_set_section_contents (abfd, o->output_section,
- o->contents, o->output_offset,
- o->_raw_size))
- goto error_return;
-
- /* Write out the magic sections. */
- o = xcoff_hash_table (info)->linkage_section;
- if (o->_raw_size > 0
- && ! bfd_set_section_contents (abfd, o->output_section, o->contents,
- o->output_offset, o->_raw_size))
- goto error_return;
- o = xcoff_hash_table (info)->toc_section;
- if (o->_raw_size > 0
- && ! bfd_set_section_contents (abfd, o->output_section, o->contents,
- o->output_offset, o->_raw_size))
- goto error_return;
- o = xcoff_hash_table (info)->descriptor_section;
- if (o->_raw_size > 0
- && ! bfd_set_section_contents (abfd, o->output_section, o->contents,
- o->output_offset, o->_raw_size))
- goto error_return;
-
- /* Write out the string table. */
- if (bfd_seek (abfd,
- (obj_sym_filepos (abfd)
- + obj_raw_syment_count (abfd) * symesz),
- SEEK_SET) != 0)
- goto error_return;
- bfd_h_put_32 (abfd,
- _bfd_stringtab_size (finfo.strtab) + STRING_SIZE_SIZE,
- (bfd_byte *) strbuf);
- if (bfd_write (strbuf, 1, STRING_SIZE_SIZE, abfd) != STRING_SIZE_SIZE)
- goto error_return;
- if (! _bfd_stringtab_emit (abfd, finfo.strtab))
- goto error_return;
-
- _bfd_stringtab_free (finfo.strtab);
-
- /* Write out the debugging string table. */
- o = xcoff_hash_table (info)->debug_section;
- if (o != NULL)
- {
- struct bfd_strtab_hash *debug_strtab;
-
- debug_strtab = xcoff_hash_table (info)->debug_strtab;
- BFD_ASSERT (o->output_section->_raw_size - o->output_offset
- >= _bfd_stringtab_size (debug_strtab));
- if (bfd_seek (abfd,
- o->output_section->filepos + o->output_offset,
- SEEK_SET) != 0)
- goto error_return;
- if (! _bfd_stringtab_emit (abfd, debug_strtab))
- goto error_return;
- }
-
- /* 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 (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.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 (external_relocs != NULL)
- free (external_relocs);
- return false;
-}
-
-/* Link an input file into the linker output file. This function
- handles all the sections and relocations of the input file at once. */
-
-static boolean
-xcoff_link_input_bfd (finfo, input_bfd)
- struct xcoff_final_link_info *finfo;
- bfd *input_bfd;