From 2d7de17d6167ef2c7240a6886541a9e0031ed798 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 27 Oct 1995 22:20:19 +0000 Subject: [PATCH] * xcofflink.c: More improvements, mostly to fix handling of constructors and a few other special cases. * coff-rs6000.c (rs6000coff_vec): Set symbol_leading_char back to zero, reverting yesterday's change. * bfd-in.h (bfd_xcoff_link_record_set): Declare. (bfd_xcoff_link_count_reloc): Declare. (bfd_xcoff_record_link_assignment): Declare. * bfd-in2.h: Rebuild. --- bfd/ChangeLog | 11 ++ bfd/bfd-in.h | 7 + bfd/bfd-in2.h | 7 + bfd/coff-rs6000.c | 3 +- bfd/xcofflink.c | 352 ++++++++++++++++++++++++++++++++++++++-------- 5 files changed, 320 insertions(+), 60 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index e46d96bee8..74c033c562 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,14 @@ +Fri Oct 27 18:14:39 1995 Ian Lance Taylor + + * xcofflink.c: More improvements, mostly to fix handling of + constructors and a few other special cases. + * coff-rs6000.c (rs6000coff_vec): Set symbol_leading_char back to + zero, reverting yesterday's change. + * bfd-in.h (bfd_xcoff_link_record_set): Declare. + (bfd_xcoff_link_count_reloc): Declare. + (bfd_xcoff_record_link_assignment): Declare. + * bfd-in2.h: Rebuild. + start-sanitize-gm Fri Oct 27 09:41:51 1995 Stu Grossman (grossman@cygnus.com) diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h index be71f7396b..d027196c90 100644 --- a/bfd/bfd-in.h +++ b/bfd/bfd-in.h @@ -602,12 +602,19 @@ extern boolean bfd_linux_size_dynamic_sections /* XCOFF support routines for the linker. */ +extern boolean bfd_xcoff_link_record_set + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, + bfd_size_type)); extern boolean bfd_xcoff_import_symbol PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, bfd_vma, const char *, const char *, const char *)); extern boolean bfd_xcoff_export_symbol PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, boolean)); +extern boolean bfd_xcoff_link_count_reloc + PARAMS ((bfd *, struct bfd_link_info *, const char *)); +extern boolean bfd_xcoff_record_link_assignment + PARAMS ((bfd *, struct bfd_link_info *, const char *)); extern boolean bfd_xcoff_size_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *, const char *, const char *, unsigned long, unsigned long, unsigned long, boolean, diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 7747b19d21..109c1fc3db 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -602,12 +602,19 @@ extern boolean bfd_linux_size_dynamic_sections /* XCOFF support routines for the linker. */ +extern boolean bfd_xcoff_link_record_set + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, + bfd_size_type)); extern boolean bfd_xcoff_import_symbol PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, bfd_vma, const char *, const char *, const char *)); extern boolean bfd_xcoff_export_symbol PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, boolean)); +extern boolean bfd_xcoff_link_count_reloc + PARAMS ((bfd *, struct bfd_link_info *, const char *)); +extern boolean bfd_xcoff_record_link_assignment + PARAMS ((bfd *, struct bfd_link_info *, const char *)); extern boolean bfd_xcoff_size_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *, const char *, const char *, unsigned long, unsigned long, unsigned long, boolean, diff --git a/bfd/coff-rs6000.c b/bfd/coff-rs6000.c index 39ad311b0e..242381d84b 100644 --- a/bfd/coff-rs6000.c +++ b/bfd/coff-rs6000.c @@ -1353,8 +1353,7 @@ const bfd_target rs6000coff_vec = HAS_SYMS | HAS_LOCALS | WP_TEXT), (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ - /* Making the leading_char a period should make for nicer messages. */ - '.', /* leading char */ + 0, /* leading char */ '/', /* ar_pad_char */ 15, /* ar_max_namelen??? FIXMEmgo */ diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c index 843dc0676e..9674563b49 100644 --- a/bfd/xcofflink.c +++ b/bfd/xcofflink.c @@ -286,6 +286,8 @@ struct xcoff_link_hash_entry #define XCOFF_BUILT_LDSYM (01000) /* Symbol is mentioned by a section which was not garbage collected. */ #define XCOFF_MARK (02000) + /* Symbol size is recorded in size_list list from hash table. */ +#define XCOFF_HAS_SIZE (04000) /* The storage mapping class. */ unsigned char smclas; @@ -333,6 +335,14 @@ struct xcoff_link_hash_table /* Whether garbage collection was done. */ 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 we keep for each section in the output file during the @@ -345,6 +355,16 @@ struct xcoff_link_section_info /* For each reloc against a global symbol whose index was not known when the reloc was handled, the global hash table entry. */ struct xcoff_link_hash_entry **rel_hashes; + /* If there is a TOC relative reloc against a global symbol, and the + index of the TOC symbol is not known when the reloc was handled, + an entry is added to this linked list. This is not an array, + like rel_hashes, because this case is quite uncommon. */ + struct xcoff_toc_rel_hash + { + struct xcoff_toc_rel_hash *next; + struct xcoff_link_hash_entry *h; + struct internal_reloc *rel; + } *toc_rel_hashes; }; /* Information that we pass around while doing the final link step. */ @@ -1564,7 +1584,8 @@ xcoff_link_add_symbols (abfd, info) flag = XCOFF_DEF_REGULAR; (*sym_hash)->flags |= flag; - if ((*sym_hash)->smclas == XMC_UA) + if ((*sym_hash)->smclas == XMC_UA + || flag == XCOFF_DEF_REGULAR) (*sym_hash)->smclas = aux.x_csect.x_smclas; } } @@ -1850,6 +1871,40 @@ xcoff_link_add_dynamic_symbols (abfd, info) /* Routines that are called after all the input files have been handled, but before the sections are laid out in memory. */ +/* Record the number of elements in a set. This is used to output the + correct csect length. */ + +boolean +bfd_xcoff_link_record_set (output_bfd, info, harg, size) + bfd *output_bfd; + struct bfd_link_info *info; + struct bfd_link_hash_entry *harg; + bfd_size_type size; +{ + struct xcoff_link_hash_entry *h = (struct xcoff_link_hash_entry *) harg; + struct xcoff_link_size_list *n; + + /* This will hardly ever be called. I don't want to burn four bytes + per global symbol, so instead the size is kept on a linked list + attached to the hash table. */ + + n = ((struct xcoff_link_size_list *) + bfd_alloc (output_bfd, sizeof (struct xcoff_link_size_list))); + if (n == NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + n->next = xcoff_hash_table (info)->size_list; + n->h = h; + n->size = size; + xcoff_hash_table (info)->size_list = n; + + h->flags |= XCOFF_HAS_SIZE; + + return true; +} + /* Import a symbol. */ boolean @@ -1956,6 +2011,79 @@ bfd_xcoff_export_symbol (output_bfd, info, harg, syscall) return true; } +/* Count a reloc against a symbol. This is called for relocs + generated by the linker script, typically for global constructors + and destructors. */ + +boolean +bfd_xcoff_link_count_reloc (output_bfd, info, name) + bfd *output_bfd; + struct bfd_link_info *info; + const char *name; +{ + struct xcoff_link_hash_entry *h; + + h = xcoff_link_hash_lookup (xcoff_hash_table (info), name, false, false, + false); + if (h == NULL) + { + (*_bfd_error_handler) ("%s: no such symbol", name); + bfd_set_error (bfd_error_no_symbols); + return false; + } + + h->flags |= XCOFF_REF_REGULAR | XCOFF_LDREL; + ++xcoff_hash_table (info)->ldrel_count; + + /* Mark the symbol to avoid garbage collection. */ + if ((h->flags & XCOFF_MARK) == 0) + { + h->flags |= XCOFF_MARK; + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + asection *hsec; + + hsec = h->root.u.def.section; + if ((hsec->flags & SEC_MARK) == 0) + { + if (! xcoff_mark (info, hsec)) + return false; + } + } + + if (h->toc_section != NULL + && (h->toc_section->flags & SEC_MARK) == 0) + { + if (! xcoff_mark (info, h->toc_section)) + return false; + } + } + + return true; +} + +/* This function is called for each symbol to which the linker script + assigns a value. */ + +boolean +bfd_xcoff_record_link_assignment (output_bfd, info, name) + bfd *output_bfd; + struct bfd_link_info *info; + const char *name; +{ + struct xcoff_link_hash_entry *h; + + h = xcoff_link_hash_lookup (xcoff_hash_table (info), name, true, true, + false); + if (h == NULL) + return false; + + h->flags |= XCOFF_DEF_REGULAR; + + return true; +} + /* This structure is used to pass information through xcoff_link_hash_traverse. */ @@ -2904,6 +3032,7 @@ _bfd_xcoff_bfd_final_link (abfd, info) { finfo.section_info[i].relocs = NULL; finfo.section_info[i].rel_hashes = NULL; + finfo.section_info[i].toc_rel_hashes = NULL; } } @@ -3107,6 +3236,7 @@ _bfd_xcoff_bfd_final_link (abfd, info) struct internal_reloc *irel; struct internal_reloc *irelend; struct xcoff_link_hash_entry **rel_hash; + struct xcoff_toc_rel_hash *toc_rel_hash; bfd_byte *erel; if (o->reloc_count == 0) @@ -3131,6 +3261,21 @@ _bfd_xcoff_bfd_final_link (abfd, info) } } + for (toc_rel_hash = finfo.section_info[o->target_index].toc_rel_hashes; + toc_rel_hash != NULL; + toc_rel_hash = toc_rel_hash->next) + { + if (toc_rel_hash->h->u.toc_indx < 0) + { + if (! ((*info->callbacks->unattached_reloc) + (info, toc_rel_hash->h->root.root.string, + (bfd *) NULL, o, toc_rel_hash->rel->r_vaddr))) + goto error_return; + toc_rel_hash->h->u.toc_indx = 0; + } + toc_rel_hash->rel->r_symndx = toc_rel_hash->h->u.toc_indx; + } + /* XCOFF requires that the relocs be sorted by address. We tend to produce them in the order in which their containing csects appear in the symbol table, which is not necessarily by @@ -4082,18 +4227,27 @@ xcoff_link_input_bfd (finfo, input_bfd) not the symbol itself. */ BFD_ASSERT (h->toc_section != NULL); BFD_ASSERT ((h->flags & XCOFF_SET_TOC) == 0); - if (h->u.toc_indx == -1) + if (h->u.toc_indx != -1) + irel->r_symndx = h->u.toc_indx; + else { - /* We could handle this case if we had to, - but I don't think it can arise. */ - (*_bfd_error_handler) - ("%s: unattached TOC reloc against `%s'", - bfd_get_filename (input_bfd), - h->root.root.string); - bfd_set_error (bfd_error_bad_value); - return false; + struct xcoff_toc_rel_hash *n; + struct xcoff_link_section_info *si; + + n = ((struct xcoff_toc_rel_hash *) + bfd_alloc (finfo->output_bfd, + sizeof (struct xcoff_toc_rel_hash))); + if (n == NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + si = finfo->section_info + target_index; + n->next = si->toc_rel_hashes; + n->h = h; + n->rel = irel; + si->toc_rel_hashes = n; } - irel->r_symndx = h->u.toc_indx; } else if (h != NULL) { @@ -4493,13 +4647,37 @@ xcoff_write_global_symbol (h, p) else if (h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) { + struct xcoff_link_size_list *l; + isym.n_value = (h->root.u.def.section->output_section->vma + h->root.u.def.section->output_offset + h->root.u.def.value); isym.n_scnum = h->root.u.def.section->output_section->target_index; isym.n_sclass = C_HIDEXT; aux.x_csect.x_smtyp = XTY_SD; - /* I don't know what the csect length should be in this case. */ + + if ((h->flags & XCOFF_HAS_SIZE) != 0) + { + for (l = xcoff_hash_table (finfo->info)->size_list; + l != NULL; + l = l->next) + { + if (l->h == h) + { + aux.x_csect.x_scnlen.l = l->size; + break; + } + } + } + } + else if (h->root.type == bfd_link_hash_common) + { + isym.n_value = (h->root.u.c.p->section->output_section->vma + + h->root.u.c.p->section->output_offset); + isym.n_scnum = h->root.u.c.p->section->output_section->target_index; + isym.n_sclass = C_EXT; + aux.x_csect.x_smtyp = XTY_CM; + aux.x_csect.x_scnlen.l = h->root.u.c.size; } else abort (); @@ -4559,8 +4737,22 @@ xcoff_reloc_link_order (output_bfd, finfo, output_section, link_order) struct bfd_link_order *link_order; { reloc_howto_type *howto; + struct xcoff_link_hash_entry *h; + asection *hsec; + bfd_vma hval; + 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 + symbol must either have a value of zero, or we must adjust + the addend by the value of the symbol. FIXME: Write this + when we need it. The old linker couldn't handle this anyhow. */ + abort (); + } howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc); if (howto == NULL) @@ -4569,7 +4761,42 @@ xcoff_reloc_link_order (output_bfd, finfo, output_section, link_order) return false; } - if (link_order->u.reloc.p->addend != 0) + h = xcoff_link_hash_lookup (xcoff_hash_table (finfo->info), + link_order->u.reloc.p->u.name, + false, false, true); + if (h == NULL) + { + if (! ((*finfo->info->callbacks->unattached_reloc) + (finfo->info, link_order->u.reloc.p->u.name, (bfd *) NULL, + (asection *) NULL, (bfd_vma) 0))) + return false; + 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; + } + else + { + hsec = NULL; + hval = 0; + } + + addend = link_order->u.reloc.p->addend; + if (hsec != NULL) + addend += (hsec->output_section->vma + + hsec->output_offset + + hval); + + if (addend != 0) { bfd_size_type size; bfd_byte *buf; @@ -4584,8 +4811,7 @@ xcoff_reloc_link_order (output_bfd, finfo, output_section, link_order) return false; } - rstat = _bfd_relocate_contents (howto, output_bfd, - link_order->u.reloc.p->addend, buf); + rstat = _bfd_relocate_contents (howto, output_bfd, addend, buf); switch (rstat) { case bfd_reloc_ok: @@ -4595,13 +4821,9 @@ xcoff_reloc_link_order (output_bfd, finfo, output_section, link_order) abort (); case bfd_reloc_overflow: if (! ((*finfo->info->callbacks->reloc_overflow) - (finfo->info, - (link_order->type == bfd_section_reloc_link_order - ? bfd_section_name (output_bfd, - link_order->u.reloc.p->u.section) - : link_order->u.reloc.p->u.name), - howto->name, link_order->u.reloc.p->addend, - (bfd *) NULL, (asection *) NULL, (bfd_vma) 0))) + (finfo->info, link_order->u.reloc.p->u.name, + howto->name, addend, (bfd *) NULL, (asection *) NULL, + (bfd_vma) 0))) { free (buf); return false; @@ -4628,44 +4850,14 @@ xcoff_reloc_link_order (output_bfd, finfo, output_section, link_order) irel->r_vaddr = output_section->vma + link_order->offset; - if (link_order->type == bfd_section_reloc_link_order) - { - /* We need to somehow locate a symbol in the right section. The - symbol must either have a value of zero, or we must adjust - the addend by the value of the symbol. FIXME: Write this - when we need it. The old linker couldn't handle this anyhow. */ - abort (); - *rel_hash_ptr = NULL; - irel->r_symndx = 0; - } + if (h->indx >= 0) + irel->r_symndx = h->indx; else { - struct xcoff_link_hash_entry *h; - - h = xcoff_link_hash_lookup (xcoff_hash_table (finfo->info), - link_order->u.reloc.p->u.name, - false, false, true); - if (h != NULL) - { - if (h->indx >= 0) - irel->r_symndx = h->indx; - else - { - /* Set the index to -2 to force this symbol to get - written out. */ - h->indx = -2; - *rel_hash_ptr = h; - irel->r_symndx = 0; - } - } - else - { - if (! ((*finfo->info->callbacks->unattached_reloc) - (finfo->info, link_order->u.reloc.p->u.name, (bfd *) NULL, - (asection *) NULL, (bfd_vma) 0))) - return false; - irel->r_symndx = 0; - } + /* Set the index to -2 to force this symbol to get written out. */ + h->indx = -2; + *rel_hash_ptr = h; + irel->r_symndx = 0; } irel->r_type = howto->type; @@ -4675,6 +4867,50 @@ xcoff_reloc_link_order (output_bfd, finfo, output_section, link_order) ++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 (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; + } + + ldrel.l_rtype = (irel->r_size << 8) | irel->r_type; + ldrel.l_rsecnm = output_section->target_index; + xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel); + ++finfo->ldrel; + return true; }