+ /* Check for magic symbol names. */
+ if ((smtyp == XTY_SD || smtyp == XTY_CM)
+ && aux.x_csect.x_smclas != XMC_TC
+ && aux.x_csect.x_smclas != XMC_TD)
+ {
+ int i;
+
+ i = -1;
+ if (name[0] == '_')
+ {
+ if (strcmp (name, "_text") == 0)
+ i = 0;
+ else if (strcmp (name, "_etext") == 0)
+ i = 1;
+ else if (strcmp (name, "_data") == 0)
+ i = 2;
+ else if (strcmp (name, "_edata") == 0)
+ i = 3;
+ else if (strcmp (name, "_end") == 0)
+ i = 4;
+ }
+ else if (name[0] == 'e' && strcmp (name, "end") == 0)
+ i = 5;
+
+ if (i != -1)
+ xcoff_hash_table (info)->special_sections[i] = csect;
+ }
+
+ /* Now we have enough information to add the symbol to the
+ linker hash table. */
+
+ if (sym.n_sclass == C_EXT)
+ {
+ boolean copy;
+
+ BFD_ASSERT (section != NULL);
+
+ /* We must copy the name into memory if we got it from the
+ syment itself, rather than the string table. */
+ copy = default_copy;
+ if (sym._n._n_n._n_zeroes != 0
+ || sym._n._n_n._n_offset == 0)
+ copy = true;
+
+ /* The AIX linker appears to only detect multiple symbol
+ definitions when there is a reference to the symbol. If
+ a symbol is defined multiple times, and the only
+ references are from the same object file, the AIX linker
+ appears to permit it. It does not merge the different
+ definitions, but handles them independently. On the
+ other hand, if there is a reference, the linker reports
+ an error.
+
+ This matters because the AIX <net/net_globals.h> header
+ file actually defines an initialized array, so we have to
+ actually permit that to work.
+
+ We also have to handle the case of statically linking a
+ shared object, which will cause symbol redefinitions,
+ although this is an easier case to detect. */
+
+ if (info->hash->creator == abfd->xvec)
+ {
+ if (! bfd_is_und_section (section))
+ *sym_hash = xcoff_link_hash_lookup (xcoff_hash_table (info),
+ name, true, copy, false);
+ else
+ *sym_hash = ((struct xcoff_link_hash_entry *)
+ bfd_wrapped_link_hash_lookup (abfd, info, name,
+ true, copy, false));
+ if (*sym_hash == NULL)
+ goto error_return;
+ if (((*sym_hash)->root.type == bfd_link_hash_defined
+ || (*sym_hash)->root.type == bfd_link_hash_defweak)
+ && ! bfd_is_und_section (section)
+ && ! bfd_is_com_section (section))
+ {
+ /* This is a second definition of a defined symbol. */
+ if ((abfd->flags & DYNAMIC) != 0
+ && ((*sym_hash)->smclas != XMC_GL
+ || aux.x_csect.x_smclas == XMC_GL
+ || ((*sym_hash)->root.u.def.section->owner->flags
+ & DYNAMIC) == 0))
+ {
+ /* The new symbol is from a shared library, and
+ either the existing symbol is not global
+ linkage code or this symbol is global linkage
+ code. If the existing symbol is global
+ linkage code and the new symbol is not, then
+ we want to use the new symbol. */
+ section = bfd_und_section_ptr;
+ value = 0;
+ }
+ else if (((*sym_hash)->root.u.def.section->owner->flags
+ & DYNAMIC) != 0)
+ {
+ /* The existing symbol is from a shared library.
+ Replace it. */
+ (*sym_hash)->root.type = bfd_link_hash_undefined;
+ (*sym_hash)->root.u.undef.abfd =
+ (*sym_hash)->root.u.def.section->owner;
+ }
+ else if ((*sym_hash)->root.next != NULL
+ || info->hash->undefs_tail == &(*sym_hash)->root)
+ {
+ /* This symbol has been referenced. In this
+ case, we just continue and permit the
+ multiple definition error. See the comment
+ above about the behaviour of the AIX linker. */
+ }
+ else if ((*sym_hash)->smclas == aux.x_csect.x_smclas)
+ {
+ /* The symbols are both csects of the same
+ class. There is at least a chance that this
+ is a semi-legitimate redefinition. */
+ section = bfd_und_section_ptr;
+ value = 0;
+ (*sym_hash)->flags |= XCOFF_MULTIPLY_DEFINED;
+ }
+ }
+ else if (((*sym_hash)->flags & XCOFF_MULTIPLY_DEFINED) != 0
+ && ((*sym_hash)->root.type == bfd_link_hash_defined
+ || (*sym_hash)->root.type == bfd_link_hash_defweak)
+ && (bfd_is_und_section (section)
+ || bfd_is_com_section (section)))
+ {
+ /* This is a reference to a multiply defined symbol.
+ Report the error now. See the comment above
+ about the behaviour of the AIX linker. We could
+ also do this with warning symbols, but I'm not
+ sure the XCOFF linker is wholly prepared to
+ handle them, and that would only be a warning,
+ not an error. */
+ if (! ((*info->callbacks->multiple_definition)
+ (info, (*sym_hash)->root.root.string,
+ (bfd *) NULL, (asection *) NULL, 0,
+ (*sym_hash)->root.u.def.section->owner,
+ (*sym_hash)->root.u.def.section,
+ (*sym_hash)->root.u.def.value)))
+ goto error_return;
+ /* Try not to give this error too many times. */
+ (*sym_hash)->flags &= ~XCOFF_MULTIPLY_DEFINED;
+ }
+ }
+
+ /* _bfd_generic_link_add_one_symbol may call the linker to
+ generate an error message, and the linker may try to read
+ the symbol table to give a good error. Right now, the
+ line numbers are in an inconsistent state, since they are
+ counted both in the real sections and in the new csects.
+ We need to leave the count in the real sections so that
+ the linker can report the line number of the error
+ correctly, so temporarily clobber the link to the csects
+ so that the linker will not try to read the line numbers
+ a second time from the csects. */
+ BFD_ASSERT (last_real->next == first_csect);
+ last_real->next = NULL;
+ if (! (_bfd_generic_link_add_one_symbol
+ (info, abfd, name, flags, section, value,
+ (const char *) NULL, copy, true,
+ (struct bfd_link_hash_entry **) sym_hash)))
+ goto error_return;
+ last_real->next = first_csect;
+
+ if (smtyp == XTY_CM)
+ {
+ if ((*sym_hash)->root.type != bfd_link_hash_common
+ || (*sym_hash)->root.u.c.p->section != csect)
+ {
+ /* We don't need the common csect we just created. */
+ csect->_raw_size = 0;
+ }
+ else
+ {
+ (*sym_hash)->root.u.c.p->alignment_power
+ = csect->alignment_power;
+ }
+ }
+
+ if (info->hash->creator == abfd->xvec)
+ {
+ int flag;
+
+ if (smtyp == XTY_ER || smtyp == XTY_CM)
+ flag = XCOFF_REF_REGULAR;
+ else
+ flag = XCOFF_DEF_REGULAR;
+ (*sym_hash)->flags |= flag;
+
+ if ((*sym_hash)->smclas == XMC_UA
+ || flag == XCOFF_DEF_REGULAR)
+ (*sym_hash)->smclas = aux.x_csect.x_smclas;
+ }
+ }
+
+ *csect_cache = csect;
+
+ esym += (sym.n_numaux + 1) * symesz;
+ sym_hash += sym.n_numaux + 1;
+ csect_cache += sym.n_numaux + 1;
+ }
+
+ BFD_ASSERT (last_real == NULL || last_real->next == first_csect);
+
+ /* Make sure that we have seen all the relocs. */
+ for (o = abfd->sections; o != first_csect; o = o->next)
+ {
+ /* Reset the section size and the line number count, since the
+ data is now attached to the csects. Don't reset the size of
+ the .debug section, since we need to read it below in
+ bfd_xcoff_size_dynamic_sections. */
+ if (strcmp (bfd_get_section_name (abfd, o), ".debug") != 0)
+ o->_raw_size = 0;
+ o->lineno_count = 0;
+
+ if ((o->flags & SEC_RELOC) != 0)
+ {
+ bfd_size_type i;
+ struct internal_reloc *rel;
+ asection **rel_csect;
+
+ rel = reloc_info[o->target_index].relocs;
+ rel_csect = reloc_info[o->target_index].csects;
+ for (i = 0; i < o->reloc_count; i++, rel++, rel_csect++)
+ {
+ if (*rel_csect == NULL)
+ {
+ (*_bfd_error_handler)
+ ("%s: reloc %s:%d not in csect",
+ bfd_get_filename (abfd), o->name, i);
+ bfd_set_error (bfd_error_bad_value);
+ goto error_return;
+ }
+
+ /* We identify all symbols which are called, so that we
+ can create glue code for calls to functions imported
+ from dynamic objects. */
+ if (info->hash->creator == abfd->xvec
+ && *rel_csect != bfd_und_section_ptr
+ && (rel->r_type == R_BR
+ || rel->r_type == R_RBR)
+ && obj_xcoff_sym_hashes (abfd)[rel->r_symndx] != NULL)
+ {
+ struct xcoff_link_hash_entry *h;
+
+ h = obj_xcoff_sym_hashes (abfd)[rel->r_symndx];
+ h->flags |= XCOFF_CALLED;
+ /* If the symbol name starts with a period, it is
+ the code of a function. If the symbol is
+ currently undefined, then add an undefined symbol
+ for the function descriptor. This should do no
+ harm, because any regular object that defines the
+ function should also define the function
+ descriptor. It helps, because it means that we
+ will identify the function descriptor with a
+ dynamic object if a dynamic object defines it. */
+ if (h->root.root.string[0] == '.'
+ && h->descriptor == NULL)
+ {
+ struct xcoff_link_hash_entry *hds;
+
+ hds = xcoff_link_hash_lookup (xcoff_hash_table (info),
+ h->root.root.string + 1,
+ true, false, true);
+ if (hds == NULL)
+ goto error_return;
+ if (hds->root.type == bfd_link_hash_new)
+ {
+ if (! (_bfd_generic_link_add_one_symbol
+ (info, abfd, hds->root.root.string,
+ (flagword) 0, bfd_und_section_ptr,
+ (bfd_vma) 0, (const char *) NULL, false,
+ true,
+ (struct bfd_link_hash_entry **) &hds)))
+ goto error_return;
+ }
+ hds->flags |= XCOFF_DESCRIPTOR;
+ BFD_ASSERT ((hds->flags & XCOFF_CALLED) == 0
+ && (h->flags & XCOFF_DESCRIPTOR) == 0);
+ hds->descriptor = h;
+ h->descriptor = hds;
+ }
+ }
+ }
+
+ free (reloc_info[o->target_index].csects);
+ reloc_info[o->target_index].csects = NULL;
+
+ /* Reset SEC_RELOC and the reloc_count, since the reloc
+ information is now attached to the csects. */
+ o->flags &=~ SEC_RELOC;
+ o->reloc_count = 0;
+
+ /* If we are not keeping memory, free the reloc information. */
+ if (! info->keep_memory
+ && coff_section_data (abfd, o) != NULL
+ && coff_section_data (abfd, o)->relocs != NULL
+ && ! coff_section_data (abfd, o)->keep_relocs)
+ {
+ free (coff_section_data (abfd, o)->relocs);
+ coff_section_data (abfd, o)->relocs = NULL;
+ }
+ }
+
+ /* Free up the line numbers. FIXME: We could cache these
+ somewhere for the final link, to avoid reading them again. */
+ if (reloc_info[o->target_index].linenos != NULL)
+ {
+ free (reloc_info[o->target_index].linenos);
+ reloc_info[o->target_index].linenos = NULL;
+ }
+ }
+
+ free (reloc_info);
+
+ obj_coff_keep_syms (abfd) = keep_syms;
+
+ return true;
+
+ error_return:
+ if (reloc_info != NULL)
+ {
+ for (o = abfd->sections; o != NULL; o = o->next)
+ {
+ if (reloc_info[o->target_index].csects != NULL)
+ free (reloc_info[o->target_index].csects);
+ if (reloc_info[o->target_index].linenos != NULL)
+ free (reloc_info[o->target_index].linenos);
+ }
+ free (reloc_info);
+ }
+ obj_coff_keep_syms (abfd) = keep_syms;
+ return false;
+}
+
+#undef N_TMASK
+#undef N_BTSHFT
+
+/* This function is used to add symbols from a dynamic object to the
+ global symbol table. */
+
+static boolean
+xcoff_link_add_dynamic_symbols (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ asection *lsec;
+ bfd_byte *buf;
+ struct internal_ldhdr ldhdr;
+ const char *strings;
+ struct external_ldsym *elsym, *elsymend;
+ struct xcoff_import_file *n;
+ const char *bname;
+ const char *mname;
+ const char *s;
+ unsigned int c;
+ struct xcoff_import_file **pp;
+
+ /* We can only handle a dynamic object if we are generating an XCOFF
+ output file. */
+ if (info->hash->creator != abfd->xvec)
+ {
+ (*_bfd_error_handler)
+ ("%s: XCOFF shared object when not producing XCOFF output",
+ bfd_get_filename (abfd));
+ bfd_set_error (bfd_error_invalid_operation);
+ return false;
+ }
+
+ /* The symbols we use from a dynamic object are not the symbols in
+ the normal symbol table, but, rather, the symbols in the export
+ table. If there is a global symbol in a dynamic object which is
+ not in the export table, the loader will not be able to find it,
+ so we don't want to find it either. Also, on AIX 4.1.3, shr.o in
+ libc.a has symbols in the export table which are not in the
+ symbol table. */
+
+ /* Read in the .loader section. FIXME: We should really use the
+ o_snloader field in the a.out header, rather than grabbing the
+ section by name. */
+ lsec = bfd_get_section_by_name (abfd, ".loader");
+ if (lsec == NULL)
+ {
+ (*_bfd_error_handler)
+ ("%s: dynamic object with no .loader section",
+ bfd_get_filename (abfd));
+ bfd_set_error (bfd_error_no_symbols);
+ return false;
+ }
+
+ if (! xcoff_get_section_contents (abfd, lsec))
+ return false;
+ buf = coff_section_data (abfd, lsec)->contents;
+
+ /* Remove the sections from this object, so that they do not get
+ included in the link. */
+ abfd->sections = NULL;
+
+ xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) buf, &ldhdr);
+
+ strings = (char *) buf + ldhdr.l_stoff;
+
+ elsym = (struct external_ldsym *) (buf + LDHDRSZ);
+ elsymend = elsym + ldhdr.l_nsyms;
+ BFD_ASSERT (sizeof (struct external_ldsym) == LDSYMSZ);
+ for (; elsym < elsymend; elsym++)
+ {
+ struct internal_ldsym ldsym;
+ char nambuf[SYMNMLEN + 1];
+ const char *name;
+ struct xcoff_link_hash_entry *h;
+
+ xcoff_swap_ldsym_in (abfd, elsym, &ldsym);
+
+ /* We are only interested in exported symbols. */
+ if ((ldsym.l_smtype & L_EXPORT) == 0)
+ continue;
+
+ if (ldsym._l._l_l._l_zeroes == 0)
+ name = strings + ldsym._l._l_l._l_offset;
+ else
+ {
+ memcpy (nambuf, ldsym._l._l_name, SYMNMLEN);
+ nambuf[SYMNMLEN] = '\0';
+ name = nambuf;
+ }
+
+ /* Normally we could not call xcoff_link_hash_lookup in an add
+ symbols routine, since we might not be using an XCOFF hash
+ table. However, we verified above that we are using an XCOFF
+ hash table. */
+
+ h = xcoff_link_hash_lookup (xcoff_hash_table (info), name, true,
+ true, true);
+ if (h == NULL)
+ return false;
+
+ h->flags |= XCOFF_DEF_DYNAMIC;
+
+ /* If the symbol is undefined, and the BFD it was found in is
+ not a dynamic object, change the BFD to this dynamic object,
+ so that we can get the correct import file ID. */
+ if ((h->root.type == bfd_link_hash_undefined
+ || h->root.type == bfd_link_hash_undefweak)
+ && (h->root.u.undef.abfd == NULL
+ || (h->root.u.undef.abfd->flags & DYNAMIC) == 0))
+ h->root.u.undef.abfd = abfd;
+
+ if (h->root.type == bfd_link_hash_new)
+ {
+ h->root.type = bfd_link_hash_undefined;
+ h->root.u.undef.abfd = abfd;
+ /* We do not want to add this to the undefined symbol list. */
+ }
+
+ if (h->smclas == XMC_UA
+ || h->root.type == bfd_link_hash_undefined
+ || h->root.type == bfd_link_hash_undefweak)
+ h->smclas = ldsym.l_smclas;
+
+ /* Unless this is an XMC_XO symbol, we don't bother to actually
+ define it, since we don't have a section to put it in anyhow.
+ Instead, the relocation routines handle the DEF_DYNAMIC flag
+ correctly. */
+
+ if (h->smclas == XMC_XO
+ && (h->root.type == bfd_link_hash_undefined
+ || h->root.type == bfd_link_hash_undefweak))
+ {
+ /* This symbol has an absolute value. */
+ h->root.type = bfd_link_hash_defined;
+ h->root.u.def.section = bfd_abs_section_ptr;
+ h->root.u.def.value = ldsym.l_value;
+ }
+
+ /* If this symbol defines a function descriptor, then it
+ implicitly defines the function code as well. */
+ if (h->smclas == XMC_DS
+ || (h->smclas == XMC_XO && name[0] != '.'))
+ h->flags |= XCOFF_DESCRIPTOR;
+ if ((h->flags & XCOFF_DESCRIPTOR) != 0)
+ {
+ struct xcoff_link_hash_entry *hds;
+
+ hds = h->descriptor;
+ if (hds == NULL)
+ {
+ char *dsnm;
+
+ dsnm = bfd_malloc (strlen (name) + 2);
+ if (dsnm == NULL)
+ return false;
+ dsnm[0] = '.';
+ strcpy (dsnm + 1, name);
+ hds = xcoff_link_hash_lookup (xcoff_hash_table (info), dsnm,
+ true, true, true);
+ free (dsnm);
+ if (hds == NULL)
+ return false;
+
+ if (hds->root.type == bfd_link_hash_new)
+ {
+ hds->root.type = bfd_link_hash_undefined;
+ hds->root.u.undef.abfd = abfd;
+ /* We do not want to add this to the undefined
+ symbol list. */
+ }
+
+ hds->descriptor = h;
+ h->descriptor = hds;
+ }
+
+ hds->flags |= XCOFF_DEF_DYNAMIC;
+ if (hds->smclas == XMC_UA)
+ hds->smclas = XMC_PR;
+
+ /* An absolute symbol appears to actually define code, not a
+ function descriptor. This is how some math functions are
+ implemented on AIX 4.1. */
+ if (h->smclas == XMC_XO
+ && (hds->root.type == bfd_link_hash_undefined
+ || hds->root.type == bfd_link_hash_undefweak))
+ {
+ hds->smclas = XMC_XO;
+ hds->root.type = bfd_link_hash_defined;
+ hds->root.u.def.section = bfd_abs_section_ptr;
+ hds->root.u.def.value = ldsym.l_value;
+ }
+ }
+ }
+
+ if (buf != NULL && ! coff_section_data (abfd, lsec)->keep_contents)
+ {
+ free (coff_section_data (abfd, lsec)->contents);
+ coff_section_data (abfd, lsec)->contents = NULL;
+ }
+
+ /* Record this file in the import files. */
+
+ n = ((struct xcoff_import_file *)
+ bfd_alloc (abfd, sizeof (struct xcoff_import_file)));
+ if (n == NULL)
+ return false;
+ n->next = NULL;
+
+ /* For some reason, the path entry in the import file list for a
+ shared object appears to always be empty. The file name is the
+ base name. */
+ n->path = "";
+ if (abfd->my_archive == NULL)
+ {
+ bname = bfd_get_filename (abfd);
+ mname = "";
+ }
+ else
+ {
+ bname = bfd_get_filename (abfd->my_archive);
+ mname = bfd_get_filename (abfd);
+ }
+ s = strrchr (bname, '/');
+ if (s != NULL)
+ bname = s + 1;
+ n->file = bname;
+ n->member = mname;
+
+ /* We start c at 1 because the first import file number is reserved
+ for LIBPATH. */
+ for (pp = &xcoff_hash_table (info)->imports, c = 1;
+ *pp != NULL;
+ pp = &(*pp)->next, ++c)
+ ;
+ *pp = n;
+
+ xcoff_data (abfd)->import_file_id = c;
+
+ return true;
+}
+\f
+/* Routines that are called after all the input files have been
+ handled, but before the sections are laid out in memory. */
+
+/* Mark a symbol as not being garbage, including the section in which
+ it is defined. */
+
+static INLINE boolean
+xcoff_mark_symbol (info, h)
+ struct bfd_link_info *info;
+ struct xcoff_link_hash_entry *h;
+{
+ if ((h->flags & XCOFF_MARK) != 0)
+ return true;
+
+ h->flags |= XCOFF_MARK;
+ if (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ {
+ asection *hsec;
+
+ hsec = h->root.u.def.section;
+ if ((hsec->flags & SEC_MARK) == 0)
+ {
+ if (! xcoff_mark (info, hsec))
+ return false;
+ }
+ }
+
+ if (h->toc_section != NULL
+ && (h->toc_section->flags & SEC_MARK) == 0)
+ {
+ if (! xcoff_mark (info, h->toc_section))
+ return false;
+ }
+
+ return true;
+}
+
+/* The mark phase of garbage collection. For a given section, mark
+ it, and all the sections which define symbols to which it refers.
+ Because this function needs to look at the relocs, we also count
+ the number of relocs which need to be copied into the .loader
+ section. */
+
+static boolean
+xcoff_mark (info, sec)
+ struct bfd_link_info *info;
+ asection *sec;
+{
+ if ((sec->flags & SEC_MARK) != 0)
+ return true;
+
+ sec->flags |= SEC_MARK;
+
+ if (sec->owner->xvec == info->hash->creator
+ && coff_section_data (sec->owner, sec) != NULL
+ && xcoff_section_data (sec->owner, sec) != NULL)
+ {
+ register struct xcoff_link_hash_entry **hp, **hpend;
+ struct internal_reloc *rel, *relend;
+
+ /* Mark all the symbols in this section. */
+
+ hp = (obj_xcoff_sym_hashes (sec->owner)
+ + xcoff_section_data (sec->owner, sec)->first_symndx);
+ hpend = (obj_xcoff_sym_hashes (sec->owner)
+ + xcoff_section_data (sec->owner, sec)->last_symndx);
+ for (; hp < hpend; hp++)
+ {
+ register struct xcoff_link_hash_entry *h;
+
+ h = *hp;
+ if (h != NULL
+ && (h->flags & XCOFF_MARK) == 0)
+ {
+ if (! xcoff_mark_symbol (info, h))
+ return false;
+ }
+ }
+
+ /* Look through the section relocs. */
+
+ if ((sec->flags & SEC_RELOC) != 0
+ && sec->reloc_count > 0)
+ {
+ rel = xcoff_read_internal_relocs (sec->owner, sec, true,
+ (bfd_byte *) NULL, false,
+ (struct internal_reloc *) NULL);
+ if (rel == NULL)
+ return false;
+ relend = rel + sec->reloc_count;
+ for (; rel < relend; rel++)
+ {
+ asection *rsec;
+ struct xcoff_link_hash_entry *h;
+
+ if ((unsigned int) rel->r_symndx
+ > obj_raw_syment_count (sec->owner))
+ continue;
+
+ h = obj_xcoff_sym_hashes (sec->owner)[rel->r_symndx];
+ if (h != NULL
+ && (h->flags & XCOFF_MARK) == 0)
+ {
+ if (! xcoff_mark_symbol (info, h))
+ return false;
+ }
+
+ rsec = xcoff_data (sec->owner)->csects[rel->r_symndx];
+ if (rsec != NULL
+ && (rsec->flags & SEC_MARK) == 0)
+ {
+ if (! xcoff_mark (info, rsec))
+ return false;
+ }
+
+ /* See if this reloc needs to be copied into the .loader
+ section. */
+ switch (rel->r_type)
+ {
+ default:
+ if (h == NULL
+ || h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak
+ || h->root.type == bfd_link_hash_common
+ || ((h->flags & XCOFF_CALLED) != 0
+ && (h->root.type == bfd_link_hash_undefined
+ || h->root.type == bfd_link_hash_undefweak)
+ && h->root.root.string[0] == '.'
+ && h->descriptor != NULL
+ && ((h->descriptor->flags & XCOFF_DEF_DYNAMIC) != 0
+ || ((h->descriptor->flags & XCOFF_IMPORT) != 0
+ && (h->descriptor->flags
+ & XCOFF_DEF_REGULAR) == 0))))
+ break;
+ /* Fall through. */
+ case R_POS:
+ case R_NEG:
+ case R_RL:
+ case R_RLA:
+ ++xcoff_hash_table (info)->ldrel_count;
+ if (h != NULL)
+ h->flags |= XCOFF_LDREL;
+ break;
+ case R_TOC:
+ case R_GL:
+ case R_TCL:
+ case R_TRL:
+ case R_TRLA:
+ /* We should never need a .loader reloc for a TOC
+ relative reloc. */
+ break;
+ }
+ }
+
+ if (! info->keep_memory
+ && coff_section_data (sec->owner, sec) != NULL
+ && coff_section_data (sec->owner, sec)->relocs != NULL
+ && ! coff_section_data (sec->owner, sec)->keep_relocs)
+ {
+ free (coff_section_data (sec->owner, sec)->relocs);
+ coff_section_data (sec->owner, sec)->relocs = NULL;
+ }
+ }
+ }
+
+ return true;
+}
+
+/* The sweep phase of garbage collection. Remove all garbage
+ sections. */
+
+static void
+xcoff_sweep (info)
+ struct bfd_link_info *info;
+{
+ bfd *sub;
+
+ for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+ {
+ asection *o;
+
+ for (o = sub->sections; o != NULL; o = o->next)
+ {
+ if ((o->flags & SEC_MARK) == 0)
+ {
+ /* Keep all sections from non-XCOFF input files. Keep
+ special sections. Keep .debug sections for the
+ moment. */
+ if (sub->xvec != info->hash->creator
+ || o == xcoff_hash_table (info)->debug_section
+ || o == xcoff_hash_table (info)->loader_section
+ || o == xcoff_hash_table (info)->linkage_section
+ || o == xcoff_hash_table (info)->toc_section
+ || o == xcoff_hash_table (info)->descriptor_section
+ || strcmp (o->name, ".debug") == 0)
+ o->flags |= SEC_MARK;
+ else
+ {
+ o->_raw_size = 0;
+ o->reloc_count = 0;
+ o->lineno_count = 0;
+ }
+ }
+ }
+ }
+}
+
+/* Record the number of elements in a set. This is used to output the
+ correct csect length. */
+
+boolean
+bfd_xcoff_link_record_set (output_bfd, info, harg, size)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+ struct bfd_link_hash_entry *harg;
+ bfd_size_type size;
+{
+ struct xcoff_link_hash_entry *h = (struct xcoff_link_hash_entry *) harg;
+ struct xcoff_link_size_list *n;
+
+ if (! XCOFF_XVECP (output_bfd->xvec))
+ return true;
+
+ /* This will hardly ever be called. I don't want to burn four bytes
+ per global symbol, so instead the size is kept on a linked list
+ attached to the hash table. */
+
+ n = ((struct xcoff_link_size_list *)
+ bfd_alloc (output_bfd, sizeof (struct xcoff_link_size_list)));
+ if (n == NULL)
+ return false;
+ n->next = xcoff_hash_table (info)->size_list;
+ n->h = h;
+ n->size = size;
+ xcoff_hash_table (info)->size_list = n;
+
+ h->flags |= XCOFF_HAS_SIZE;
+
+ return true;
+}
+
+/* Import a symbol. */
+
+boolean
+bfd_xcoff_import_symbol (output_bfd, info, harg, val, imppath, impfile,
+ impmember)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+ struct bfd_link_hash_entry *harg;
+ bfd_vma val;
+ const char *imppath;
+ const char *impfile;
+ const char *impmember;
+{
+ struct xcoff_link_hash_entry *h = (struct xcoff_link_hash_entry *) harg;
+
+ if (! XCOFF_XVECP (output_bfd->xvec))
+ return true;
+
+ h->flags |= XCOFF_IMPORT;
+
+ if (val != (bfd_vma) -1)
+ {
+ if (h->root.type == bfd_link_hash_defined
+ && (! bfd_is_abs_section (h->root.u.def.section)
+ || h->root.u.def.value != val))
+ {
+ if (! ((*info->callbacks->multiple_definition)
+ (info, h->root.root.string, h->root.u.def.section->owner,
+ h->root.u.def.section, h->root.u.def.value,
+ output_bfd, bfd_abs_section_ptr, val)))
+ return false;
+ }
+
+ h->root.type = bfd_link_hash_defined;
+ h->root.u.def.section = bfd_abs_section_ptr;
+ h->root.u.def.value = val;
+ }
+
+ /* We overload the ldindx field to hold the l_ifile value for this
+ symbol. */
+ BFD_ASSERT (h->ldsym == NULL);
+ BFD_ASSERT ((h->flags & XCOFF_BUILT_LDSYM) == 0);
+ if (imppath == NULL)
+ h->ldindx = -1;
+ else
+ {
+ unsigned int c;
+ struct xcoff_import_file **pp;
+
+ /* We start c at 1 because the first entry in the import list is
+ reserved for the library search path. */
+ for (pp = &xcoff_hash_table (info)->imports, c = 1;
+ *pp != NULL;
+ pp = &(*pp)->next, ++c)
+ {
+ if (strcmp ((*pp)->path, imppath) == 0
+ && strcmp ((*pp)->file, impfile) == 0
+ && strcmp ((*pp)->member, impmember) == 0)
+ break;
+ }
+
+ if (*pp == NULL)