From: Ian Lance Taylor Date: Thu, 30 Dec 1993 20:03:34 +0000 (+0000) Subject: Added new files for linker support, and removed old seclet files. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=da6b2d99f7b95caf5f31a31e28a310e0b63b2ee5;p=binutils-gdb.git Added new files for linker support, and removed old seclet files. --- diff --git a/bfd/.Sanitize b/bfd/.Sanitize index b2b21611a94..0e844a7fc54 100644 --- a/bfd/.Sanitize +++ b/bfd/.Sanitize @@ -121,6 +121,8 @@ elfcode.h filemode.c format.c gen-aout.c +genlink.h +hash.c host-aout.c hosts hp300bsd.c @@ -148,6 +150,7 @@ libhppa.h libieee.h libnlm.h liboasys.h +linker.c lynx-core.c m68klynx.c mipsbsd.c @@ -171,8 +174,6 @@ ptrace-core.c reloc.c reloc16.c rs6000-core.c -seclet.c -seclet.h section.c som.c som.h diff --git a/bfd/genlink.h b/bfd/genlink.h new file mode 100644 index 00000000000..fed0849847e --- /dev/null +++ b/bfd/genlink.h @@ -0,0 +1,103 @@ +/* genlink.h -- interface to the BFD generic linker + Copyright 1993 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef GENLINK_H +#define GENLINK_H + +/* This header file is internal to BFD. It describes the internal + structures and functions used by the BFD generic linker, in case + any of the more specific linkers want to use or call them. Note + that some functions, such as _bfd_generic_link_hash_table_create, + are declared in libbfd.h, because they are expected to be widely + used. The functions and structures in this file will probably only + be used by a few files besides linker.c itself. In fact, this file + is not particularly complete; I have only put in the interfaces I + actually needed. */ + +/* The generic linker uses a hash table which is a derived class of + the standard linker hash table, just as the other backend specific + linkers do. Do not confuse the generic linker hash table with the + standard BFD linker hash table it is built upon. The generic + linker hash table is onl referred to in this file. */ + +/* Generic linker hash table entries. */ + +struct generic_link_hash_entry +{ + struct bfd_link_hash_entry root; + /* Symbol from input BFD. */ + asymbol *sym; +}; + +/* Generic linker hash table. */ + +struct generic_link_hash_table +{ + struct bfd_link_hash_table root; +}; + +/* Look up an entry in an generic link hash table. */ + +#define _bfd_generic_link_hash_lookup(table, string, create, copy, follow) \ + ((struct generic_link_hash_entry *) \ + bfd_link_hash_lookup (&(table)->root, (string), (create), (copy), (follow))) + +/* Traverse an generic link hash table. */ + +#define _bfd_generic_link_hash_traverse(table, func, info) \ + (bfd_link_hash_traverse \ + (&(table)->root, \ + (boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \ + (info))) + +/* Get the generic link hash table from the info structure. This is + just a cast. */ + +#define _bfd_generic_hash_table(p) \ + ((struct generic_link_hash_table *) ((p)->hash)) + +/* Add the symbols of input_bfd to the symbols being built for + output_bfd. */ +extern boolean _bfd_generic_link_output_symbols + PARAMS ((bfd *output_bfd, bfd *input_bfd, struct bfd_link_info *, + size_t *psymalloc)); + +/* This structure is used to pass information to + _bfd_generic_link_write_global_symbol, which may be called via + _bfd_generic_link_hash_traverse. */ + +struct generic_write_global_symbol_info +{ + bfd *output_bfd; + size_t *psymalloc; +}; + +/* Write out a single global symbol. This is expected to be called + via _bfd_generic_link_hash_traverse. The second argument must + actually be a struct generic_write_global_symbol_info *. */ +extern boolean _bfd_generic_link_write_global_symbol + PARAMS ((struct generic_link_hash_entry *, PTR)); + +/* Handle a bfd_indirect_link_order. */ +extern boolean _bfd_generic_indirect_link_order + PARAMS ((bfd *, struct bfd_link_info *, asection *, + struct bfd_link_order *)); + +#endif diff --git a/bfd/hash.c b/bfd/hash.c new file mode 100644 index 00000000000..991b2c3d207 --- /dev/null +++ b/bfd/hash.c @@ -0,0 +1,181 @@ +/* hash.c -- hash table routines for BFD + Copyright 1993 Free Software Foundation, Inc. + Written by Steve Chamberlain + +This file is part of GLD, the Gnu Linker. + +GLD is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GLD is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GLD; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "obstack.h" + +/* Obstack allocation and deallocation routines. */ +#define obstack_chunk_alloc bfd_xmalloc_by_size_t +#define obstack_chunk_free free + +/* The default number of entries to use when creating a hash table. */ +#define DEFAULT_SIZE (4051) + +/* Create a new hash table, given a number of entries. */ + +boolean +bfd_hash_table_init_n (table, newfunc, size) + struct bfd_hash_table *table; + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); + unsigned int size; +{ + unsigned int alloc; + + alloc = size * sizeof (struct bfd_hash_entry *); + obstack_begin (&table->memory, alloc); + table->table = ((struct bfd_hash_entry **) + obstack_alloc (&table->memory, alloc)); + memset ((PTR) table->table, 0, alloc); + table->size = size; + table->newfunc = newfunc; + return true; +} + +/* Create a new hash table with the default number of entries. */ + +boolean +bfd_hash_table_init (table, newfunc) + struct bfd_hash_table *table; + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); +{ + return bfd_hash_table_init_n (table, newfunc, DEFAULT_SIZE); +} + +/* Free a hash table. */ + +void +bfd_hash_table_free (table) + struct bfd_hash_table *table; +{ + obstack_free (&table->memory, (PTR) NULL); +} + +/* Look up a string in a hash table. */ + +struct bfd_hash_entry * +bfd_hash_lookup (table, string, create, copy) + struct bfd_hash_table *table; + const char *string; + boolean create; + boolean copy; +{ + register const unsigned char *s; + register unsigned long hash; + register unsigned int c; + struct bfd_hash_entry *hashp; + unsigned int len; + unsigned int index; + + hash = 0; + len = 0; + s = (const unsigned char *) string; + while ((c = *s++) != '\0') + { + hash += c + (c << 17); + hash ^= hash >> 2; + ++len; + } + hash += len + (len << 17); + hash ^= hash >> 2; + + index = hash % table->size; + for (hashp = table->table[index]; + hashp != (struct bfd_hash_entry *) NULL; + hashp = hashp->next) + { + if (hashp->hash == hash + && strcmp (hashp->string, string) == 0) + return hashp; + } + + if (! create) + return (struct bfd_hash_entry *) NULL; + + hashp = (*table->newfunc) ((struct bfd_hash_entry *) NULL, table, string); + if (hashp == (struct bfd_hash_entry *) NULL) + return (struct bfd_hash_entry *) NULL; + if (copy) + { + char *new; + + new = (char *) obstack_alloc (&table->memory, len + 1); + strcpy (new, string); + string = new; + } + hashp->string = string; + hashp->hash = hash; + hashp->next = table->table[index]; + table->table[index] = hashp; + + return hashp; +} + +/* Base method for creating a new hash table entry. */ + +/*ARGSUSED*/ +struct bfd_hash_entry * +bfd_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + if (entry == (struct bfd_hash_entry *) NULL) + entry = ((struct bfd_hash_entry *) + bfd_hash_allocate (table, sizeof (struct bfd_hash_entry))); + return entry; +} + +/* Allocate space in a hash table. */ + +PTR +bfd_hash_allocate (table, size) + struct bfd_hash_table *table; + size_t size; +{ + return obstack_alloc (&table->memory, size); +} + +/* Traverse a hash table. */ + +void +bfd_hash_traverse (table, func, info) + struct bfd_hash_table *table; + boolean (*func) PARAMS ((struct bfd_hash_entry *, PTR)); + PTR info; +{ + unsigned int i; + + for (i = 0; i < table->size; i++) + { + struct bfd_hash_entry *p; + + for (p = table->table[i]; p != NULL; p = p->next) + { + if (! (*func) (p, info)) + return; + } + } +} diff --git a/bfd/linker.c b/bfd/linker.c new file mode 100644 index 00000000000..0e8c9f49090 --- /dev/null +++ b/bfd/linker.c @@ -0,0 +1,1484 @@ +/* linker.c -- BFD linker routines + Copyright 1993 Free Software Foundation, Inc. + Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support + +This file is part of BFD + +GLD is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GLD is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GLD; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "bfdlink.h" +#include "genlink.h" + +static struct bfd_hash_entry *generic_link_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, + const char *)); +static boolean generic_link_add_object_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean generic_link_check_archive_element + PARAMS ((bfd *, struct bfd_link_info *, boolean *pneeded)); +static boolean generic_link_add_symbol_list + PARAMS ((bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **)); +static boolean generic_add_output_symbol + PARAMS ((bfd *, size_t *psymalloc, asymbol *)); +static boolean default_fill_link_order + PARAMS ((bfd *, struct bfd_link_info *, asection *, + struct bfd_link_order *)); + +/* The link hash table structure is defined in bfdlink.h. It provides + a base hash table which the backend specific hash tables are built + upon. */ + +/* Routine to create an entry in the link hash table. */ + +struct bfd_hash_entry * +_bfd_link_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct bfd_link_hash_entry *ret = (struct bfd_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct bfd_link_hash_entry *) NULL) + ret = ((struct bfd_link_hash_entry *) + bfd_hash_allocate (table, sizeof (struct bfd_link_hash_entry))); + + /* Call the allocation method of the superclass. */ + ret = ((struct bfd_link_hash_entry *) + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + + /* Initialize the local fields. */ + ret->type = bfd_link_hash_new; + ret->written = false; + ret->next = NULL; + + return (struct bfd_hash_entry *) ret; +} + +/* Initialize a link hash table. The BFD argument is the one + responsible for creating this table. */ + +boolean +_bfd_link_hash_table_init (table, abfd, newfunc) + struct bfd_link_hash_table *table; + bfd *abfd; + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); +{ + table->creator = abfd->xvec; + table->undefs = NULL; + table->undefs_tail = NULL; + return bfd_hash_table_init (&table->table, newfunc); +} + +/* Look up a symbol in a link hash table. If follow is true, we + follow bfd_link_hash_indirect and bfd_link_hash_warning links to + the real symbol. */ + +struct bfd_link_hash_entry * +bfd_link_hash_lookup (table, string, create, copy, follow) + struct bfd_link_hash_table *table; + const char *string; + boolean create; + boolean copy; + boolean follow; +{ + struct bfd_link_hash_entry *ret; + + ret = ((struct bfd_link_hash_entry *) + bfd_hash_lookup (&table->table, string, create, copy)); + + if (follow && ret != (struct bfd_link_hash_entry *) NULL) + { + while (ret->type == bfd_link_hash_indirect + || ret->type == bfd_link_hash_warning) + ret = ret->u.i.link; + } + + return ret; +} + +/* Traverse a generic link hash table. The only reason this is not a + macro is to do better type checking. This code presumes that an + argument passed as a struct bfd_hash_entry * may be cause as a + struct bfd_link_hash_entry * with no explicit cast required on the + call. */ + +void +bfd_link_hash_traverse (table, func, info) + struct bfd_link_hash_table *table; + boolean (*func) PARAMS ((struct bfd_link_hash_entry *, PTR)); + PTR info; +{ + bfd_hash_traverse (&table->table, + ((boolean (*) PARAMS ((struct bfd_hash_entry *, PTR))) + func), + info); +} + +/* Add a symbol to the linker hash table undefs list. */ + +INLINE void +bfd_link_add_undef (table, h) + struct bfd_link_hash_table *table; + struct bfd_link_hash_entry *h; +{ + BFD_ASSERT (h->next == NULL); + if (table->undefs_tail != (struct bfd_link_hash_entry *) NULL) + table->undefs_tail->next = h; + if (table->undefs == (struct bfd_link_hash_entry *) NULL) + table->undefs = h; + table->undefs_tail = h; +} + +/* Routine to create an entry in an generic link hash table. */ + +static struct bfd_hash_entry * +generic_link_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct generic_link_hash_entry *ret = + (struct generic_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct generic_link_hash_entry *) NULL) + ret = ((struct generic_link_hash_entry *) + bfd_hash_allocate (table, sizeof (struct generic_link_hash_entry))); + + /* Call the allocation method of the superclass. */ + ret = ((struct generic_link_hash_entry *) + _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret, + table, string)); + + /* Set local fields. */ + ret->sym = NULL; + + return (struct bfd_hash_entry *) ret; +} + +/* Create an generic link hash table. */ + +struct bfd_link_hash_table * +_bfd_generic_link_hash_table_create (abfd) + bfd *abfd; +{ + struct generic_link_hash_table *ret; + + ret = ((struct generic_link_hash_table *) + bfd_xmalloc (sizeof (struct generic_link_hash_table))); + if (! _bfd_link_hash_table_init (&ret->root, abfd, + generic_link_hash_newfunc)) + { + free (ret); + return (struct bfd_link_hash_table *) NULL; + } + return &ret->root; +} + +/* Generic function to add symbols from an object file to the global + hash table. */ + +boolean +_bfd_generic_link_add_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + boolean ret; + + switch (bfd_get_format (abfd)) + { + case bfd_object: + ret = generic_link_add_object_symbols (abfd, info); + break; + case bfd_archive: + ret = _bfd_generic_link_add_archive_symbols + (abfd, info, generic_link_check_archive_element); + break; + default: + bfd_error = wrong_format; + 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; +} + +/* Add symbols from an object file to the global hash table. */ + +static boolean +generic_link_add_object_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + size_t symsize; + asymbol **symbols; + bfd_size_type symbol_count; + + symsize = get_symtab_upper_bound (abfd); + symbols = (asymbol **) alloca (symsize); + symbol_count = bfd_canonicalize_symtab (abfd, symbols); + + return generic_link_add_symbol_list (abfd, info, symbol_count, symbols); +} + +/* We build a hash table of all symbols defined in an archive. */ + +/* An archive symbol may be defined by multiple archive elements. + This linked list is used to hold the elements. */ + +struct archive_list +{ + struct archive_list *next; + int indx; +}; + +/* An entry in an archive hash table. */ + +struct archive_hash_entry +{ + struct bfd_hash_entry root; + /* Where the symbol is defined. */ + struct archive_list *defs; +}; + +/* An archive hash table itself. */ + +struct archive_hash_table +{ + struct bfd_hash_table table; +}; + +static struct bfd_hash_entry *archive_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +static boolean archive_hash_table_init + PARAMS ((struct archive_hash_table *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *))); + +/* Create a new entry for an archive hash table. */ + +static struct bfd_hash_entry * +archive_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct archive_hash_entry *ret = (struct archive_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct archive_hash_entry *) NULL) + ret = ((struct archive_hash_entry *) + bfd_hash_allocate (table, sizeof (struct archive_hash_entry))); + + /* Call the allocation method of the superclass. */ + ret = ((struct archive_hash_entry *) + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + + /* Initialize the local fields. */ + ret->defs = (struct archive_list *) NULL; + + return (struct bfd_hash_entry *) ret; +} + +/* Initialize an archive hash table. */ + +static boolean +archive_hash_table_init (table, newfunc) + struct archive_hash_table *table; + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); +{ + return bfd_hash_table_init (&table->table, newfunc); +} + +/* Look up an entry in an archive hash table. */ + +#define archive_hash_lookup(t, string, create, copy) \ + ((struct archive_hash_entry *) \ + bfd_hash_lookup (&(t)->table, (string), (create), (copy))) + +/* Free an archive hash table. */ + +#define archive_hash_table_free(t) bfd_hash_table_free (&(t)->table) + +/* Generic function to add symbols from an archive file to the global + hash file. This function presumes that the archive symbol table + has already been read in (this is normally done by the + bfd_check_format entry point). It looks through the undefined and + common symbols and searches the archive symbol table for them. If + it finds an entry, it includes the associated object file in the + link. + + The old linker looked through the archive symbol table for + undefined symbols. We do it the other way around, looking through + undefined symbols for symbols defined in the archive. The + advantage of the newer scheme is that we only have to look through + the list of undefined symbols once, whereas the old method had to + re-search the symbol table each time a new object file was added. + + The CHECKFN argument is used to see if an object file should be + included. CHECKFN should set *PNEEDED to true if the object file + should be included, and must also call the bfd_link_info + add_archive_element callback function and handle adding the symbols + to the global hash table. CHECKFN should only return false if some + sort of error occurs. + + For some formats, such as a.out, it is possible to look through an + object file but not actually include it in the link. The + archive_pass field in a BFD is used to avoid checking the symbols + of an object files too many times. When an object is included in + the link, archive_pass is set to -1. If an object is scanned but + not included, archive_pass is set to the pass number. The pass + number is incremented each time a new object file is included. The + pass number is used because when a new object file is included it + may create new undefined symbols which cause a previously examined + object file to be included. */ + +boolean +_bfd_generic_link_add_archive_symbols (abfd, info, checkfn) + bfd *abfd; + struct bfd_link_info *info; + boolean (*checkfn) PARAMS ((bfd *, struct bfd_link_info *, + boolean *pneeded)); +{ + carsym *arsyms; + carsym *arsym_end; + register carsym *arsym; + int pass; + struct archive_hash_table arsym_hash; + int indx; + struct bfd_link_hash_entry **pundef; + + if (! bfd_has_map (abfd)) + { + bfd_error = no_symbols; + return false; + } + + arsyms = bfd_ardata (abfd)->symdefs; + arsym_end = arsyms + bfd_ardata (abfd)->symdef_count; + + /* In order to quickly determine whether an symbol is defined in + this archive, we build a hash table of the symbols. */ + if (! archive_hash_table_init (&arsym_hash, archive_hash_newfunc)) + return false; + for (arsym = arsyms, indx = 0; arsym < arsym_end; arsym++, indx++) + { + struct archive_hash_entry *arh; + struct archive_list *l; + + 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)); + l->next = arh->defs; + arh->defs = l; + l->indx = indx; + } + + pass = 1; + + /* New undefined symbols are added to the end of the list, so we + only need to look through it once. */ + pundef = &info->hash->undefs; + while (*pundef != (struct bfd_link_hash_entry *) NULL) + { + struct bfd_link_hash_entry *h; + struct archive_hash_entry *arh; + struct archive_list *l; + + h = *pundef; + + /* When a symbol is defined, it is not necessarily removed from + the list. */ + if (h->type != bfd_link_hash_undefined + && h->type != bfd_link_hash_common) + { + /* Remove this entry from the list, for general cleanliness + and because we are going to look through the list again + if we search any more libraries. We can't remove the + entry if it is the tail, because that would lose any + entries we add to the list later on. */ + if (*pundef != info->hash->undefs_tail) + *pundef = (*pundef)->next; + else + pundef = &(*pundef)->next; + continue; + } + + /* Look for this symbol in the archive symbol map. */ + arh = archive_hash_lookup (&arsym_hash, h->root.string, false, false); + if (arh == (struct archive_hash_entry *) NULL) + { + pundef = &(*pundef)->next; + continue; + } + + /* Look at all the objects which define this symbol. */ + for (l = arh->defs; l != (struct archive_list *) NULL; l = l->next) + { + bfd *element; + boolean needed; + + /* If the symbol has gotten defined along the way, quit. */ + if (h->type != bfd_link_hash_undefined + && h->type != bfd_link_hash_common) + break; + + element = bfd_get_elt_at_index (abfd, l->indx); + if (element == (bfd *) NULL) + return false; + + /* If we've already included this element, or if we've + already checked it on this pass, continue. */ + if (element->archive_pass == -1 + || element->archive_pass == pass) + continue; + + /* If we can't figure this element out, just ignore it. */ + if (! bfd_check_format (element, bfd_object)) + { + element->archive_pass = -1; + continue; + } + + /* CHECKFN will see if this element should be included, and + go ahead and include it if appropriate. */ + if (! (*checkfn) (element, info, &needed)) + return false; + + if (! needed) + element->archive_pass = pass; + else + { + element->archive_pass = -1; + + /* Increment the pass count to show that we may need to + recheck object files which were already checked. */ + ++pass; + } + } + + pundef = &(*pundef)->next; + } + + archive_hash_table_free (&arsym_hash); + + return true; +} + +/* See if we should include an archive element. */ + +static boolean +generic_link_check_archive_element (abfd, info, pneeded) + bfd *abfd; + struct bfd_link_info *info; + boolean *pneeded; +{ + size_t symsize; + asymbol **symbols; + bfd_size_type symbol_count; + asymbol **pp, **ppend; + + *pneeded = false; + + symsize = get_symtab_upper_bound (abfd); + symbols = (asymbol **) alloca (symsize); + symbol_count = bfd_canonicalize_symtab (abfd, symbols); + + pp = symbols; + ppend = symbols + symbol_count; + for (; pp < ppend; pp++) + { + asymbol *p; + struct bfd_link_hash_entry *h; + + p = *pp; + + /* We are only interested in globally visible symbols. */ + if (! bfd_is_com_section (p->section) + && (p->flags & (BSF_GLOBAL | BSF_INDIRECT | BSF_WEAK)) == 0) + continue; + + /* We are only interested if we know something about this + symbol, and it is undefined or common. An undefined weak + symbol (type bfd_link_hash_weak) is not considered to be a + reference when pulling files out of an archive. See the SVR4 + ABI, p. 4-27. */ + h = bfd_link_hash_lookup (info->hash, bfd_asymbol_name (p), false, + false, true); + if (h == (struct bfd_link_hash_entry *) NULL + || (h->type != bfd_link_hash_undefined + && h->type != bfd_link_hash_common)) + continue; + + /* P is a symbol we are looking for. */ + + if (! bfd_is_com_section (p->section)) + { + /* This object file defines this symbol, so pull it in. */ + if (! (*info->callbacks->add_archive_element) (info, abfd, + bfd_asymbol_name (p))) + return false; + if (! generic_link_add_symbol_list (abfd, info, symbol_count, + symbols)) + return false; + *pneeded = true; + return true; + } + + /* P is a common symbol. */ + + if (h->type == bfd_link_hash_undefined) + { + bfd *symbfd; + + symbfd = h->u.undef.abfd; + if (symbfd == (bfd *) NULL) + { + /* This symbol was created as undefined from outside + BFD. We assume that we should link in the object + file. This is for the -u option in the linker. */ + if (! (*info->callbacks->add_archive_element) + (info, abfd, bfd_asymbol_name (p))) + return false; + *pneeded = true; + return true; + } + + /* Turn the symbol into a common symbol but do not link in + the object file. This is how a.out works. Object + formats that require different semantics must implement + this function differently. This symbol is already on the + undefs list. */ + h->type = bfd_link_hash_common; + h->u.c.size = bfd_asymbol_value (p); + h->u.c.section = bfd_make_section_old_way (symbfd, + "COMMON"); + } + else + { + /* Adjust the size of the common symbol if necessary. This + is how a.out works. Object formats that require + different semantics must implement this function + differently. */ + if (bfd_asymbol_value (p) > h->u.c.size) + h->u.c.size = bfd_asymbol_value (p); + } + } + + /* This archive element is not needed. */ + return true; +} + +/* Add the symbol from an object file to the global hash table. */ + +static boolean +generic_link_add_symbol_list (abfd, info, symbol_count, symbols) + bfd *abfd; + struct bfd_link_info *info; + bfd_size_type symbol_count; + asymbol **symbols; +{ + asymbol **pp, **ppend; + + pp = symbols; + ppend = symbols + symbol_count; + for (; pp < ppend; pp++) + { + asymbol *p; + + p = *pp; + + if ((p->flags & (BSF_INDIRECT + | BSF_WARNING + | BSF_GLOBAL + | BSF_CONSTRUCTOR + | BSF_WEAK)) != 0 + || bfd_get_section (p) == &bfd_und_section + || bfd_is_com_section (bfd_get_section (p)) + || bfd_get_section (p) == &bfd_ind_section) + { + const char *name; + const char *string; + struct generic_link_hash_entry *h; + + name = bfd_asymbol_name (p); + if ((p->flags & BSF_INDIRECT) != 0 + || p->section == &bfd_ind_section) + string = bfd_asymbol_name ((asymbol *) p->value); + else if ((p->flags & BSF_WARNING) != 0) + { + /* The name of P is actually the warning string, and the + value is actually a pointer to the symbol to warn + about. */ + string = name; + name = bfd_asymbol_name ((asymbol *) p->value); + } + else + string = NULL; + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, name, p->flags, bfd_get_section (p), + p->value, string, false, + (struct bfd_link_hash_entry **) &h))) + return false; + + /* Save the BFD symbol so that we don't lose any backend + specific information that may be attached to it. We only + want this one if it gives more information than the + existing one; we don't want to replace a defined symbol + with an undefined one. This routine may be called with a + hash table other than the generic hash table, so we only + do this if we are certain that the hash table is a + generic one. */ + if (info->hash->creator == abfd->xvec) + { + if (h->sym == (asymbol *) NULL + || (bfd_get_section (p) != &bfd_und_section + && (! bfd_is_com_section (bfd_get_section (p)) + || (bfd_get_section (h->sym) == &bfd_und_section)))) + h->sym = p; + } + } + } + + return true; +} + +/* We use a state table to deal with adding symbols from an object + file. The first index into the state table describes the symbol + from the object file. The second index into the state table is the + type of the symbol in the hash table. */ + +/* The symbol from the object file is turned into one of these row + values. */ + +enum link_row +{ + UNDEF_ROW, /* Undefined. */ + UNDEFW_ROW, /* Weak undefined. */ + DEF_ROW, /* Defined. */ + DEFW_ROW, /* Weak defined. */ + COMMON_ROW, /* Common. */ + INDR_ROW, /* Indirect. */ + WARN_ROW, /* Warning. */ + SET_ROW /* Member of set. */ +}; + +/* The actions to take in the state table. */ + +enum link_action +{ + FAIL, /* Abort. */ + UND, /* Mark symbol undefined. */ + WEAK, /* Mark symbol weak undefined. */ + DEF, /* Mark symbol defined. */ + COM, /* Mark symbol common. */ + CREF, /* Possibly warn about common reference to defined symbol. */ + CDEF, /* Define existing common symbol. */ + NOACT, /* No action. */ + BIG, /* Mark symbol common using largest size. */ + MDEF, /* Multiple definition error. */ + IND, /* Make indirect symbol. */ + SET, /* Add value to set. */ + MWARN, /* Make warning symbol. */ + WARN, /* Issue warning. */ + CYCLE, /* Repeat with symbol pointed to. */ + WARNC /* Issue warning and then CYCLE. */ +}; + +/* The state table itself. The first index is a link_row and the + second index is a bfd_link_hash_type. */ + +static const enum link_action link_action[8][7] = +{ + /* current\prev new undef weak def com indr warn */ + /* UNDEF_ROW */ {UND, NOACT, NOACT, NOACT, NOACT, CYCLE, WARNC }, + /* UNDEFW_ROW */ {WEAK, WEAK, NOACT, NOACT, NOACT, CYCLE, WARNC }, + /* DEF_ROW */ {DEF, DEF, DEF, MDEF, CDEF, CYCLE, CYCLE }, + /* DEFW_ROW */ {DEF, DEF, DEF, NOACT, NOACT, CYCLE, CYCLE }, + /* COMMON_ROW */ {COM, COM, COM, CREF, BIG, CYCLE, WARNC }, + /* INDR_ROW */ {IND, IND, IND, MDEF, MDEF, MDEF, WARNC }, + /* WARN_ROW */ {MWARN, WARN, WARN, MWARN, MWARN, MWARN, NOACT }, + /* SET_ROW */ {SET, SET, SET, SET, SET, CYCLE, WARNC } +}; + +/* Add a symbol to the global hash table. + ABFD is the BFD the symbol comes from. + NAME is the name of the symbol. + FLAGS is the BSF_* bits associated with the symbol. + SECTION is the section in which the symbol is defined; this may be + bfd_und_section or bfd_com_section. + VALUE is the value of the symbol, relative to the section. + STRING is used for either an indirect symbol, in which case it is + the name of the symbol to indirect to, or a warning symbol, in + which case it is the warning string. + COPY is true if NAME or STRING must be copied into locally + allocated memory if they need to be saved. + 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, hashp) + struct bfd_link_info *info; + bfd *abfd; + const char *name; + flagword flags; + asection *section; + bfd_vma value; + const char *string; + boolean copy; + struct bfd_link_hash_entry **hashp; +{ + enum link_row row; + struct bfd_link_hash_entry *h; + boolean cycle; + + if (section == &bfd_ind_section + || (flags & BSF_INDIRECT) != 0) + row = INDR_ROW; + else if ((flags & BSF_WARNING) != 0) + row = WARN_ROW; + else if ((flags & BSF_CONSTRUCTOR) != 0) + row = SET_ROW; + else if (section == &bfd_und_section) + { + if ((flags & BSF_WEAK) != 0) + row = UNDEFW_ROW; + else + row = UNDEF_ROW; + } + else if ((flags & BSF_WEAK) != 0) + row = DEFW_ROW; + else if (bfd_is_com_section (section)) + row = COMMON_ROW; + else + row = DEF_ROW; + + h = bfd_link_hash_lookup (info->hash, name, true, copy, false); + if (h == (struct bfd_link_hash_entry *) NULL) + { + if (hashp != (struct bfd_link_hash_entry **) NULL) + *hashp = NULL; + return false; + } + + if (info->notice_hash != (struct bfd_hash_table *) NULL + && (bfd_hash_lookup (info->notice_hash, name, false, false) + != (struct bfd_hash_entry *) NULL)) + { + if (! (*info->callbacks->notice) (info, name, abfd, section, value)) + return false; + } + + if (hashp != (struct bfd_link_hash_entry **) NULL) + *hashp = h; + + do + { + enum link_action action; + + cycle = false; + action = link_action[(int) row][(int) h->type]; + switch (action) + { + case FAIL: + abort (); + case UND: + h->type = bfd_link_hash_undefined; + h->u.undef.abfd = abfd; + bfd_link_add_undef (info->hash, h); + break; + case WEAK: + h->type = bfd_link_hash_weak; + h->u.undef.abfd = abfd; + break; + case CDEF: + BFD_ASSERT (h->type == bfd_link_hash_common); + if (! ((*info->callbacks->multiple_common) + (info, name, + h->u.c.section->owner, bfd_link_hash_common, h->u.c.size, + abfd, bfd_link_hash_defined, (bfd_vma) 0))) + return false; + /* Fall through. */ + case DEF: + h->type = bfd_link_hash_defined; + h->u.def.section = section; + h->u.def.value = value; + break; + case COM: + if (h->type == bfd_link_hash_new) + bfd_link_add_undef (info->hash, h); + h->type = bfd_link_hash_common; + h->u.c.size = value; + if (section == &bfd_com_section) + h->u.c.section = bfd_make_section_old_way (abfd, "COMMON"); + else if (section->owner != abfd) + h->u.c.section = bfd_make_section_old_way (abfd, section->name); + else + h->u.c.section = section; + break; + case NOACT: + break; + case BIG: + BFD_ASSERT (h->type == bfd_link_hash_common); + if (! ((*info->callbacks->multiple_common) + (info, name, + h->u.c.section->owner, bfd_link_hash_common, h->u.c.size, + abfd, bfd_link_hash_common, value))) + return false; + if (value > h->u.c.size) + h->u.c.size = value; + if (h->u.c.section == (asection *) NULL) + h->u.c.section = bfd_make_section_old_way (abfd, "COMMON"); + break; + case CREF: + BFD_ASSERT (h->type == bfd_link_hash_defined); + if (! ((*info->callbacks->multiple_common) + (info, name, + h->u.def.section->owner, bfd_link_hash_defined, (bfd_vma) 0, + abfd, bfd_link_hash_common, value))) + return false; + break; + case MDEF: + { + asection *msec; + bfd_vma mval; + + switch (h->type) + { + case bfd_link_hash_defined: + msec = h->u.def.section; + mval = h->u.def.value; + break; + case bfd_link_hash_common: + msec = &bfd_com_section; + mval = h->u.c.size; + break; + case bfd_link_hash_indirect: + msec = &bfd_ind_section; + mval = 0; + break; + default: + abort (); + } + + if (! ((*info->callbacks->multiple_definition) + (info, name, msec->owner, msec, mval, abfd, section, + value))) + return false; + } + break; + case IND: + { + struct bfd_link_hash_entry *inh; + + /* STRING is the name of the symbol we want to indirect + to. */ + inh = bfd_link_hash_lookup (info->hash, string, true, copy, + false); + if (inh == (struct bfd_link_hash_entry *) NULL) + return false; + if (inh->type == bfd_link_hash_new) + { + inh->type = bfd_link_hash_undefined; + inh->u.undef.abfd = abfd; + bfd_link_add_undef (info->hash, inh); + } + h->type = bfd_link_hash_indirect; + h->u.i.link = inh; + } + break; + case SET: + if (! (*info->callbacks->add_to_set) (info, h, abfd, section, value)) + return false; + break; + case WARN: + case WARNC: + if (h->u.i.warning != NULL) + { + if (! (*info->callbacks->warning) (info, h->u.i.warning)) + return false; + /* Only issue a warning once. */ + h->u.i.warning = NULL; + } + if (action == WARN) + break; + /* Fall through. */ + case CYCLE: + h = h->u.i.link; + cycle = true; + break; + case MWARN: + { + struct bfd_link_hash_entry *sub; + + /* STRING is the warning to give. */ + sub = ((struct bfd_link_hash_entry *) + bfd_hash_allocate (&info->hash->table, + sizeof (struct bfd_link_hash_entry))); + *sub = *h; + h->type = bfd_link_hash_warning; + h->u.i.link = sub; + if (! copy) + h->u.i.warning = string; + else + { + char *w; + + w = bfd_hash_allocate (&info->hash->table, + strlen (string) + 1); + strcpy (w, string); + h->u.i.warning = w; + } + } + break; + } + } + while (cycle); + + return true; +} + +/* Generic final link routine. */ + +boolean +_bfd_generic_final_link (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + bfd *sub; + asection *o; + struct bfd_link_order *p; + size_t outsymalloc; + struct generic_write_global_symbol_info wginfo; + + abfd->outsymbols = (asymbol **) NULL; + abfd->symcount = 0; + outsymalloc = 0; + + /* Build the output symbol table. This also reads in the symbols + for all the input BFDs, keeping them in the outsymbols field. */ + for (sub = info->input_bfds; sub != (bfd *) NULL; sub = sub->link_next) + if (! _bfd_generic_link_output_symbols (abfd, sub, info, &outsymalloc)) + return false; + + /* Accumulate the global symbols. */ + wginfo.output_bfd = abfd; + wginfo.psymalloc = &outsymalloc; + _bfd_generic_link_hash_traverse (_bfd_generic_hash_table (info), + _bfd_generic_link_write_global_symbol, + (PTR) &wginfo); + + if (info->relocateable) + { + /* Allocate space for the output relocs for each section. */ + for (o = abfd->sections; + 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) + { + asection *input_section; + bfd *input_bfd; + bfd_size_type relsize; + arelent **relocs; + bfd_size_type reloc_count; + + input_section = p->u.indirect.section; + input_bfd = input_section->owner; + relsize = bfd_get_reloc_upper_bound (input_bfd, + input_section); + relocs = (arelent **) bfd_xmalloc (relsize); + reloc_count = + bfd_canonicalize_reloc (input_bfd, input_section, + relocs, + bfd_get_outsymbols (input_bfd)); + BFD_ASSERT (reloc_count == input_section->reloc_count); + o->reloc_count += reloc_count; + free (relocs); + } + } + if (o->reloc_count > 0) + { + o->orelocation = ((arelent **) + bfd_alloc (abfd, + (o->reloc_count + * sizeof (arelent *)))); + /* Reset the count so that it can be used as an index + when putting in the output relocs. */ + o->reloc_count = 0; + } + } + } + + /* Handle all the link order information for the sections. */ + for (o = abfd->sections; + o != (asection *) NULL; + o = o->next) + { + for (p = o->link_order_head; + p != (struct bfd_link_order *) NULL; + p = p->next) + { + switch (p->type) + { + case bfd_indirect_link_order: + if (! _bfd_generic_indirect_link_order (abfd, info, o, p)) + return false; + break; + default: + if (! _bfd_default_link_order (abfd, info, o, p)) + return false; + break; + } + } + } + + return true; +} + +/* Add an output symbol to the output BFD. */ + +static boolean +generic_add_output_symbol (output_bfd, psymalloc, sym) + bfd *output_bfd; + size_t *psymalloc; + asymbol *sym; +{ + if (output_bfd->symcount >= *psymalloc) + { + asymbol **newsyms; + + if (*psymalloc == 0) + *psymalloc = 124; + else + *psymalloc *= 2; + if (output_bfd->outsymbols == (asymbol **) NULL) + newsyms = (asymbol **) malloc (*psymalloc * sizeof (asymbol *)); + else + newsyms = (asymbol **) realloc (output_bfd->outsymbols, + *psymalloc * sizeof (asymbol *)); + if (newsyms == (asymbol **) NULL) + { + bfd_error = no_memory; + return false; + } + output_bfd->outsymbols = newsyms; + } + + output_bfd->outsymbols[output_bfd->symcount] = sym; + ++output_bfd->symcount; + + return true; +} + +/* Handle the symbols for an input BFD. */ + +boolean +_bfd_generic_link_output_symbols (output_bfd, input_bfd, info, psymalloc) + bfd *output_bfd; + bfd *input_bfd; + struct bfd_link_info *info; + size_t *psymalloc; +{ + size_t symsize; + asymbol **sym_ptr; + asymbol **sym_end; + + symsize = get_symtab_upper_bound (input_bfd); + input_bfd->outsymbols = (asymbol **) bfd_alloc (input_bfd, symsize); + input_bfd->symcount = bfd_canonicalize_symtab (input_bfd, + input_bfd->outsymbols); + + /* Create a filename symbol if we are supposed to. */ + if (info->create_object_symbols_section != (asection *) NULL) + { + asection *sec; + + for (sec = input_bfd->sections; + sec != (asection *) NULL; + sec = sec->next) + { + if (sec->output_section == info->create_object_symbols_section) + { + asymbol *newsym; + + newsym = bfd_make_empty_symbol (input_bfd); + newsym->name = input_bfd->filename; + newsym->value = 0; + newsym->flags = BSF_LOCAL | BSF_FILE; + newsym->section = sec; + + if (! generic_add_output_symbol (output_bfd, psymalloc, + newsym)) + return false; + + break; + } + } + } + + /* Adjust the values of the globally visible symbols, and write out + local symbols. */ + sym_ptr = bfd_get_outsymbols (input_bfd); + sym_end = sym_ptr + bfd_get_symcount (input_bfd); + for (; sym_ptr < sym_end; sym_ptr++) + { + asymbol *sym; + struct generic_link_hash_entry *h; + boolean output; + + h = (struct generic_link_hash_entry *) NULL; + sym = *sym_ptr; + if ((sym->flags & (BSF_INDIRECT + | BSF_WARNING + | BSF_GLOBAL + | BSF_CONSTRUCTOR + | BSF_WEAK)) != 0 + || bfd_get_section (sym) == &bfd_und_section + || bfd_is_com_section (bfd_get_section (sym)) + || bfd_get_section (sym) == &bfd_ind_section) + { + h = _bfd_generic_link_hash_lookup (_bfd_generic_hash_table (info), + bfd_asymbol_name (sym), + false, false, true); + if (h != (struct generic_link_hash_entry *) NULL) + { + /* Force all references to this symbol to point to + the same area in memory. It is possible that + this routine will be called with a hash table + other than a generic hash table, so we double + check that. */ + if (info->hash->creator == input_bfd->xvec) + { + if (h->sym != (asymbol *) NULL) + *sym_ptr = sym = h->sym; + } + + switch (h->root.type) + { + default: + case bfd_link_hash_new: + abort (); + case bfd_link_hash_undefined: + case bfd_link_hash_weak: + break; + case bfd_link_hash_defined: + sym->value = h->root.u.def.value; + sym->section = h->root.u.def.section; + sym->flags |= BSF_GLOBAL; + break; + case bfd_link_hash_common: + sym->value = h->root.u.c.size; + sym->flags |= BSF_GLOBAL; + /* We do not set the section of the symbol to + c.section. c.section is saved so that we know + where to allocate the symbol if we define it. In + this case the type is still bfd_link_hash_common, + so we did not define it, so we do not want to use + that section. */ + BFD_ASSERT (bfd_is_com_section (sym->section)); + break; + } + } + } + + /* This switch is straight from the old code in + write_file_locals in ldsym.c. */ + if (info->strip == strip_some + && (bfd_hash_lookup (info->keep_hash, bfd_asymbol_name (sym), + false, false) + == (struct bfd_hash_entry *) NULL)) + output = false; + else if ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0) + { + /* If this symbol is marked as occurring now, rather + than at the end, output it now. This is used for + COFF C_EXT FCN symbols. FIXME: There must be a + better way. */ + if (bfd_asymbol_bfd (sym) == input_bfd + && (sym->flags & BSF_NOT_AT_END) != 0) + output = true; + else + output = false; + } + else if (sym->section == &bfd_ind_section) + output = false; + else if ((sym->flags & BSF_DEBUGGING) != 0) + { + if (info->strip == strip_none) + output = true; + else + output = false; + } + else if (sym->section == &bfd_und_section + || bfd_is_com_section (sym->section)) + output = false; + else if ((sym->flags & BSF_LOCAL) != 0) + { + if ((sym->flags & BSF_WARNING) != 0) + output = false; + else + { + switch (info->discard) + { + default: + case discard_all: + output = false; + break; + case discard_l: + if (bfd_asymbol_name (sym)[0] == info->lprefix[0] + && (info->lprefix_len == 1 + || strncmp (bfd_asymbol_name (sym), info->lprefix, + info->lprefix_len) == 0)) + output = false; + else + output = true; + break; + case discard_none: + output = true; + break; + } + } + } + else if ((sym->flags & BSF_CONSTRUCTOR)) + { + if (info->strip != strip_all) + output = true; + else + output = false; + } + else + abort (); + + if (output) + { + if (! generic_add_output_symbol (output_bfd, psymalloc, sym)) + return false; + if (h != (struct generic_link_hash_entry *) NULL) + h->root.written = true; + } + } + + return true; +} + +/* Write out a global symbol, if it hasn't already been written out. + This is called for each symbol in the hash table. */ + +boolean +_bfd_generic_link_write_global_symbol (h, data) + struct generic_link_hash_entry *h; + PTR data; +{ + struct generic_write_global_symbol_info *wginfo = + (struct generic_write_global_symbol_info *) data; + asymbol *sym; + + if (h->root.written) + return true; + + if (h->sym != (asymbol *) NULL) + { + sym = h->sym; + BFD_ASSERT (strcmp (bfd_asymbol_name (sym), h->root.root.string) == 0); + } + else + { + sym = bfd_make_empty_symbol (wginfo->output_bfd); + sym->name = h->root.root.string; + sym->flags = 0; + } + + switch (h->root.type) + { + default: + case bfd_link_hash_new: + abort (); + case bfd_link_hash_undefined: + sym->section = &bfd_und_section; + sym->value = 0; + break; + case bfd_link_hash_weak: + sym->section = &bfd_und_section; + sym->value = 0; + sym->flags |= BSF_WEAK; + case bfd_link_hash_defined: + sym->section = h->root.u.def.section; + sym->value = h->root.u.def.value; + break; + case bfd_link_hash_common: + sym->value = h->root.u.c.size; + /* Do not set the section; see _bfd_generic_link_output_symbols. */ + BFD_ASSERT (bfd_is_com_section (sym->section)); + break; + case bfd_link_hash_indirect: + case bfd_link_hash_warning: + /* FIXME: What should we do here? */ + break; + } + + sym->flags |= BSF_GLOBAL; + + if (! generic_add_output_symbol (wginfo->output_bfd, wginfo->psymalloc, + sym)) + { + /* FIXME: No way to return failure. */ + abort (); + } + + h->root.written = true; + + return true; +} + +/* Handle an indirect section when doing a generic link. */ + +boolean +_bfd_generic_indirect_link_order (output_bfd, info, output_section, link_order) + bfd *output_bfd; + struct bfd_link_info *info; + asection *output_section; + struct bfd_link_order *link_order; +{ + asection *input_section; + bfd *input_bfd; + bfd_byte *contents; + + BFD_ASSERT ((output_section->flags & SEC_HAS_CONTENTS) != 0); + + if (link_order->size == 0) + return true; + + input_section = link_order->u.indirect.section; + input_bfd = input_section->owner; + + BFD_ASSERT (input_section->output_section == output_section); + BFD_ASSERT (input_section->output_offset == link_order->offset); + BFD_ASSERT (bfd_section_size (input_bfd, input_section) == link_order->size); + + /* 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))); + + /* Output the section contents. */ + if (! bfd_set_section_contents (output_bfd, output_section, contents, + link_order->offset, link_order->size)) + return false; + + return true; +} + +/* Allocate a new link_order for a section. */ + +struct bfd_link_order * +bfd_new_link_order (abfd, section) + bfd *abfd; + asection *section; +{ + struct bfd_link_order *new; + + new = ((struct bfd_link_order *) + bfd_alloc_by_size_t (abfd, sizeof (struct bfd_link_order))); + + new->type = bfd_undefined_link_order; + new->offset = 0; + new->size = 0; + new->next = (struct bfd_link_order *) NULL; + + if (section->link_order_tail != (struct bfd_link_order *) NULL) + section->link_order_tail->next = new; + else + section->link_order_head = new; + section->link_order_tail = new; + + return new; +} + +/* Default link order processing routine. */ + +boolean +_bfd_default_link_order (abfd, info, sec, link_order) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + struct bfd_link_order *link_order; +{ + switch (link_order->type) + { + case bfd_undefined_link_order: + default: + abort (); + case bfd_indirect_link_order: + abort (); + case bfd_fill_link_order: + return default_fill_link_order (abfd, info, sec, link_order); + } +} + +/* Default routine to handle a bfd_fill_link_order. */ + +static boolean +default_fill_link_order (abfd, info, sec, link_order) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + struct bfd_link_order *link_order; +{ + size_t size; + char *space; + size_t i; + int fill; + + BFD_ASSERT ((sec->flags & SEC_HAS_CONTENTS) != 0); + + size = (size_t) link_order->size; + space = (char *) alloca (size); + 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); +} diff --git a/bfd/seclet.c b/bfd/seclet.c deleted file mode 100644 index 5a6c37d3bbf..00000000000 --- a/bfd/seclet.c +++ /dev/null @@ -1,185 +0,0 @@ -/* seclet.c - Copyright (C) 1992, 1993 Free Software Foundation, Inc. - Written by Cygnus Support. - -This file is part of BFD, the Binary File Descriptor library. - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/* This module is part of BFD */ - - -/* The intention is that one day, all the code which uses sections - will change and use seclets instead - maybe seglet would have been - a better name.. - - Anyway, a seclet contains enough info to be able to describe an - area of output memory in one go. - - The only description so far catered for is that of the - <>, which is a select which points to a - <
> and the <> associated with the section, so - that relocation can be done when needed. - - One day there will be more types - they will at least migrate from - the linker's data structures - also there could be extra stuff, - like a bss seclet, which descibes a lump of memory as containing - zeros compactly, without the horrible SEC_* flag cruft. - - -*/ - -#include "bfd.h" -#include "sysdep.h" -#include "libbfd.h" -#include "seclet.h" -#include "coff/internal.h" - -/* Create a new seclet and attach it to a section. */ - -bfd_seclet_type * -DEFUN(bfd_new_seclet,(abfd, section), - bfd *abfd AND - asection *section) -{ - bfd_seclet_type *n = (bfd_seclet_type *)bfd_alloc(abfd, sizeof(bfd_seclet_type)); - if (section->seclets_tail != (bfd_seclet_type *)NULL) { - section->seclets_tail->next = n; - } - else - { - section->seclets_head = n; - } - section->seclets_tail = n; - - return n; -} - -/* Given an indirect seclet which points to an input section, relocate - the contents of the seclet and put the data in its final - destination. */ - -static boolean -DEFUN(rel,(abfd, seclet, output_section, data, relocateable), - bfd *abfd AND - bfd_seclet_type *seclet AND - asection *output_section AND - PTR data AND - boolean relocateable) -{ - if ((output_section->flags & SEC_HAS_CONTENTS) != 0 - && seclet->size) - { - data = (PTR) bfd_get_relocated_section_contents(abfd, seclet, data, - relocateable); - if(bfd_set_section_contents(abfd, - output_section, - data, - seclet->offset, - seclet->size) == false) - { - return false; - } - } - return true; -} - -/* Put the contents of a seclet in its final destination. */ - -static boolean -DEFUN(seclet_dump_seclet,(abfd, seclet, section, data, relocateable), - bfd *abfd AND - bfd_seclet_type *seclet AND - asection *section AND - PTR data AND - boolean relocateable) -{ - switch (seclet->type) - { - case bfd_indirect_seclet: - /* The contents of this section come from another one somewhere - else */ - return rel(abfd, seclet, section, data, relocateable); - - case bfd_fill_seclet: - /* Fill in the section with us */ - { - char *d = bfd_xmalloc(seclet->size); - unsigned int i; - for (i =0; i < seclet->size; i+=2) { - d[i] = seclet->u.fill.value >> 8; - } - for (i = 1; i < seclet->size; i+=2) { - d[i] = seclet->u.fill.value ; - } - /* Don't bother to fill in empty sections */ - if (!(bfd_get_section_flags(abfd, section) & SEC_HAS_CONTENTS)) - { - return true; - } - return bfd_set_section_contents(abfd, section, d, seclet->offset, - seclet->size); - } - - default: - abort(); - } - - return true; -} - -/* -INTERNAL_FUNCTION - bfd_generic_seclet_link - -SYNOPSIS - boolean bfd_generic_seclet_link - (bfd *abfd, - PTR data, - boolean relocateable); - -DESCRIPTION - - The generic seclet linking routine. The caller should have - set up seclets for all the output sections. The DATA argument - should point to a memory area large enough to hold the largest - section. This function looks through the seclets and moves - the contents into the output sections. If RELOCATEABLE is - true, the orelocation fields of the output sections must - already be initialized. - -*/ - -boolean -DEFUN(bfd_generic_seclet_link,(abfd, data, relocateable), - bfd *abfd AND - PTR data AND - boolean relocateable) -{ - asection *o = abfd->sections; - while (o != (asection *)NULL) - { - bfd_seclet_type *p = o->seclets_head; - while (p != (bfd_seclet_type *)NULL) - { - if (seclet_dump_seclet(abfd, p, o, data, relocateable) == false) - return false; - p = p ->next; - } - o = o->next; - } - - return true; -} diff --git a/bfd/seclet.h b/bfd/seclet.h deleted file mode 100644 index de5fdff0bb1..00000000000 --- a/bfd/seclet.h +++ /dev/null @@ -1,55 +0,0 @@ -/* Definitions of little sections (seclets) for BFD. - Copyright 1992 Free Software Foundation, Inc. - Hacked by Steve Chamberlain of Cygnus Support. - -This file is part of BFD, the Binary File Descriptor library. - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#ifndef _SECLET_H -#define _SECLET_H - -enum bfd_seclet_enum -{ - bfd_indirect_seclet, - bfd_fill_seclet -}; - -struct bfd_seclet -{ - struct bfd_seclet *next; - enum bfd_seclet_enum type; - unsigned int offset; - unsigned int size; - union - { - struct - { - asection *section; - asymbol **symbols; - } indirect; - struct { - int value; - } fill; - } - u; -}; - -typedef struct bfd_seclet bfd_seclet_type; - -bfd_seclet_type * -bfd_new_seclet PARAMS ((bfd *, asection *)); - -#endif