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. */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "bfd.h"
#include "sysdep.h"
file at the end of <<NAME(aout,final_link)>>.
*/
-static struct bfd_hash_entry *generic_link_hash_newfunc
- PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *,
- const char *));
static boolean generic_link_read_symbols
PARAMS ((bfd *));
static boolean generic_link_add_symbols
static boolean generic_link_add_symbol_list
PARAMS ((bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **,
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 *));
static boolean generic_add_output_symbol
ret = ((struct bfd_link_hash_entry *)
bfd_hash_allocate (table, sizeof (struct bfd_link_hash_entry)));
if (ret == (struct bfd_link_hash_entry *) NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return NULL;
- }
+ return NULL;
/* Call the allocation method of the superclass. */
ret = ((struct bfd_link_hash_entry *)
return ret;
}
+/* Look up a symbol in the main linker hash table if the symbol might
+ be wrapped. This should only be used for references to an
+ 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;
+ boolean create;
+ boolean copy;
+ boolean follow;
+{
+ if (info->wrap_hash != NULL)
+ {
+ const char *l;
+
+ l = string;
+ if (*l == bfd_get_symbol_leading_char (abfd))
+ ++l;
+
+#undef WRAP
+#define WRAP "__wrap_"
+
+ if (bfd_hash_lookup (info->wrap_hash, l, false, false) != NULL)
+ {
+ char *n;
+ struct bfd_link_hash_entry *h;
+
+ /* This symbol is being wrapped. We want to replace all
+ references to SYM with references to __wrap_SYM. */
+
+ n = (char *) bfd_malloc (strlen (l) + sizeof WRAP + 1);
+ if (n == NULL)
+ return NULL;
+
+ /* Note that symbol_leading_char may be '\0'. */
+ n[0] = bfd_get_symbol_leading_char (abfd);
+ n[1] = '\0';
+ strcat (n, WRAP);
+ strcat (n, l);
+ h = bfd_link_hash_lookup (info->hash, n, create, true, follow);
+ free (n);
+ return h;
+ }
+
+#undef WRAP
+
+#undef REAL
+#define REAL "__real_"
+
+ if (*l == '_'
+ && strncmp (l, REAL, sizeof REAL - 1) == 0
+ && bfd_hash_lookup (info->wrap_hash, l + sizeof REAL - 1,
+ false, false) != NULL)
+ {
+ char *n;
+ struct bfd_link_hash_entry *h;
+
+ /* This is a reference to __real_SYM, where SYM is being
+ wrapped. We want to replace all references to __real_SYM
+ with references to SYM. */
+
+ n = (char *) bfd_malloc (strlen (l + sizeof REAL - 1) + 2);
+ if (n == NULL)
+ return NULL;
+
+ /* Note that symbol_leading_char may be '\0'. */
+ n[0] = bfd_get_symbol_leading_char (abfd);
+ n[1] = '\0';
+ strcat (n, l + sizeof REAL - 1);
+ h = bfd_link_hash_lookup (info->hash, n, create, true, follow);
+ free (n);
+ return h;
+ }
+
+#undef REAL
+ }
+
+ return bfd_link_hash_lookup (info->hash, string, create, copy, follow);
+}
+
/* 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 caught as a
\f
/* 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 *
+_bfd_generic_link_hash_newfunc (entry, table, string)
struct bfd_hash_entry *entry;
struct bfd_hash_table *table;
const char *string;
ret = ((struct generic_link_hash_entry *)
bfd_hash_allocate (table, sizeof (struct generic_link_hash_entry)));
if (ret == (struct generic_link_hash_entry *) NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return NULL;
- }
+ return NULL;
/* Call the allocation method of the superclass. */
ret = ((struct generic_link_hash_entry *)
struct generic_link_hash_table *ret;
ret = ((struct generic_link_hash_table *)
- malloc (sizeof (struct generic_link_hash_table)));
- if (!ret)
- {
- bfd_set_error (bfd_error_no_memory);
- return (struct bfd_link_hash_table *) NULL;
- }
+ bfd_alloc (abfd, sizeof (struct generic_link_hash_table)));
+ if (ret == NULL)
+ return (struct bfd_link_hash_table *) NULL;
if (! _bfd_link_hash_table_init (&ret->root, abfd,
- generic_link_hash_newfunc))
+ _bfd_generic_link_hash_newfunc))
{
free (ret);
return (struct bfd_link_hash_table *) NULL;
return false;
abfd->outsymbols = (asymbol **) bfd_alloc (abfd, symsize);
if (abfd->outsymbols == NULL && symsize != 0)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
symcount = bfd_canonicalize_symtab (abfd, abfd->outsymbols);
if (symcount < 0)
return false;
ret = ((struct archive_hash_entry *)
bfd_hash_allocate (table, sizeof (struct archive_hash_entry)));
if (ret == (struct archive_hash_entry *) NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return NULL;
- }
+ return NULL;
/* Call the allocation method of the superclass. */
ret = ((struct archive_hash_entry *)
struct generic_link_hash_entry *h;
name = bfd_asymbol_name (p);
- if ((p->flags & BSF_INDIRECT) != 0
- || bfd_is_ind_section (p->section))
- string = bfd_asymbol_name ((asymbol *) p->value);
- else if ((p->flags & BSF_WARNING) != 0)
+ if (((p->flags & BSF_INDIRECT) != 0
+ || bfd_is_ind_section (p->section))
+ && pp + 1 < ppend)
+ {
+ pp++;
+ string = bfd_asymbol_name (*pp);
+ }
+ else if ((p->flags & BSF_WARNING) != 0
+ && pp + 1 < ppend)
{
/* The name of P is actually the warning string, and the
- value is actually a pointer to the symbol to warn
- about. */
+ next symbol is the one to warn about. */
string = name;
- name = bfd_asymbol_name ((asymbol *) p->value);
+ pp++;
+ name = bfd_asymbol_name (*pp);
}
else
string = NULL;
static const enum link_action link_action[8][8] =
{
/* current\prev new undef undefw def defw com indr warn */
- /* UNDEF_ROW */ {UND, NOACT, NOACT, REF, REF, NOACT, REFC, WARNC },
+ /* UNDEF_ROW */ {UND, NOACT, UND, REF, REF, NOACT, REFC, WARNC },
/* UNDEFW_ROW */ {WEAK, NOACT, NOACT, REF, REF, NOACT, REFC, WARNC },
/* DEF_ROW */ {DEF, DEF, DEF, MDEF, DEF, CDEF, MDEF, CYCLE },
/* DEFW_ROW */ {DEFW, DEFW, DEFW, NOACT, NOACT, NOACT, NOACT, CYCLE },
/* COMMON_ROW */ {COM, COM, COM, CREF, CREF, BIG, CREF, WARNC },
/* INDR_ROW */ {IND, IND, IND, MDEF, IND, CIND, MIND, CYCLE },
- /* WARN_ROW */ {MWARN, WARN, WARN, CWARN, CWARN, WARN, CWARN, CYCLE },
+ /* WARN_ROW */ {MWARN, WARN, WARN, CWARN, CWARN, WARN, CWARN, MWARN },
/* SET_ROW */ {SET, SET, SET, SET, SET, SET, CYCLE, CYCLE }
};
Adding an entry to a set does not count as a reference to a set,
and no warning is issued (SET_ROW/warn). */
+/* 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;
+{
+ while (h->type == bfd_link_hash_warning)
+ h = h->u.i.link;
+ switch (h->type)
+ {
+ default:
+ return NULL;
+ case bfd_link_hash_undefined:
+ case bfd_link_hash_undefweak:
+ return h->u.undef.abfd;
+ case bfd_link_hash_defined:
+ case bfd_link_hash_defweak:
+ return h->u.def.section->owner;
+ case bfd_link_hash_common:
+ return h->u.c.p->section->owner;
+ }
+ /*NOTREACHED*/
+}
+
/* Add a symbol to the global hash table.
ABFD is the BFD the symbol comes from.
NAME is the name of the symbol.
row = DEF_ROW;
if (hashp != NULL && *hashp != NULL)
- {
- h = *hashp;
- BFD_ASSERT (strcmp (h->root.string, name) == 0);
- }
+ h = *hashp;
else
{
- h = bfd_link_hash_lookup (info->hash, name, true, copy, false);
+ if (row == UNDEF_ROW || row == UNDEFW_ROW)
+ h = bfd_wrapped_link_hash_lookup (abfd, info, name, true, copy, false);
+ else
+ h = bfd_link_hash_lookup (info->hash, name, true, copy, false);
if (h == NULL)
{
if (hashp != NULL)
}
}
- 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->notice_all
+ || (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))
+ if (! (*info->callbacks->notice) (info, h->root.string, abfd, section,
+ value))
return false;
}
previously common. */
BFD_ASSERT (h->type == bfd_link_hash_common);
if (! ((*info->callbacks->multiple_common)
- (info, name,
+ (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)))
return false;
case DEF:
case DEFW:
{
- enum bfd_link_order_type oldtype;
+ enum bfd_link_hash_type oldtype;
/* Define a symbol. */
oldtype = h->type;
if (! ((*info->callbacks->constructor)
(info,
c == 'I' ? true : false,
- name, abfd, section, value)))
+ h->root.string, abfd, section, value)))
return false;
}
}
two sizes. */
BFD_ASSERT (h->type == bfd_link_hash_common);
if (! ((*info->callbacks->multiple_common)
- (info, name,
+ (info, h->root.string,
h->u.c.p->section->owner, bfd_link_hash_common, h->u.c.size,
abfd, bfd_link_hash_common, value)))
return false;
else
obfd = NULL;
if (! ((*info->callbacks->multiple_common)
- (info, name, obfd, h->type, (bfd_vma) 0,
+ (info, h->root.string, obfd, h->type, (bfd_vma) 0,
abfd, bfd_link_hash_common, value)))
return false;
}
break;
if (! ((*info->callbacks->multiple_definition)
- (info, name, msec->owner, msec, mval, abfd, section,
- value)))
+ (info, h->root.string, msec->owner, msec, mval, abfd,
+ section, value)))
return false;
}
break;
/* Create an indirect symbol from an existing common symbol. */
BFD_ASSERT (h->type == bfd_link_hash_common);
if (! ((*info->callbacks->multiple_common)
- (info, name,
+ (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)))
return false;
/* STRING is the name of the symbol we want to indirect
to. */
- inh = bfd_link_hash_lookup (info->hash, string, true, copy,
- false);
+ inh = bfd_wrapped_link_hash_lookup (abfd, info, string, true,
+ copy, false);
if (inh == (struct bfd_link_hash_entry *) NULL)
return false;
if (inh->type == bfd_link_hash_new)
/* Issue a warning and cycle. */
if (h->u.i.warning != NULL)
{
- if (! (*info->callbacks->warning) (info, h->u.i.warning))
+ if (! (*info->callbacks->warning) (info, h->u.i.warning,
+ h->root.string, abfd,
+ (asection *) NULL,
+ (bfd_vma) 0))
return false;
/* Only issue a warning once. */
h->u.i.warning = NULL;
case WARN:
/* Issue a warning. */
- if (! (*info->callbacks->warning) (info, string))
+ if (! (*info->callbacks->warning) (info, string, h->root.string,
+ hash_entry_bfd (h),
+ (asection *) NULL, (bfd_vma) 0))
return false;
break;
ensure this. */
if (h->next != NULL || info->hash->undefs_tail == h)
{
- if (! (*info->callbacks->warning) (info, string))
+ if (! (*info->callbacks->warning) (info, string, h->root.string,
+ hash_entry_bfd (h),
+ (asection *) NULL,
+ (bfd_vma) 0))
return false;
break;
}
/* STRING is the warning to give. */
sub = ((struct bfd_link_hash_entry *)
- bfd_hash_allocate (&info->hash->table,
- sizeof (struct bfd_link_hash_entry)));
- if (!sub)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ ((*info->hash->table.newfunc)
+ ((struct bfd_hash_entry *) NULL, &info->hash->table,
+ h->root.string)));
+ if (sub == NULL)
+ return false;
*sub = *h;
- h->type = bfd_link_hash_warning;
- h->u.i.link = sub;
+ sub->type = bfd_link_hash_warning;
+ sub->u.i.link = h;
if (! copy)
- h->u.i.warning = string;
+ sub->u.i.warning = string;
else
{
char *w;
w = bfd_hash_allocate (&info->hash->table,
strlen (string) + 1);
+ if (w == NULL)
+ return false;
strcpy (w, string);
- h->u.i.warning = w;
+ sub->u.i.warning = w;
}
+
+ bfd_hash_replace (&info->hash->table,
+ (struct bfd_hash_entry *) h,
+ (struct bfd_hash_entry *) sub);
+ if (hashp != NULL)
+ *hashp = sub;
}
break;
}
abfd->symcount = 0;
outsymalloc = 0;
+ /* Mark all sections which will be included in the output file. */
+ for (o = abfd->sections; o != NULL; o = o->next)
+ for (p = o->link_order_head; p != NULL; p = p->next)
+ if (p->type == bfd_indirect_link_order)
+ p->u.indirect.section->linker_mark = true;
+
/* Build the output symbol table. */
for (sub = info->input_bfds; sub != (bfd *) NULL; sub = sub->link_next)
if (! _bfd_generic_link_output_symbols (abfd, sub, info, &outsymalloc))
input_section);
if (relsize < 0)
return false;
- relocs = (arelent **) malloc ((size_t) relsize);
+ relocs = (arelent **) bfd_malloc ((size_t) relsize);
if (!relocs && relsize != 0)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
symbols = _bfd_generic_link_get_symbols (input_bfd);
reloc_count = bfd_canonicalize_reloc (input_bfd,
input_section,
symbols);
if (reloc_count < 0)
return false;
- BFD_ASSERT (reloc_count == input_section->reloc_count);
+ BFD_ASSERT ((unsigned long) reloc_count
+ == input_section->reloc_count);
o->reloc_count += reloc_count;
free (relocs);
}
(o->reloc_count
* sizeof (arelent *))));
if (!o->orelocation)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
o->flags |= SEC_RELOC;
/* Reset the count so that it can be used as an index
when putting in the output relocs. */
*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 *));
+ newsyms = (asymbol **) bfd_realloc (output_bfd->outsymbols,
+ *psymalloc * sizeof (asymbol *));
if (newsyms == (asymbol **) NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
output_bfd->outsymbols = newsyms;
}
the relocs in the output format being used. */
h = NULL;
}
+ else if (bfd_is_und_section (bfd_get_section (sym)))
+ h = ((struct generic_link_hash_entry *)
+ bfd_wrapped_link_hash_lookup (output_bfd, info,
+ bfd_asymbol_name (sym),
+ false, false, true));
else
h = _bfd_generic_link_hash_lookup (_bfd_generic_hash_table (info),
bfd_asymbol_name (sym),
/* 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))
+ 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)))
output = false;
else if ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0)
{
else
abort ();
+ /* If this symbol is in a section which is not being included
+ in the output file, then we don't want to output the symbol. */
+ if (sym->section->linker_mark == false)
+ output = false;
+
if (output)
{
if (! generic_add_output_symbol (output_bfd, psymalloc, sym))
switch (h->type)
{
default:
- case bfd_link_hash_new:
abort ();
+ break;
+ case bfd_link_hash_new:
+ /* This can happen when a constructor symbol is seen but we are
+ not building constructors. */
+ if (sym->section != NULL)
+ {
+ BFD_ASSERT ((sym->flags & BSF_CONSTRUCTOR) != 0);
+ }
+ else
+ {
+ sym->flags |= BSF_CONSTRUCTOR;
+ sym->section = bfd_abs_section_ptr;
+ sym->value = 0;
+ }
+ break;
case bfd_link_hash_undefined:
sym->section = bfd_und_section_ptr;
sym->value = 0;
return true;
if (h->sym != (asymbol *) NULL)
- {
- sym = h->sym;
- BFD_ASSERT (strcmp (bfd_asymbol_name (sym), h->root.root.string) == 0);
- }
+ sym = h->sym;
else
{
sym = bfd_make_empty_symbol (wginfo->output_bfd);
r = (arelent *) bfd_alloc (abfd, sizeof (arelent));
if (r == (arelent *) NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
r->address = link_order->offset;
r->howto = bfd_reloc_type_lookup (abfd, link_order->u.reloc.p->reloc);
{
struct generic_link_hash_entry *h;
- h = _bfd_generic_link_hash_lookup (_bfd_generic_hash_table (info),
+ h = ((struct generic_link_hash_entry *)
+ bfd_wrapped_link_hash_lookup (abfd, info,
link_order->u.reloc.p->u.name,
- false, false, true);
+ false, false, true));
if (h == (struct generic_link_hash_entry *) NULL
|| ! h->written)
{
size = bfd_get_reloc_size (r->howto);
buf = (bfd_byte *) bfd_zmalloc (size);
if (buf == (bfd_byte *) NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
rstat = _bfd_relocate_contents (r->howto, abfd,
link_order->u.reloc.p->addend, buf);
switch (rstat)
new = ((struct bfd_link_order *)
bfd_alloc_by_size_t (abfd, sizeof (struct bfd_link_order)));
if (!new)
- {
- bfd_set_error (bfd_error_no_memory);
- return NULL;
- }
+ return NULL;
new->type = bfd_undefined_link_order;
new->offset = 0;
BFD_ASSERT ((sec->flags & SEC_HAS_CONTENTS) != 0);
size = (size_t) link_order->size;
- space = (char *) malloc (size);
+ space = (char *) bfd_malloc (size);
if (space == NULL && size != 0)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
fill = link_order->u.fill.value;
for (i = 0; i < size; i += 2)
because somebody is attempting to link together different
types of object files. Handling this case correctly is
difficult, and sometimes impossible. */
- abort ();
+ (*_bfd_error_handler)
+ ("Attempt to do relocateable 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;
}
if (! generic_linker)
generic_link_add_symbol_list. */
if (sym->udata.p != NULL)
h = (struct bfd_link_hash_entry *) 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),
+ false, false, true);
else
h = bfd_link_hash_lookup (info->hash,
bfd_asymbol_name (sym),
}
/* Get and relocate the section contents. */
- contents = (bfd_byte *) malloc (bfd_section_size (input_bfd, input_section));
+ contents = ((bfd_byte *)
+ bfd_malloc (bfd_section_size (input_bfd, input_section)));
if (contents == NULL && bfd_section_size (input_bfd, input_section) != 0)
- {
- bfd_set_error (bfd_error_no_memory);
- goto error_return;
- }
+ goto error_return;
new_contents = (bfd_get_relocated_section_contents
(output_bfd, info, link_order, contents, info->relocateable,
_bfd_generic_link_get_symbols (input_bfd)));