/* linker.c -- BFD linker routines
- Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
- Free Software Foundation, Inc.
+ Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+ 2003, 2004 Free Software Foundation, Inc.
Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support
-This file is part of BFD, the Binary File Descriptor library.
+ 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 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.
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "bfd.h"
#include "sysdep.h"
For example, with each entry in the hash table the a.out
linker keeps the index the symbol has in the final output file
- (this index number is used so that when doing a relocateable
+ (this index number is used so that when doing a relocatable
link the symbol index used in the output file can be quickly
filled in when copying over a reloc). The a.out linker code
defines the required structures and functions for a hash table
the input sections and copy the data into the output sections.
It must build an output symbol table including any local
symbols from the input files and the global symbols from the
- hash table. When producing relocateable output, it must
+ hash table. When producing relocatable output, it must
modify the input relocs and write them into the output file.
There may also be object format dependent work to be done.
types of information. They also describe relocs that must be
created by the BFD backend, but do not correspond to any input
file; this is used to support -Ur, which builds constructors
- while generating a relocateable object file.
+ while generating a relocatable object file.
INODE
Relocating the section contents, Writing the symbol table, Information provided by the linker, Performing the Final Link
input files. The <<_bfd_final_link>> function should read the
contents of the section and any associated relocs, apply the
relocs to the section contents, and write out the modified
- section contents. If performing a relocateable link, the
+ section contents. If performing a relocatable link, the
relocs themselves must also be modified and written out.
@findex _bfd_relocate_contents
file at the end of <<NAME(aout,final_link)>>.
*/
-static bfd_boolean generic_link_read_symbols
- PARAMS ((bfd *));
-static bfd_boolean generic_link_add_symbols
- PARAMS ((bfd *, struct bfd_link_info *, bfd_boolean collect));
static bfd_boolean generic_link_add_object_symbols
- PARAMS ((bfd *, struct bfd_link_info *, bfd_boolean collect));
+ (bfd *, struct bfd_link_info *, bfd_boolean collect);
+static bfd_boolean generic_link_add_symbols
+ (bfd *, struct bfd_link_info *, bfd_boolean);
static bfd_boolean generic_link_check_archive_element_no_collect
- PARAMS ((bfd *, struct bfd_link_info *, bfd_boolean *pneeded));
+ (bfd *, struct bfd_link_info *, bfd_boolean *);
static bfd_boolean generic_link_check_archive_element_collect
- PARAMS ((bfd *, struct bfd_link_info *, bfd_boolean *pneeded));
+ (bfd *, struct bfd_link_info *, bfd_boolean *);
static bfd_boolean generic_link_check_archive_element
- PARAMS ((bfd *, struct bfd_link_info *, bfd_boolean *pneeded,
- bfd_boolean collect));
+ (bfd *, struct bfd_link_info *, bfd_boolean *, bfd_boolean);
static bfd_boolean generic_link_add_symbol_list
- PARAMS ((bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **,
- bfd_boolean collect));
-static bfd *hash_entry_bfd
- PARAMS ((struct bfd_link_hash_entry *));
-static void set_symbol_from_hash
- PARAMS ((asymbol *, struct bfd_link_hash_entry *));
+ (bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **,
+ bfd_boolean);
static bfd_boolean generic_add_output_symbol
- PARAMS ((bfd *, size_t *psymalloc, asymbol *));
+ (bfd *, size_t *psymalloc, asymbol *);
static bfd_boolean default_data_link_order
- PARAMS ((bfd *, struct bfd_link_info *, asection *,
- struct bfd_link_order *));
+ (bfd *, struct bfd_link_info *, asection *, struct bfd_link_order *);
static bfd_boolean default_indirect_link_order
- PARAMS ((bfd *, struct bfd_link_info *, asection *,
- struct bfd_link_order *, bfd_boolean));
+ (bfd *, struct bfd_link_info *, asection *, struct bfd_link_order *,
+ bfd_boolean);
/* The link hash table structure is defined in bfdlink.h. It provides
a base hash table which the backend specific hash tables are built
/* 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;
+_bfd_link_hash_newfunc (struct bfd_hash_entry *entry,
+ struct bfd_hash_table *table,
+ const char *string)
{
/* Allocate the structure if it has not already been allocated by a
subclass. */
if (entry == NULL)
{
- entry = (struct bfd_hash_entry *)
- bfd_hash_allocate (table, sizeof (struct bfd_link_hash_entry));
+ entry = bfd_hash_allocate (table, sizeof (struct bfd_link_hash_entry));
if (entry == NULL)
return entry;
}
/* Initialize the local fields. */
h->type = bfd_link_hash_new;
- h->next = NULL;
+ h->u.undef.next = NULL;
}
return entry;
responsible for creating this table. */
bfd_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 *));
+_bfd_link_hash_table_init
+ (struct bfd_link_hash_table *table,
+ bfd *abfd,
+ struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *,
+ struct bfd_hash_table *,
+ const char *))
{
table->creator = abfd->xvec;
table->undefs = NULL;
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;
- bfd_boolean create;
- bfd_boolean copy;
- bfd_boolean follow;
+bfd_link_hash_lookup (struct bfd_link_hash_table *table,
+ const char *string,
+ bfd_boolean create,
+ bfd_boolean copy,
+ bfd_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)
+ if (follow && ret != NULL)
{
while (ret->type == bfd_link_hash_indirect
|| ret->type == bfd_link_hash_warning)
undefined symbol, not for definitions of a symbol. */
struct bfd_link_hash_entry *
-bfd_wrapped_link_hash_lookup (abfd, info, string, create, copy, follow)
- bfd *abfd;
- struct bfd_link_info *info;
- const char *string;
- bfd_boolean create;
- bfd_boolean copy;
- bfd_boolean follow;
+bfd_wrapped_link_hash_lookup (bfd *abfd,
+ struct bfd_link_info *info,
+ const char *string,
+ bfd_boolean create,
+ bfd_boolean copy,
+ bfd_boolean follow)
{
bfd_size_type amt;
if (info->wrap_hash != NULL)
{
const char *l;
+ char prefix = '\0';
l = string;
- if (*l == bfd_get_symbol_leading_char (abfd))
- ++l;
+ if (*l == bfd_get_symbol_leading_char (abfd) || *l == info->wrap_char)
+ {
+ prefix = *l;
+ ++l;
+ }
#undef WRAP
#define WRAP "__wrap_"
references to SYM with references to __wrap_SYM. */
amt = strlen (l) + sizeof WRAP + 1;
- n = (char *) bfd_malloc (amt);
+ n = bfd_malloc (amt);
if (n == NULL)
return NULL;
- /* Note that symbol_leading_char may be '\0'. */
- n[0] = bfd_get_symbol_leading_char (abfd);
+ n[0] = prefix;
n[1] = '\0';
strcat (n, WRAP);
strcat (n, l);
with references to SYM. */
amt = strlen (l + sizeof REAL - 1) + 2;
- n = (char *) bfd_malloc (amt);
+ n = bfd_malloc (amt);
if (n == NULL)
return NULL;
- /* Note that symbol_leading_char may be '\0'. */
- n[0] = bfd_get_symbol_leading_char (abfd);
+ n[0] = prefix;
n[1] = '\0';
strcat (n, l + sizeof REAL - 1);
h = bfd_link_hash_lookup (info->hash, n, create, TRUE, follow);
call. */
void
-bfd_link_hash_traverse (table, func, info)
- struct bfd_link_hash_table *table;
- bfd_boolean (*func) PARAMS ((struct bfd_link_hash_entry *, PTR));
- PTR info;
+bfd_link_hash_traverse
+ (struct bfd_link_hash_table *table,
+ bfd_boolean (*func) (struct bfd_link_hash_entry *, void *),
+ void *info)
{
bfd_hash_traverse (&table->table,
- ((bfd_boolean (*) PARAMS ((struct bfd_hash_entry *, PTR)))
- func),
+ (bfd_boolean (*) (struct bfd_hash_entry *, void *)) 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;
+void
+bfd_link_add_undef (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)
+ BFD_ASSERT (h->u.undef.next == NULL);
+ if (table->undefs_tail != NULL)
+ table->undefs_tail->u.undef.next = h;
+ if (table->undefs == NULL)
table->undefs = h;
table->undefs_tail = h;
}
\f
-/* Routine to create an entry in an generic link hash table. */
+/* Routine to create an entry in a generic link hash table. */
struct bfd_hash_entry *
-_bfd_generic_link_hash_newfunc (entry, table, string)
- struct bfd_hash_entry *entry;
- struct bfd_hash_table *table;
- const char *string;
+_bfd_generic_link_hash_newfunc (struct bfd_hash_entry *entry,
+ struct bfd_hash_table *table,
+ const char *string)
{
/* Allocate the structure if it has not already been allocated by a
subclass. */
if (entry == NULL)
{
- entry = (struct bfd_hash_entry *)
+ entry =
bfd_hash_allocate (table, sizeof (struct generic_link_hash_entry));
if (entry == NULL)
return entry;
return entry;
}
-/* Create an generic link hash table. */
+/* Create a generic link hash table. */
struct bfd_link_hash_table *
-_bfd_generic_link_hash_table_create (abfd)
- bfd *abfd;
+_bfd_generic_link_hash_table_create (bfd *abfd)
{
struct generic_link_hash_table *ret;
bfd_size_type amt = sizeof (struct generic_link_hash_table);
- ret = (struct generic_link_hash_table *) bfd_malloc (amt);
+ ret = bfd_malloc (amt);
if (ret == NULL)
- return (struct bfd_link_hash_table *) NULL;
+ return NULL;
if (! _bfd_link_hash_table_init (&ret->root, abfd,
_bfd_generic_link_hash_newfunc))
{
free (ret);
- return (struct bfd_link_hash_table *) NULL;
+ return NULL;
}
return &ret->root;
}
void
-_bfd_generic_link_hash_table_free (hash)
- struct bfd_link_hash_table *hash;
+_bfd_generic_link_hash_table_free (struct bfd_link_hash_table *hash)
{
struct generic_link_hash_table *ret
= (struct generic_link_hash_table *) hash;
structure. */
static bfd_boolean
-generic_link_read_symbols (abfd)
- bfd *abfd;
+generic_link_read_symbols (bfd *abfd)
{
- if (bfd_get_outsymbols (abfd) == (asymbol **) NULL)
+ if (bfd_get_outsymbols (abfd) == NULL)
{
long symsize;
long symcount;
symsize = bfd_get_symtab_upper_bound (abfd);
if (symsize < 0)
return FALSE;
- bfd_get_outsymbols (abfd) =
- (asymbol **) bfd_alloc (abfd, (bfd_size_type) symsize);
+ bfd_get_outsymbols (abfd) = bfd_alloc (abfd, symsize);
if (bfd_get_outsymbols (abfd) == NULL && symsize != 0)
return FALSE;
symcount = bfd_canonicalize_symtab (abfd, bfd_get_outsymbols (abfd));
constructors by name. */
bfd_boolean
-_bfd_generic_link_add_symbols (abfd, info)
- bfd *abfd;
- struct bfd_link_info *info;
+_bfd_generic_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
{
return generic_link_add_symbols (abfd, info, FALSE);
}
for which gcc uses collect2 and do not support stabs. */
bfd_boolean
-_bfd_generic_link_add_symbols_collect (abfd, info)
- bfd *abfd;
- struct bfd_link_info *info;
+_bfd_generic_link_add_symbols_collect (bfd *abfd, struct bfd_link_info *info)
{
return generic_link_add_symbols (abfd, info, TRUE);
}
file are absolute. */
void
-_bfd_generic_link_just_syms (sec, info)
- asection *sec;
- struct bfd_link_info *info ATTRIBUTE_UNUSED;
+_bfd_generic_link_just_syms (asection *sec,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED)
{
sec->output_section = bfd_abs_section_ptr;
sec->output_offset = sec->vma;
/* Add symbols from an object file to the global hash table. */
static bfd_boolean
-generic_link_add_symbols (abfd, info, collect)
- bfd *abfd;
- struct bfd_link_info *info;
- bfd_boolean collect;
+generic_link_add_symbols (bfd *abfd,
+ struct bfd_link_info *info,
+ bfd_boolean collect)
{
bfd_boolean ret;
/* Add symbols from an object file to the global hash table. */
static bfd_boolean
-generic_link_add_object_symbols (abfd, info, collect)
- bfd *abfd;
- struct bfd_link_info *info;
- bfd_boolean collect;
+generic_link_add_object_symbols (bfd *abfd,
+ struct bfd_link_info *info,
+ bfd_boolean collect)
{
bfd_size_type symcount;
- struct symbol_cache_entry **outsyms;
+ struct bfd_symbol **outsyms;
if (! generic_link_read_symbols (abfd))
return FALSE;
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 bfd_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;
+archive_hash_newfunc (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)));
- if (ret == (struct archive_hash_entry *) NULL)
+ if (ret == NULL)
+ ret = bfd_hash_allocate (table, sizeof (struct archive_hash_entry));
+ if (ret == NULL)
return NULL;
/* Call the allocation method of the superclass. */
if (ret)
{
/* Initialize the local fields. */
- ret->defs = (struct archive_list *) NULL;
+ ret->defs = NULL;
}
- return (struct bfd_hash_entry *) ret;
+ return &ret->root;
}
/* Initialize an archive hash table. */
static bfd_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 *));
+archive_hash_table_init
+ (struct archive_hash_table *table,
+ struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *,
+ struct bfd_hash_table *,
+ const char *))
{
return bfd_hash_table_init (&table->table, newfunc);
}
object file to be included. */
bfd_boolean
-_bfd_generic_link_add_archive_symbols (abfd, info, checkfn)
- bfd *abfd;
- struct bfd_link_info *info;
- bfd_boolean (*checkfn)
- PARAMS ((bfd *, struct bfd_link_info *, bfd_boolean *pneeded));
+_bfd_generic_link_add_archive_symbols
+ (bfd *abfd,
+ struct bfd_link_info *info,
+ bfd_boolean (*checkfn) (bfd *, struct bfd_link_info *, bfd_boolean *))
{
carsym *arsyms;
carsym *arsym_end;
if (! bfd_has_map (abfd))
{
/* An empty archive is a special case. */
- if (bfd_openr_next_archived_file (abfd, (bfd *) NULL) == NULL)
+ if (bfd_openr_next_archived_file (abfd, NULL) == NULL)
return TRUE;
bfd_set_error (bfd_error_no_armap);
return FALSE;
struct archive_list *l, **pp;
arh = archive_hash_lookup (&arsym_hash, arsym->name, TRUE, FALSE);
- if (arh == (struct archive_hash_entry *) NULL)
+ if (arh == NULL)
goto error_return;
l = ((struct archive_list *)
archive_hash_allocate (&arsym_hash, sizeof (struct archive_list)));
if (l == NULL)
goto error_return;
l->indx = indx;
- for (pp = &arh->defs;
- *pp != (struct archive_list *) NULL;
- pp = &(*pp)->next)
+ for (pp = &arh->defs; *pp != NULL; pp = &(*pp)->next)
;
*pp = l;
l->next = NULL;
/* 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)
+ while (*pundef != NULL)
{
struct bfd_link_hash_entry *h;
struct archive_hash_entry *arh;
us to lose track of whether the symbol has been
referenced). */
if (*pundef != info->hash->undefs_tail)
- *pundef = (*pundef)->next;
+ *pundef = (*pundef)->u.undef.next;
else
- pundef = &(*pundef)->next;
+ pundef = &(*pundef)->u.undef.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)
+ if (arh == NULL)
{
/* If we haven't found the exact symbol we're looking for,
let's look for its import thunk */
if (info->pei386_auto_import)
{
bfd_size_type amt = strlen (h->root.string) + 10;
- char *buf = (char *) bfd_malloc (amt);
+ char *buf = bfd_malloc (amt);
if (buf == NULL)
return FALSE;
arh = archive_hash_lookup (&arsym_hash, buf, FALSE, FALSE);
free(buf);
}
- if (arh == (struct archive_hash_entry *) NULL)
+ if (arh == NULL)
{
- pundef = &(*pundef)->next;
+ pundef = &(*pundef)->u.undef.next;
continue;
}
}
/* Look at all the objects which define this symbol. */
- for (l = arh->defs; l != (struct archive_list *) NULL; l = l->next)
+ for (l = arh->defs; l != NULL; l = l->next)
{
bfd *element;
bfd_boolean needed;
break;
element = bfd_get_elt_at_index (abfd, l->indx);
- if (element == (bfd *) NULL)
+ if (element == NULL)
goto error_return;
/* If we've already included this element, or if we've
}
}
- pundef = &(*pundef)->next;
+ pundef = &(*pundef)->u.undef.next;
}
archive_hash_table_free (&arsym_hash);
for finding them. */
static bfd_boolean
-generic_link_check_archive_element_no_collect (abfd, info, pneeded)
- bfd *abfd;
- struct bfd_link_info *info;
- bfd_boolean *pneeded;
+generic_link_check_archive_element_no_collect (
+ bfd *abfd,
+ struct bfd_link_info *info,
+ bfd_boolean *pneeded)
{
return generic_link_check_archive_element (abfd, info, pneeded, FALSE);
}
symbol name, as collect2 does. */
static bfd_boolean
-generic_link_check_archive_element_collect (abfd, info, pneeded)
- bfd *abfd;
- struct bfd_link_info *info;
- bfd_boolean *pneeded;
+generic_link_check_archive_element_collect (bfd *abfd,
+ struct bfd_link_info *info,
+ bfd_boolean *pneeded)
{
return generic_link_check_archive_element (abfd, info, pneeded, TRUE);
}
constructors. */
static bfd_boolean
-generic_link_check_archive_element (abfd, info, pneeded, collect)
- bfd *abfd;
- struct bfd_link_info *info;
- bfd_boolean *pneeded;
- bfd_boolean collect;
+generic_link_check_archive_element (bfd *abfd,
+ struct bfd_link_info *info,
+ bfd_boolean *pneeded,
+ bfd_boolean collect)
{
asymbol **pp, **ppend;
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
+ if (h == NULL
|| (h->type != bfd_link_hash_undefined
&& h->type != bfd_link_hash_common))
continue;
unsigned int power;
symbfd = h->u.undef.abfd;
- if (symbfd == (bfd *) NULL)
+ if (symbfd == NULL)
{
/* This symbol was created as undefined from outside
BFD. We assume that we should link in the object
will be linked in. */
h->type = bfd_link_hash_common;
h->u.c.p =
- ((struct bfd_link_hash_common_entry *)
- bfd_hash_allocate (&info->hash->table,
- sizeof (struct bfd_link_hash_common_entry)));
+ bfd_hash_allocate (&info->hash->table,
+ sizeof (struct bfd_link_hash_common_entry));
if (h->u.c.p == NULL)
return FALSE;
as is done by collect2. */
static bfd_boolean
-generic_link_add_symbol_list (abfd, info, symbol_count, symbols, collect)
- bfd *abfd;
- struct bfd_link_info *info;
- bfd_size_type symbol_count;
- asymbol **symbols;
- bfd_boolean collect;
+generic_link_add_symbol_list (bfd *abfd,
+ struct bfd_link_info *info,
+ bfd_size_type symbol_count,
+ asymbol **symbols,
+ bfd_boolean collect)
{
asymbol **pp, **ppend;
generic one. */
if (info->hash->creator == abfd->xvec)
{
- if (h->sym == (asymbol *) NULL
+ if (h->sym == NULL
|| (! bfd_is_und_section (bfd_get_section (p))
&& (! bfd_is_com_section (bfd_get_section (p))
|| bfd_is_und_section (bfd_get_section (h->sym)))))
it gets rewritten to not use asymbol structures.
Setting this is also used to check whether these
symbols were set up by the generic linker. */
- p->udata.p = (PTR) h;
+ p->udata.p = h;
}
}
/* Return the BFD in which a hash entry has been defined, if known. */
static bfd *
-hash_entry_bfd (h)
- struct bfd_link_hash_entry *h;
+hash_entry_bfd (struct bfd_link_hash_entry *h)
{
while (h->type == bfd_link_hash_warning)
h = h->u.i.link;
the hash table entry, and stored it in *HASHP. */
bfd_boolean
-_bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
- string, copy, collect, hashp)
- struct bfd_link_info *info;
- bfd *abfd;
- const char *name;
- flagword flags;
- asection *section;
- bfd_vma value;
- const char *string;
- bfd_boolean copy;
- bfd_boolean collect;
- struct bfd_link_hash_entry **hashp;
+_bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
+ bfd *abfd,
+ const char *name,
+ flagword flags,
+ asection *section,
+ bfd_vma value,
+ const char *string,
+ bfd_boolean copy,
+ bfd_boolean collect,
+ struct bfd_link_hash_entry **hashp)
{
enum link_row row;
struct bfd_link_hash_entry *h;
}
if (info->notice_all
- || (info->notice_hash != (struct bfd_hash_table *) NULL
- && (bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE)
- != (struct bfd_hash_entry *) NULL)))
+ || (info->notice_hash != NULL
+ && bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE) != NULL))
{
if (! (*info->callbacks->notice) (info, h->root.string, abfd, section,
value))
return FALSE;
}
- if (hashp != (struct bfd_link_hash_entry **) NULL)
+ if (hashp != NULL)
*hashp = h;
do
if (! ((*info->callbacks->multiple_common)
(info, h->root.string,
h->u.c.p->section->owner, bfd_link_hash_common, h->u.c.size,
- abfd, bfd_link_hash_defined, (bfd_vma) 0)))
+ abfd, bfd_link_hash_defined, 0)))
return FALSE;
/* Fall through. */
case DEF:
bfd_link_add_undef (info->hash, h);
h->type = bfd_link_hash_common;
h->u.c.p =
- ((struct bfd_link_hash_common_entry *)
- bfd_hash_allocate (&info->hash->table,
- sizeof (struct bfd_link_hash_common_entry)));
+ bfd_hash_allocate (&info->hash->table,
+ sizeof (struct bfd_link_hash_common_entry));
if (h->u.c.p == NULL)
return FALSE;
case REF:
/* A reference to a defined symbol. */
- if (h->next == NULL && info->hash->undefs_tail != h)
- h->next = h;
+ if (h->u.undef.next == NULL && info->hash->undefs_tail != h)
+ h->u.undef.next = h;
break;
case BIG:
else
obfd = NULL;
if (! ((*info->callbacks->multiple_common)
- (info, h->root.string, obfd, h->type, (bfd_vma) 0,
+ (info, h->root.string, obfd, h->type, 0,
abfd, bfd_link_hash_common, value)))
return FALSE;
}
if (! ((*info->callbacks->multiple_common)
(info, h->root.string,
h->u.c.p->section->owner, bfd_link_hash_common, h->u.c.size,
- abfd, bfd_link_hash_indirect, (bfd_vma) 0)))
+ abfd, bfd_link_hash_indirect, 0)))
return FALSE;
/* Fall through. */
case IND:
to. */
inh = bfd_wrapped_link_hash_lookup (abfd, info, string, TRUE,
copy, FALSE);
- if (inh == (struct bfd_link_hash_entry *) NULL)
+ if (inh == NULL)
return FALSE;
if (inh->type == bfd_link_hash_indirect
&& inh->u.i.link == h)
{
(*_bfd_error_handler)
- (_("%s: indirect symbol `%s' to `%s' is a loop"),
- bfd_archive_filename (abfd), name, string);
+ (_("%B: indirect symbol `%s' to `%s' is a loop"),
+ abfd, name, string);
bfd_set_error (bfd_error_invalid_operation);
return FALSE;
}
{
if (! (*info->callbacks->warning) (info, h->u.i.warning,
h->root.string, abfd,
- (asection *) NULL,
- (bfd_vma) 0))
+ NULL, 0))
return FALSE;
/* Only issue a warning once. */
h->u.i.warning = NULL;
case REFC:
/* A reference to an indirect symbol. */
- if (h->next == NULL && info->hash->undefs_tail != h)
- h->next = h;
+ if (h->u.undef.next == NULL && info->hash->undefs_tail != h)
+ h->u.undef.next = h;
h = h->u.i.link;
cycle = TRUE;
break;
case WARN:
/* Issue a warning. */
if (! (*info->callbacks->warning) (info, string, h->root.string,
- hash_entry_bfd (h),
- (asection *) NULL, (bfd_vma) 0))
+ hash_entry_bfd (h), NULL, 0))
return FALSE;
break;
case CWARN:
/* Warn if this symbol has been referenced already,
otherwise add a warning. A symbol has been referenced if
- the next field is not NULL, or it is the tail of the
+ the u.undef.next field is not NULL, or it is the tail of the
undefined symbol list. The REF case above helps to
ensure this. */
- if (h->next != NULL || info->hash->undefs_tail == h)
+ if (h->u.undef.next != NULL || info->hash->undefs_tail == h)
{
if (! (*info->callbacks->warning) (info, string, h->root.string,
- hash_entry_bfd (h),
- (asection *) NULL,
- (bfd_vma) 0))
+ hash_entry_bfd (h), NULL, 0))
return FALSE;
break;
}
/* STRING is the warning to give. */
sub = ((struct bfd_link_hash_entry *)
((*info->hash->table.newfunc)
- ((struct bfd_hash_entry *) NULL, &info->hash->table,
- h->root.string)));
+ (NULL, &info->hash->table, h->root.string)));
if (sub == NULL)
return FALSE;
*sub = *h;
/* Generic final link routine. */
bfd_boolean
-_bfd_generic_final_link (abfd, info)
- bfd *abfd;
- struct bfd_link_info *info;
+_bfd_generic_final_link (bfd *abfd, struct bfd_link_info *info)
{
bfd *sub;
asection *o;
size_t outsymalloc;
struct generic_write_global_symbol_info wginfo;
- bfd_get_outsymbols (abfd) = (asymbol **) NULL;
+ bfd_get_outsymbols (abfd) = NULL;
bfd_get_symcount (abfd) = 0;
outsymalloc = 0;
p->u.indirect.section->linker_mark = TRUE;
/* Build the output symbol table. */
- for (sub = info->input_bfds; sub != (bfd *) NULL; sub = sub->link_next)
+ for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
if (! _bfd_generic_link_output_symbols (abfd, sub, info, &outsymalloc))
return FALSE;
wginfo.psymalloc = &outsymalloc;
_bfd_generic_link_hash_traverse (_bfd_generic_hash_table (info),
_bfd_generic_link_write_global_symbol,
- (PTR) &wginfo);
+ &wginfo);
/* Make sure we have a trailing NULL pointer on OUTSYMBOLS. We
shouldn't really need one, since we have SYMCOUNT, but some old
if (! generic_add_output_symbol (abfd, &outsymalloc, NULL))
return FALSE;
- if (info->relocateable)
+ if (info->relocatable)
{
/* Allocate space for the output relocs for each section. */
- for (o = abfd->sections;
- o != (asection *) NULL;
- o = o->next)
+ for (o = abfd->sections; o != NULL; o = o->next)
{
o->reloc_count = 0;
- for (p = o->link_order_head;
- p != (struct bfd_link_order *) NULL;
- p = p->next)
+ for (p = o->link_order_head; p != NULL; p = p->next)
{
if (p->type == bfd_section_reloc_link_order
|| p->type == bfd_symbol_reloc_link_order)
input_section);
if (relsize < 0)
return FALSE;
- relocs = (arelent **) bfd_malloc ((bfd_size_type) relsize);
+ relocs = bfd_malloc (relsize);
if (!relocs && relsize != 0)
return FALSE;
symbols = _bfd_generic_link_get_symbols (input_bfd);
input_section,
relocs,
symbols);
+ free (relocs);
if (reloc_count < 0)
return FALSE;
BFD_ASSERT ((unsigned long) reloc_count
== input_section->reloc_count);
o->reloc_count += reloc_count;
- free (relocs);
}
}
if (o->reloc_count > 0)
amt = o->reloc_count;
amt *= sizeof (arelent *);
- o->orelocation = (arelent **) bfd_alloc (abfd, amt);
+ o->orelocation = bfd_alloc (abfd, amt);
if (!o->orelocation)
return FALSE;
o->flags |= SEC_RELOC;
}
/* Handle all the link order information for the sections. */
- for (o = abfd->sections;
- o != (asection *) NULL;
- o = o->next)
+ for (o = abfd->sections; o != NULL; o = o->next)
{
- for (p = o->link_order_head;
- p != (struct bfd_link_order *) NULL;
- p = p->next)
+ for (p = o->link_order_head; p != NULL; p = p->next)
{
switch (p->type)
{
/* Add an output symbol to the output BFD. */
static bfd_boolean
-generic_add_output_symbol (output_bfd, psymalloc, sym)
- bfd *output_bfd;
- size_t *psymalloc;
- asymbol *sym;
+generic_add_output_symbol (bfd *output_bfd, size_t *psymalloc, asymbol *sym)
{
if (bfd_get_symcount (output_bfd) >= *psymalloc)
{
*psymalloc *= 2;
amt = *psymalloc;
amt *= sizeof (asymbol *);
- newsyms = (asymbol **) bfd_realloc (bfd_get_outsymbols (output_bfd), amt);
- if (newsyms == (asymbol **) NULL)
+ newsyms = bfd_realloc (bfd_get_outsymbols (output_bfd), amt);
+ if (newsyms == NULL)
return FALSE;
bfd_get_outsymbols (output_bfd) = newsyms;
}
/* Handle the symbols for an input BFD. */
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;
+_bfd_generic_link_output_symbols (bfd *output_bfd,
+ bfd *input_bfd,
+ struct bfd_link_info *info,
+ size_t *psymalloc)
{
asymbol **sym_ptr;
asymbol **sym_end;
return FALSE;
/* Create a filename symbol if we are supposed to. */
- if (info->create_object_symbols_section != (asection *) NULL)
+ if (info->create_object_symbols_section != NULL)
{
asection *sec;
- for (sec = input_bfd->sections;
- sec != (asection *) NULL;
- sec = sec->next)
+ for (sec = input_bfd->sections; sec != NULL; sec = sec->next)
{
if (sec->output_section == info->create_object_symbols_section)
{
struct generic_link_hash_entry *h;
bfd_boolean output;
- h = (struct generic_link_hash_entry *) NULL;
+ h = NULL;
sym = *sym_ptr;
if ((sym->flags & (BSF_INDIRECT
| BSF_WARNING
|| bfd_is_ind_section (bfd_get_section (sym)))
{
if (sym->udata.p != NULL)
- h = (struct generic_link_hash_entry *) sym->udata.p;
+ h = sym->udata.p;
else if ((sym->flags & BSF_CONSTRUCTOR) != 0)
{
/* This case normally means that the main linker code
bfd_asymbol_name (sym),
FALSE, FALSE, TRUE);
- if (h != (struct generic_link_hash_entry *) NULL)
+ if (h != NULL)
{
/* Force all references to this symbol to point to
the same area in memory. It is possible that
check that. */
if (info->hash->creator == input_bfd->xvec)
{
- if (h->sym != (asymbol *) NULL)
+ if (h->sym != NULL)
*sym_ptr = sym = h->sym;
}
write_file_locals in ldsym.c. */
if (info->strip == strip_all
|| (info->strip == strip_some
- && (bfd_hash_lookup (info->keep_hash, bfd_asymbol_name (sym),
- FALSE, FALSE)
- == (struct bfd_hash_entry *) NULL)))
+ && bfd_hash_lookup (info->keep_hash, bfd_asymbol_name (sym),
+ FALSE, FALSE) == NULL))
output = FALSE;
else if ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0)
{
break;
case discard_sec_merge:
output = TRUE;
- if (info->relocateable
+ if (info->relocatable
|| ! (sym->section->flags & SEC_MERGE))
break;
/* FALLTHROUGH */
{
if (! generic_add_output_symbol (output_bfd, psymalloc, sym))
return FALSE;
- if (h != (struct generic_link_hash_entry *) NULL)
+ if (h != NULL)
h->written = TRUE;
}
}
hash table entry. */
static void
-set_symbol_from_hash (sym, h)
- asymbol *sym;
- struct bfd_link_hash_entry *h;
+set_symbol_from_hash (asymbol *sym, struct bfd_link_hash_entry *h)
{
switch (h->type)
{
This is called for each symbol in the hash table. */
bfd_boolean
-_bfd_generic_link_write_global_symbol (h, data)
- struct generic_link_hash_entry *h;
- PTR data;
+_bfd_generic_link_write_global_symbol (struct generic_link_hash_entry *h,
+ void *data)
{
- struct generic_write_global_symbol_info *wginfo =
- (struct generic_write_global_symbol_info *) data;
+ struct generic_write_global_symbol_info *wginfo = data;
asymbol *sym;
if (h->root.type == bfd_link_hash_warning)
FALSE, FALSE) == NULL))
return TRUE;
- if (h->sym != (asymbol *) NULL)
+ if (h->sym != NULL)
sym = h->sym;
else
{
/* Create a relocation. */
bfd_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;
+_bfd_generic_reloc_link_order (bfd *abfd,
+ struct bfd_link_info *info,
+ asection *sec,
+ struct bfd_link_order *link_order)
{
arelent *r;
- if (! info->relocateable)
+ if (! info->relocatable)
abort ();
- if (sec->orelocation == (arelent **) NULL)
+ if (sec->orelocation == NULL)
abort ();
- r = (arelent *) bfd_alloc (abfd, (bfd_size_type) sizeof (arelent));
- if (r == (arelent *) NULL)
+ r = bfd_alloc (abfd, sizeof (arelent));
+ if (r == NULL)
return FALSE;
r->address = link_order->offset;
bfd_wrapped_link_hash_lookup (abfd, info,
link_order->u.reloc.p->u.name,
FALSE, FALSE, TRUE));
- if (h == (struct generic_link_hash_entry *) NULL
+ if (h == NULL
|| ! h->written)
{
if (! ((*info->callbacks->unattached_reloc)
- (info, link_order->u.reloc.p->u.name,
- (bfd *) NULL, (asection *) NULL, (bfd_vma) 0)))
+ (info, link_order->u.reloc.p->u.name, NULL, NULL, 0)))
return FALSE;
bfd_set_error (bfd_error_bad_value);
return FALSE;
file_ptr loc;
size = bfd_get_reloc_size (r->howto);
- buf = (bfd_byte *) bfd_zmalloc (size);
- if (buf == (bfd_byte *) NULL)
+ buf = bfd_zmalloc (size);
+ if (buf == NULL)
return FALSE;
rstat = _bfd_relocate_contents (r->howto, abfd,
(bfd_vma) link_order->u.reloc.p->addend,
abort ();
case bfd_reloc_overflow:
if (! ((*info->callbacks->reloc_overflow)
- (info,
+ (info, NULL,
(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)))
+ NULL, NULL, 0)))
{
free (buf);
return FALSE;
break;
}
loc = link_order->offset * bfd_octets_per_byte (abfd);
- ok = bfd_set_section_contents (abfd, sec, (PTR) buf, loc,
- (bfd_size_type) size);
+ ok = bfd_set_section_contents (abfd, sec, buf, loc, size);
free (buf);
if (! ok)
return FALSE;
/* Allocate a new link_order for a section. */
struct bfd_link_order *
-bfd_new_link_order (abfd, section)
- bfd *abfd;
- asection *section;
+bfd_new_link_order (bfd *abfd, asection *section)
{
bfd_size_type amt = sizeof (struct bfd_link_order);
struct bfd_link_order *new;
- new = (struct bfd_link_order *) bfd_zalloc (abfd, amt);
+ new = bfd_zalloc (abfd, amt);
if (!new)
return NULL;
new->type = bfd_undefined_link_order;
- if (section->link_order_tail != (struct bfd_link_order *) NULL)
+ if (section->link_order_tail != NULL)
section->link_order_tail->next = new;
else
section->link_order_head = new;
of how the particular backends generates relocs. */
bfd_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;
+_bfd_default_link_order (bfd *abfd,
+ struct bfd_link_info *info,
+ asection *sec,
+ struct bfd_link_order *link_order)
{
switch (link_order->type)
{
/* Default routine to handle a bfd_data_link_order. */
static bfd_boolean
-default_data_link_order (abfd, info, sec, link_order)
- bfd *abfd;
- struct bfd_link_info *info ATTRIBUTE_UNUSED;
- asection *sec;
- struct bfd_link_order *link_order;
+default_data_link_order (bfd *abfd,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ asection *sec,
+ struct bfd_link_order *link_order)
{
bfd_size_type size;
size_t fill_size;
if (fill_size != 0 && fill_size < size)
{
bfd_byte *p;
- fill = (bfd_byte *) bfd_malloc (size);
+ fill = bfd_malloc (size);
if (fill == NULL)
return FALSE;
p = fill;
/* Default routine to handle a bfd_indirect_link_order. */
static bfd_boolean
-default_indirect_link_order (output_bfd, info, output_section, link_order,
- generic_linker)
- bfd *output_bfd;
- struct bfd_link_info *info;
- asection *output_section;
- struct bfd_link_order *link_order;
- bfd_boolean generic_linker;
+default_indirect_link_order (bfd *output_bfd,
+ struct bfd_link_info *info,
+ asection *output_section,
+ struct bfd_link_order *link_order,
+ bfd_boolean generic_linker)
{
asection *input_section;
bfd *input_bfd;
BFD_ASSERT (input_section->output_section == output_section);
BFD_ASSERT (input_section->output_offset == link_order->offset);
- BFD_ASSERT (input_section->_cooked_size == link_order->size);
+ BFD_ASSERT (input_section->size == link_order->size);
- if (info->relocateable
+ if (info->relocatable
&& input_section->reloc_count > 0
- && output_section->orelocation == (arelent **) NULL)
+ && output_section->orelocation == NULL)
{
/* Space has not been allocated for the output relocations.
This can happen when we are called by a specific backend
types of object files. Handling this case correctly is
difficult, and sometimes impossible. */
(*_bfd_error_handler)
- (_("Attempt to do relocateable link with %s input and %s output"),
+ (_("Attempt to do relocatable link with %s input and %s output"),
bfd_get_target (input_bfd), bfd_get_target (output_bfd));
bfd_set_error (bfd_error_wrong_format);
return FALSE;
/* sym->udata may have been set by
generic_link_add_symbol_list. */
if (sym->udata.p != NULL)
- h = (struct bfd_link_hash_entry *) sym->udata.p;
+ h = sym->udata.p;
else if (bfd_is_und_section (bfd_get_section (sym)))
h = bfd_wrapped_link_hash_lookup (output_bfd, info,
bfd_asymbol_name (sym),
}
/* Get and relocate the section contents. */
- sec_size = bfd_section_size (input_bfd, input_section);
- contents = ((bfd_byte *) bfd_malloc (sec_size));
+ sec_size = (input_section->rawsize > input_section->size
+ ? input_section->rawsize
+ : input_section->size);
+ contents = bfd_malloc (sec_size);
if (contents == NULL && sec_size != 0)
goto error_return;
new_contents = (bfd_get_relocated_section_contents
- (output_bfd, info, link_order, contents, info->relocateable,
+ (output_bfd, info, link_order, contents, info->relocatable,
_bfd_generic_link_get_symbols (input_bfd)));
if (!new_contents)
goto error_return;
/* Output the section contents. */
loc = link_order->offset * bfd_octets_per_byte (output_bfd);
if (! bfd_set_section_contents (output_bfd, output_section,
- (PTR) new_contents, loc, link_order->size))
+ new_contents, loc, link_order->size))
goto error_return;
if (contents != NULL)
list. */
unsigned int
-_bfd_count_link_order_relocs (link_order)
- struct bfd_link_order *link_order;
+_bfd_count_link_order_relocs (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)
+ for (l = link_order; l != NULL; l = l->next)
{
if (l->type == bfd_section_reloc_link_order
|| l->type == bfd_symbol_reloc_link_order)
bfd_link_split_section
SYNOPSIS
- bfd_boolean bfd_link_split_section(bfd *abfd, asection *sec);
+ bfd_boolean bfd_link_split_section (bfd *abfd, asection *sec);
DESCRIPTION
Return nonzero if @var{sec} should be split during a
*/
bfd_boolean
-_bfd_generic_link_split_section (abfd, sec)
- bfd *abfd ATTRIBUTE_UNUSED;
- asection *sec ATTRIBUTE_UNUSED;
+_bfd_generic_link_split_section (bfd *abfd ATTRIBUTE_UNUSED,
+ asection *sec ATTRIBUTE_UNUSED)
{
return FALSE;
}
+
+/*
+FUNCTION
+ bfd_section_already_linked
+
+SYNOPSIS
+ void bfd_section_already_linked (bfd *abfd, asection *sec);
+
+DESCRIPTION
+ Check if @var{sec} has been already linked during a reloceatable
+ or final link.
+
+.#define bfd_section_already_linked(abfd, sec) \
+. BFD_SEND (abfd, _section_already_linked, (abfd, sec))
+.
+
+*/
+
+/* Sections marked with the SEC_LINK_ONCE flag should only be linked
+ once into the output. This routine checks each section, and
+ arrange to discard it if a section of the same name has already
+ been linked. This code assumes that all relevant sections have the
+ SEC_LINK_ONCE flag set; that is, it does not depend solely upon the
+ section name. bfd_section_already_linked is called via
+ bfd_map_over_sections. */
+
+/* The hash table. */
+
+static struct bfd_hash_table _bfd_section_already_linked_table;
+
+/* Support routines for the hash table used by section_already_linked,
+ initialize the table, traverse, lookup, fill in an entry and remove
+ the table. */
+
+void
+bfd_section_already_linked_table_traverse
+ (bfd_boolean (*func) (struct bfd_section_already_linked_hash_entry *,
+ void *), void *info)
+{
+ bfd_hash_traverse (&_bfd_section_already_linked_table,
+ (bfd_boolean (*) (struct bfd_hash_entry *,
+ void *)) func,
+ info);
+}
+
+struct bfd_section_already_linked_hash_entry *
+bfd_section_already_linked_table_lookup (const char *name)
+{
+ return ((struct bfd_section_already_linked_hash_entry *)
+ bfd_hash_lookup (&_bfd_section_already_linked_table, name,
+ TRUE, FALSE));
+}
+
+void
+bfd_section_already_linked_table_insert
+ (struct bfd_section_already_linked_hash_entry *already_linked_list,
+ asection *sec)
+{
+ struct bfd_section_already_linked *l;
+
+ /* Allocate the memory from the same obstack as the hash table is
+ kept in. */
+ l = bfd_hash_allocate (&_bfd_section_already_linked_table, sizeof *l);
+ l->sec = sec;
+ l->next = already_linked_list->entry;
+ already_linked_list->entry = l;
+}
+
+static struct bfd_hash_entry *
+already_linked_newfunc (struct bfd_hash_entry *entry ATTRIBUTE_UNUSED,
+ struct bfd_hash_table *table,
+ const char *string ATTRIBUTE_UNUSED)
+{
+ struct bfd_section_already_linked_hash_entry *ret =
+ bfd_hash_allocate (table, sizeof *ret);
+
+ ret->entry = NULL;
+
+ return &ret->root;
+}
+
+bfd_boolean
+bfd_section_already_linked_table_init (void)
+{
+ return bfd_hash_table_init_n (&_bfd_section_already_linked_table,
+ already_linked_newfunc, 42);
+}
+
+void
+bfd_section_already_linked_table_free (void)
+{
+ bfd_hash_table_free (&_bfd_section_already_linked_table);
+}
+
+/* This is used on non-ELF inputs. */
+
+void
+_bfd_generic_section_already_linked (bfd *abfd, asection *sec)
+{
+ flagword flags;
+ const char *name;
+ struct bfd_section_already_linked *l;
+ struct bfd_section_already_linked_hash_entry *already_linked_list;
+
+ flags = sec->flags;
+ if ((flags & SEC_LINK_ONCE) == 0)
+ return;
+
+ /* FIXME: When doing a relocatable link, we may have trouble
+ copying relocations in other sections that refer to local symbols
+ in the section being discarded. Those relocations will have to
+ be converted somehow; as of this writing I'm not sure that any of
+ the backends handle that correctly.
+
+ It is tempting to instead not discard link once sections when
+ doing a relocatable link (technically, they should be discarded
+ whenever we are building constructors). However, that fails,
+ because the linker winds up combining all the link once sections
+ into a single large link once section, which defeats the purpose
+ of having link once sections in the first place. */
+
+ name = bfd_get_section_name (abfd, sec);
+
+ already_linked_list = bfd_section_already_linked_table_lookup (name);
+
+ for (l = already_linked_list->entry; l != NULL; l = l->next)
+ {
+ bfd_boolean skip = FALSE;
+ struct coff_comdat_info *s_comdat
+ = bfd_coff_get_comdat_section (abfd, sec);
+ struct coff_comdat_info *l_comdat
+ = bfd_coff_get_comdat_section (l->sec->owner, l->sec);
+
+ /* We may have 3 different sections on the list: group section,
+ comdat section and linkonce section. SEC may be a linkonce or
+ comdat section. We always ignore group section. For non-COFF
+ inputs, we also ignore comdat section.
+
+ FIXME: Is that safe to match a linkonce section with a comdat
+ section for COFF inputs? */
+ if ((l->sec->flags & SEC_GROUP) != 0)
+ skip = TRUE;
+ else if (bfd_get_flavour (abfd) == bfd_target_coff_flavour)
+ {
+ if (s_comdat != NULL
+ && l_comdat != NULL
+ && strcmp (s_comdat->name, l_comdat->name) != 0)
+ skip = TRUE;
+ }
+ else if (l_comdat != NULL)
+ skip = TRUE;
+
+ if (!skip)
+ {
+ /* The section has already been linked. See if we should
+ issue a warning. */
+ switch (flags & SEC_LINK_DUPLICATES)
+ {
+ default:
+ abort ();
+
+ case SEC_LINK_DUPLICATES_DISCARD:
+ break;
+
+ case SEC_LINK_DUPLICATES_ONE_ONLY:
+ (*_bfd_error_handler)
+ (_("%B: warning: ignoring duplicate section `%A'\n"),
+ abfd, sec);
+ break;
+
+ case SEC_LINK_DUPLICATES_SAME_CONTENTS:
+ /* FIXME: We should really dig out the contents of both
+ sections and memcmp them. The COFF/PE spec says that
+ the Microsoft linker does not implement this
+ correctly, so I'm not going to bother doing it
+ either. */
+ /* Fall through. */
+ case SEC_LINK_DUPLICATES_SAME_SIZE:
+ if (sec->size != l->sec->size)
+ (*_bfd_error_handler)
+ (_("%B: warning: duplicate section `%A' has different size\n"),
+ abfd, sec);
+ break;
+ }
+
+ /* Set the output_section field so that lang_add_section
+ does not create a lang_input_section structure for this
+ section. Since there might be a symbol in the section
+ being discarded, we must retain a pointer to the section
+ which we are really going to use. */
+ sec->output_section = bfd_abs_section_ptr;
+ sec->kept_section = l->sec;
+
+ return;
+ }
+ }
+
+ /* This is the first section with this name. Record it. */
+ bfd_section_already_linked_table_insert (already_linked_list, sec);
+}