From f1cca64780428243ea7d62192a2395a60cb90263 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 22 Mar 1994 00:27:05 +0000 Subject: [PATCH] Support for link_order types which generate relocs in order to support -Ur in the linker. * linker.c (generic_link_add_symbol_list): Remove bitsize argument from call to _bfd_generic_link_add_one_symbol. (_bfd_generic_link_add_one_symbol): Remove bitsize argument. Don't pass bitsize to constructor call back. Pass BFD_RELOC_CTOR instead of bitsize to add_to_set call back. (_bfd_generic_final_link): Account for link_order relocs when allocating space for relocations. Handle them in link_order loop. (_bfd_generic_reloc_link_order): New function. (_bfd_default_link_order): If a reloc_link_order is seen here, abort. (_bfd_count_link_order_relocs): New function. * libbfd-in.h (_bfd_generic_link_add_one_symbol): Remove bitsize argument from declaration. (_bfd_generic_reloc_link_order): Declare. (_bfd_count_link_order_relocs): Declare. * libbfd.h: Rebuilt. * aoutx.h (aout_link_add_symbols): Remove bitsize argument from call to _bfd_generic_link_add_one_symbol. (NAME(aout,final_link)): Account for link_order relocs when allocating space for relocations. Handle them after handling all input BFDs. (aout_link_reloc_link_order): New function. * ecoff.c (ecoff_link_add_externals): Remove bitsize argument from call to _bfd_generic_link_add_one_symbol. (ecoff_bfd_final_link): Account for link_order relocs when allocating space for relocations. Handle them in link_order loop. (ecoff_link_write_external): Set the storage class of a defined linker created symbol based on the section it is in. Correct bfd_link_hash_weak case to use .sc rather than .st. (ecoff_reloc_link_order): New function. * coff-alpha.c (alpha_bfd_reloc_type_lookup): Handle BFD_RELOC_CTOR. * coff-mips.c (mips_bfd_reloc_type_lookup): Likewise. --- bfd/ChangeLog | 45 +++++++++ bfd/coff-mips.c | 6 +- bfd/libbfd-in.h | 16 +++- bfd/libbfd.h | 16 +++- bfd/linker.c | 292 ++++++++++++++++++++++++++++++++++++++++++++++---------- 5 files changed, 319 insertions(+), 56 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 9fbc9fb..51736c2 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,48 @@ +Mon Mar 21 12:28:19 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + Support for link_order types which generate relocs in order to + support -Ur in the linker. + * linker.c (generic_link_add_symbol_list): Remove bitsize argument + from call to _bfd_generic_link_add_one_symbol. + (_bfd_generic_link_add_one_symbol): Remove bitsize argument. + Don't pass bitsize to constructor call back. Pass BFD_RELOC_CTOR + instead of bitsize to add_to_set call back. + (_bfd_generic_final_link): Account for link_order relocs when + allocating space for relocations. Handle them in link_order loop. + (_bfd_generic_reloc_link_order): New function. + (_bfd_default_link_order): If a reloc_link_order is seen here, + abort. + (_bfd_count_link_order_relocs): New function. + * libbfd-in.h (_bfd_generic_link_add_one_symbol): Remove bitsize + argument from declaration. + (_bfd_generic_reloc_link_order): Declare. + (_bfd_count_link_order_relocs): Declare. + * libbfd.h: Rebuilt. + * aoutx.h (aout_link_add_symbols): Remove bitsize argument from + call to _bfd_generic_link_add_one_symbol. + (NAME(aout,final_link)): Account for link_order relocs when + allocating space for relocations. Handle them after handling all + input BFDs. + (aout_link_reloc_link_order): New function. + * ecoff.c (ecoff_link_add_externals): Remove bitsize argument from + call to _bfd_generic_link_add_one_symbol. + (ecoff_bfd_final_link): Account for link_order relocs when + allocating space for relocations. Handle them in link_order loop. + (ecoff_link_write_external): Set the storage class of a defined + linker created symbol based on the section it is in. Correct + bfd_link_hash_weak case to use .sc rather than .st. + (ecoff_reloc_link_order): New function. + * coff-alpha.c (alpha_bfd_reloc_type_lookup): Handle + BFD_RELOC_CTOR. + * coff-mips.c (mips_bfd_reloc_type_lookup): Likewise. + + * sunos.c (sunos_read_dynamic_info): Remove unused locals dynsym + and buf. + + * cisco-core.c (cisco_core_file_p): Only pass one argument to + bfd_zmalloc. Free a pointer, not a union. + (cisco_bfd_is_local_label): Correct cast from asection to asymbol. + Sun Mar 20 09:24:36 1994 Jeffrey A. Law (law@snake.cs.utah.edu) * bfd/som.c (som_begin_writing): Fix thinko (off by one error). diff --git a/bfd/coff-mips.c b/bfd/coff-mips.c index a9939c8..a9a95e5 100644 --- a/bfd/coff-mips.c +++ b/bfd/coff-mips.c @@ -697,6 +697,7 @@ mips_bfd_reloc_type_lookup (abfd, code) mips_type = MIPS_R_REFHALF; break; case BFD_RELOC_32: + case BFD_RELOC_CTOR: mips_type = MIPS_R_REFWORD; break; case BFD_RELOC_MIPS_JMP: @@ -798,7 +799,7 @@ mips_relocate_section (output_bfd, info, input_bfd, input_section, * sizeof (asection *)))); if (!symndx_to_section) { - bfd_error = no_memory; + bfd_set_error (bfd_error_no_memory); return false; } @@ -903,7 +904,8 @@ mips_relocate_section (output_bfd, info, input_bfd, input_section, /* The GPREL reloc uses an addend: the difference in the GP values. */ - if (int_rel.r_type != MIPS_R_GPREL) + if (int_rel.r_type != MIPS_R_GPREL + && int_rel.r_type != MIPS_R_LITERAL) addend = 0; else { diff --git a/bfd/libbfd-in.h b/bfd/libbfd-in.h index 7ed6bc4..6327bc5 100644 --- a/bfd/libbfd-in.h +++ b/bfd/libbfd-in.h @@ -153,6 +153,10 @@ boolean bfd_generic_set_section_contents PARAMS ((bfd *abfd, sec_ptr section, PTR location, file_ptr offset, bfd_size_type count)); +/* Generic routine to determine of the given symbol is a local + label. */ +extern boolean bfd_generic_is_local_label PARAMS ((bfd *, asymbol *)); + /* A routine to create entries for a bfd_link_hash_table. */ extern struct bfd_hash_entry *_bfd_link_hash_newfunc PARAMS ((struct bfd_hash_entry *entry, @@ -186,18 +190,26 @@ typedef struct bfd_link_hash_entry _bfd_link_hash_entry; extern boolean _bfd_generic_link_add_one_symbol PARAMS ((struct bfd_link_info *, bfd *, const char *name, flagword, asection *, bfd_vma, const char *, boolean copy, - boolean constructor, unsigned int bitsize, - struct bfd_link_hash_entry **)); + boolean constructor, struct bfd_link_hash_entry **)); /* Generic link routine. */ extern boolean _bfd_generic_final_link PARAMS ((bfd *, struct bfd_link_info *)); +/* Generic reloc_link_order processing routine. */ +extern boolean _bfd_generic_reloc_link_order + PARAMS ((bfd *, struct bfd_link_info *, asection *, + struct bfd_link_order *)); + /* Default link order processing routine. */ extern boolean _bfd_default_link_order PARAMS ((bfd *, struct bfd_link_info *, asection *, struct bfd_link_order *)); +/* Count the number of reloc entries in a link order list. */ +extern unsigned int _bfd_count_link_order_relocs + PARAMS ((struct bfd_link_order *)); + /* Final link relocation routine. */ extern bfd_reloc_status_type _bfd_final_link_relocate PARAMS ((const reloc_howto_type *, bfd *, asection *, bfd_byte *, diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 59ccdf7..5a02d0f 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -153,6 +153,10 @@ boolean bfd_generic_set_section_contents PARAMS ((bfd *abfd, sec_ptr section, PTR location, file_ptr offset, bfd_size_type count)); +/* Generic routine to determine of the given symbol is a local + label. */ +extern boolean bfd_generic_is_local_label PARAMS ((bfd *, asymbol *)); + /* A routine to create entries for a bfd_link_hash_table. */ extern struct bfd_hash_entry *_bfd_link_hash_newfunc PARAMS ((struct bfd_hash_entry *entry, @@ -186,18 +190,26 @@ typedef struct bfd_link_hash_entry _bfd_link_hash_entry; extern boolean _bfd_generic_link_add_one_symbol PARAMS ((struct bfd_link_info *, bfd *, const char *name, flagword, asection *, bfd_vma, const char *, boolean copy, - boolean constructor, unsigned int bitsize, - struct bfd_link_hash_entry **)); + boolean constructor, struct bfd_link_hash_entry **)); /* Generic link routine. */ extern boolean _bfd_generic_final_link PARAMS ((bfd *, struct bfd_link_info *)); +/* Generic reloc_link_order processing routine. */ +extern boolean _bfd_generic_reloc_link_order + PARAMS ((bfd *, struct bfd_link_info *, asection *, + struct bfd_link_order *)); + /* Default link order processing routine. */ extern boolean _bfd_default_link_order PARAMS ((bfd *, struct bfd_link_info *, asection *, struct bfd_link_order *)); +/* Count the number of reloc entries in a link order list. */ +extern unsigned int _bfd_count_link_order_relocs + PARAMS ((struct bfd_link_order *)); + /* Final link relocation routine. */ extern bfd_reloc_status_type _bfd_final_link_relocate PARAMS ((const reloc_howto_type *, bfd *, asection *, bfd_byte *, diff --git a/bfd/linker.c b/bfd/linker.c index 0e2c31b..7a67696 100644 --- a/bfd/linker.c +++ b/bfd/linker.c @@ -625,14 +625,6 @@ _bfd_generic_link_add_symbols (abfd, info) ret = false; } - /* If we might be using the C based alloca function, make sure we - have dumped the symbol tables we just allocated. */ -#ifndef __GNUC__ -#ifndef alloca - alloca (0); -#endif -#endif - return ret; } @@ -646,12 +638,20 @@ generic_link_add_object_symbols (abfd, info) size_t symsize; asymbol **symbols; bfd_size_type symbol_count; + boolean result; symsize = get_symtab_upper_bound (abfd); - symbols = (asymbol **) alloca (symsize); + symbols = (asymbol **) malloc (symsize); + if (symbols == NULL && symsize != 0) + { + bfd_set_error (bfd_error_no_memory); + return false; + } symbol_count = bfd_canonicalize_symtab (abfd, symbols); - return generic_link_add_symbol_list (abfd, info, symbol_count, symbols); + result = generic_link_add_symbol_list (abfd, info, symbol_count, symbols); + free (symbols); + return result; } /* We build a hash table of all symbols defined in an archive. */ @@ -813,8 +813,15 @@ _bfd_generic_link_add_archive_symbols (abfd, info, checkfn) arh = archive_hash_lookup (&arsym_hash, arsym->name, true, false); if (arh == (struct archive_hash_entry *) NULL) - return false; - l = (struct archive_list *) alloca (sizeof (struct archive_list)); + goto error_return; + l = (struct archive_list *) + obstack_alloc (&(&(&arsym_hash)->table)->memory, + sizeof (struct archive_list)); + if (l == NULL) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } l->indx = indx; for (pp = &arh->defs; *pp != (struct archive_list *) NULL; @@ -875,7 +882,7 @@ _bfd_generic_link_add_archive_symbols (abfd, info, checkfn) element = bfd_get_elt_at_index (abfd, l->indx); if (element == (bfd *) NULL) - return false; + goto error_return; /* If we've already included this element, or if we've already checked it on this pass, continue. */ @@ -893,7 +900,7 @@ _bfd_generic_link_add_archive_symbols (abfd, info, checkfn) /* CHECKFN will see if this element should be included, and go ahead and include it if appropriate. */ if (! (*checkfn) (element, info, &needed)) - return false; + goto error_return; if (! needed) element->archive_pass = pass; @@ -913,6 +920,10 @@ _bfd_generic_link_add_archive_symbols (abfd, info, checkfn) archive_hash_table_free (&arsym_hash); return true; + + error_return: + archive_hash_table_free (&arsym_hash); + return false; } /* See if we should include an archive element. */ @@ -924,14 +935,20 @@ generic_link_check_archive_element (abfd, info, pneeded) boolean *pneeded; { size_t symsize; - asymbol **symbols; + asymbol **symbols = NULL; bfd_size_type symbol_count; asymbol **pp, **ppend; *pneeded = false; symsize = get_symtab_upper_bound (abfd); - symbols = (asymbol **) alloca (symsize); + symbols = (asymbol **) malloc (symsize); + if (symbols == NULL && symsize != 0) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + symbol_count = bfd_canonicalize_symtab (abfd, symbols); pp = symbols; @@ -967,12 +984,12 @@ generic_link_check_archive_element (abfd, info, pneeded) /* This object file defines this symbol, so pull it in. */ if (! (*info->callbacks->add_archive_element) (info, abfd, bfd_asymbol_name (p))) - return false; + goto error_return; if (! generic_link_add_symbol_list (abfd, info, symbol_count, symbols)) - return false; + goto error_return; *pneeded = true; - return true; + goto successful_return; } /* P is a common symbol. */ @@ -989,9 +1006,9 @@ generic_link_check_archive_element (abfd, info, pneeded) file. This is for the -u option in the linker. */ if (! (*info->callbacks->add_archive_element) (info, abfd, bfd_asymbol_name (p))) - return false; + goto error_return; *pneeded = true; - return true; + goto successful_return; } /* Turn the symbol into a common symbol but do not link in @@ -1022,7 +1039,16 @@ generic_link_check_archive_element (abfd, info, pneeded) } /* This archive element is not needed. */ + + successful_return: + if (symbols != NULL) + free (symbols); return true; + + error_return: + if (symbols != NULL) + free (symbols); + return false; } /* Add the symbol from an object file to the global hash table. */ @@ -1076,12 +1102,10 @@ generic_link_add_symbol_list (abfd, info, symbol_count, symbols) compatibility. As backends are converted they can arrange to pass the right value (the right value is the size of a function pointer if gcc uses collect2 for the - object file format, zero if it does not). - FIXME: We pass the bitsize as 32, which is just plain - wrong, but actually doesn't matter very much. */ + object file format, zero if it does not). */ if (! (_bfd_generic_link_add_one_symbol (info, abfd, name, p->flags, bfd_get_section (p), - p->value, string, false, 0, 32, + p->value, string, false, 0, (struct bfd_link_hash_entry **) &h))) return false; @@ -1186,13 +1210,12 @@ static const enum link_action link_action[8][7] = allocated memory if they need to be saved. CONSTRUCTOR is true if we should automatically collect gcc constructor or destructor names. - BITSIZE is the number of bits in constructor or set entries. HASHP, if not NULL, is a place to store the created hash table entry. */ boolean _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value, - string, copy, constructor, bitsize, hashp) + string, copy, constructor, hashp) struct bfd_link_info *info; bfd *abfd; const char *name; @@ -1202,7 +1225,6 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value, const char *string; boolean copy; boolean constructor; - unsigned int bitsize; struct bfd_link_hash_entry **hashp; { enum link_row row; @@ -1314,7 +1336,7 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value, { if (! ((*info->callbacks->constructor) (info, - c == 'I' ? true : false, bitsize, + c == 'I' ? true : false, name, abfd, section, value))) return false; } @@ -1410,8 +1432,8 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value, } break; case SET: - if (! (*info->callbacks->add_to_set) (info, h, bitsize, abfd, - section, value)) + if (! (*info->callbacks->add_to_set) (info, h, BFD_RELOC_CTOR, + abfd, section, value)) return false; break; case WARN: @@ -1504,12 +1526,14 @@ _bfd_generic_final_link (abfd, info) o != (asection *) NULL; o = o->next) { - o->reloc_count = 0; for (p = o->link_order_head; p != (struct bfd_link_order *) NULL; p = p->next) { - if (p->type == bfd_indirect_link_order) + if (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order) + ++o->reloc_count; + else if (p->type == bfd_indirect_link_order) { asection *input_section; bfd *input_bfd; @@ -1522,7 +1546,7 @@ _bfd_generic_final_link (abfd, info) relsize = bfd_get_reloc_upper_bound (input_bfd, input_section); relocs = (arelent **) malloc ((size_t) relsize); - if (!relocs) + if (!relocs && relsize != 0) { bfd_set_error (bfd_error_no_memory); return false; @@ -1563,8 +1587,18 @@ _bfd_generic_final_link (abfd, info) p != (struct bfd_link_order *) NULL; p = p->next) { - if (! _bfd_default_link_order (abfd, info, o, p)) - return false; + switch (p->type) + { + case bfd_section_reloc_link_order: + case bfd_symbol_reloc_link_order: + if (! _bfd_generic_reloc_link_order (abfd, info, o, p)) + return false; + break; + default: + if (! _bfd_default_link_order (abfd, info, o, p)) + return false; + break; + } } } @@ -1893,6 +1927,116 @@ _bfd_generic_link_write_global_symbol (h, data) return true; } + +/* Create a relocation. */ + +boolean +_bfd_generic_reloc_link_order (abfd, info, sec, link_order) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + struct bfd_link_order *link_order; +{ + arelent *r; + + if (! info->relocateable) + abort (); + if (sec->orelocation == (arelent **) NULL) + abort (); + + r = (arelent *) bfd_alloc (abfd, sizeof (arelent)); + if (r == (arelent *) NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + + r->address = link_order->offset; + r->howto = bfd_reloc_type_lookup (abfd, link_order->u.reloc.p->reloc); + if (r->howto == (const reloc_howto_type *) NULL) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + /* Get the symbol to use for the relocation. */ + if (link_order->type == bfd_section_reloc_link_order) + r->sym_ptr_ptr = link_order->u.reloc.p->u.section->symbol_ptr_ptr; + else + { + struct generic_link_hash_entry *h; + + h = _bfd_generic_link_hash_lookup (_bfd_generic_hash_table (info), + link_order->u.reloc.p->u.name, + false, false, true); + if (h == (struct generic_link_hash_entry *) NULL + || ! h->root.written) + { + if (! ((*info->callbacks->unattached_reloc) + (info, link_order->u.reloc.p->u.name, + (bfd *) NULL, (asection *) NULL, (bfd_vma) 0))) + return false; + bfd_set_error (bfd_error_bad_value); + return false; + } + r->sym_ptr_ptr = &h->sym; + } + + /* If this is an inplace reloc, write the addend to the object file. + Otherwise, store it in the reloc addend. */ + if (! r->howto->partial_inplace) + r->addend = link_order->u.reloc.p->addend; + else + { + bfd_size_type size; + bfd_reloc_status_type rstat; + bfd_byte *buf; + boolean ok; + + size = bfd_get_reloc_size (r->howto); + buf = (bfd_byte *) bfd_zmalloc (size); + if (buf == (bfd_byte *) NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + rstat = _bfd_relocate_contents (r->howto, abfd, + link_order->u.reloc.p->addend, buf); + switch (rstat) + { + case bfd_reloc_ok: + break; + default: + case bfd_reloc_outofrange: + abort (); + case bfd_reloc_overflow: + if (! ((*info->callbacks->reloc_overflow) + (info, + (link_order->type == bfd_section_reloc_link_order + ? bfd_section_name (abfd, link_order->u.reloc.p->u.section) + : link_order->u.reloc.p->u.name), + r->howto->name, link_order->u.reloc.p->addend, + (bfd *) NULL, (asection *) NULL, (bfd_vma) 0))) + { + free (buf); + return false; + } + break; + } + ok = bfd_set_section_contents (abfd, sec, (PTR) buf, + (file_ptr) link_order->offset, size); + free (buf); + if (! ok) + return false; + + r->addend = 0; + } + + sec->orelocation[sec->reloc_count] = r; + ++sec->reloc_count; + + return true; +} /* Allocate a new link_order for a section. */ @@ -1925,7 +2069,9 @@ bfd_new_link_order (abfd, section) return new; } -/* Default link order processing routine. */ +/* Default link order processing routine. Note that we can not handle + the reloc_link_order types here, since they depend upon the details + of how the particular backends generates relocs. */ boolean _bfd_default_link_order (abfd, info, sec, link_order) @@ -1937,6 +2083,8 @@ _bfd_default_link_order (abfd, info, sec, link_order) switch (link_order->type) { case bfd_undefined_link_order: + case bfd_section_reloc_link_order: + case bfd_symbol_reloc_link_order: default: abort (); case bfd_indirect_link_order: @@ -1960,19 +2108,28 @@ default_fill_link_order (abfd, info, sec, link_order) char *space; size_t i; int fill; + boolean result; BFD_ASSERT ((sec->flags & SEC_HAS_CONTENTS) != 0); size = (size_t) link_order->size; - space = (char *) alloca (size); + space = (char *) malloc (size); + if (space == NULL && size != 0) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + fill = link_order->u.fill.value; for (i = 0; i < size; i += 2) space[i] = fill >> 8; for (i = 1; i < size; i += 2) space[i] = fill; - return bfd_set_section_contents (abfd, sec, space, - (file_ptr) link_order->offset, - link_order->size); + result = bfd_set_section_contents (abfd, sec, space, + (file_ptr) link_order->offset, + link_order->size); + free (space); + return result; } /* Default routine to handle a bfd_indirect_link_order. */ @@ -1986,7 +2143,8 @@ default_indirect_link_order (output_bfd, info, output_section, link_order) { asection *input_section; bfd *input_bfd; - bfd_byte *contents; + bfd_byte *contents = NULL; + bfd_byte *new_contents; BFD_ASSERT ((output_section->flags & SEC_HAS_CONTENTS) != 0); @@ -2032,17 +2190,51 @@ default_indirect_link_order (output_bfd, info, output_section, link_order) } /* Get and relocate the section contents. */ - contents = (bfd_byte *) alloca (bfd_section_size (input_bfd, input_section)); - contents = (bfd_get_relocated_section_contents - (output_bfd, info, link_order, contents, info->relocateable, - bfd_get_outsymbols (input_bfd))); - if (!contents) - return false; + contents = (bfd_byte *) malloc (bfd_section_size (input_bfd, input_section)); + if (contents == NULL && bfd_section_size (input_bfd, input_section) != 0) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + new_contents = (bfd_get_relocated_section_contents + (output_bfd, info, link_order, contents, info->relocateable, + bfd_get_outsymbols (input_bfd))); + if (!new_contents) + goto error_return; /* Output the section contents. */ - if (! bfd_set_section_contents (output_bfd, output_section, (PTR) contents, + if (! bfd_set_section_contents (output_bfd, output_section, + (PTR) new_contents, link_order->offset, link_order->size)) - return false; + goto error_return; + if (contents != NULL) + free (contents); return true; + + error_return: + if (contents != NULL) + free (contents); + return false; +} + +/* A little routine to count the number of relocs in a link_order + list. */ + +unsigned int +_bfd_count_link_order_relocs (link_order) + struct bfd_link_order *link_order; +{ + register unsigned int c; + register struct bfd_link_order *l; + + c = 0; + for (l = link_order; l != (struct bfd_link_order *) NULL; l = l->next) + { + if (l->type == bfd_section_reloc_link_order + || l->type == bfd_symbol_reloc_link_order) + ++c; + } + + return c; } -- 2.7.4