X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Fxcofflink.c;h=1c2d0cbc23f25774be801e9e3f2f0de27d5b854e;hb=f1f2b5f40ef91b70acaa733f6f92f08de5efa29f;hp=aacd0782cf805309d95c0d62214a408faa5e3f3c;hpb=3df13c4a63ba23bb8e9b0b38f2dcd98d8d0b4a4b;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c index aacd0782cf..1c2d0cbc23 100644 --- a/bfd/xcofflink.c +++ b/bfd/xcofflink.c @@ -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,9 +825,6 @@ 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; @@ -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. */ @@ -792,7 +1054,8 @@ xcoff_link_create_extra_sections (bfd * abfd, struct bfd_link_info *info) 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; @@ -1087,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; @@ -1096,7 +1358,7 @@ 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 @@ -1216,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; @@ -1327,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]; @@ -1482,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; @@ -1573,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; @@ -1614,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); @@ -1627,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 @@ -1651,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->output_bfd->xvec == 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), @@ -1672,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. */ @@ -1704,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) { @@ -1723,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))) { @@ -1759,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, @@ -1781,7 +2042,9 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) { 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; @@ -2073,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]; @@ -2122,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; @@ -2132,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; @@ -2198,6 +2466,21 @@ _bfd_xcoff_bfd_link_add_symbols (bfd *abfd, struct bfd_link_info *info) } } +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) +{ + struct xcoff_link_hash_entry *h; + + 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. */ @@ -2233,69 +2516,171 @@ xcoff_find_function (struct bfd_link_info *info, } return TRUE; } - -/* 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. */ + +/* Return true if the given bfd contains at least one shared object. */ 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) +xcoff_archive_contains_shared_object_p (struct bfd_link_info *info, + bfd *archive) { - unsigned int c; - struct xcoff_import_file **pp; + struct xcoff_archive_info *archive_info; + bfd *member; - /* 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 + archive_info = xcoff_get_archive_info (info, archive); + if (!archive_info->know_contains_shared_object_p) { - /* 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); + member = bfd_openr_next_archived_file (archive, NULL); + while (member != NULL && (member->flags & DYNAMIC) == 0) + member = bfd_openr_next_archived_file (archive, member); - 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; + archive_info->contains_shared_object_p = (member != NULL); + archive_info->know_contains_shared_object_p = 1; } - return TRUE; + return archive_info->contains_shared_object_p; } - -/* 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; +/* Symbol H qualifies for export by -bexpfull. Return true if it also + qualifies for export by -bexpall. */ - h->flags |= XCOFF_MARK; +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. */ @@ -2351,6 +2736,10 @@ xcoff_mark_symbol (struct bfd_link_info *info, struct xcoff_link_hash_entry *h) /* 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 @@ -2455,6 +2844,30 @@ xcoff_mark_symbol (struct bfd_link_info *info, struct xcoff_link_hash_entry *h) 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 it, and all the sections which define symbols to which it refers. Because this function needs to look at the relocs, we also count @@ -2504,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 @@ -2512,58 +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 - && !bfd_is_und_section (rsec) - && !bfd_is_abs_section (rsec) - && (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 - /* We will always provide a local definition of - function symbols. */ - || (h->flags & XCOFF_CALLED) != 0) - break; - /* Fall through. */ - case R_POS: - case R_NEG: - case R_RL: - case R_RLA: - 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)) - break; ++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; } } @@ -2723,6 +3111,7 @@ 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; } if (!xcoff_set_import_path (info, h, imppath, impfile, impmember)) @@ -2790,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)) @@ -2823,145 +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; + ldinfo = (struct xcoff_loader_info *) data; + if (xcoff_auto_export_p (ldinfo->info, h, ldinfo->auto_export_flags)) + { + if (!xcoff_mark_symbol (ldinfo->info, h)) + ldinfo->failed = TRUE; + } + return TRUE; +} - /* __rtinit, this symbol has special handling. */ - if (h->flags & XCOFF_RTINIT) - return TRUE; +/* Add a symbol to the .loader symbols, if necessary. */ - /* 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] != '.') - { - 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; +/* INPUT_BFD has an external symbol associated with hash table entry H + and csect CSECT. Return true if INPUT_BFD defines H. */ - 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); - } - } +static bfd_boolean +xcoff_final_definition_p (bfd *input_bfd, struct xcoff_link_hash_entry *h, + asection *csect) +{ + switch (h->root.type) + { + 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; - if (export) - h->flags |= XCOFF_EXPORT; + default: + abort (); } +} - /* 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; +/* See if H should have a loader symbol associated with it. */ - /* If this symbol is exported, but not defined, we need to try to - define it. */ +static bfd_boolean +xcoff_build_ldsym (struct xcoff_loader_info *ldinfo, + struct xcoff_link_hash_entry *h) +{ + bfd_size_type amt; + + /* Warn if this symbol is exported but not defined. */ if ((h->flags & XCOFF_EXPORT) != 0 && (h->flags & XCOFF_WAS_UNDEFINED) != 0) { (*_bfd_error_handler) (_("warning: attempt to export undefined symbol `%s'"), h->root.root.string); - h->ldsym = NULL; 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 - && (! xcoff_hash_table (ldinfo->info)->gc - || (h->flags & XCOFF_MARK) != 0) - && 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; - } - /* 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. */ @@ -2976,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. */ @@ -2989,6 +3326,58 @@ xcoff_build_ldsyms (struct xcoff_link_hash_entry *h, void * p) 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; } @@ -3035,25 +3424,19 @@ xcoff_keep_symbol_p (struct bfd_link_info *info, bfd *input_bfd, if (info->strip == strip_all) return 0; - /* We can ignore external references that were resolved by the link. */ - smtyp = SMTYP_SMTYP (aux->x_csect.x_smtyp); - if (isym->n_sclass == C_EXT - && smtyp == XTY_ER - && h->root.type != bfd_link_hash_undefined) - return 0; - - /* We can ignore common symbols if they got defined somewhere else. */ - if (isym->n_sclass == C_EXT - && smtyp == XTY_CM - && (h->root.type != bfd_link_hash_common - || h->root.u.c.p->section != csect) - && (h->root.type != bfd_link_hash_defined - || h->root.u.def.section != csect)) - 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 - && isym->n_sclass != C_EXT + && !EXTERN_SYM_P (isym->n_sclass) && (isym->n_sclass != C_HIDEXT || smtyp != XTY_SD)) return 0; @@ -3081,7 +3464,7 @@ xcoff_keep_symbol_p (struct bfd_link_info *info, bfd *input_bfd, return 0; if (info->discard == discard_l - && isym->n_sclass != C_EXT + && !EXTERN_SYM_P (isym->n_sclass) && (isym->n_sclass != C_HIDEXT || smtyp != XTY_SD) && bfd_is_local_label_name (input_bfd, name)) return 0; @@ -3090,6 +3473,119 @@ xcoff_keep_symbol_p (struct bfd_link_info *info, bfd *input_bfd, 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; + } + + /* 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. @@ -3102,10 +3598,9 @@ xcoff_keep_symbol_p (struct bfd_link_info *info, bfd *input_bfd, -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, @@ -3118,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; @@ -3147,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; @@ -3161,17 +3649,9 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd, xcoff_hash_table (info)->textro = textro; xcoff_hash_table (info)->rtld = rtld; - 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; - } - /* __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; @@ -3222,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; @@ -3254,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; } @@ -3277,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) @@ -3467,9 +3869,8 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd, bfd_coff_swap_sym_in (sub, esym, &sym); - /* If this is a C_EXT or C_HIDEXT symbol, we need the csect - information too. */ - if (sym.n_sclass == C_EXT || sym.n_sclass == C_HIDEXT) + /* Read in the csect information, if any. */ + if (CSECT_SYM_P (sym.n_sclass)) { BFD_ASSERT (sym.n_numaux > 0); bfd_coff_swap_aux_in (sub, esym + symesz * sym.n_numaux, @@ -3512,6 +3913,8 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd, } else *debug_index = -1; + if (*sym_hash != 0) + (*sym_hash)->flags |= XCOFF_ALLOCATED; if (*lineno_counts > 0) csect->output_section->lineno_count += *lineno_counts; } @@ -3587,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. */ @@ -3668,9 +4156,8 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, 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, @@ -3686,11 +4173,10 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, .loader symbol information. If this is an external symbol reference to a defined symbol, though, then wait until we get to the definition. */ - if (isymp->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; @@ -3722,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; @@ -3783,7 +4271,7 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, /* Assign the next unused index to this symbol. */ *indexp = output_index; - if (isymp->n_sclass == C_EXT) + if (EXTERN_SYM_P (isymp->n_sclass)) { BFD_ASSERT (*sym_hash != NULL); (*sym_hash)->indx = output_index; @@ -3818,6 +4306,7 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, 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; @@ -3865,6 +4354,16 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, } } + /* 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 is -1. We try to get this right, below, just before we @@ -3989,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) { @@ -4069,8 +4567,7 @@ 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) @@ -4114,14 +4611,13 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, bfd_coff_swap_lineno_in (input_bfd, linp, &lin); lin.l_addr.l_symndx = *indexp; bfd_coff_swap_lineno_out (output_bfd, &lin, linp); - linp += linesz; /* Copy the other entries, adjusting their addresses. */ linpend = linp + *lineno_counts * linesz; offset = (o->output_section->vma + o->output_offset - o->vma); - for (; linp < linpend; linp += linesz) + for (linp += linesz; linp < linpend; linp += linesz) { bfd_coff_swap_lineno_in (input_bfd, linp, &lin); lin.l_addr.l_paddr += offset; @@ -4196,6 +4692,7 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, } } + sym_hash += add; indexp += add; isymp += add; csectpp += add; @@ -4302,7 +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; *rel_hash = NULL; @@ -4435,97 +4931,20 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo, } } - 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: - 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)) - break; - /* 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 (h->ldindx < 0) - { - (*_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) - { - (*_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; } } @@ -4882,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; @@ -4935,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. */ @@ -5006,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; @@ -5044,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 @@ -5106,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) @@ -5165,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 @@ -5175,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 @@ -5237,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); @@ -5275,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 @@ -5303,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) @@ -5393,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; } @@ -5481,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; @@ -5973,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;