/* linker.c -- BFD linker routines
- Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
- Free Software Foundation, Inc.
+ Copyright (C) 1993-2016 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.
@findex _bfd_generic_link_add_archive_symbols
In most cases the work of looking through the symbols in the
archive should be done by the
- <<_bfd_generic_link_add_archive_symbols>> function. This
- function builds a hash table from the archive symbol table and
- looks through the list of undefined symbols to see which
- elements should be included.
+ <<_bfd_generic_link_add_archive_symbols>> function.
<<_bfd_generic_link_add_archive_symbols>> is passed a function
to call to make the final decision about adding an archive
element to the link and to do the actual work of adding the
- symbols to the linker hash table.
-
- The function passed to
- <<_bfd_generic_link_add_archive_symbols>> must read the
- symbols of the archive element and decide whether the archive
- element should be included in the link. If the element is to
+ symbols to the linker hash table. If the element is to
be included, the <<add_archive_element>> linker callback
routine must be called with the element as an argument, and
the element's symbols must be added to the linker hash table
just as though the element had itself been passed to the
- <<_bfd_link_add_symbols>> function. The <<add_archive_element>>
- callback has the option to indicate that it would like to
- replace the element archive with a substitute BFD, in which
- case it is the symbols of that substitute BFD that must be
- added to the linker hash table instead.
+ <<_bfd_link_add_symbols>> function.
When the a.out <<_bfd_link_add_symbols>> function receives an
archive, it calls <<_bfd_generic_link_add_archive_symbols>>
The <<input_bfds>> field of the <<bfd_link_info>> structure
will point to a list of all the input files included in the
- link. These files are linked through the <<link_next>> field
+ link. These files are linked through the <<link.next>> field
of the <<bfd>> structure.
Each section in the output file will have a list of
static bfd_boolean generic_link_add_symbols
(bfd *, struct bfd_link_info *, bfd_boolean);
static bfd_boolean generic_link_check_archive_element_no_collect
- (bfd *, struct bfd_link_info *, bfd_boolean *);
+ (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, const char *,
+ bfd_boolean *);
static bfd_boolean generic_link_check_archive_element_collect
- (bfd *, struct bfd_link_info *, bfd_boolean *);
+ (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, const char *,
+ bfd_boolean *);
static bfd_boolean generic_link_check_archive_element
- (bfd *, struct bfd_link_info *, bfd_boolean *, bfd_boolean);
+ (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, const char *,
+ bfd_boolean *, bfd_boolean);
static bfd_boolean generic_link_add_symbol_list
(bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **,
bfd_boolean);
const char *),
unsigned int entsize)
{
+ bfd_boolean ret;
+
+ BFD_ASSERT (!abfd->is_linker_output && !abfd->link.hash);
table->undefs = NULL;
table->undefs_tail = NULL;
table->type = bfd_link_generic_hash_table;
- return bfd_hash_table_init (&table->table, newfunc, entsize);
+ ret = bfd_hash_table_init (&table->table, newfunc, entsize);
+ if (ret)
+ {
+ /* Arrange for destruction of this hash table on closing ABFD. */
+ table->hash_table_free = _bfd_generic_link_hash_table_free;
+ abfd->link.hash = table;
+ abfd->is_linker_output = TRUE;
+ }
+ return ret;
}
/* Look up a symbol in a link hash table. If follow is TRUE, we
return h;
}
-#undef WRAP
-
#undef REAL
#define REAL "__real_"
return bfd_link_hash_lookup (info->hash, string, create, copy, follow);
}
+/* If H is a wrapped symbol, ie. the symbol name starts with "__wrap_"
+ and the remainder is found in wrap_hash, return the real symbol. */
+
+struct bfd_link_hash_entry *
+unwrap_hash_lookup (struct bfd_link_info *info,
+ bfd *input_bfd,
+ struct bfd_link_hash_entry *h)
+{
+ const char *l = h->root.string;
+
+ if (*l == bfd_get_symbol_leading_char (input_bfd)
+ || *l == info->wrap_char)
+ ++l;
+
+ if (CONST_STRNEQ (l, WRAP))
+ {
+ l += sizeof WRAP - 1;
+
+ if (bfd_hash_lookup (info->wrap_hash, l, FALSE, FALSE) != NULL)
+ {
+ char save = 0;
+ if (l - (sizeof WRAP - 1) != h->root.string)
+ {
+ --l;
+ save = *l;
+ *(char *) l = *h->root.string;
+ }
+ h = bfd_link_hash_lookup (info->hash, l, FALSE, FALSE, FALSE);
+ if (save)
+ *(char *) l = save;
+ }
+ }
+ return h;
+}
+#undef WRAP
+
/* Traverse a generic link hash table. Differs from bfd_hash_traverse
in the treatment of warning symbols. When warning symbols are
created they replace the real symbol, so you don't get to see the
}
void
-_bfd_generic_link_hash_table_free (struct bfd_link_hash_table *hash)
+_bfd_generic_link_hash_table_free (bfd *obfd)
{
- struct generic_link_hash_table *ret
- = (struct generic_link_hash_table *) hash;
+ struct generic_link_hash_table *ret;
+ BFD_ASSERT (obfd->is_linker_output && obfd->link.hash);
+ ret = (struct generic_link_hash_table *) obfd->link.hash;
bfd_hash_table_free (&ret->root.table);
free (ret);
+ obfd->link.hash = NULL;
+ obfd->is_linker_output = FALSE;
}
/* Grab the symbols for an object file when doing a generic link. We
_bfd_generic_link_just_syms (asection *sec,
struct bfd_link_info *info ATTRIBUTE_UNUSED)
{
+ sec->sec_info_type = SEC_INFO_TYPE_JUST_SYMS;
sec->output_section = bfd_abs_section_ptr;
sec->output_offset = sec->vma;
}
-/* Copy the type of a symbol assiciated with a linker hast table entry.
- Override this so that symbols created in linker scripts get their
- type from the RHS of the assignment.
+/* Copy the symbol type and other attributes for a linker script
+ assignment from HSRC to HDEST.
The default implementation does nothing. */
void
_bfd_generic_copy_link_hash_symbol_type (bfd *abfd ATTRIBUTE_UNUSED,
- struct bfd_link_hash_entry * hdest ATTRIBUTE_UNUSED,
- struct bfd_link_hash_entry * hsrc ATTRIBUTE_UNUSED)
+ struct bfd_link_hash_entry *hdest ATTRIBUTE_UNUSED,
+ struct bfd_link_hash_entry *hsrc ATTRIBUTE_UNUSED)
{
}
return generic_link_add_symbol_list (abfd, info, symcount, outsyms, collect);
}
\f
-/* 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;
- unsigned 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;
-};
-
-/* Create a new entry for an archive hash table. */
-
-static struct bfd_hash_entry *
-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 == NULL)
- ret = (struct archive_hash_entry *)
- bfd_hash_allocate (table, sizeof (struct archive_hash_entry));
- if (ret == NULL)
- return NULL;
-
- /* Call the allocation method of the superclass. */
- ret = ((struct archive_hash_entry *)
- bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
-
- if (ret)
- {
- /* Initialize the local fields. */
- ret->defs = NULL;
- }
-
- return &ret->root;
-}
-
-/* Initialize an archive hash table. */
-
-static bfd_boolean
-archive_hash_table_init
- (struct archive_hash_table *table,
- struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *,
- struct bfd_hash_table *,
- const char *),
- unsigned int entsize)
-{
- return bfd_hash_table_init (&table->table, newfunc, entsize);
-}
-
-/* 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)))
-
-/* Allocate space in an archive hash table. */
-
-#define archive_hash_allocate(t, size) bfd_hash_allocate (&(t)->table, (size))
-
-/* 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 must notice if the callback
- indicates a substitute BFD, and arrange to add those symbols instead
- if it does so. 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. */
+ bfd_check_format entry point). It looks through the archive symbol
+ table for symbols that are undefined or common in the linker global
+ symbol hash table. When one is found, the CHECKFN argument is used
+ to see if an object file should be included. This allows targets
+ to customize common symbol behaviour. 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 must notice
+ if the callback indicates a substitute BFD, and arrange to add
+ those symbols instead if it does so. CHECKFN should only return
+ FALSE if some sort of error occurs. */
bfd_boolean
_bfd_generic_link_add_archive_symbols
(bfd *abfd,
struct bfd_link_info *info,
- bfd_boolean (*checkfn) (bfd *, struct bfd_link_info *, bfd_boolean *))
+ bfd_boolean (*checkfn) (bfd *, struct bfd_link_info *,
+ struct bfd_link_hash_entry *, const char *,
+ bfd_boolean *))
{
- carsym *arsyms;
- carsym *arsym_end;
- register carsym *arsym;
- int pass;
- struct archive_hash_table arsym_hash;
- unsigned int indx;
- struct bfd_link_hash_entry **pundef;
+ bfd_boolean loop;
+ bfd_size_type amt;
+ unsigned char *included;
if (! bfd_has_map (abfd))
{
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,
- sizeof (struct archive_hash_entry)))
+ amt = bfd_ardata (abfd)->symdef_count;
+ if (amt == 0)
+ return TRUE;
+ amt *= sizeof (*included);
+ included = (unsigned char *) bfd_zmalloc (amt);
+ if (included == NULL)
return FALSE;
- for (arsym = arsyms, indx = 0; arsym < arsym_end; arsym++, indx++)
- {
- struct archive_hash_entry *arh;
- struct archive_list *l, **pp;
-
- arh = archive_hash_lookup (&arsym_hash, arsym->name, TRUE, FALSE);
- 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 != NULL; pp = &(*pp)->next)
- ;
- *pp = l;
- l->next = NULL;
- }
- /* The archive_pass field in the archive itself is used to
- initialize PASS, sine we may search the same archive multiple
- times. */
- pass = abfd->archive_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 != NULL)
+ do
{
- 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 (it would also cause
- us to lose track of whether the symbol has been
- referenced). */
- if (*pundef != info->hash->undefs_tail)
- *pundef = (*pundef)->u.undef.next;
- else
- 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 == NULL)
+ carsym *arsyms;
+ carsym *arsym_end;
+ carsym *arsym;
+ unsigned int indx;
+ file_ptr last_ar_offset = -1;
+ bfd_boolean needed = FALSE;
+ bfd *element = NULL;
+
+ loop = FALSE;
+ arsyms = bfd_ardata (abfd)->symdefs;
+ arsym_end = arsyms + bfd_ardata (abfd)->symdef_count;
+ for (arsym = arsyms, indx = 0; arsym < arsym_end; arsym++, indx++)
{
- /* 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);
- if (buf == NULL)
- return FALSE;
+ struct bfd_link_hash_entry *h;
+ struct bfd_link_hash_entry *undefs_tail;
- sprintf (buf, "__imp_%s", h->root.string);
- arh = archive_hash_lookup (&arsym_hash, buf, FALSE, FALSE);
- free(buf);
- }
- if (arh == NULL)
+ if (included[indx])
+ continue;
+ if (needed && arsym->file_offset == last_ar_offset)
{
- pundef = &(*pundef)->u.undef.next;
+ included[indx] = 1;
continue;
}
- }
- /* Look at all the objects which define this symbol. */
- for (l = arh->defs; l != NULL; l = l->next)
- {
- bfd *element;
- bfd_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;
+ h = bfd_link_hash_lookup (info->hash, arsym->name,
+ FALSE, FALSE, TRUE);
- element = bfd_get_elt_at_index (abfd, l->indx);
- if (element == NULL)
- goto error_return;
-
- /* 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)
+ if (h == NULL
+ && info->pei386_auto_import
+ && CONST_STRNEQ (arsym->name, "__imp_"))
+ h = bfd_link_hash_lookup (info->hash, arsym->name + 6,
+ FALSE, FALSE, TRUE);
+ if (h == NULL)
continue;
- /* If we can't figure this element out, just ignore it. */
- if (! bfd_check_format (element, bfd_object))
+ if (h->type != bfd_link_hash_undefined
+ && h->type != bfd_link_hash_common)
{
- element->archive_pass = -1;
+ if (h->type != bfd_link_hash_undefweak)
+ /* Symbol must be defined. Don't check it again. */
+ included[indx] = 1;
continue;
}
+ if (last_ar_offset != arsym->file_offset)
+ {
+ last_ar_offset = arsym->file_offset;
+ element = _bfd_get_elt_at_filepos (abfd, last_ar_offset);
+ if (element == NULL
+ || !bfd_check_format (element, bfd_object))
+ goto error_return;
+ }
+
+ undefs_tail = info->hash->undefs_tail;
+
/* CHECKFN will see if this element should be included, and
go ahead and include it if appropriate. */
- if (! (*checkfn) (element, info, &needed))
+ if (! (*checkfn) (element, info, h, arsym->name, &needed))
goto error_return;
- if (! needed)
- element->archive_pass = pass;
- else
+ if (needed)
{
- element->archive_pass = -1;
+ unsigned int mark;
- /* Increment the pass count to show that we may need to
- recheck object files which were already checked. */
- ++pass;
+ /* Look backward to mark all symbols from this object file
+ which we have already seen in this pass. */
+ mark = indx;
+ do
+ {
+ included[mark] = 1;
+ if (mark == 0)
+ break;
+ --mark;
+ }
+ while (arsyms[mark].file_offset == last_ar_offset);
+
+ if (undefs_tail != info->hash->undefs_tail)
+ loop = TRUE;
}
}
+ } while (loop);
- pundef = &(*pundef)->u.undef.next;
- }
-
- archive_hash_table_free (&arsym_hash);
-
- /* Save PASS in case we are called again. */
- abfd->archive_pass = pass;
-
+ free (included);
return TRUE;
error_return:
- archive_hash_table_free (&arsym_hash);
+ free (included);
return FALSE;
}
\f
for finding them. */
static bfd_boolean
-generic_link_check_archive_element_no_collect (
- bfd *abfd,
+generic_link_check_archive_element_no_collect (bfd *abfd,
struct bfd_link_info *info,
+ struct bfd_link_hash_entry *h,
+ const char *name,
bfd_boolean *pneeded)
{
- return generic_link_check_archive_element (abfd, info, pneeded, FALSE);
+ return generic_link_check_archive_element (abfd, info, h, name, pneeded,
+ FALSE);
}
/* See if we should include an archive element. This version is used
static bfd_boolean
generic_link_check_archive_element_collect (bfd *abfd,
struct bfd_link_info *info,
+ struct bfd_link_hash_entry *h,
+ const char *name,
bfd_boolean *pneeded)
{
- return generic_link_check_archive_element (abfd, info, pneeded, TRUE);
+ return generic_link_check_archive_element (abfd, info, h, name, pneeded,
+ TRUE);
}
/* See if we should include an archive element. Optionally collect
static bfd_boolean
generic_link_check_archive_element (bfd *abfd,
struct bfd_link_info *info,
+ struct bfd_link_hash_entry *h,
+ const char *name ATTRIBUTE_UNUSED,
bfd_boolean *pneeded,
bfd_boolean collect)
{
for (; pp < ppend; pp++)
{
asymbol *p;
- struct bfd_link_hash_entry *h;
p = *pp;
/* P is a symbol we are looking for. */
- if (! bfd_is_com_section (p->section))
+ if (! bfd_is_com_section (p->section)
+ || (h->type == bfd_link_hash_undefined
+ && h->u.undef.abfd == NULL))
{
- bfd_size_type symcount;
- asymbol **symbols;
- bfd *oldbfd = abfd;
-
- /* This object file defines this symbol, so pull it in. */
+ /* P is not a common symbol, or an undefined reference was
+ created from outside BFD such as from a linker -u option.
+ This object file defines the symbol, so pull it in. */
+ *pneeded = TRUE;
if (!(*info->callbacks
->add_archive_element) (info, abfd, bfd_asymbol_name (p),
&abfd))
return FALSE;
/* Potentially, the add_archive_element hook may have set a
substitute BFD for us. */
- if (abfd != oldbfd
- && !bfd_generic_link_read_symbols (abfd))
- return FALSE;
- symcount = _bfd_generic_link_get_symcount (abfd);
- symbols = _bfd_generic_link_get_symbols (abfd);
- if (! generic_link_add_symbol_list (abfd, info, symcount,
- symbols, collect))
- return FALSE;
- *pneeded = TRUE;
- return TRUE;
+ return generic_link_add_object_symbols (abfd, info, collect);
}
/* P is a common symbol. */
bfd_vma size;
unsigned int power;
- symbfd = h->u.undef.abfd;
- if (symbfd == 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),
- &abfd))
- return FALSE;
- /* Potentially, the add_archive_element hook may have set a
- substitute BFD for us. But no symbols are going to get
- registered by anything we're returning to from here. */
- *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
undefs list. We add the section to a common section
attached to symbfd to ensure that it is in a BFD which
will be linked in. */
+ symbfd = h->u.undef.abfd;
h->type = bfd_link_hash_common;
h->u.c.p = (struct bfd_link_hash_common_entry *)
bfd_hash_allocate (&info->hash->table,
CIND, /* Make indirect symbol from existing common symbol. */
SET, /* Add value to set. */
MWARN, /* Make warning symbol. */
- WARN, /* Issue warning. */
- CWARN, /* Warn if referenced, else MWARN. */
+ WARN, /* Warn if referenced, else MWARN. */
CYCLE, /* Repeat with symbol pointed to. */
REFC, /* Mark indirect symbol referenced and then CYCLE. */
WARNC /* Issue warning and then CYCLE. */
/* DEFW_ROW */ {DEFW, DEFW, DEFW, NOACT, NOACT, NOACT, NOACT, CYCLE },
/* COMMON_ROW */ {COM, COM, COM, CREF, COM, BIG, REFC, WARNC },
/* INDR_ROW */ {IND, IND, IND, MDEF, IND, CIND, MIND, CYCLE },
- /* WARN_ROW */ {MWARN, WARN, WARN, CWARN, CWARN, WARN, CWARN, NOACT },
+ /* WARN_ROW */ {MWARN, WARN, WARN, WARN, WARN, WARN, WARN, NOACT },
/* SET_ROW */ {SET, SET, SET, SET, SET, SET, CYCLE, CYCLE }
};
{
enum link_row row;
struct bfd_link_hash_entry *h;
+ struct bfd_link_hash_entry *inh = NULL;
bfd_boolean cycle;
BFD_ASSERT (section != NULL);
if (bfd_is_ind_section (section)
|| (flags & BSF_INDIRECT) != 0)
- row = INDR_ROW;
+ {
+ row = INDR_ROW;
+ /* Create the indirect symbol here. This is for the benefit of
+ the plugin "notice" function.
+ STRING is the name of the symbol we want to indirect to. */
+ inh = bfd_wrapped_link_hash_lookup (abfd, info, string, TRUE,
+ copy, FALSE);
+ if (inh == NULL)
+ return FALSE;
+ }
else if ((flags & BSF_WARNING) != 0)
row = WARN_ROW;
else if ((flags & BSF_CONSTRUCTOR) != 0)
else if ((flags & BSF_WEAK) != 0)
row = DEFW_ROW;
else if (bfd_is_com_section (section))
- row = COMMON_ROW;
+ {
+ row = COMMON_ROW;
+ if (!bfd_link_relocatable (info)
+ && strcmp (name, "__gnu_lto_slim") == 0)
+ (*_bfd_error_handler)
+ (_("%s: plugin needed to handle lto object"),
+ bfd_get_filename (abfd));
+ }
else
row = DEF_ROW;
|| (info->notice_hash != NULL
&& bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE) != NULL))
{
- if (! (*info->callbacks->notice) (info, h,
- abfd, section, value, flags, string))
+ if (! (*info->callbacks->notice) (info, h, inh,
+ abfd, section, value, flags))
return FALSE;
}
h->type = bfd_link_hash_defined;
h->u.def.section = section;
h->u.def.value = value;
+ h->linker_def = 0;
/* If we have been asked to, we act like collect2 and
identify all functions that might be global
}
else
h->u.c.p->section = section;
+ h->linker_def = 0;
break;
case REF:
return FALSE;
/* Fall through. */
case IND:
- /* Create an indirect symbol. */
- {
- struct bfd_link_hash_entry *inh;
-
- /* STRING is the name of the symbol we want to indirect
- to. */
- inh = bfd_wrapped_link_hash_lookup (abfd, info, string, TRUE,
- copy, FALSE);
- if (inh == NULL)
+ if (inh->type == bfd_link_hash_indirect
+ && inh->u.i.link == h)
+ {
+ (*_bfd_error_handler)
+ (_("%B: indirect symbol `%s' to `%s' is a loop"),
+ abfd, name, string);
+ bfd_set_error (bfd_error_invalid_operation);
return FALSE;
- if (inh->type == bfd_link_hash_indirect
- && inh->u.i.link == h)
- {
- (*_bfd_error_handler)
- (_("%B: indirect symbol `%s' to `%s' is a loop"),
- abfd, name, string);
- bfd_set_error (bfd_error_invalid_operation);
- 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);
- }
+ }
+ 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);
+ }
- /* If the indirect symbol has been referenced, we need to
- push the reference down to the symbol we are
- referencing. */
- if (h->type != bfd_link_hash_new)
- {
- row = UNDEF_ROW;
- cycle = TRUE;
- }
+ /* If the indirect symbol has been referenced, we need to
+ push the reference down to the symbol we are referencing. */
+ if (h->type != bfd_link_hash_new)
+ {
+ /* ??? If inh->type == bfd_link_hash_undefweak this
+ converts inh to bfd_link_hash_undefined. */
+ row = UNDEF_ROW;
+ cycle = TRUE;
+ }
- h->type = bfd_link_hash_indirect;
- h->u.i.link = inh;
- }
+ h->type = bfd_link_hash_indirect;
+ h->u.i.link = inh;
+ /* Not setting h = h->u.i.link here means that when cycle is
+ set above we'll always go to REFC, and then cycle again
+ to the indirected symbol. This means that any successful
+ change of an existing symbol to indirect counts as a
+ reference. ??? That may not be correct when the existing
+ symbol was defweak. */
break;
case SET:
break;
case WARNC:
- /* Issue a warning and cycle. */
- if (h->u.i.warning != NULL)
+ /* Issue a warning and cycle, except when the reference is
+ in LTO IR. */
+ if (h->u.i.warning != NULL
+ && (abfd->flags & BFD_PLUGIN) == 0)
{
if (! (*info->callbacks->warning) (info, h->u.i.warning,
h->root.string, abfd,
break;
case WARN:
- /* Issue a warning. */
- if (! (*info->callbacks->warning) (info, string, h->root.string,
- 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 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->u.undef.next != NULL || info->hash->undefs_tail == h)
+ /* Warn if this symbol has been referenced already from non-IR,
+ otherwise add a warning. */
+ if ((!info->lto_plugin_active
+ && (h->u.undef.next != NULL || info->hash->undefs_tail == h))
+ || h->non_ir_ref)
{
if (! (*info->callbacks->warning) (info, string, h->root.string,
hash_entry_bfd (h), NULL, 0))
p->u.indirect.section->linker_mark = TRUE;
/* Build the output symbol table. */
- for (sub = info->input_bfds; sub != 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;
if (! generic_add_output_symbol (abfd, &outsymalloc, NULL))
return FALSE;
- if (info->relocatable)
+ if (bfd_link_relocatable (info))
{
/* Allocate space for the output relocs for each section. */
for (o = abfd->sections; o != NULL; o = o->next)
/* fall through */
case bfd_link_hash_defined:
sym->flags |= BSF_GLOBAL;
- sym->flags &=~ BSF_CONSTRUCTOR;
+ sym->flags &=~ (BSF_WEAK | BSF_CONSTRUCTOR);
sym->value = h->root.u.def.value;
sym->section = h->root.u.def.section;
break;
break;
case discard_sec_merge:
output = TRUE;
- if (info->relocatable
+ if (bfd_link_relocatable (info)
|| ! (sym->section->flags & SEC_MERGE))
break;
/* FALLTHROUGH */
else
output = FALSE;
}
+ else if (sym->flags == 0
+ && (sym->section->owner->flags & BFD_PLUGIN) != 0)
+ /* LTO doesn't set symbol information. We get here with the
+ generic linker for a symbol that was "common" but no longer
+ needs to be global. */
+ output = FALSE;
else
abort ();
{
arelent *r;
- if (! info->relocatable)
+ if (! bfd_link_relocatable (info))
abort ();
if (sec->orelocation == NULL)
abort ();
size = bfd_get_reloc_size (r->howto);
buf = (bfd_byte *) bfd_zmalloc (size);
- if (buf == NULL)
+ if (buf == NULL && size != 0)
return FALSE;
rstat = _bfd_relocate_contents (r->howto, abfd,
(bfd_vma) link_order->u.reloc.p->addend,
BFD_ASSERT (input_section->output_offset == link_order->offset);
BFD_ASSERT (input_section->size == link_order->size);
- if (info->relocatable
+ if (bfd_link_relocatable (info)
&& input_section->reloc_count > 0
&& output_section->orelocation == NULL)
{
goto error_return;
new_contents = (bfd_get_relocated_section_contents
(output_bfd, info, link_order, contents,
- info->relocatable,
+ bfd_link_relocatable (info),
_bfd_generic_link_get_symbols (input_bfd)));
if (!new_contents)
goto error_return;
/* 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
+ 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. */
files over IR because the first pass may contain a
mix of LTO and normal objects and we must keep the
first match, be it IR or real. */
- if (info->loading_lto_outputs
+ if (sec->owner->lto_output
&& (l->sec->owner->flags & BFD_PLUGIN) != 0)
{
l->sec = sec;
return FALSE;
}
+/* Choose a neighbouring section to S in OBFD that will be output, or
+ the absolute section if ADDR is out of bounds of the neighbours. */
+
+asection *
+_bfd_nearby_section (bfd *obfd, asection *s, bfd_vma addr)
+{
+ asection *next, *prev, *best;
+
+ /* Find preceding kept section. */
+ for (prev = s->prev; prev != NULL; prev = prev->prev)
+ if ((prev->flags & SEC_EXCLUDE) == 0
+ && !bfd_section_removed_from_list (obfd, prev))
+ break;
+
+ /* Find following kept section. Start at prev->next because
+ other sections may have been added after S was removed. */
+ if (s->prev != NULL)
+ next = s->prev->next;
+ else
+ next = s->owner->sections;
+ for (; next != NULL; next = next->next)
+ if ((next->flags & SEC_EXCLUDE) == 0
+ && !bfd_section_removed_from_list (obfd, next))
+ break;
+
+ /* Choose better of two sections, based on flags. The idea
+ is to choose a section that will be in the same segment
+ as S would have been if it was kept. */
+ best = next;
+ if (prev == NULL)
+ {
+ if (next == NULL)
+ best = bfd_abs_section_ptr;
+ }
+ else if (next == NULL)
+ best = prev;
+ else if (((prev->flags ^ next->flags)
+ & (SEC_ALLOC | SEC_THREAD_LOCAL | SEC_LOAD)) != 0)
+ {
+ if (((next->flags ^ s->flags)
+ & (SEC_ALLOC | SEC_THREAD_LOCAL)) != 0
+ /* We prefer to choose a loaded section. Section S
+ doesn't have SEC_LOAD set (it being excluded, that
+ part of the flag processing didn't happen) so we
+ can't compare that flag to those of NEXT and PREV. */
+ || ((prev->flags & SEC_LOAD) != 0
+ && (next->flags & SEC_LOAD) == 0))
+ best = prev;
+ }
+ else if (((prev->flags ^ next->flags) & SEC_READONLY) != 0)
+ {
+ if (((next->flags ^ s->flags) & SEC_READONLY) != 0)
+ best = prev;
+ }
+ else if (((prev->flags ^ next->flags) & SEC_CODE) != 0)
+ {
+ if (((next->flags ^ s->flags) & SEC_CODE) != 0)
+ best = prev;
+ }
+ else
+ {
+ /* Flags we care about are the same. Prefer the following
+ section if that will result in a positive valued sym. */
+ if (addr < next->vma)
+ best = prev;
+ }
+
+ return best;
+}
+
/* Convert symbols in excluded output sections to use a kept section. */
static bfd_boolean
&& (s->output_section->flags & SEC_EXCLUDE) != 0
&& bfd_section_removed_from_list (obfd, s->output_section))
{
- asection *op, *op1;
+ asection *op;
h->u.def.value += s->output_offset + s->output_section->vma;
-
- /* Find preceding kept section. */
- for (op1 = s->output_section->prev; op1 != NULL; op1 = op1->prev)
- if ((op1->flags & SEC_EXCLUDE) == 0
- && !bfd_section_removed_from_list (obfd, op1))
- break;
-
- /* Find following kept section. Start at prev->next because
- other sections may have been added after S was removed. */
- if (s->output_section->prev != NULL)
- op = s->output_section->prev->next;
- else
- op = s->output_section->owner->sections;
- for (; op != NULL; op = op->next)
- if ((op->flags & SEC_EXCLUDE) == 0
- && !bfd_section_removed_from_list (obfd, op))
- break;
-
- /* Choose better of two sections, based on flags. The idea
- is to choose a section that will be in the same segment
- as S would have been if it was kept. */
- if (op1 == NULL)
- {
- if (op == NULL)
- op = bfd_abs_section_ptr;
- }
- else if (op == NULL)
- op = op1;
- else if (((op1->flags ^ op->flags)
- & (SEC_ALLOC | SEC_THREAD_LOCAL | SEC_LOAD)) != 0)
- {
- if (((op->flags ^ s->flags)
- & (SEC_ALLOC | SEC_THREAD_LOCAL)) != 0
- /* We prefer to choose a loaded section. Section S
- doesn't have SEC_LOAD set (it being excluded, that
- part of the flag processing didn't happen) so we
- can't compare that flag to those of OP and OP1. */
- || ((op1->flags & SEC_LOAD) != 0
- && (op->flags & SEC_LOAD) == 0))
- op = op1;
- }
- else if (((op1->flags ^ op->flags) & SEC_READONLY) != 0)
- {
- if (((op->flags ^ s->flags) & SEC_READONLY) != 0)
- op = op1;
- }
- else if (((op1->flags ^ op->flags) & SEC_CODE) != 0)
- {
- if (((op->flags ^ s->flags) & SEC_CODE) != 0)
- op = op1;
- }
- else
- {
- /* Flags we care about are the same. Prefer the following
- section if that will result in a positive valued sym. */
- if (h->u.def.value < op->vma)
- op = op1;
- }
-
+ op = _bfd_nearby_section (obfd, s->output_section, h->u.def.value);
h->u.def.value -= op->vma;
h->u.def.section = op;
}
/*
FUNCTION
- bfd_find_version_for_sym
+ bfd_find_version_for_sym
SYNOPSIS
struct bfd_elf_version_tree * bfd_find_version_for_sym
bfd_find_version_for_sym (verdefs, sym_name, &hidden);
return hidden;
}
+
+/*
+FUNCTION
+ bfd_link_check_relocs
+
+SYNOPSIS
+ bfd_boolean bfd_link_check_relocs
+ (bfd *abfd, struct bfd_link_info *info);
+
+DESCRIPTION
+ Checks the relocs in ABFD for validity.
+ Does not execute the relocs.
+ Return TRUE if everything is OK, FALSE otherwise.
+ This is the external entry point to this code.
+*/
+
+bfd_boolean
+bfd_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
+{
+ return BFD_SEND (abfd, _bfd_link_check_relocs, (abfd, info));
+}
+
+/*
+FUNCTION
+ _bfd_generic_link_check_relocs
+
+SYNOPSIS
+ bfd_boolean _bfd_generic_link_check_relocs
+ (bfd *abfd, struct bfd_link_info *info);
+
+DESCRIPTION
+ Stub function for targets that do not implement reloc checking.
+ Return TRUE.
+ This is an internal function. It should not be called from
+ outside the BFD library.
+*/
+
+bfd_boolean
+_bfd_generic_link_check_relocs (bfd *abfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED)
+{
+ return TRUE;
+}