X-Git-Url: https://oss.titaniummirror.com/gitweb?p=msp430-binutils.git;a=blobdiff_plain;f=bfd%2Fxcofflink.c;fp=bfd%2Fxcofflink.c;h=8885ca305c0376f7f105e81ca5266f725a6fd969;hp=f14c62b2846deaa834e90af733834858b9c81c39;hb=d5da4f291af551c0b8b79e1d4a9b173d60e5c10e;hpb=7b5ea4fcdf2819e070665ab5610f8b48e3867c10 diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c index f14c62b..8885ca3 100644 --- a/bfd/xcofflink.c +++ b/bfd/xcofflink.c @@ -1,6 +1,6 @@ /* POWER/PowerPC XCOFF linker support. Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, - 2005, 2006, 2007 Free Software Foundation, Inc. + 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. Written by Ian Lance Taylor , Cygnus Support. This file is part of BFD, the Binary File Descriptor library. @@ -28,6 +28,7 @@ #include "coff/xcoff.h" #include "libcoff.h" #include "libxcoff.h" +#include "libiberty.h" /* This file holds the XCOFF linker code. */ @@ -75,6 +76,88 @@ struct xcoff_link_section_info } *toc_rel_hashes; }; +/* Information that the XCOFF linker collects about an archive. */ +struct xcoff_archive_info +{ + /* The archive described by this entry. */ + bfd *archive; + + /* The import path and import filename to use when referring to + this archive in the .loader section. */ + const char *imppath; + const char *impfile; + + /* True if the archive contains a dynamic object. */ + unsigned int contains_shared_object_p : 1; + + /* True if the previous field is valid. */ + unsigned int know_contains_shared_object_p : 1; +}; + +struct xcoff_link_hash_table +{ + struct bfd_link_hash_table root; + + /* The .debug string hash table. We need to compute this while + reading the input files, so that we know how large the .debug + section will be before we assign section positions. */ + struct bfd_strtab_hash *debug_strtab; + + /* The .debug section we will use for the final output. */ + asection *debug_section; + + /* The .loader section we will use for the final output. */ + asection *loader_section; + + /* A count of non TOC relative relocs which will need to be + allocated in the .loader section. */ + size_t ldrel_count; + + /* The .loader section header. */ + struct internal_ldhdr ldhdr; + + /* The .gl section we use to hold global linkage code. */ + asection *linkage_section; + + /* The .tc section we use to hold toc entries we build for global + linkage code. */ + asection *toc_section; + + /* The .ds section we use to hold function descriptors which we + create for exported symbols. */ + asection *descriptor_section; + + /* The list of import files. */ + struct xcoff_import_file *imports; + + /* Required alignment of sections within the output file. */ + unsigned long file_align; + + /* Whether the .text section must be read-only. */ + bfd_boolean textro; + + /* Whether -brtl was specified. */ + bfd_boolean rtld; + + /* Whether garbage collection was done. */ + bfd_boolean gc; + + /* A linked list of symbols for which we have size information. */ + struct xcoff_link_size_list + { + struct xcoff_link_size_list *next; + struct xcoff_link_hash_entry *h; + bfd_size_type size; + } + *size_list; + + /* Information about archives. */ + htab_t archive_info; + + /* Magic sections: _text, _etext, _data, _edata, _end, end. */ + asection *special_sections[XCOFF_NUMBER_OF_SPECIAL_SECTIONS]; +}; + /* Information that we pass around while doing the final link step. */ struct xcoff_final_link_info @@ -258,7 +341,12 @@ _bfd_xcoff_canonicalize_dynamic_symtab (bfd *abfd, asymbol **psyms) symbuf->symbol.flags = BSF_NO_FLAGS; if ((ldsym.l_smtype & L_EXPORT) != 0) - symbuf->symbol.flags |= BSF_GLOBAL; + { + if ((ldsym.l_smtype & L_WEAK) != 0) + symbuf->symbol.flags |= BSF_WEAK; + else + symbuf->symbol.flags |= BSF_GLOBAL; + } /* FIXME: We have no way to record the other information stored with the loader symbol. */ @@ -398,6 +486,56 @@ _bfd_xcoff_canonicalize_dynamic_reloc (bfd *abfd, return ldhdr.l_nreloc; } +/* Hash functions for xcoff_link_hash_table's archive_info. */ + +static hashval_t +xcoff_archive_info_hash (const void *data) +{ + const struct xcoff_archive_info *info; + + info = (const struct xcoff_archive_info *) data; + return htab_hash_pointer (info->archive); +} + +static int +xcoff_archive_info_eq (const void *data1, const void *data2) +{ + const struct xcoff_archive_info *info1; + const struct xcoff_archive_info *info2; + + info1 = (const struct xcoff_archive_info *) data1; + info2 = (const struct xcoff_archive_info *) data2; + return info1->archive == info2->archive; +} + +/* Return information about archive ARCHIVE. Return NULL on error. */ + +static struct xcoff_archive_info * +xcoff_get_archive_info (struct bfd_link_info *info, bfd *archive) +{ + struct xcoff_link_hash_table *htab; + struct xcoff_archive_info *entryp, entry; + void **slot; + + htab = xcoff_hash_table (info); + entry.archive = archive; + slot = htab_find_slot (htab->archive_info, &entry, INSERT); + if (!slot) + return NULL; + + entryp = *slot; + if (!entryp) + { + entryp = bfd_zalloc (archive, sizeof (entry)); + if (!entryp) + return NULL; + + entryp->archive = archive; + *slot = entryp; + } + return entryp; +} + /* Routine to create an entry in an XCOFF link hash table. */ static struct bfd_hash_entry * @@ -464,6 +602,8 @@ _bfd_xcoff_bfd_link_hash_table_create (bfd *abfd) ret->file_align = 0; ret->textro = FALSE; ret->gc = FALSE; + ret->archive_info = htab_create (37, xcoff_archive_info_hash, + xcoff_archive_info_eq, NULL); memset (ret->special_sections, 0, sizeof ret->special_sections); /* The linker will always generate a full a.out header. We need to @@ -540,6 +680,139 @@ xcoff_read_internal_relocs (bfd *abfd, require_internal, internal_relocs); } +/* Split FILENAME into an import path and an import filename, + storing them in *IMPPATH and *IMPFILE respectively. */ + +bfd_boolean +bfd_xcoff_split_import_path (bfd *abfd, const char *filename, + const char **imppath, const char **impfile) +{ + const char *basename; + size_t length; + char *path; + + basename = lbasename (filename); + length = basename - filename; + if (length == 0) + /* The filename has no directory component, so use an empty path. */ + *imppath = ""; + else if (length == 1) + /* The filename is in the root directory. */ + *imppath = "/"; + else + { + /* Extract the (non-empty) directory part. Note that we don't + need to strip duplicate directory separators from any part + of the string; the native linker doesn't do that either. */ + path = bfd_alloc (abfd, length); + if (path == NULL) + return FALSE; + memcpy (path, filename, length - 1); + path[length - 1] = 0; + *imppath = path; + } + *impfile = basename; + return TRUE; +} + +/* Set ARCHIVE's import path as though its filename had been given + as FILENAME. */ + +bfd_boolean +bfd_xcoff_set_archive_import_path (struct bfd_link_info *info, + bfd *archive, const char *filename) +{ + struct xcoff_archive_info *archive_info; + + archive_info = xcoff_get_archive_info (info, archive); + return (archive_info != NULL + && bfd_xcoff_split_import_path (archive, filename, + &archive_info->imppath, + &archive_info->impfile)); +} + +/* H is an imported symbol. Set the import module's path, file and member + to IMPATH, IMPFILE and IMPMEMBER respectively. All three are null if + no specific import module is specified. */ + +static bfd_boolean +xcoff_set_import_path (struct bfd_link_info *info, + struct xcoff_link_hash_entry *h, + const char *imppath, const char *impfile, + const char *impmember) +{ + unsigned int c; + struct xcoff_import_file **pp; + + /* 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 + { + /* 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) + { + struct xcoff_import_file *n; + bfd_size_type amt = sizeof (* n); + + n = bfd_alloc (info->output_bfd, amt); + if (n == NULL) + return FALSE; + n->next = NULL; + n->path = imppath; + n->file = impfile; + n->member = impmember; + *pp = n; + } + h->ldindx = c; + } + return TRUE; +} + +/* H is the bfd symbol associated with exported .loader symbol LDSYM. + Return true if LDSYM defines H. */ + +static bfd_boolean +xcoff_dynamic_definition_p (struct xcoff_link_hash_entry *h, + struct internal_ldsym *ldsym) +{ + /* If we didn't know about H before processing LDSYM, LDSYM + definitely defines H. */ + if (h->root.type == bfd_link_hash_new) + return TRUE; + + /* If H is currently a weak dynamic symbol, and if LDSYM is a strong + dynamic symbol, LDSYM trumps the current definition of H. */ + if ((ldsym->l_smtype & L_WEAK) == 0 + && (h->flags & XCOFF_DEF_DYNAMIC) != 0 + && (h->flags & XCOFF_DEF_REGULAR) == 0 + && (h->root.type == bfd_link_hash_defweak + || h->root.type == bfd_link_hash_undefweak)) + return TRUE; + + /* If H is currently undefined, LDSYM defines it. */ + if ((h->flags & XCOFF_DEF_DYNAMIC) == 0 + && (h->root.type == bfd_link_hash_undefined + || h->root.type == bfd_link_hash_undefweak)) + return TRUE; + + return FALSE; +} + /* This function is used to add symbols from a dynamic object to the global symbol table. */ @@ -552,15 +825,12 @@ xcoff_link_add_dynamic_symbols (bfd *abfd, struct bfd_link_info *info) const char *strings; bfd_byte *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) + if (info->output_bfd->xvec != abfd->xvec) { (*_bfd_error_handler) (_("%s: XCOFF shared object when not producing XCOFF output"), @@ -638,43 +908,33 @@ xcoff_link_add_dynamic_symbols (bfd *abfd, struct bfd_link_info *info) 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 (!xcoff_dynamic_definition_p (h, &ldsym)) + continue; - if (h->smclas == XMC_XO - && (h->root.type == bfd_link_hash_undefined - || h->root.type == bfd_link_hash_undefweak)) + h->flags |= XCOFF_DEF_DYNAMIC; + h->smclas = ldsym.l_smclas; + if (h->smclas == XMC_XO) { /* This symbol has an absolute value. */ - h->root.type = bfd_link_hash_defined; + if ((ldsym.l_smtype & L_WEAK) != 0) + h->root.type = bfd_link_hash_defweak; + else + h->root.type = bfd_link_hash_defined; h->root.u.def.section = bfd_abs_section_ptr; h->root.u.def.value = ldsym.l_value; } + else + { + /* Otherwise, we don't bother to actually define the symbol, + since we don't have a section to put it in anyhow. + We assume instead that an undefined XCOFF_DEF_DYNAMIC symbol + should be imported from the symbol's undef.abfd. */ + if ((ldsym.l_smtype & L_WEAK) != 0) + h->root.type = bfd_link_hash_undefweak; + else + h->root.type = bfd_link_hash_undefined; + h->root.u.undef.abfd = abfd; + } /* If this symbol defines a function descriptor, then it implicitly defines the function code as well. */ @@ -701,33 +961,30 @@ xcoff_link_add_dynamic_symbols (bfd *abfd, struct bfd_link_info *info) 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)) + if (xcoff_dynamic_definition_p (hds, &ldsym)) { - 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; + hds->root.type = h->root.type; + hds->flags |= XCOFF_DEF_DYNAMIC; + if (h->smclas == XMC_XO) + { + /* An absolute symbol appears to actually define code, not a + function descriptor. This is how some math functions are + implemented on AIX 4.1. */ + hds->smclas = XMC_XO; + hds->root.u.def.section = bfd_abs_section_ptr; + hds->root.u.def.value = ldsym.l_value; + } + else + { + hds->smclas = XMC_PR; + hds->root.u.undef.abfd = abfd; + /* We do not want to add this to the undefined + symbol list. */ + } } } } @@ -744,25 +1001,30 @@ xcoff_link_add_dynamic_symbols (bfd *abfd, struct bfd_link_info *info) 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 = ""; + if (!bfd_xcoff_split_import_path (abfd, abfd->filename, + &n->path, &n->file)) + return FALSE; + n->member = ""; } else { - bname = bfd_get_filename (abfd->my_archive); - mname = bfd_get_filename (abfd); + struct xcoff_archive_info *archive_info; + + archive_info = xcoff_get_archive_info (info, abfd->my_archive); + if (!archive_info->impfile) + { + if (!bfd_xcoff_split_import_path (archive_info->archive, + archive_info->archive->filename, + &archive_info->imppath, + &archive_info->impfile)) + return FALSE; + } + n->path = archive_info->imppath; + n->file = archive_info->impfile; + n->member = 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. */ @@ -786,13 +1048,14 @@ xcoff_link_create_extra_sections (bfd * abfd, struct bfd_link_info *info) { bfd_boolean return_value = FALSE; - if (info->hash->creator == abfd->xvec) + if (info->output_bfd->xvec == abfd->xvec) { /* We need to build a .loader section, so we do it here. This won't work if we're producing an XCOFF output file with no XCOFF input files. FIXME. */ - if (xcoff_hash_table (info)->loader_section == NULL) + if (!info->relocatable + && xcoff_hash_table (info)->loader_section == NULL) { asection *lsec; flagword flags = SEC_HAS_CONTENTS | SEC_IN_MEMORY; @@ -947,6 +1210,7 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) bfd_size_type symcount; struct xcoff_link_hash_entry **sym_hash; asection **csect_cache; + unsigned int *lineno_counts; bfd_size_type linesz; asection *o; asection *last_real; @@ -1013,6 +1277,15 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) goto error_return; xcoff_data (abfd)->csects = csect_cache; + /* We garbage-collect line-number information on a symbol-by-symbol + basis, so we need to have quick access to the number of entries + per symbol. */ + amt = symcount * sizeof (unsigned int); + lineno_counts = bfd_zalloc (abfd, amt); + if (lineno_counts == NULL && symcount != 0) + goto error_return; + xcoff_data (abfd)->lineno_counts = lineno_counts; + /* While splitting sections into csects, we need to assign the relocs correctly. The relocs and the csects must both be in order by VMA within a given section, so we handle this by @@ -1077,7 +1350,6 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) const char *name; char buf[SYMNMLEN + 1]; int smtyp; - flagword flags; asection *section; bfd_vma value; struct xcoff_link_hash_entry *set_toc; @@ -1086,23 +1358,15 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) /* In this pass we are only interested in symbols with csect information. */ - if (sym.n_sclass != C_EXT && sym.n_sclass != C_HIDEXT) + if (!CSECT_SYM_P (sym.n_sclass)) { /* Set csect_cache, Normally csect is a .pr, .rw etc. created in the loop If C_FILE or first time, handle special - Advance esym, sym_hash, csect_hash ptr's - Keep track of the last_symndx for the current file. */ - if (sym.n_sclass == C_FILE && csect != NULL) - { - xcoff_section_data (abfd, csect)->last_symndx = - ((esym - - (bfd_byte *) obj_coff_external_syms (abfd)) - / symesz); - csect = NULL; - } - + Advance esym, sym_hash, csect_hash ptrs. */ + if (sym.n_sclass == C_FILE) + csect = NULL; if (csect != NULL) *csect_cache = csect; else if (first_csect == NULL || sym.n_sclass == C_FILE) @@ -1112,6 +1376,7 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) esym += (sym.n_numaux + 1) * symesz; sym_hash += sym.n_numaux + 1; csect_cache += sym.n_numaux + 1; + lineno_counts += sym.n_numaux + 1; continue; } @@ -1182,7 +1447,7 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) if (lin.l_lnno == 0) break; } - csect->lineno_count += (linp - linpstart) / linesz; + *lineno_counts = (linp - linpstart) / linesz; /* The setting of line_filepos will only be useful if all the line number entries for a csect are contiguous; this only matters for @@ -1213,7 +1478,6 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) smtyp = SMTYP_SMTYP (aux.x_csect.x_smtyp); - flags = BSF_GLOBAL; section = NULL; value = 0; set_toc = NULL; @@ -1253,13 +1517,6 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) break; case XTY_SD: - /* This is a csect definition. */ - if (csect != NULL) - { - xcoff_section_data (abfd, csect)->last_symndx = - ((esym - (bfd_byte *) obj_coff_external_syms (abfd)) / symesz); - } - csect = NULL; csect_index = -(unsigned) 1; @@ -1294,7 +1551,7 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) place. */ if (aux.x_csect.x_smclas == XMC_TC && sym.n_sclass == C_HIDEXT - && info->hash->creator == abfd->xvec + && info->output_bfd->xvec == abfd->xvec && ((bfd_xcoff_is_xcoff32 (abfd) && aux.x_csect.x_scnlen.l == 4) || (bfd_xcoff_is_xcoff64 (abfd) @@ -1331,7 +1588,7 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) erelsym = ((bfd_byte *) obj_coff_external_syms (abfd) + rel->r_symndx * symesz); bfd_coff_swap_sym_in (abfd, (void *) erelsym, (void *) &relsym); - if (relsym.n_sclass == C_EXT) + if (EXTERN_SYM_P (relsym.n_sclass)) { const char *relname; char relbuf[SYMNMLEN + 1]; @@ -1486,9 +1743,9 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) if (first_csect == NULL) first_csect = csect; - /* If this symbol is C_EXT, we treat it as starting at the + /* If this symbol is external, we treat it as starting at the beginning of the newly created section. */ - if (sym.n_sclass == C_EXT) + if (EXTERN_SYM_P (sym.n_sclass)) { section = csect; value = 0; @@ -1541,14 +1798,6 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) named .tocbss, and rely on the linker script to put that in the TOC area. */ - if (csect != NULL) - { - xcoff_section_data (abfd, csect)->last_symndx = - ((esym - - (bfd_byte *) obj_coff_external_syms (abfd)) - / symesz); - } - if (aux.x_csect.x_smclas == XMC_TD) { /* The linker script puts the .td section in the data @@ -1585,7 +1834,7 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) if (first_csect == NULL) first_csect = csect; - if (sym.n_sclass == C_EXT) + if (EXTERN_SYM_P (sym.n_sclass)) { csect->flags |= SEC_IS_COMMON; csect->size = 0; @@ -1626,9 +1875,10 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) /* Now we have enough information to add the symbol to the linker hash table. */ - if (sym.n_sclass == C_EXT) + if (EXTERN_SYM_P (sym.n_sclass)) { bfd_boolean copy; + flagword flags; BFD_ASSERT (section != NULL); @@ -1639,6 +1889,15 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) || sym._n._n_n._n_offset == 0) copy = TRUE; + /* Ignore global linkage code when linking statically. */ + if (info->static_link + && (smtyp == XTY_SD || smtyp == XTY_LD) + && aux.x_csect.x_smclas == XMC_GL) + { + section = bfd_und_section_ptr; + value = 0; + } + /* 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 @@ -1663,8 +1922,7 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) 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) + else if (info->output_bfd->xvec == abfd->xvec) { if (! bfd_is_und_section (section)) *sym_hash = xcoff_link_hash_lookup (xcoff_hash_table (info), @@ -1684,23 +1942,8 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) && ! 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) + if (((*sym_hash)->flags & XCOFF_DEF_REGULAR) == 0 + && ((*sym_hash)->flags & XCOFF_DEF_DYNAMIC) != 0) { /* The existing symbol is from a shared library. Replace it. */ @@ -1716,6 +1959,12 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) section = bfd_und_section_ptr; value = 0; } + else if (sym.n_sclass == C_AIX_WEAKEXT + || (*sym_hash)->root.type == bfd_link_hash_defweak) + { + /* At least one of the definitions is weak. + Allow the normal rules to take effect. */ + } else if ((*sym_hash)->root.u.undef.next != NULL || info->hash->undefs_tail == &(*sym_hash)->root) { @@ -1735,8 +1984,7 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) } } 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) + && (*sym_hash)->root.type == bfd_link_hash_defined && (bfd_is_und_section (section) || bfd_is_com_section (section))) { @@ -1771,6 +2019,7 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) a second time from the csects. */ BFD_ASSERT (last_real->next == first_csect); last_real->next = NULL; + flags = (sym.n_sclass == C_EXT ? BSF_GLOBAL : BSF_WEAK); if (! (_bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value, NULL, copy, TRUE, @@ -1789,11 +2038,13 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) = csect->alignment_power; } - if (info->hash->creator == abfd->xvec) + if (info->output_bfd->xvec == abfd->xvec) { int flag; - if (smtyp == XTY_ER || smtyp == XTY_CM) + if (smtyp == XTY_ER + || smtyp == XTY_CM + || section == bfd_und_section_ptr) flag = XCOFF_REF_REGULAR; else flag = XCOFF_DEF_REGULAR; @@ -1805,11 +2056,20 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) } } - *csect_cache = csect; + if (smtyp == XTY_ER) + *csect_cache = section; + else + { + *csect_cache = csect; + if (csect != NULL) + xcoff_section_data (abfd, csect)->last_symndx + = (esym - (bfd_byte *) obj_coff_external_syms (abfd)) / symesz; + } esym += (sym.n_numaux + 1) * symesz; sym_hash += sym.n_numaux + 1; csect_cache += sym.n_numaux + 1; + lineno_counts += sym.n_numaux + 1; } BFD_ASSERT (last_real == NULL || last_real->next == first_csect); @@ -1845,19 +2105,16 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) 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 + /* We identify all function symbols that are the target + of a relocation, so that we can create glue code for + functions imported from dynamic objects. */ + if (info->output_bfd->xvec == 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 @@ -1890,11 +2147,12 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) hds = (struct xcoff_link_hash_entry *) bh; } hds->flags |= XCOFF_DESCRIPTOR; - BFD_ASSERT ((hds->flags & XCOFF_CALLED) == 0 - && (h->flags & XCOFF_DESCRIPTOR) == 0); + BFD_ASSERT ((h->flags & XCOFF_DESCRIPTOR) == 0); hds->descriptor = h; h->descriptor = hds; } + if (h->root.root.string[0] == '.') + h->flags |= XCOFF_CALLED; } } @@ -2066,7 +2324,7 @@ xcoff_link_check_ar_symbols (bfd *abfd, if ((abfd->flags & DYNAMIC) != 0 && ! info->static_link - && info->hash->creator == abfd->xvec) + && info->output_bfd->xvec == abfd->xvec) return xcoff_link_check_dynamic_ar_symbols (abfd, info, pneeded); symesz = bfd_coff_symesz (abfd); @@ -2078,7 +2336,7 @@ xcoff_link_check_ar_symbols (bfd *abfd, bfd_coff_swap_sym_in (abfd, (void *) esym, (void *) &sym); - if (sym.n_sclass == C_EXT && sym.n_scnum != N_UNDEF) + if (EXTERN_SYM_P (sym.n_sclass) && sym.n_scnum != N_UNDEF) { const char *name; char buf[SYMNMLEN + 1]; @@ -2099,7 +2357,7 @@ xcoff_link_check_ar_symbols (bfd *abfd, undefined references in shared objects. */ if (h != NULL && h->type == bfd_link_hash_undefined - && (info->hash->creator != abfd->xvec + && (info->output_bfd->xvec != abfd->xvec || (((struct xcoff_link_hash_entry *) h)->flags & XCOFF_DEF_DYNAMIC) == 0)) { @@ -2127,6 +2385,9 @@ xcoff_link_check_archive_element (bfd *abfd, struct bfd_link_info *info, bfd_boolean *pneeded) { + bfd_boolean keep_syms_p; + + keep_syms_p = (obj_coff_external_syms (abfd) != NULL); if (! _bfd_coff_get_external_symbols (abfd)) return FALSE; @@ -2137,9 +2398,11 @@ xcoff_link_check_archive_element (bfd *abfd, { if (! xcoff_link_add_symbols (abfd, info)) return FALSE; + if (info->keep_memory) + keep_syms_p = TRUE; } - if (! info->keep_memory || ! *pneeded) + if (!keep_syms_p) { if (! _bfd_coff_free_symbols (abfd)) return FALSE; @@ -2180,7 +2443,7 @@ _bfd_xcoff_bfd_link_add_symbols (bfd *abfd, struct bfd_link_info *info) while (member != NULL) { if (bfd_check_format (member, bfd_object) - && (info->hash->creator == member->xvec) + && (info->output_bfd->xvec == member->xvec) && (! bfd_has_map (abfd) || (member->flags & DYNAMIC) != 0)) { bfd_boolean needed; @@ -2203,38 +2466,406 @@ _bfd_xcoff_bfd_link_add_symbols (bfd *abfd, struct bfd_link_info *info) } } -/* Mark a symbol as not being garbage, including the section in which - it is defined. */ - -static inline bfd_boolean -xcoff_mark_symbol (struct bfd_link_info *info, struct xcoff_link_hash_entry *h) +bfd_boolean +_bfd_xcoff_define_common_symbol (bfd *output_bfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + struct bfd_link_hash_entry *harg) { - if ((h->flags & XCOFF_MARK) != 0) - return TRUE; + struct xcoff_link_hash_entry *h; - h->flags |= XCOFF_MARK; - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) + if (!bfd_generic_define_common_symbol (output_bfd, info, harg)) + return FALSE; + + h = (struct xcoff_link_hash_entry *) harg; + h->flags |= XCOFF_DEF_REGULAR; + return TRUE; +} + +/* If symbol H has not been interpreted as a function descriptor, + see whether it should be. Set up its descriptor information if so. */ + +static bfd_boolean +xcoff_find_function (struct bfd_link_info *info, + struct xcoff_link_hash_entry *h) +{ + if ((h->flags & XCOFF_DESCRIPTOR) == 0 + && h->root.root.string[0] != '.') { - asection *hsec; + char *fnname; + struct xcoff_link_hash_entry *hfn; + bfd_size_type amt; - hsec = h->root.u.def.section; - if (! bfd_is_abs_section (hsec) - && (hsec->flags & SEC_MARK) == 0) + amt = strlen (h->root.root.string) + 2; + fnname = bfd_malloc (amt); + if (fnname == NULL) + return FALSE; + fnname[0] = '.'; + strcpy (fnname + 1, h->root.root.string); + hfn = xcoff_link_hash_lookup (xcoff_hash_table (info), + fnname, FALSE, FALSE, TRUE); + free (fnname); + if (hfn != NULL + && hfn->smclas == XMC_PR + && (hfn->root.type == bfd_link_hash_defined + || hfn->root.type == bfd_link_hash_defweak)) { - if (! xcoff_mark (info, hsec)) - return FALSE; + h->flags |= XCOFF_DESCRIPTOR; + h->descriptor = hfn; + hfn->descriptor = h; } } + return TRUE; +} + +/* Return true if the given bfd contains at least one shared object. */ - if (h->toc_section != NULL - && (h->toc_section->flags & SEC_MARK) == 0) +static bfd_boolean +xcoff_archive_contains_shared_object_p (struct bfd_link_info *info, + bfd *archive) +{ + struct xcoff_archive_info *archive_info; + bfd *member; + + archive_info = xcoff_get_archive_info (info, archive); + if (!archive_info->know_contains_shared_object_p) { - if (! xcoff_mark (info, h->toc_section)) - return FALSE; - } + member = bfd_openr_next_archived_file (archive, NULL); + while (member != NULL && (member->flags & DYNAMIC) == 0) + member = bfd_openr_next_archived_file (archive, member); - return TRUE; + archive_info->contains_shared_object_p = (member != NULL); + archive_info->know_contains_shared_object_p = 1; + } + return archive_info->contains_shared_object_p; +} + +/* Symbol H qualifies for export by -bexpfull. Return true if it also + qualifies for export by -bexpall. */ + +static bfd_boolean +xcoff_covered_by_expall_p (struct xcoff_link_hash_entry *h) +{ + /* Exclude symbols beginning with '_'. */ + if (h->root.root.string[0] == '_') + return FALSE; + + /* Exclude archive members that would otherwise be unreferenced. */ + if ((h->flags & XCOFF_MARK) == 0 + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && h->root.u.def.section->owner != NULL + && h->root.u.def.section->owner->my_archive != NULL) + return FALSE; + + return TRUE; +} + +/* Return true if symbol H qualifies for the forms of automatic export + specified by AUTO_EXPORT_FLAGS. */ + +static bfd_boolean +xcoff_auto_export_p (struct bfd_link_info *info, + struct xcoff_link_hash_entry *h, + unsigned int auto_export_flags) +{ + /* Don't automatically export things that were explicitly exported. */ + if ((h->flags & XCOFF_EXPORT) != 0) + return FALSE; + + /* Don't export things that we don't define. */ + if ((h->flags & XCOFF_DEF_REGULAR) == 0) + return FALSE; + + /* Don't export functions; export their descriptors instead. */ + if (h->root.root.string[0] == '.') + return FALSE; + + /* We don't export a symbol which is being defined by an object + included from an archive which contains a shared object. The + rationale is that if an archive contains both an unshared and + a shared object, then there must be some reason that the + unshared object is unshared, and we don't want to start + providing a shared version of it. In particular, this solves + a bug involving the _savefNN set of functions. gcc will call + those functions without providing a slot to restore the TOC, + so it is essential that these functions be linked in directly + and not from a shared object, which means that a shared + object which also happens to link them in must not export + them. This is confusing, but I haven't been able to think of + a different approach. Note that the symbols can, of course, + be exported explicitly. */ + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + bfd *owner; + + owner = h->root.u.def.section->owner; + if (owner != NULL + && owner->my_archive != NULL + && xcoff_archive_contains_shared_object_p (info, owner->my_archive)) + return FALSE; + } + + /* Otherwise, all symbols are exported by -bexpfull. */ + if ((auto_export_flags & XCOFF_EXPFULL) != 0) + return TRUE; + + /* Despite its name, -bexpall exports most but not all symbols. */ + if ((auto_export_flags & XCOFF_EXPALL) != 0 + && xcoff_covered_by_expall_p (h)) + return TRUE; + + return FALSE; +} + +/* Return true if relocation REL needs to be copied to the .loader section. + If REL is against a global symbol, H is that symbol, otherwise it + is null. */ + +static bfd_boolean +xcoff_need_ldrel_p (struct bfd_link_info *info, struct internal_reloc *rel, + struct xcoff_link_hash_entry *h) +{ + if (!xcoff_hash_table (info)->loader_section) + return FALSE; + + switch (rel->r_type) + { + 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. */ + return FALSE; + + default: + /* In this case, relocations against defined symbols can be resolved + statically. */ + if (h == NULL + || h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak + || h->root.type == bfd_link_hash_common) + return FALSE; + + /* We will always provide a local definition of function symbols, + even if we don't have one yet. */ + if ((h->flags & XCOFF_CALLED) != 0) + return FALSE; + + return TRUE; + + case R_POS: + case R_NEG: + case R_RL: + case R_RLA: + /* Absolute relocations against absolute symbols can be + resolved statically. */ + if (h != NULL + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && bfd_is_abs_section (h->root.u.def.section)) + return FALSE; + + return TRUE; + } +} + +/* Mark a symbol as not being garbage, including the section in which + it is defined. */ + +static inline bfd_boolean +xcoff_mark_symbol (struct bfd_link_info *info, struct xcoff_link_hash_entry *h) +{ + if ((h->flags & XCOFF_MARK) != 0) + return TRUE; + + h->flags |= XCOFF_MARK; + + /* If we're marking an undefined symbol, try find some way of + defining it. */ + if (!info->relocatable + && (h->flags & XCOFF_IMPORT) == 0 + && (h->flags & XCOFF_DEF_REGULAR) == 0 + && (h->root.type == bfd_link_hash_undefined + || h->root.type == bfd_link_hash_undefweak)) + { + /* First check whether this symbol can be interpreted as an + undefined function descriptor for a defined function symbol. */ + if (!xcoff_find_function (info, h)) + return FALSE; + + if ((h->flags & XCOFF_DESCRIPTOR) != 0 + && (h->descriptor->root.type == bfd_link_hash_defined + || h->descriptor->root.type == bfd_link_hash_defweak)) + { + /* This is a descriptor for a defined symbol, but the input + objects have not defined the descriptor itself. Fill in + the definition automatically. + + Note that we do this even if we found a dynamic definition + of H. The local function definition logically overrides + the dynamic one. */ + asection *sec; + + sec = xcoff_hash_table (info)->descriptor_section; + h->root.type = bfd_link_hash_defined; + h->root.u.def.section = sec; + h->root.u.def.value = sec->size; + h->smclas = XMC_DS; + h->flags |= XCOFF_DEF_REGULAR; + + /* The size of the function descriptor depends on whether this + is xcoff32 (12) or xcoff64 (24). */ + sec->size += bfd_xcoff_function_descriptor_size (sec->owner); + + /* A function descriptor uses two relocs: one for the + associated code, and one for the TOC address. */ + xcoff_hash_table (info)->ldrel_count += 2; + sec->reloc_count += 2; + + /* Mark the function itself. */ + if (!xcoff_mark_symbol (info, h->descriptor)) + return FALSE; + + /* Mark the TOC section, so that we get an anchor + to relocate against. */ + if (!xcoff_mark (info, xcoff_hash_table (info)->toc_section)) + return FALSE; + + /* We handle writing out the contents of the descriptor in + xcoff_write_global_symbol. */ + } + else if (info->static_link) + /* We can't get a symbol value dynamically, so just assume + that it's undefined. */ + h->flags |= XCOFF_WAS_UNDEFINED; + else if ((h->flags & XCOFF_CALLED) != 0) + { + /* This is a function symbol for which we need to create + linkage code. */ + asection *sec; + struct xcoff_link_hash_entry *hds; + + /* Mark the descriptor (and its TOC section). */ + hds = h->descriptor; + BFD_ASSERT ((hds->root.type == bfd_link_hash_undefined + || hds->root.type == bfd_link_hash_undefweak) + && (hds->flags & XCOFF_DEF_REGULAR) == 0); + if (!xcoff_mark_symbol (info, hds)) + return FALSE; + + /* Treat this symbol as undefined if the descriptor was. */ + if ((hds->flags & XCOFF_WAS_UNDEFINED) != 0) + h->flags |= XCOFF_WAS_UNDEFINED; + + /* Allocate room for the global linkage code itself. */ + sec = xcoff_hash_table (info)->linkage_section; + h->root.type = bfd_link_hash_defined; + h->root.u.def.section = sec; + h->root.u.def.value = sec->size; + h->smclas = XMC_GL; + h->flags |= XCOFF_DEF_REGULAR; + sec->size += bfd_xcoff_glink_code_size (info->output_bfd); + + /* The global linkage code requires a TOC entry for the + descriptor. */ + if (hds->toc_section == NULL) + { + int byte_size; + + /* 32 vs 64 + xcoff32 uses 4 bytes in the toc. + xcoff64 uses 8 bytes in the toc. */ + if (bfd_xcoff_is_xcoff64 (info->output_bfd)) + byte_size = 8; + else if (bfd_xcoff_is_xcoff32 (info->output_bfd)) + byte_size = 4; + else + return FALSE; + + /* Allocate room in the fallback TOC section. */ + hds->toc_section = xcoff_hash_table (info)->toc_section; + hds->u.toc_offset = hds->toc_section->size; + hds->toc_section->size += byte_size; + if (!xcoff_mark (info, hds->toc_section)) + return FALSE; + + /* Allocate room for a static and dynamic R_TOC + relocation. */ + ++xcoff_hash_table (info)->ldrel_count; + ++hds->toc_section->reloc_count; + + /* Set the index to -2 to force this symbol to + get written out. */ + hds->indx = -2; + hds->flags |= XCOFF_SET_TOC | XCOFF_LDREL; + } + } + else if ((h->flags & XCOFF_DEF_DYNAMIC) == 0) + { + /* Record that the symbol was undefined, then import it. + -brtl links use a special fake import file. */ + h->flags |= XCOFF_WAS_UNDEFINED | XCOFF_IMPORT; + if (xcoff_hash_table (info)->rtld) + { + if (!xcoff_set_import_path (info, h, "", "..", "")) + return FALSE; + } + else + { + if (!xcoff_set_import_path (info, h, NULL, NULL, NULL)) + return FALSE; + } + } + } + + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + asection *hsec; + + hsec = h->root.u.def.section; + if (! bfd_is_abs_section (hsec) + && (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; +} + +/* Look for a symbol called NAME. If the symbol is defined, mark it. + If the symbol exists, set FLAGS. */ + +static bfd_boolean +xcoff_mark_symbol_by_name (struct bfd_link_info *info, + const char *name, unsigned int flags) +{ + struct xcoff_link_hash_entry *h; + + h = xcoff_link_hash_lookup (xcoff_hash_table (info), name, + FALSE, FALSE, TRUE); + if (h != NULL) + { + h->flags |= flags; + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + if (!xcoff_mark (info, h->root.u.def.section)) + return FALSE; + } + } + return TRUE; } /* The mark phase of garbage collection. For a given section, mark @@ -2252,30 +2883,28 @@ xcoff_mark (struct bfd_link_info *info, asection *sec) sec->flags |= SEC_MARK; - if (sec->owner->xvec == info->hash->creator + if (sec->owner->xvec == info->output_bfd->xvec && coff_section_data (sec->owner, sec) != NULL && xcoff_section_data (sec->owner, sec) != NULL) { - struct xcoff_link_hash_entry **hp, **hpend; + struct xcoff_link_hash_entry **syms; struct internal_reloc *rel, *relend; + asection **csects; + unsigned long i, first, last; /* 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++) - { - struct xcoff_link_hash_entry *h; - - h = *hp; - if (h != NULL - && (h->flags & XCOFF_MARK) == 0) - { - if (! xcoff_mark_symbol (info, h)) - return FALSE; - } - } + syms = obj_xcoff_sym_hashes (sec->owner); + csects = xcoff_data (sec->owner)->csects; + first = xcoff_section_data (sec->owner, sec)->first_symndx; + last = xcoff_section_data (sec->owner, sec)->last_symndx; + for (i = first; i <= last; i++) + if (csects[i] == sec + && syms[i] != NULL + && (syms[i]->flags & XCOFF_MARK) == 0) + { + if (!xcoff_mark_symbol (info, syms[i])) + return FALSE; + } /* Look through the section relocs. */ if ((sec->flags & SEC_RELOC) != 0 @@ -2288,7 +2917,6 @@ xcoff_mark (struct bfd_link_info *info, asection *sec) relend = rel + sec->reloc_count; for (; rel < relend; rel++) { - asection *rsec; struct xcoff_link_hash_entry *h; if ((unsigned int) rel->r_symndx @@ -2296,57 +2924,34 @@ xcoff_mark (struct bfd_link_info *info, asection *sec) continue; h = obj_xcoff_sym_hashes (sec->owner)[rel->r_symndx]; - if (h != NULL - && (h->flags & XCOFF_MARK) == 0) + if (h != NULL) { - if (! xcoff_mark_symbol (info, h)) - return FALSE; + if ((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) + else { - if (! xcoff_mark (info, rsec)) - return FALSE; + asection *rsec; + + 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) + if (xcoff_need_ldrel_p (info, rel, h)) { - 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; } } @@ -2386,11 +2991,10 @@ xcoff_sweep (struct bfd_link_info *info) /* Keep all sections from non-XCOFF input files. Keep special sections. Keep .debug sections for the moment. */ - if (sub->xvec != info->hash->creator + if (sub->xvec != info->output_bfd->xvec || 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; @@ -2398,7 +3002,6 @@ xcoff_sweep (struct bfd_link_info *info) { o->size = 0; o->reloc_count = 0; - o->lineno_count = 0; } } } @@ -2478,8 +3081,7 @@ bfd_xcoff_import_symbol (bfd *output_bfd, hds->root.u.undef.abfd = h->root.u.undef.abfd; } hds->flags |= XCOFF_DESCRIPTOR; - BFD_ASSERT ((hds->flags & XCOFF_CALLED) == 0 - && (h->flags & XCOFF_DESCRIPTOR) == 0); + BFD_ASSERT ((h->flags & XCOFF_DESCRIPTOR) == 0); hds->descriptor = h; h->descriptor = hds; } @@ -2509,48 +3111,11 @@ bfd_xcoff_import_symbol (bfd *output_bfd, h->root.type = bfd_link_hash_defined; h->root.u.def.section = bfd_abs_section_ptr; h->root.u.def.value = val; + h->smclas = XMC_XO; } - /* 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) - { - struct xcoff_import_file *n; - bfd_size_type amt = sizeof (* n); - - n = bfd_alloc (output_bfd, amt); - if (n == NULL) - return FALSE; - n->next = NULL; - n->path = imppath; - n->file = impfile; - n->member = impmember; - *pp = n; - } - - h->ldindx = c; - } + if (!xcoff_set_import_path (info, h, imppath, impfile, impmember)) + return FALSE; return TRUE; } @@ -2572,46 +3137,18 @@ bfd_xcoff_export_symbol (bfd *output_bfd, /* FIXME: I'm not at all sure what syscall is supposed to mean, so I'm just going to ignore it until somebody explains it. */ - /* See if this is a function descriptor. It may be one even though - it is not so marked. */ - if ((h->flags & XCOFF_DESCRIPTOR) == 0 - && h->root.root.string[0] != '.') - { - char *fnname; - struct xcoff_link_hash_entry *hfn; - bfd_size_type amt = strlen (h->root.root.string) + 2; + /* Make sure we don't garbage collect this symbol. */ + if (! xcoff_mark_symbol (info, h)) + return FALSE; - fnname = bfd_malloc (amt); - if (fnname == NULL) - return FALSE; - fnname[0] = '.'; - strcpy (fnname + 1, h->root.root.string); - hfn = xcoff_link_hash_lookup (xcoff_hash_table (info), - fnname, FALSE, FALSE, TRUE); - free (fnname); - if (hfn != NULL - && hfn->smclas == XMC_PR - && (hfn->root.type == bfd_link_hash_defined - || hfn->root.type == bfd_link_hash_defweak)) - { - h->flags |= XCOFF_DESCRIPTOR; - h->descriptor = hfn; - hfn->descriptor = h; - } - } - - /* Make sure we don't garbage collect this symbol. */ - if (! xcoff_mark_symbol (info, h)) - return FALSE; - - /* If this is a function descriptor, make sure we don't garbage - collect the associated function code. We normally don't have to - worry about this, because the descriptor will be attached to a - section with relocs, but if we are creating the descriptor - ourselves those relocs will not be visible to the mark code. */ - if ((h->flags & XCOFF_DESCRIPTOR) != 0) - { - if (! xcoff_mark_symbol (info, h->descriptor)) + /* If this is a function descriptor, make sure we don't garbage + collect the associated function code. We normally don't have to + worry about this, because the descriptor will be attached to a + section with relocs, but if we are creating the descriptor + ourselves those relocs will not be visible to the mark code. */ + if ((h->flags & XCOFF_DESCRIPTOR) != 0) + { + if (! xcoff_mark_symbol (info, h->descriptor)) return FALSE; } @@ -2642,8 +3179,12 @@ bfd_xcoff_link_count_reloc (bfd *output_bfd, return FALSE; } - h->flags |= XCOFF_REF_REGULAR | XCOFF_LDREL; - ++xcoff_hash_table (info)->ldrel_count; + h->flags |= XCOFF_REF_REGULAR; + if (xcoff_hash_table (info)->loader_section) + { + h->flags |= XCOFF_LDREL; + ++xcoff_hash_table (info)->ldrel_count; + } /* Mark the symbol to avoid garbage collection. */ if (! xcoff_mark_symbol (info, h)) @@ -2675,244 +3216,84 @@ bfd_xcoff_record_link_assignment (bfd *output_bfd, return TRUE; } -/* Add a symbol to the .loader symbols, if necessary. */ +/* An xcoff_link_hash_traverse callback for which DATA points to an + xcoff_loader_info. Mark all symbols that should be automatically + exported. */ static bfd_boolean -xcoff_build_ldsyms (struct xcoff_link_hash_entry *h, void * p) +xcoff_mark_auto_exports (struct xcoff_link_hash_entry *h, void *data) { - struct xcoff_loader_info *ldinfo = (struct xcoff_loader_info *) p; - bfd_size_type amt; + struct xcoff_loader_info *ldinfo; - if (h->root.type == bfd_link_hash_warning) - h = (struct xcoff_link_hash_entry *) h->root.u.i.link; - - /* __rtinit, this symbol has special handling. */ - if (h->flags & XCOFF_RTINIT) - return TRUE; - - /* If this is a final link, and the symbol was defined as a common - symbol in a regular object file, and there was no definition in - any dynamic object, then the linker will have allocated space for - the symbol in a common section but the XCOFF_DEF_REGULAR flag - will not have been set. */ - if (h->root.type == bfd_link_hash_defined - && (h->flags & XCOFF_DEF_REGULAR) == 0 - && (h->flags & XCOFF_REF_REGULAR) != 0 - && (h->flags & XCOFF_DEF_DYNAMIC) == 0 - && (bfd_is_abs_section (h->root.u.def.section) - || (h->root.u.def.section->owner->flags & DYNAMIC) == 0)) - h->flags |= XCOFF_DEF_REGULAR; - - /* If all defined symbols should be exported, mark them now. We - don't want to export the actual functions, just the function - descriptors. */ - if (ldinfo->export_defineds - && (h->flags & XCOFF_DEF_REGULAR) != 0 - && h->root.root.string[0] != '.') + ldinfo = (struct xcoff_loader_info *) data; + if (xcoff_auto_export_p (ldinfo->info, h, ldinfo->auto_export_flags)) { - bfd_boolean export; - - /* We don't export a symbol which is being defined by an object - included from an archive which contains a shared object. The - rationale is that if an archive contains both an unshared and - a shared object, then there must be some reason that the - unshared object is unshared, and we don't want to start - providing a shared version of it. In particular, this solves - a bug involving the _savefNN set of functions. gcc will call - those functions without providing a slot to restore the TOC, - so it is essential that these functions be linked in directly - and not from a shared object, which means that a shared - object which also happens to link them in must not export - them. This is confusing, but I haven't been able to think of - a different approach. Note that the symbols can, of course, - be exported explicitly. */ - export = TRUE; - if ((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && h->root.u.def.section->owner != NULL - && h->root.u.def.section->owner->my_archive != NULL) - { - bfd *arbfd, *member; - - arbfd = h->root.u.def.section->owner->my_archive; - member = bfd_openr_next_archived_file (arbfd, NULL); - while (member != NULL) - { - if ((member->flags & DYNAMIC) != 0) - { - export = FALSE; - break; - } - member = bfd_openr_next_archived_file (arbfd, member); - } - } - - if (export) - h->flags |= XCOFF_EXPORT; + if (!xcoff_mark_symbol (ldinfo->info, h)) + ldinfo->failed = TRUE; } + return TRUE; +} - /* We don't want to garbage collect symbols which are not defined in - XCOFF files. This is a convenient place to mark them. */ - if (xcoff_hash_table (ldinfo->info)->gc - && (h->flags & XCOFF_MARK) == 0 - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && (h->root.u.def.section->owner == NULL - || (h->root.u.def.section->owner->xvec - != ldinfo->info->hash->creator))) - h->flags |= XCOFF_MARK; - - /* If this symbol is called and defined in a dynamic object, or it - is imported, then we need to set up global linkage code for it. - (Unless we did garbage collection and we didn't need this - symbol.) */ - if ((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)) - && (! xcoff_hash_table (ldinfo->info)->gc - || (h->flags & XCOFF_MARK) != 0)) - { - asection *sec; - struct xcoff_link_hash_entry *hds; - - sec = xcoff_hash_table (ldinfo->info)->linkage_section; - h->root.type = bfd_link_hash_defined; - h->root.u.def.section = sec; - h->root.u.def.value = sec->size; - h->smclas = XMC_GL; - h->flags |= XCOFF_DEF_REGULAR; - sec->size += bfd_xcoff_glink_code_size(ldinfo->output_bfd); - - /* The global linkage code requires a TOC entry for the - descriptor. */ - hds = h->descriptor; - BFD_ASSERT ((hds->root.type == bfd_link_hash_undefined - || hds->root.type == bfd_link_hash_undefweak) - && (hds->flags & XCOFF_DEF_REGULAR) == 0); - hds->flags |= XCOFF_MARK; - if (hds->toc_section == NULL) - { - int byte_size; - - /* 32 vs 64 - xcoff32 uses 4 bytes in the toc. - xcoff64 uses 8 bytes in the toc. */ - if (bfd_xcoff_is_xcoff64 (ldinfo->output_bfd)) - byte_size = 8; - else if (bfd_xcoff_is_xcoff32 (ldinfo->output_bfd)) - byte_size = 4; - else - return FALSE; +/* Add a symbol to the .loader symbols, if necessary. */ - hds->toc_section = xcoff_hash_table (ldinfo->info)->toc_section; - hds->u.toc_offset = hds->toc_section->size; - hds->toc_section->size += byte_size; - ++xcoff_hash_table (ldinfo->info)->ldrel_count; - ++hds->toc_section->reloc_count; - hds->indx = -2; - hds->flags |= XCOFF_SET_TOC | XCOFF_LDREL; - - /* We need to call xcoff_build_ldsyms recursively here, - because we may already have passed hds on the traversal. */ - xcoff_build_ldsyms (hds, p); - } - } +/* INPUT_BFD has an external symbol associated with hash table entry H + and csect CSECT. Return true if INPUT_BFD defines H. */ - /* If this symbol is exported, but not defined, we need to try to - define it. */ - if ((h->flags & XCOFF_EXPORT) != 0 - && (h->flags & XCOFF_IMPORT) == 0 - && (h->flags & XCOFF_DEF_REGULAR) == 0 - && (h->flags & XCOFF_DEF_DYNAMIC) == 0 - && (h->root.type == bfd_link_hash_undefined - || h->root.type == bfd_link_hash_undefweak)) +static bfd_boolean +xcoff_final_definition_p (bfd *input_bfd, struct xcoff_link_hash_entry *h, + asection *csect) +{ + switch (h->root.type) { - if ((h->flags & XCOFF_DESCRIPTOR) != 0 - && (h->descriptor->root.type == bfd_link_hash_defined - || h->descriptor->root.type == bfd_link_hash_defweak)) - { - asection *sec; - - /* This is an undefined function descriptor associated with - a defined entry point. We can build up a function - descriptor ourselves. Believe it or not, the AIX linker - actually does this, and there are cases where we need to - do it as well. */ - sec = xcoff_hash_table (ldinfo->info)->descriptor_section; - h->root.type = bfd_link_hash_defined; - h->root.u.def.section = sec; - h->root.u.def.value = sec->size; - h->smclas = XMC_DS; - h->flags |= XCOFF_DEF_REGULAR; + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + /* No input bfd owns absolute symbols. They are written by + xcoff_write_global_symbol instead. */ + return (!bfd_is_abs_section (csect) + && h->root.u.def.section == csect); + + case bfd_link_hash_common: + return h->root.u.c.p->section->owner == input_bfd; + + case bfd_link_hash_undefined: + case bfd_link_hash_undefweak: + /* We can't treat undef.abfd as the owner because that bfd + might be a dynamic object. Allow any bfd to claim it. */ + return TRUE; - /* The size of the function descriptor depends if this is an - xcoff32 (12) or xcoff64 (24). */ - sec->size += - bfd_xcoff_function_descriptor_size(ldinfo->output_bfd); + default: + abort (); + } +} - /* A function descriptor uses two relocs: one for the - associated code, and one for the TOC address. */ - xcoff_hash_table (ldinfo->info)->ldrel_count += 2; - sec->reloc_count += 2; +/* See if H should have a loader symbol associated with it. */ - /* We handle writing out the contents of the descriptor in - xcoff_write_global_symbol. */ - } - else - { - (*_bfd_error_handler) - (_("warning: attempt to export undefined symbol `%s'"), - h->root.root.string); - h->ldsym = NULL; - return TRUE; - } - } +static bfd_boolean +xcoff_build_ldsym (struct xcoff_loader_info *ldinfo, + struct xcoff_link_hash_entry *h) +{ + bfd_size_type amt; - /* If this is still a common symbol, and it wasn't garbage - collected, we need to actually allocate space for it in the .bss - section. */ - if (h->root.type == bfd_link_hash_common - && (! xcoff_hash_table (ldinfo->info)->gc - || (h->flags & XCOFF_MARK) != 0) - && h->root.u.c.p->section->size == 0) + /* Warn if this symbol is exported but not defined. */ + if ((h->flags & XCOFF_EXPORT) != 0 + && (h->flags & XCOFF_WAS_UNDEFINED) != 0) { - BFD_ASSERT (bfd_is_com_section (h->root.u.c.p->section)); - h->root.u.c.p->section->size = h->root.u.c.size; + (*_bfd_error_handler) + (_("warning: attempt to export undefined symbol `%s'"), + h->root.root.string); + return TRUE; } /* We need to add a symbol to the .loader section if it is mentioned in a reloc which we are copying to the .loader section and it was not defined or common, or if it is the entry point, or if it is being exported. */ - if (((h->flags & XCOFF_LDREL) == 0 || h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak || h->root.type == bfd_link_hash_common) && (h->flags & XCOFF_ENTRY) == 0 && (h->flags & XCOFF_EXPORT) == 0) - { - h->ldsym = NULL; - return TRUE; - } - - /* We don't need to add this symbol if we did garbage collection and - we did not mark this symbol. */ - if (xcoff_hash_table (ldinfo->info)->gc - && (h->flags & XCOFF_MARK) == 0) - { - h->ldsym = NULL; - return TRUE; - } - - /* We may have already processed this symbol due to the recursive - call above. */ - if ((h->flags & XCOFF_BUILT_LDSYM) != 0) return TRUE; /* We need to add this symbol to the .loader symbols. */ @@ -2927,7 +3308,12 @@ xcoff_build_ldsyms (struct xcoff_link_hash_entry *h, void * p) } if ((h->flags & XCOFF_IMPORT) != 0) - h->ldsym->l_ifile = h->ldindx; + { + /* Give imported descriptors class XMC_DS rather than XMC_UA. */ + if ((h->flags & XCOFF_DESCRIPTOR) != 0) + h->smclas = XMC_DS; + h->ldsym->l_ifile = h->ldindx; + } /* The first 3 symbol table indices are reserved to indicate the data, text and bss sections. */ @@ -2935,14 +3321,271 @@ xcoff_build_ldsyms (struct xcoff_link_hash_entry *h, void * p) ++ldinfo->ldsym_count; - if (! bfd_xcoff_put_ldsymbol_name (ldinfo->output_bfd, ldinfo, - h->ldsym, h->root.root.string)) - return FALSE; + if (! bfd_xcoff_put_ldsymbol_name (ldinfo->output_bfd, ldinfo, + h->ldsym, h->root.root.string)) + return FALSE; + + h->flags |= XCOFF_BUILT_LDSYM; + return TRUE; +} + +/* An xcoff_htab_traverse callback that is called for each symbol + once garbage collection is complete. */ + +static bfd_boolean +xcoff_post_gc_symbol (struct xcoff_link_hash_entry *h, void * p) +{ + struct xcoff_loader_info *ldinfo = (struct xcoff_loader_info *) p; + + if (h->root.type == bfd_link_hash_warning) + h = (struct xcoff_link_hash_entry *) h->root.u.i.link; + + /* __rtinit, this symbol has special handling. */ + if (h->flags & XCOFF_RTINIT) + return TRUE; + + /* We don't want to garbage collect symbols which are not defined in + XCOFF files. This is a convenient place to mark them. */ + if (xcoff_hash_table (ldinfo->info)->gc + && (h->flags & XCOFF_MARK) == 0 + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && (h->root.u.def.section->owner == NULL + || (h->root.u.def.section->owner->xvec + != ldinfo->info->output_bfd->xvec))) + h->flags |= XCOFF_MARK; + + /* Skip discarded symbols. */ + if (xcoff_hash_table (ldinfo->info)->gc + && (h->flags & XCOFF_MARK) == 0) + return TRUE; + + /* If this is still a common symbol, and it wasn't garbage + collected, we need to actually allocate space for it in the .bss + section. */ + if (h->root.type == bfd_link_hash_common + && h->root.u.c.p->section->size == 0) + { + BFD_ASSERT (bfd_is_com_section (h->root.u.c.p->section)); + h->root.u.c.p->section->size = h->root.u.c.size; + } + + if (xcoff_hash_table (ldinfo->info)->loader_section) + { + if (xcoff_auto_export_p (ldinfo->info, h, ldinfo->auto_export_flags)) + h->flags |= XCOFF_EXPORT; + + if (!xcoff_build_ldsym (ldinfo, h)) + return FALSE; + } + + return TRUE; +} + +/* INPUT_BFD includes XCOFF symbol ISYM, which is associated with linker + hash table entry H and csect CSECT. AUX contains ISYM's auxillary + csect information, if any. NAME is the function's name if the name + is stored in the .debug section, otherwise it is null. + + Return 1 if we should include an appropriately-adjusted ISYM + in the output file, 0 if we should discard ISYM, or -1 if an + error occured. */ + +static int +xcoff_keep_symbol_p (struct bfd_link_info *info, bfd *input_bfd, + struct internal_syment *isym, + union internal_auxent *aux, + struct xcoff_link_hash_entry *h, + asection *csect, const char *name) +{ + int smtyp; + + /* If we are skipping this csect, we want to strip the symbol too. */ + if (csect == NULL) + return 0; + + /* Likewise if we garbage-collected the csect. */ + if (xcoff_hash_table (info)->gc + && !bfd_is_abs_section (csect) + && !bfd_is_und_section (csect) + && (csect->flags & SEC_MARK) == 0) + return 0; + + /* An XCOFF linker always removes C_STAT symbols. */ + if (isym->n_sclass == C_STAT) + return 0; + + /* We generate the TOC anchor separately. */ + if (isym->n_sclass == C_HIDEXT + && aux->x_csect.x_smclas == XMC_TC0) + return 0; + + /* If we are stripping all symbols, we want to discard this one. */ + if (info->strip == strip_all) + return 0; + + /* Discard symbols that are defined elsewhere. */ + if (EXTERN_SYM_P (isym->n_sclass)) + { + if ((h->flags & XCOFF_ALLOCATED) != 0) + return 0; + if (!xcoff_final_definition_p (input_bfd, h, csect)) + return 0; + } + + /* If we're discarding local symbols, check whether ISYM is local. */ + smtyp = SMTYP_SMTYP (aux->x_csect.x_smtyp); + if (info->discard == discard_all + && !EXTERN_SYM_P (isym->n_sclass) + && (isym->n_sclass != C_HIDEXT || smtyp != XTY_SD)) + return 0; + + /* If we're stripping debugging symbols, check whether ISYM is one. */ + if (info->strip == strip_debugger + && isym->n_scnum == N_DEBUG) + return 0; + + /* If we are stripping symbols based on name, check how ISYM's + name should be handled. */ + if (info->strip == strip_some + || info->discard == discard_l) + { + char buf[SYMNMLEN + 1]; + + if (name == NULL) + { + name = _bfd_coff_internal_syment_name (input_bfd, isym, buf); + if (name == NULL) + return -1; + } + + if (info->strip == strip_some + && bfd_hash_lookup (info->keep_hash, name, FALSE, FALSE) == NULL) + return 0; + + if (info->discard == discard_l + && !EXTERN_SYM_P (isym->n_sclass) + && (isym->n_sclass != C_HIDEXT || smtyp != XTY_SD) + && bfd_is_local_label_name (input_bfd, name)) + return 0; + } + + return 1; +} + +/* Lay out the .loader section, filling in the header and the import paths. + LIBPATH is as for bfd_xcoff_size_dynamic_sections. */ + +static bfd_boolean +xcoff_build_loader_section (struct xcoff_loader_info *ldinfo, + const char *libpath) +{ + bfd *output_bfd; + struct xcoff_link_hash_table *htab; + struct internal_ldhdr *ldhdr; + struct xcoff_import_file *fl; + bfd_size_type stoff; + size_t impsize, impcount; + asection *lsec; + char *out; + + /* Work out the size of the import file names. Each import file ID + consists of three null terminated strings: the path, the file + name, and the archive member name. The first entry in the list + of names is the path to use to find objects, which the linker has + passed in as the libpath argument. For some reason, the path + entry in the other import file names appears to always be empty. */ + output_bfd = ldinfo->output_bfd; + htab = xcoff_hash_table (ldinfo->info); + impsize = strlen (libpath) + 3; + impcount = 1; + for (fl = htab->imports; fl != NULL; fl = fl->next) + { + ++impcount; + impsize += (strlen (fl->path) + + strlen (fl->file) + + strlen (fl->member) + + 3); + } + + /* Set up the .loader section header. */ + ldhdr = &htab->ldhdr; + ldhdr->l_version = bfd_xcoff_ldhdr_version(output_bfd); + ldhdr->l_nsyms = ldinfo->ldsym_count; + ldhdr->l_nreloc = htab->ldrel_count; + ldhdr->l_istlen = impsize; + ldhdr->l_nimpid = impcount; + ldhdr->l_impoff = (bfd_xcoff_ldhdrsz (output_bfd) + + ldhdr->l_nsyms * bfd_xcoff_ldsymsz (output_bfd) + + ldhdr->l_nreloc * bfd_xcoff_ldrelsz (output_bfd)); + ldhdr->l_stlen = ldinfo->string_size; + stoff = ldhdr->l_impoff + impsize; + if (ldinfo->string_size == 0) + ldhdr->l_stoff = 0; + else + ldhdr->l_stoff = stoff; + + /* 64 bit elements to ldhdr + The swap out routine for 32 bit will ignore them. + Nothing fancy, symbols come after the header and relocs come + after symbols. */ + ldhdr->l_symoff = bfd_xcoff_ldhdrsz (output_bfd); + ldhdr->l_rldoff = (bfd_xcoff_ldhdrsz (output_bfd) + + ldhdr->l_nsyms * bfd_xcoff_ldsymsz (output_bfd)); + + /* We now know the final size of the .loader section. Allocate + space for it. */ + lsec = htab->loader_section; + lsec->size = stoff + ldhdr->l_stlen; + lsec->contents = bfd_zalloc (output_bfd, lsec->size); + if (lsec->contents == NULL) + return FALSE; + + /* Set up the header. */ + bfd_xcoff_swap_ldhdr_out (output_bfd, ldhdr, lsec->contents); + + /* Set up the import file names. */ + out = (char *) lsec->contents + ldhdr->l_impoff; + strcpy (out, libpath); + out += strlen (libpath) + 1; + *out++ = '\0'; + *out++ = '\0'; + for (fl = htab->imports; fl != NULL; fl = fl->next) + { + const char *s; + + s = fl->path; + while ((*out++ = *s++) != '\0') + ; + s = fl->file; + while ((*out++ = *s++) != '\0') + ; + s = fl->member; + while ((*out++ = *s++) != '\0') + ; + } + + BFD_ASSERT ((bfd_size_type) ((bfd_byte *) out - lsec->contents) == stoff); + + /* Set up the symbol string table. */ + if (ldinfo->string_size > 0) + { + memcpy (out, ldinfo->strings, ldinfo->string_size); + free (ldinfo->strings); + ldinfo->strings = NULL; + } - h->flags |= XCOFF_BUILT_LDSYM; + /* We can't set up the symbol table or the relocs yet, because we + don't yet know the final position of the various sections. The + .loader symbols are written out when the corresponding normal + symbols are written out in xcoff_link_input_bfd or + xcoff_write_global_symbol. The .loader relocs are written out + when the corresponding normal relocs are handled in + xcoff_link_input_bfd. */ return TRUE; } + /* Build the .loader section. This is called by the XCOFF linker emulation before_allocation routine. We must set the size of the .loader section before the linker lays out the output file. @@ -2955,10 +3598,9 @@ xcoff_build_ldsyms (struct xcoff_link_hash_entry *h, void * p) -bmaxdata linker option). GC is whether to do garbage collection (the -bgc linker option). MODTYPE is the module type (the -bmodtype linker option). TEXTRO is whether the text section must - be read only (the -btextro linker option). EXPORT_DEFINEDS is - whether all defined symbols should be exported (the -unix linker - option). SPECIAL_SECTIONS is set by this routine to csects with - magic names like _end. */ + be read only (the -btextro linker option). AUTO_EXPORT_FLAGS + is a mask of XCOFF_EXPALL and XCOFF_EXPFULL. SPECIAL_SECTIONS + is set by this routine to csects with magic names like _end. */ bfd_boolean bfd_xcoff_size_dynamic_sections (bfd *output_bfd, @@ -2971,19 +3613,12 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd, bfd_boolean gc, int modtype, bfd_boolean textro, - bfd_boolean export_defineds, + unsigned int auto_export_flags, asection **special_sections, bfd_boolean rtld) { - struct xcoff_link_hash_entry *hentry; - asection *lsec; struct xcoff_loader_info ldinfo; int i; - size_t impsize, impcount; - struct xcoff_import_file *fl; - struct internal_ldhdr *ldhdr; - bfd_size_type stoff; - char *out; asection *sec; bfd *sub; struct bfd_strtab_hash *debug_strtab; @@ -3000,7 +3635,7 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd, ldinfo.failed = FALSE; ldinfo.output_bfd = output_bfd; ldinfo.info = info; - ldinfo.export_defineds = export_defineds; + ldinfo.auto_export_flags = auto_export_flags; ldinfo.ldsym_count = 0; ldinfo.string_size = 0; ldinfo.strings = NULL; @@ -3012,18 +3647,11 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd, xcoff_hash_table (info)->file_align = file_align; xcoff_hash_table (info)->textro = textro; - - hentry = NULL; - if (entry != NULL) - { - hentry = xcoff_link_hash_lookup (xcoff_hash_table (info), entry, - FALSE, FALSE, TRUE); - if (hentry != NULL) - hentry->flags |= XCOFF_ENTRY; - } + xcoff_hash_table (info)->rtld = rtld; /* __rtinit */ - if (info->init_function || info->fini_function || rtld) + if (xcoff_hash_table (info)->loader_section + && (info->init_function || info->fini_function || rtld)) { struct xcoff_link_hash_entry *hsym; struct internal_ldsym *ldsym; @@ -3074,11 +3702,7 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd, } /* Garbage collect unused sections. */ - if (info->relocatable - || ! gc - || hentry == NULL - || (hentry->root.type != bfd_link_hash_defined - && hentry->root.type != bfd_link_hash_defweak)) + if (info->relocatable || !gc) { gc = FALSE; xcoff_hash_table (info)->gc = FALSE; @@ -3091,7 +3715,12 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd, for (o = sub->sections; o != NULL; o = o->next) { - if ((o->flags & SEC_MARK) == 0) + /* We shouldn't unconditionaly mark the TOC section. + The output file should only have a TOC if either + (a) one of the input files did or (b) we end up + creating TOC references as part of the link process. */ + if (o != xcoff_hash_table (info)->toc_section + && (o->flags & SEC_MARK) == 0) { if (! xcoff_mark (info, o)) goto error_return; @@ -3101,8 +3730,22 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd, } else { - if (! xcoff_mark (info, hentry->root.u.def.section)) + if (entry != NULL + && !xcoff_mark_symbol_by_name (info, entry, XCOFF_ENTRY)) goto error_return; + if (info->init_function != NULL + && !xcoff_mark_symbol_by_name (info, info->init_function, 0)) + goto error_return; + if (info->fini_function != NULL + && !xcoff_mark_symbol_by_name (info, info->fini_function, 0)) + goto error_return; + if (auto_export_flags != 0) + { + xcoff_link_hash_traverse (xcoff_hash_table (info), + xcoff_mark_auto_exports, &ldinfo); + if (ldinfo.failed) + goto error_return; + } xcoff_sweep (info); xcoff_hash_table (info)->gc = TRUE; } @@ -3124,103 +3767,15 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd, /* I'm not sure what to do in this bizarre case. */ return TRUE; - xcoff_link_hash_traverse (xcoff_hash_table (info), xcoff_build_ldsyms, + xcoff_link_hash_traverse (xcoff_hash_table (info), xcoff_post_gc_symbol, (void *) &ldinfo); if (ldinfo.failed) goto error_return; - /* Work out the size of the import file names. Each import file ID - consists of three null terminated strings: the path, the file - name, and the archive member name. The first entry in the list - of names is the path to use to find objects, which the linker has - passed in as the libpath argument. For some reason, the path - entry in the other import file names appears to always be empty. */ - impsize = strlen (libpath) + 3; - impcount = 1; - for (fl = xcoff_hash_table (info)->imports; fl != NULL; fl = fl->next) - { - ++impcount; - impsize += (strlen (fl->path) - + strlen (fl->file) - + strlen (fl->member) - + 3); - } - - /* Set up the .loader section header. */ - ldhdr = &xcoff_hash_table (info)->ldhdr; - ldhdr->l_version = bfd_xcoff_ldhdr_version(output_bfd); - ldhdr->l_nsyms = ldinfo.ldsym_count; - ldhdr->l_nreloc = xcoff_hash_table (info)->ldrel_count; - ldhdr->l_istlen = impsize; - ldhdr->l_nimpid = impcount; - ldhdr->l_impoff = (bfd_xcoff_ldhdrsz(output_bfd) - + ldhdr->l_nsyms * bfd_xcoff_ldsymsz(output_bfd) - + ldhdr->l_nreloc * bfd_xcoff_ldrelsz(output_bfd)); - ldhdr->l_stlen = ldinfo.string_size; - stoff = ldhdr->l_impoff + impsize; - if (ldinfo.string_size == 0) - ldhdr->l_stoff = 0; - else - ldhdr->l_stoff = stoff; - - /* 64 bit elements to ldhdr - The swap out routine for 32 bit will ignore them. - Nothing fancy, symbols come after the header and relocs come - after symbols. */ - ldhdr->l_symoff = bfd_xcoff_ldhdrsz (output_bfd); - ldhdr->l_rldoff = (bfd_xcoff_ldhdrsz (output_bfd) - + ldhdr->l_nsyms * bfd_xcoff_ldsymsz (output_bfd)); - - /* We now know the final size of the .loader section. Allocate - space for it. */ - lsec = xcoff_hash_table (info)->loader_section; - lsec->size = stoff + ldhdr->l_stlen; - lsec->contents = bfd_zalloc (output_bfd, lsec->size); - if (lsec->contents == NULL) + if (xcoff_hash_table (info)->loader_section + && !xcoff_build_loader_section (&ldinfo, libpath)) goto error_return; - /* Set up the header. */ - bfd_xcoff_swap_ldhdr_out (output_bfd, ldhdr, lsec->contents); - - /* Set up the import file names. */ - out = (char *) lsec->contents + ldhdr->l_impoff; - strcpy (out, libpath); - out += strlen (libpath) + 1; - *out++ = '\0'; - *out++ = '\0'; - for (fl = xcoff_hash_table (info)->imports; fl != NULL; fl = fl->next) - { - const char *s; - - s = fl->path; - while ((*out++ = *s++) != '\0') - ; - s = fl->file; - while ((*out++ = *s++) != '\0') - ; - s = fl->member; - while ((*out++ = *s++) != '\0') - ; - } - - BFD_ASSERT ((bfd_size_type) ((bfd_byte *) out - lsec->contents) == stoff); - - /* Set up the symbol string table. */ - if (ldinfo.string_size > 0) - { - memcpy (out, ldinfo.strings, ldinfo.string_size); - free (ldinfo.strings); - ldinfo.strings = NULL; - } - - /* We can't set up the symbol table or the relocs yet, because we - don't yet know the final position of the various sections. The - .loader symbols are written out when the corresponding normal - symbols are written out in xcoff_link_input_bfd or - xcoff_write_global_symbol. The .loader relocs are written out - when the corresponding normal relocs are handled in - xcoff_link_input_bfd. */ - /* Allocate space for the magic sections. */ sec = xcoff_hash_table (info)->linkage_section; if (sec->size > 0) @@ -3244,96 +3799,142 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd, goto error_return; } - /* Now that we've done garbage collection, figure out the contents - of the .debug section. */ + /* Now that we've done garbage collection, decide which symbols to keep, + and figure out the contents of the .debug section. */ debug_strtab = xcoff_hash_table (info)->debug_strtab; for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) { asection *subdeb; bfd_size_type symcount; - unsigned long *debug_index; + long *debug_index; asection **csectpp; + unsigned int *lineno_counts; + struct xcoff_link_hash_entry **sym_hash; bfd_byte *esym, *esymend; bfd_size_type symesz; - if (sub->xvec != info->hash->creator) - continue; - subdeb = bfd_get_section_by_name (sub, ".debug"); - if (subdeb == NULL || subdeb->size == 0) + if (sub->xvec != info->output_bfd->xvec) continue; - if (info->strip == strip_all - || info->strip == strip_debugger - || info->discard == discard_all) - { - subdeb->size = 0; - continue; - } + if ((sub->flags & DYNAMIC) != 0 + && !info->static_link) + continue; if (! _bfd_coff_get_external_symbols (sub)) goto error_return; symcount = obj_raw_syment_count (sub); - debug_index = bfd_zalloc (sub, symcount * sizeof (unsigned long)); + debug_index = bfd_zalloc (sub, symcount * sizeof (long)); if (debug_index == NULL) goto error_return; xcoff_data (sub)->debug_indices = debug_index; - /* Grab the contents of the .debug section. We use malloc and - copy the names into the debug stringtab, rather than - bfd_alloc, because I expect that, when linking many files - together, many of the strings will be the same. Storing the - strings in the hash table should save space in this case. */ - if (! bfd_malloc_and_get_section (sub, subdeb, &debug_contents)) - goto error_return; + if (info->strip == strip_all + || info->strip == strip_debugger + || info->discard == discard_all) + /* We're stripping all debugging information, so there's no need + to read SUB's .debug section. */ + subdeb = NULL; + else + { + /* Grab the contents of SUB's .debug section, if any. */ + subdeb = bfd_get_section_by_name (sub, ".debug"); + if (subdeb != NULL && subdeb->size > 0) + { + /* We use malloc and copy the names into the debug + stringtab, rather than bfd_alloc, because I expect + that, when linking many files together, many of the + strings will be the same. Storing the strings in the + hash table should save space in this case. */ + if (!bfd_malloc_and_get_section (sub, subdeb, &debug_contents)) + goto error_return; + } + } csectpp = xcoff_data (sub)->csects; + lineno_counts = xcoff_data (sub)->lineno_counts; + sym_hash = obj_xcoff_sym_hashes (sub); + symesz = bfd_coff_symesz (sub); + esym = (bfd_byte *) obj_coff_external_syms (sub); + esymend = esym + symcount * symesz; - /* Dynamic object do not have csectpp's. */ - if (NULL != csectpp) + while (esym < esymend) { - symesz = bfd_coff_symesz (sub); - esym = (bfd_byte *) obj_coff_external_syms (sub); - esymend = esym + symcount * symesz; + struct internal_syment sym; + union internal_auxent aux; + asection *csect; + const char *name; + int keep_p; - while (esym < esymend) + bfd_coff_swap_sym_in (sub, esym, &sym); + + /* Read in the csect information, if any. */ + if (CSECT_SYM_P (sym.n_sclass)) { - struct internal_syment sym; + BFD_ASSERT (sym.n_numaux > 0); + bfd_coff_swap_aux_in (sub, esym + symesz * sym.n_numaux, + sym.n_type, sym.n_sclass, + sym.n_numaux - 1, sym.n_numaux, &aux); + } - bfd_coff_swap_sym_in (sub, (void *) esym, (void *) &sym); + /* If this symbol's name is stored in the debug section, + get a pointer to it. */ + if (debug_contents != NULL + && sym._n._n_n._n_zeroes == 0 + && bfd_coff_symname_in_debug (sub, &sym)) + name = (const char *) debug_contents + sym._n._n_n._n_offset; + else + name = NULL; - *debug_index = (unsigned long) -1; + /* Decide whether to copy this symbol to the output file. */ + csect = *csectpp; + keep_p = xcoff_keep_symbol_p (info, sub, &sym, &aux, + *sym_hash, csect, name); + if (keep_p < 0) + return FALSE; - if (sym._n._n_n._n_zeroes == 0 - && *csectpp != NULL - && (! gc - || ((*csectpp)->flags & SEC_MARK) != 0 - || *csectpp == bfd_abs_section_ptr) - && bfd_coff_symname_in_debug (sub, &sym)) + if (!keep_p) + /* Use a debug_index of -2 to record that a symbol should + be stripped. */ + *debug_index = -2; + else + { + /* See whether we should store the symbol name in the + output .debug section. */ + if (name != NULL) { - char *name; bfd_size_type indx; - name = (char *) debug_contents + sym._n._n_n._n_offset; indx = _bfd_stringtab_add (debug_strtab, name, TRUE, TRUE); if (indx == (bfd_size_type) -1) goto error_return; *debug_index = indx; } - - esym += (sym.n_numaux + 1) * symesz; - csectpp += sym.n_numaux + 1; - debug_index += sym.n_numaux + 1; + else + *debug_index = -1; + if (*sym_hash != 0) + (*sym_hash)->flags |= XCOFF_ALLOCATED; + if (*lineno_counts > 0) + csect->output_section->lineno_count += *lineno_counts; } + + esym += (sym.n_numaux + 1) * symesz; + csectpp += sym.n_numaux + 1; + sym_hash += sym.n_numaux + 1; + lineno_counts += sym.n_numaux + 1; + debug_index += sym.n_numaux + 1; } - free (debug_contents); - debug_contents = NULL; + if (debug_contents) + { + free (debug_contents); + debug_contents = NULL; - /* Clear the size of subdeb, so that it is not included directly - in the output file. */ - subdeb->size = 0; + /* Clear the size of subdeb, so that it is not included directly + in the output file. */ + subdeb->size = 0; + } if (! info->keep_memory) { @@ -3389,6 +3990,91 @@ bfd_xcoff_link_generate_rtinit (bfd *abfd, return TRUE; } +/* Return the section that defines H. Return null if no section does. */ + +static asection * +xcoff_symbol_section (struct xcoff_link_hash_entry *h) +{ + switch (h->root.type) + { + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + return h->root.u.def.section; + + case bfd_link_hash_common: + return h->root.u.c.p->section; + + default: + return NULL; + } +} + +/* Add a .loader relocation for input relocation IREL. If the loader + relocation should be against an output section, HSEC points to the + input section that IREL is against, otherwise HSEC is null. H is the + symbol that IREL is against, or null if it isn't against a global symbol. + REFERENCE_BFD is the bfd to use in error messages about the relocation. */ + +static bfd_boolean +xcoff_create_ldrel (bfd *output_bfd, struct xcoff_final_link_info *finfo, + asection *output_section, bfd *reference_bfd, + struct internal_reloc *irel, asection *hsec, + struct xcoff_link_hash_entry *h) +{ + struct internal_ldrel ldrel; + + ldrel.l_vaddr = irel->r_vaddr; + if (hsec != NULL) + { + const char *secname; + + secname = hsec->output_section->name; + if (strcmp (secname, ".text") == 0) + ldrel.l_symndx = 0; + else if (strcmp (secname, ".data") == 0) + ldrel.l_symndx = 1; + else if (strcmp (secname, ".bss") == 0) + ldrel.l_symndx = 2; + else + { + (*_bfd_error_handler) + (_("%B: loader reloc in unrecognized section `%s'"), + reference_bfd, secname); + bfd_set_error (bfd_error_nonrepresentable_section); + return FALSE; + } + } + else if (h != NULL) + { + if (h->ldindx < 0) + { + (*_bfd_error_handler) + (_("%B: `%s' in loader reloc but not loader sym"), + reference_bfd, h->root.root.string); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + ldrel.l_symndx = h->ldindx; + } + else + ldrel.l_symndx = -(bfd_size_type) 1; + + ldrel.l_rtype = (irel->r_size << 8) | irel->r_type; + ldrel.l_rsecnm = output_section->target_index; + if (xcoff_hash_table (finfo->info)->textro + && strcmp (output_section->name, ".text") == 0) + { + (*_bfd_error_handler) + (_("%B: loader reloc in read-only section %A"), + reference_bfd, output_section); + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + bfd_xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel); + finfo->ldrel += bfd_xcoff_ldrelsz (output_bfd); + return TRUE; +} + /* Link an input file into the linker output file. This function handles all the sections and relocations of the input file at once. */ @@ -3410,7 +4096,8 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, struct xcoff_link_hash_entry **sym_hash; struct internal_syment *isymp; asection **csectpp; - unsigned long *debug_index; + unsigned int *lineno_counts; + long *debug_index; long *indexp; unsigned long output_index; bfd_byte *outsym; @@ -3450,6 +4137,9 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, if (! _bfd_coff_get_external_symbols (input_bfd)) return FALSE; + /* Make one pass over the symbols and assign indices to symbols that + we have decided to keep. Also use create .loader symbol information + and update information in hash table entries. */ esym = (bfd_byte *) obj_coff_external_syms (input_bfd); esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz; sym_hash = obj_xcoff_sym_hashes (input_bfd); @@ -3458,24 +4148,16 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, isymp = finfo->internal_syms; indexp = finfo->sym_indices; output_index = syment_base; - outsym = finfo->outsyms; - incls = 0; - oline = NULL; - while (esym < esym_end) { - struct internal_syment isym; union internal_auxent aux; int smtyp = 0; - bfd_boolean skip; - bfd_boolean require; int add; bfd_coff_swap_sym_in (input_bfd, (void *) esym, (void *) isymp); - /* If this is a C_EXT or C_HIDEXT symbol, we need the csect - information. */ - if (isymp->n_sclass == C_EXT || isymp->n_sclass == C_HIDEXT) + /* Read in the csect information, if any. */ + if (CSECT_SYM_P (isymp->n_sclass)) { BFD_ASSERT (isymp->n_numaux > 0); bfd_coff_swap_aux_in (input_bfd, @@ -3487,39 +4169,32 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, smtyp = SMTYP_SMTYP (aux.x_csect.x_smtyp); } - /* Make a copy of *isymp so that the relocate_section function - always sees the original values. This is more reliable than - always recomputing the symbol value even if we are stripping - the symbol. */ - isym = *isymp; - /* If this symbol is in the .loader section, swap out the .loader symbol information. If this is an external symbol reference to a defined symbol, though, then wait until we get to the definition. */ - if (isym.n_sclass == C_EXT + if (EXTERN_SYM_P (isymp->n_sclass) && *sym_hash != NULL && (*sym_hash)->ldsym != NULL - && (smtyp != XTY_ER - || (*sym_hash)->root.type == bfd_link_hash_undefined)) + && xcoff_final_definition_p (input_bfd, *sym_hash, *csectpp)) { struct xcoff_link_hash_entry *h; struct internal_ldsym *ldsym; h = *sym_hash; ldsym = h->ldsym; - if (isym.n_scnum > 0) + if (isymp->n_scnum > 0) { ldsym->l_scnum = (*csectpp)->output_section->target_index; - ldsym->l_value = (isym.n_value + ldsym->l_value = (isymp->n_value + (*csectpp)->output_section->vma + (*csectpp)->output_offset - (*csectpp)->vma); } else { - ldsym->l_scnum = isym.n_scnum; - ldsym->l_value = isym.n_value; + ldsym->l_scnum = isymp->n_scnum; + ldsym->l_value = isymp->n_value; } ldsym->l_smtype = smtyp; @@ -3533,6 +4208,8 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, ldsym->l_smtype |= L_EXPORT; if ((h->flags & XCOFF_ENTRY) != 0) ldsym->l_smtype |= L_ENTRY; + if (isymp->n_sclass == C_AIX_WEAKEXT) + ldsym->l_smtype |= L_WEAK; ldsym->l_smclas = aux.x_csect.x_smclas; @@ -3584,184 +4261,82 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, } } - *indexp = -1; - - skip = FALSE; - require = FALSE; - add = 1 + isym.n_numaux; - - /* If we are skipping this csect, we want to skip this symbol. */ - if (*csectpp == NULL) - skip = TRUE; - - /* If we garbage collected this csect, we want to skip this - symbol. */ - if (! skip - && xcoff_hash_table (finfo->info)->gc - && ((*csectpp)->flags & SEC_MARK) == 0 - && *csectpp != bfd_abs_section_ptr) - skip = TRUE; - - /* An XCOFF linker always skips C_STAT symbols. */ - if (! skip - && isymp->n_sclass == C_STAT) - skip = TRUE; - - /* We skip all but the first TOC anchor. */ - if (! skip - && isymp->n_sclass == C_HIDEXT - && aux.x_csect.x_smclas == XMC_TC0) - { - if (finfo->toc_symindx != -1) - skip = TRUE; - else - { - bfd_vma tocval, tocend; - bfd *inp; - - tocval = ((*csectpp)->output_section->vma - + (*csectpp)->output_offset - + isym.n_value - - (*csectpp)->vma); - - /* We want to find out if tocval is a good value to use - as the TOC anchor--that is, whether we can access all - of the TOC using a 16 bit offset from tocval. This - test assumes that the TOC comes at the end of the - output section, as it does in the default linker - script. */ - tocend = ((*csectpp)->output_section->vma - + (*csectpp)->output_section->size); - for (inp = finfo->info->input_bfds; - inp != NULL; - inp = inp->link_next) - { - - for (o = inp->sections; o != NULL; o = o->next) - if (strcmp (o->name, ".tocbss") == 0) - { - bfd_vma new_toc_end; - new_toc_end = (o->output_section->vma - + o->output_offset - + o->size); - if (new_toc_end > tocend) - tocend = new_toc_end; - } - - } - - if (tocval + 0x10000 < tocend) - { - (*_bfd_error_handler) - (_("TOC overflow: 0x%lx > 0x10000; try -mminimal-toc when compiling"), - (unsigned long) (tocend - tocval)); - bfd_set_error (bfd_error_file_too_big); - return FALSE; - } - - if (tocval + 0x8000 < tocend) - { - bfd_vma tocadd; + add = 1 + isymp->n_numaux; - tocadd = tocend - (tocval + 0x8000); - tocval += tocadd; - isym.n_value += tocadd; - } + if (*debug_index == -2) + /* We've decided to strip this symbol. */ + *indexp = -1; + else + { + /* Assign the next unused index to this symbol. */ + *indexp = output_index; - finfo->toc_symindx = output_index; - xcoff_data (finfo->output_bfd)->toc = tocval; - xcoff_data (finfo->output_bfd)->sntoc = - (*csectpp)->output_section->target_index; - require = TRUE; + if (EXTERN_SYM_P (isymp->n_sclass)) + { + BFD_ASSERT (*sym_hash != NULL); + (*sym_hash)->indx = output_index; + } + /* If this is a symbol in the TOC which we may have merged + (class XMC_TC), remember the symbol index of the TOC + symbol. */ + if (isymp->n_sclass == C_HIDEXT + && aux.x_csect.x_smclas == XMC_TC + && *sym_hash != NULL) + { + BFD_ASSERT (((*sym_hash)->flags & XCOFF_SET_TOC) == 0); + BFD_ASSERT ((*sym_hash)->toc_section != NULL); + (*sym_hash)->u.toc_indx = output_index; } - } - /* If we are stripping all symbols, we want to skip this one. */ - if (! skip - && finfo->info->strip == strip_all) - skip = TRUE; - - /* We can skip resolved external references. */ - if (! skip - && isym.n_sclass == C_EXT - && smtyp == XTY_ER - && (*sym_hash)->root.type != bfd_link_hash_undefined) - skip = TRUE; - - /* We can skip common symbols if they got defined somewhere - else. */ - if (! skip - && isym.n_sclass == C_EXT - && smtyp == XTY_CM - && ((*sym_hash)->root.type != bfd_link_hash_common - || (*sym_hash)->root.u.c.p->section != *csectpp) - && ((*sym_hash)->root.type != bfd_link_hash_defined - || (*sym_hash)->root.u.def.section != *csectpp)) - skip = TRUE; - - /* Skip local symbols if we are discarding them. */ - if (! skip - && finfo->info->discard == discard_all - && isym.n_sclass != C_EXT - && (isym.n_sclass != C_HIDEXT - || smtyp != XTY_SD)) - skip = TRUE; - - /* If we stripping debugging symbols, and this is a debugging - symbol, then skip it. */ - if (! skip - && finfo->info->strip == strip_debugger - && isym.n_scnum == N_DEBUG) - skip = TRUE; - - /* If some symbols are stripped based on the name, work out the - name and decide whether to skip this symbol. We don't handle - this correctly for symbols whose names are in the .debug - section; to get it right we would need a new bfd_strtab_hash - function to return the string given the index. */ - if (! skip - && (finfo->info->strip == strip_some - || finfo->info->discard == discard_l) - && (debug_index == NULL || *debug_index == (unsigned long) -1)) - { - const char *name; - char buf[SYMNMLEN + 1]; + output_index += add; + } - name = _bfd_coff_internal_syment_name (input_bfd, &isym, buf); + esym += add * isymesz; + isymp += add; + csectpp += add; + sym_hash += add; + debug_index += add; + ++indexp; + for (--add; add > 0; --add) + *indexp++ = -1; + } - if (name == NULL) - return FALSE; + /* Now write out the symbols that we decided to keep. */ - if ((finfo->info->strip == strip_some - && (bfd_hash_lookup (finfo->info->keep_hash, name, FALSE, - FALSE) == NULL)) - || (finfo->info->discard == discard_l - && (isym.n_sclass != C_EXT - && (isym.n_sclass != C_HIDEXT - || smtyp != XTY_SD)) - && bfd_is_local_label_name (input_bfd, name))) - skip = TRUE; - } + esym = (bfd_byte *) obj_coff_external_syms (input_bfd); + esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz; + sym_hash = obj_xcoff_sym_hashes (input_bfd); + isymp = finfo->internal_syms; + indexp = finfo->sym_indices; + csectpp = xcoff_data (input_bfd)->csects; + lineno_counts = xcoff_data (input_bfd)->lineno_counts; + debug_index = xcoff_data (input_bfd)->debug_indices; + outsym = finfo->outsyms; + incls = 0; + oline = NULL; + while (esym < esym_end) + { + int add; - /* We can not skip the first TOC anchor. */ - if (skip - && require - && finfo->info->strip != strip_all) - skip = FALSE; + add = 1 + isymp->n_numaux; - /* We now know whether we are to skip this symbol or not. */ - if (! skip) + if (*indexp < 0) + esym += add * isymesz; + else { - /* Adjust the symbol in order to output it. */ + struct internal_syment isym; + int i; + /* Adjust the symbol in order to output it. */ + isym = *isymp; if (isym._n._n_n._n_zeroes == 0 && isym._n._n_n._n_offset != 0) { /* This symbol has a long name. Enter it in the string table we are building. If *debug_index != -1, the name has already been entered in the .debug section. */ - if (debug_index != NULL && *debug_index != (unsigned long) -1) + if (*debug_index >= 0) isym._n._n_n._n_offset = *debug_index; else { @@ -3779,16 +4354,15 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, } } - if (isym.n_sclass != C_BSTAT - && isym.n_sclass != C_ESTAT - && isym.n_sclass != C_DECL - && isym.n_scnum > 0) - { - isym.n_scnum = (*csectpp)->output_section->target_index; - isym.n_value += ((*csectpp)->output_section->vma - + (*csectpp)->output_offset - - (*csectpp)->vma); - } + /* Make __rtinit C_HIDEXT rather than C_EXT. This avoids + multiple definition problems when linking a shared object + statically. (The native linker doesn't enter __rtinit into + the normal table at all, but having a local symbol can make + the objdump output easier to read.) */ + if (isym.n_sclass == C_EXT + && *sym_hash + && ((*sym_hash)->flags & XCOFF_RTINIT) != 0) + isym.n_sclass = C_HIDEXT; /* The value of a C_FILE symbol is the symbol index of the next C_FILE symbol. The value of the last C_FILE symbol @@ -3798,10 +4372,10 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, if (isym.n_sclass == C_FILE) { if (finfo->last_file_index != -1 - && finfo->last_file.n_value != (bfd_vma) output_index) + && finfo->last_file.n_value != (bfd_vma) *indexp) { /* We must correct the value of the last C_FILE entry. */ - finfo->last_file.n_value = output_index; + finfo->last_file.n_value = *indexp; if ((bfd_size_type) finfo->last_file_index >= syment_base) { /* The last C_FILE symbol is in this input file. */ @@ -3832,7 +4406,7 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, } } - finfo->last_file_index = output_index; + finfo->last_file_index = *indexp; finfo->last_file = isym; } @@ -3845,84 +4419,12 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, isym.n_value = finfo->line_filepos; ++incls; } - - /* Output the symbol. */ - - bfd_coff_swap_sym_out (output_bfd, (void *) &isym, (void *) outsym); - - *indexp = output_index; - - if (isym.n_sclass == C_EXT) - { - long indx; - struct xcoff_link_hash_entry *h; - - indx = ((esym - (bfd_byte *) obj_coff_external_syms (input_bfd)) - / isymesz); - h = obj_xcoff_sym_hashes (input_bfd)[indx]; - BFD_ASSERT (h != NULL); - h->indx = output_index; - } - - /* If this is a symbol in the TOC which we may have merged - (class XMC_TC), remember the symbol index of the TOC - symbol. */ - if (isym.n_sclass == C_HIDEXT - && aux.x_csect.x_smclas == XMC_TC - && *sym_hash != NULL) - { - BFD_ASSERT (((*sym_hash)->flags & XCOFF_SET_TOC) == 0); - BFD_ASSERT ((*sym_hash)->toc_section != NULL); - (*sym_hash)->u.toc_indx = output_index; - } - - output_index += add; - outsym += add * osymesz; - } - - esym += add * isymesz; - isymp += add; - csectpp += add; - sym_hash += add; - if (debug_index != NULL) - debug_index += add; - ++indexp; - for (--add; add > 0; --add) - *indexp++ = -1; - } - - /* Fix up the aux entries and the C_BSTAT symbols. This must be - done in a separate pass, because we don't know the correct symbol - indices until we have already decided which symbols we are going - to keep. */ - - esym = (bfd_byte *) obj_coff_external_syms (input_bfd); - esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz; - isymp = finfo->internal_syms; - indexp = finfo->sym_indices; - csectpp = xcoff_data (input_bfd)->csects; - outsym = finfo->outsyms; - while (esym < esym_end) - { - int add; - - add = 1 + isymp->n_numaux; - - if (*indexp < 0) - esym += add * isymesz; - else - { - int i; - - if (isymp->n_sclass == C_BSTAT) + /* The value of a C_BSTAT symbol is the symbol table + index of the containing csect. */ + else if (isym.n_sclass == C_BSTAT) { - struct internal_syment isym; - bfd_vma indx; - /* The value of a C_BSTAT symbol is the symbol table - index of the containing csect. */ - bfd_coff_swap_sym_in (output_bfd, (void *) outsym, (void *) &isym); indx = isym.n_value; if (indx < obj_raw_syment_count (input_bfd)) { @@ -3933,10 +4435,20 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, isym.n_value = 0; else isym.n_value = symindx; - bfd_coff_swap_sym_out (output_bfd, (void *) &isym, - (void *) outsym); } } + else if (isym.n_sclass != C_ESTAT + && isym.n_sclass != C_DECL + && isym.n_scnum > 0) + { + isym.n_scnum = (*csectpp)->output_section->target_index; + isym.n_value += ((*csectpp)->output_section->vma + + (*csectpp)->output_offset + - (*csectpp)->vma); + } + + /* Output the symbol. */ + bfd_coff_swap_sym_out (output_bfd, (void *) &isym, (void *) outsym); esym += isymesz; outsym += osymesz; @@ -3976,8 +4488,7 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, aux.x_file.x_n.x_offset = STRING_SIZE_SIZE + indx; } } - else if ((isymp->n_sclass == C_EXT - || isymp->n_sclass == C_HIDEXT) + else if (CSECT_SYM_P (isymp->n_sclass) && i + 1 == isymp->n_numaux) { @@ -4056,15 +4567,13 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, /* Copy over the line numbers, unless we are stripping them. We do this on a symbol by symbol basis in order to more easily handle garbage collection. */ - if ((isymp->n_sclass == C_EXT - || isymp->n_sclass == C_HIDEXT) + if (CSECT_SYM_P (isymp->n_sclass) && i == 0 && isymp->n_numaux > 1 && ISFCN (isymp->n_type) && aux.x_sym.x_fcnary.x_fcn.x_lnnoptr != 0) { - if (finfo->info->strip != strip_none - && finfo->info->strip != strip_some) + if (*lineno_counts == 0) aux.x_sym.x_fcnary.x_fcn.x_lnnoptr = 0; else { @@ -4072,14 +4581,21 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, unsigned int enc_count; bfd_signed_vma linoff; struct internal_lineno lin; + bfd_byte *linp; + bfd_byte *linpend; + bfd_vma offset; + file_ptr pos; + bfd_size_type amt; + /* Read in the enclosing section's line-number + information, if we haven't already. */ o = *csectpp; enclosing = xcoff_section_data (abfd, o)->enclosing; enc_count = xcoff_section_data (abfd, o)->lineno_count; if (oline != enclosing) { - file_ptr pos = enclosing->line_filepos; - bfd_size_type amt = linesz * enc_count; + pos = enclosing->line_filepos; + amt = linesz * enc_count; if (bfd_seek (input_bfd, pos, SEEK_SET) != 0 || (bfd_bread (finfo->linenos, amt, input_bfd) != amt)) @@ -4087,114 +4603,82 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, oline = enclosing; } + /* Copy across the first entry, adjusting its + symbol index. */ linoff = (aux.x_sym.x_fcnary.x_fcn.x_lnnoptr - enclosing->line_filepos); - - bfd_coff_swap_lineno_in (input_bfd, - (void *) (finfo->linenos + linoff), - (void *) &lin); - if (lin.l_lnno != 0 - || ((bfd_size_type) lin.l_addr.l_symndx - != ((esym - - isymesz - - ((bfd_byte *) - obj_coff_external_syms (input_bfd))) - / isymesz))) - aux.x_sym.x_fcnary.x_fcn.x_lnnoptr = 0; - else + linp = finfo->linenos + linoff; + bfd_coff_swap_lineno_in (input_bfd, linp, &lin); + lin.l_addr.l_symndx = *indexp; + bfd_coff_swap_lineno_out (output_bfd, &lin, linp); + + /* Copy the other entries, adjusting their addresses. */ + linpend = linp + *lineno_counts * linesz; + offset = (o->output_section->vma + + o->output_offset + - o->vma); + for (linp += linesz; linp < linpend; linp += linesz) { - bfd_byte *linpend, *linp; - bfd_vma offset; - bfd_size_type count; - - lin.l_addr.l_symndx = *indexp; - bfd_coff_swap_lineno_out (output_bfd, (void *) &lin, - (void *) (finfo->linenos - + linoff)); - - linpend = (finfo->linenos - + enc_count * linesz); - offset = (o->output_section->vma - + o->output_offset - - o->vma); - for (linp = finfo->linenos + linoff + linesz; - linp < linpend; - linp += linesz) - { - bfd_coff_swap_lineno_in (input_bfd, (void *) linp, - (void *) &lin); - if (lin.l_lnno == 0) - break; - lin.l_addr.l_paddr += offset; - bfd_coff_swap_lineno_out (output_bfd, - (void *) &lin, - (void *) linp); - } - - count = (linp - (finfo->linenos + linoff)) / linesz; + bfd_coff_swap_lineno_in (input_bfd, linp, &lin); + lin.l_addr.l_paddr += offset; + bfd_coff_swap_lineno_out (output_bfd, &lin, linp); + } - aux.x_sym.x_fcnary.x_fcn.x_lnnoptr = - (o->output_section->line_filepos + /* Write out the entries we've just processed. */ + pos = (o->output_section->line_filepos + o->output_section->lineno_count * linesz); + amt = linesz * *lineno_counts; + if (bfd_seek (output_bfd, pos, SEEK_SET) != 0 + || bfd_bwrite (finfo->linenos + linoff, + amt, output_bfd) != amt) + return FALSE; + o->output_section->lineno_count += *lineno_counts; - if (bfd_seek (output_bfd, - aux.x_sym.x_fcnary.x_fcn.x_lnnoptr, - SEEK_SET) != 0 - || (bfd_bwrite (finfo->linenos + linoff, - linesz * count, output_bfd) - != linesz * count)) - return FALSE; - - o->output_section->lineno_count += count; + /* Record the offset of the symbol's line numbers + in the output file. */ + aux.x_sym.x_fcnary.x_fcn.x_lnnoptr = pos; - if (incls > 0) + if (incls > 0) + { + struct internal_syment *iisp, *iispend; + long *iindp; + bfd_byte *oos; + bfd_vma range_start, range_end; + int iiadd; + + /* Update any C_BINCL or C_EINCL symbols + that refer to a line number in the + range we just output. */ + iisp = finfo->internal_syms; + iispend = iisp + obj_raw_syment_count (input_bfd); + iindp = finfo->sym_indices; + oos = finfo->outsyms; + range_start = enclosing->line_filepos + linoff; + range_end = range_start + *lineno_counts * linesz; + while (iisp < iispend) { - struct internal_syment *iisp, *iispend; - long *iindp; - bfd_byte *oos; - int iiadd; - - /* Update any C_BINCL or C_EINCL symbols - that refer to a line number in the - range we just output. */ - iisp = finfo->internal_syms; - iispend = (iisp - + obj_raw_syment_count (input_bfd)); - iindp = finfo->sym_indices; - oos = finfo->outsyms; - while (iisp < iispend) + if (*iindp >= 0 + && (iisp->n_sclass == C_BINCL + || iisp->n_sclass == C_EINCL) + && iisp->n_value >= range_start + && iisp->n_value < range_end) { - if (*iindp >= 0 - && (iisp->n_sclass == C_BINCL - || iisp->n_sclass == C_EINCL) - && ((bfd_size_type) iisp->n_value - >= (bfd_size_type)(enclosing->line_filepos + linoff)) - && ((bfd_size_type) iisp->n_value - < (enclosing->line_filepos - + enc_count * linesz))) - { - struct internal_syment iis; - - bfd_coff_swap_sym_in (output_bfd, - (void *) oos, - (void *) &iis); - iis.n_value = - (iisp->n_value - - enclosing->line_filepos - - linoff - + aux.x_sym.x_fcnary.x_fcn.x_lnnoptr); - bfd_coff_swap_sym_out (output_bfd, - (void *) &iis, - (void *) oos); - --incls; - } - - iiadd = 1 + iisp->n_numaux; - if (*iindp >= 0) - oos += iiadd * osymesz; - iisp += iiadd; - iindp += iiadd; + struct internal_syment iis; + + bfd_coff_swap_sym_in (output_bfd, oos, &iis); + iis.n_value = (iisp->n_value + - range_start + + pos); + bfd_coff_swap_sym_out (output_bfd, + &iis, oos); + --incls; } + + iiadd = 1 + iisp->n_numaux; + if (*iindp >= 0) + oos += iiadd * osymesz; + iisp += iiadd; + iindp += iiadd; } } } @@ -4208,9 +4692,12 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, } } + sym_hash += add; indexp += add; isymp += add; csectpp += add; + lineno_counts += add; + debug_index += add; } /* If we swapped out a C_FILE symbol, guess that the next C_FILE @@ -4312,8 +4799,6 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, for (; irel < irelend; irel++, rel_hash++) { struct xcoff_link_hash_entry *h = NULL; - struct internal_ldrel ldrel; - bfd_boolean quiet; *rel_hash = NULL; @@ -4446,104 +4931,20 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, } } - quiet = FALSE; - switch (irel->r_type) + if (xcoff_need_ldrel_p (finfo->info, irel, h)) { - 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) - break; - /* Fall through. */ - case R_POS: - case R_NEG: - case R_RL: - case R_RLA: - /* This reloc needs to be copied into the .loader - section. */ - ldrel.l_vaddr = irel->r_vaddr; - if (r_symndx == -1) - ldrel.l_symndx = -(bfd_size_type ) 1; - else if (h == NULL - || (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak - || h->root.type == bfd_link_hash_common)) - { - asection *sec; + asection *sec; - if (h == NULL) - sec = xcoff_data (input_bfd)->csects[r_symndx]; - else if (h->root.type == bfd_link_hash_common) - sec = h->root.u.c.p->section; - else - sec = h->root.u.def.section; - sec = sec->output_section; - - if (strcmp (sec->name, ".text") == 0) - ldrel.l_symndx = 0; - else if (strcmp (sec->name, ".data") == 0) - ldrel.l_symndx = 1; - else if (strcmp (sec->name, ".bss") == 0) - ldrel.l_symndx = 2; - else - { - (*_bfd_error_handler) - (_("%B: loader reloc in unrecognized section `%A'"), - input_bfd, sec); - bfd_set_error (bfd_error_nonrepresentable_section); - return FALSE; - } - } + if (r_symndx == -1) + sec = NULL; + else if (h == NULL) + sec = xcoff_data (input_bfd)->csects[r_symndx]; else - { - if (! finfo->info->relocatable - && (h->flags & XCOFF_DEF_DYNAMIC) == 0 - && (h->flags & XCOFF_IMPORT) == 0) - { - /* We already called the undefined_symbol - callback for this relocation, in - _bfd_ppc_xcoff_relocate_section. Don't - issue any more warnings. */ - quiet = TRUE; - } - if (h->ldindx < 0 && ! quiet) - { - (*_bfd_error_handler) - (_("%B: `%s' in loader reloc but not loader sym"), - input_bfd, - h->root.root.string); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - ldrel.l_symndx = h->ldindx; - } - ldrel.l_rtype = (irel->r_size << 8) | irel->r_type; - ldrel.l_rsecnm = o->output_section->target_index; - if (xcoff_hash_table (finfo->info)->textro - && strcmp (o->output_section->name, ".text") == 0 - && ! quiet) - { - (*_bfd_error_handler) - (_("%B: loader reloc in read-only section %A"), - input_bfd, o->output_section); - bfd_set_error (bfd_error_invalid_operation); - return FALSE; - } - bfd_xcoff_swap_ldrel_out (output_bfd, &ldrel, - finfo->ldrel); - - finfo->ldrel += bfd_xcoff_ldrelsz(output_bfd); - 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; + sec = xcoff_symbol_section (h); + if (!xcoff_create_ldrel (output_bfd, finfo, + o->output_section, input_bfd, + irel, sec, h)) + return FALSE; } } @@ -4587,6 +4988,144 @@ xcoff_sort_relocs (const void * p1, const void * p2) return 0; } +/* Return true if section SEC is a TOC section. */ + +static inline bfd_boolean +xcoff_toc_section_p (asection *sec) +{ + const char *name; + + name = sec->name; + if (name[0] == '.' && name[1] == 't') + { + if (name[2] == 'c') + { + if (name[3] == '0' && name[4] == 0) + return TRUE; + if (name[3] == 0) + return TRUE; + } + if (name[2] == 'd' && name[3] == 0) + return TRUE; + } + return FALSE; +} + +/* See if the link requires a TOC (it usually does!). If so, find a + good place to put the TOC anchor csect, and write out the associated + symbol. */ + +static bfd_boolean +xcoff_find_tc0 (bfd *output_bfd, struct xcoff_final_link_info *finfo) +{ + bfd_vma toc_start, toc_end, start, end, best_address; + asection *sec; + bfd *input_bfd; + int section_index; + struct internal_syment irsym; + union internal_auxent iraux; + file_ptr pos; + size_t size; + + /* Set [TOC_START, TOC_END) to the range of the TOC. Record the + index of a csect at the beginning of the TOC. */ + toc_start = ~(bfd_vma) 0; + toc_end = 0; + section_index = -1; + for (input_bfd = finfo->info->input_bfds; + input_bfd != NULL; + input_bfd = input_bfd->link_next) + for (sec = input_bfd->sections; sec != NULL; sec = sec->next) + if ((sec->flags & SEC_MARK) != 0 && xcoff_toc_section_p (sec)) + { + start = sec->output_section->vma + sec->output_offset; + if (toc_start > start) + { + toc_start = start; + section_index = sec->output_section->target_index; + } + + end = start + sec->size; + if (toc_end < end) + toc_end = end; + } + + /* There's no need for a TC0 symbol if we don't have a TOC. */ + if (toc_end < toc_start) + { + xcoff_data (output_bfd)->toc = toc_start; + return TRUE; + } + + if (toc_end - toc_start < 0x8000) + /* Every TOC csect can be accessed from TOC_START. */ + best_address = toc_start; + else + { + /* Find the lowest TOC csect that is still within range of TOC_END. */ + best_address = toc_end; + for (input_bfd = finfo->info->input_bfds; + input_bfd != NULL; + input_bfd = input_bfd->link_next) + for (sec = input_bfd->sections; sec != NULL; sec = sec->next) + if ((sec->flags & SEC_MARK) != 0 && xcoff_toc_section_p (sec)) + { + start = sec->output_section->vma + sec->output_offset; + if (start < best_address + && start + 0x8000 >= toc_end) + { + best_address = start; + section_index = sec->output_section->target_index; + } + } + + /* Make sure that the start of the TOC is also within range. */ + if (best_address > toc_start + 0x8000) + { + (*_bfd_error_handler) + (_("TOC overflow: 0x%lx > 0x10000; try -mminimal-toc " + "when compiling"), + (unsigned long) (toc_end - toc_start)); + bfd_set_error (bfd_error_file_too_big); + return FALSE; + } + } + + /* Record the chosen TOC value. */ + finfo->toc_symindx = obj_raw_syment_count (output_bfd); + xcoff_data (output_bfd)->toc = best_address; + xcoff_data (output_bfd)->sntoc = section_index; + + /* Fill out the TC0 symbol. */ + if (!bfd_xcoff_put_symbol_name (output_bfd, finfo->strtab, &irsym, "TOC")) + return FALSE; + irsym.n_value = best_address; + irsym.n_scnum = section_index; + irsym.n_sclass = C_HIDEXT; + irsym.n_type = T_NULL; + irsym.n_numaux = 1; + bfd_coff_swap_sym_out (output_bfd, &irsym, finfo->outsyms); + + /* Fill out the auxillary csect information. */ + memset (&iraux, 0, sizeof iraux); + iraux.x_csect.x_smtyp = XTY_SD; + iraux.x_csect.x_smclas = XMC_TC0; + iraux.x_csect.x_scnlen.l = 0; + bfd_coff_swap_aux_out (output_bfd, &iraux, T_NULL, C_HIDEXT, 0, 1, + finfo->outsyms + bfd_coff_symesz (output_bfd)); + + /* Write the contents to the file. */ + pos = obj_sym_filepos (output_bfd); + pos += obj_raw_syment_count (output_bfd) * bfd_coff_symesz (output_bfd); + size = 2 * bfd_coff_symesz (output_bfd); + if (bfd_seek (output_bfd, pos, SEEK_SET) != 0 + || bfd_bwrite (finfo->outsyms, size, output_bfd) != size) + return FALSE; + obj_raw_syment_count (output_bfd) += 2; + + return TRUE; +} + /* Write out a non-XCOFF global symbol. */ static bfd_boolean @@ -4762,7 +5301,6 @@ xcoff_write_global_symbol (struct xcoff_link_hash_entry *h, void * inf) asection *osec; int oindx; struct internal_reloc *irel; - struct internal_ldrel ldrel; struct internal_syment irsym; union internal_auxent iraux; @@ -4815,12 +5353,9 @@ xcoff_write_global_symbol (struct xcoff_link_hash_entry *h, void * inf) finfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL; ++osec->reloc_count; - ldrel.l_vaddr = irel->r_vaddr; - ldrel.l_symndx = h->ldindx; - ldrel.l_rtype = (irel->r_size << 8) | R_POS; - ldrel.l_rsecnm = oindx; - bfd_xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel); - finfo->ldrel += bfd_xcoff_ldrelsz(output_bfd); + if (!xcoff_create_ldrel (output_bfd, finfo, osec, + output_bfd, irel, NULL, h)) + return FALSE; /* We need to emit a symbol to define a csect which holds the reloc. */ @@ -4886,7 +5421,6 @@ xcoff_write_global_symbol (struct xcoff_link_hash_entry *h, void * inf) struct xcoff_link_hash_entry *hentry; asection *esec; struct internal_reloc *irel; - struct internal_ldrel ldrel; asection *tsec; unsigned int reloc_size, byte_size; @@ -4924,26 +5458,9 @@ xcoff_write_global_symbol (struct xcoff_link_hash_entry *h, void * inf) finfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL; ++osec->reloc_count; - ldrel.l_vaddr = irel->r_vaddr; - if (strcmp (esec->output_section->name, ".text") == 0) - ldrel.l_symndx = 0; - else if (strcmp (esec->output_section->name, ".data") == 0) - ldrel.l_symndx = 1; - else if (strcmp (esec->output_section->name, ".bss") == 0) - ldrel.l_symndx = 2; - else - { - (*_bfd_error_handler) - (_("%s: loader reloc in unrecognized section `%s'"), - bfd_get_filename (output_bfd), - esec->output_section->name); - bfd_set_error (bfd_error_nonrepresentable_section); - return FALSE; - } - ldrel.l_rtype = (reloc_size << 8) | R_POS; - ldrel.l_rsecnm = oindx; - bfd_xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel); - finfo->ldrel += bfd_xcoff_ldrelsz(output_bfd); + if (!xcoff_create_ldrel (output_bfd, finfo, osec, + output_bfd, irel, esec, NULL)) + return FALSE; /* There are three items to write out, the address of the code @@ -4986,26 +5503,9 @@ xcoff_write_global_symbol (struct xcoff_link_hash_entry *h, void * inf) finfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL; ++osec->reloc_count; - ldrel.l_vaddr = irel->r_vaddr; - if (strcmp (tsec->output_section->name, ".text") == 0) - ldrel.l_symndx = 0; - else if (strcmp (tsec->output_section->name, ".data") == 0) - ldrel.l_symndx = 1; - else if (strcmp (tsec->output_section->name, ".bss") == 0) - ldrel.l_symndx = 2; - else - { - (*_bfd_error_handler) - (_("%s: loader reloc in unrecognized section `%s'"), - bfd_get_filename (output_bfd), - tsec->output_section->name); - bfd_set_error (bfd_error_nonrepresentable_section); - return FALSE; - } - ldrel.l_rtype = (reloc_size << 8) | R_POS; - ldrel.l_rsecnm = oindx; - bfd_xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel); - finfo->ldrel += bfd_xcoff_ldrelsz(output_bfd); + if (!xcoff_create_ldrel (output_bfd, finfo, osec, + output_bfd, irel, tsec, NULL)) + return FALSE; } if (h->indx >= 0 || finfo->info->strip == strip_all) @@ -5045,7 +5545,11 @@ xcoff_write_global_symbol (struct xcoff_link_hash_entry *h, void * inf) { isym.n_value = 0; isym.n_scnum = N_UNDEF; - isym.n_sclass = C_EXT; + if (h->root.type == bfd_link_hash_undefweak + && C_WEAKEXT == C_AIX_WEAKEXT) + isym.n_sclass = C_WEAKEXT; + else + isym.n_sclass = C_EXT; aux.x_csect.x_smtyp = XTY_ER; } else if ((h->root.type == bfd_link_hash_defined @@ -5055,7 +5559,11 @@ xcoff_write_global_symbol (struct xcoff_link_hash_entry *h, void * inf) BFD_ASSERT (bfd_is_abs_section (h->root.u.def.section)); isym.n_value = h->root.u.def.value; isym.n_scnum = N_UNDEF; - isym.n_sclass = C_EXT; + if (h->root.type == bfd_link_hash_undefweak + && C_WEAKEXT == C_AIX_WEAKEXT) + isym.n_sclass = C_WEAKEXT; + else + isym.n_sclass = C_EXT; aux.x_csect.x_smtyp = XTY_ER; } else if (h->root.type == bfd_link_hash_defined @@ -5117,7 +5625,11 @@ xcoff_write_global_symbol (struct xcoff_link_hash_entry *h, void * inf) /* We just output an SD symbol. Now output an LD symbol. */ h->indx += 2; - isym.n_sclass = C_EXT; + if (h->root.type == bfd_link_hash_undefweak + && C_WEAKEXT == C_AIX_WEAKEXT) + isym.n_sclass = C_WEAKEXT; + else + isym.n_sclass = C_EXT; bfd_coff_swap_sym_out (output_bfd, (void *) &isym, (void *) outsym); outsym += bfd_coff_symesz (output_bfd); @@ -5155,7 +5667,6 @@ xcoff_reloc_link_order (bfd *output_bfd, bfd_vma addend; struct internal_reloc *irel; struct xcoff_link_hash_entry **rel_hash_ptr; - struct internal_ldrel ldrel; if (link_order->type == bfd_section_reloc_link_order) /* We need to somehow locate a symbol in the right section. The @@ -5183,22 +5694,12 @@ xcoff_reloc_link_order (bfd *output_bfd, return TRUE; } - if (h->root.type == bfd_link_hash_common) - { - hsec = h->root.u.c.p->section; - hval = 0; - } - else if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - hsec = h->root.u.def.section; - hval = h->root.u.def.value; - } + hsec = xcoff_symbol_section (h); + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + hval = h->root.u.def.value; else - { - hsec = NULL; - hval = 0; - } + hval = 0; addend = link_order->u.reloc.p->addend; if (hsec != NULL) @@ -5273,49 +5774,13 @@ xcoff_reloc_link_order (bfd *output_bfd, ++output_section->reloc_count; /* Now output the reloc to the .loader section. */ - - ldrel.l_vaddr = irel->r_vaddr; - - if (hsec != NULL) - { - const char *secname; - - secname = hsec->output_section->name; - - if (strcmp (secname, ".text") == 0) - ldrel.l_symndx = 0; - else if (strcmp (secname, ".data") == 0) - ldrel.l_symndx = 1; - else if (strcmp (secname, ".bss") == 0) - ldrel.l_symndx = 2; - else - { - (*_bfd_error_handler) - (_("%s: loader reloc in unrecognized section `%s'"), - bfd_get_filename (output_bfd), secname); - bfd_set_error (bfd_error_nonrepresentable_section); - return FALSE; - } - } - else + if (xcoff_hash_table (finfo->info)->loader_section) { - if (h->ldindx < 0) - { - (*_bfd_error_handler) - (_("%s: `%s' in loader reloc but not loader sym"), - bfd_get_filename (output_bfd), - h->root.root.string); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - ldrel.l_symndx = h->ldindx; + if (!xcoff_create_ldrel (output_bfd, finfo, output_section, + output_bfd, irel, hsec, h)) + return FALSE; } - ldrel.l_rtype = (irel->r_size << 8) | irel->r_type; - ldrel.l_rsecnm = output_section->target_index; - bfd_xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel); - finfo->ldrel += bfd_xcoff_ldrelsz(output_bfd); - return TRUE; } @@ -5361,12 +5826,20 @@ _bfd_xcoff_bfd_final_link (bfd *abfd, struct bfd_link_info *info) finfo.contents = NULL; finfo.external_relocs = NULL; - finfo.ldsym = (xcoff_hash_table (info)->loader_section->contents - + bfd_xcoff_ldhdrsz (abfd)); - finfo.ldrel = (xcoff_hash_table (info)->loader_section->contents - + bfd_xcoff_ldhdrsz(abfd) - + (xcoff_hash_table (info)->ldhdr.l_nsyms - * bfd_xcoff_ldsymsz(abfd))); + if (xcoff_hash_table (info)->loader_section) + { + finfo.ldsym = (xcoff_hash_table (info)->loader_section->contents + + bfd_xcoff_ldhdrsz (abfd)); + finfo.ldrel = (xcoff_hash_table (info)->loader_section->contents + + bfd_xcoff_ldhdrsz (abfd) + + (xcoff_hash_table (info)->ldhdr.l_nsyms + * bfd_xcoff_ldsymsz (abfd))); + } + else + { + finfo.ldsym = NULL; + finfo.ldrel = NULL; + } xcoff_data (abfd)->coff.link_info = info; @@ -5374,15 +5847,15 @@ _bfd_xcoff_bfd_final_link (bfd *abfd, struct bfd_link_info *info) if (finfo.strtab == NULL) goto error_return; - /* Count the line number and relocation entries required for the - output file. Determine a few maximum sizes. */ + /* Count the relocation entries required for the output file. + (We've already counted the line numbers.) 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->map_head.link_order; p != NULL; p = p->next) { if (p->type == bfd_indirect_link_order) @@ -5397,18 +5870,12 @@ _bfd_xcoff_bfd_final_link (bfd *abfd, struct bfd_link_info *info) 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->rawsize > max_contents_size) max_contents_size = sec->rawsize; if (sec->size > max_contents_size) max_contents_size = sec->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 @@ -5663,7 +6130,10 @@ _bfd_xcoff_bfd_final_link (bfd *abfd, struct bfd_link_info *info) goto error_return; obj_raw_syment_count (abfd) = 0; - xcoff_data (abfd)->toc = (bfd_vma) -1; + + /* Find a TOC symbol, if we need one. */ + if (!xcoff_find_tc0 (abfd, &finfo)) + 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 @@ -5856,13 +6326,16 @@ _bfd_xcoff_bfd_final_link (bfd *abfd, struct bfd_link_info *info) } /* 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, - (file_ptr) o->output_offset, o->size)) - goto error_return; + if (o) + { + BFD_ASSERT ((bfd_byte *) finfo.ldrel + == (xcoff_hash_table (info)->loader_section->contents + + xcoff_hash_table (info)->ldhdr.l_impoff)); + if (!bfd_set_section_contents (abfd, o->output_section, o->contents, + (file_ptr) o->output_offset, o->size)) + goto error_return; + } /* Write out the magic sections. */ o = xcoff_hash_table (info)->linkage_section;