/* linker.c -- BFD linker routines
- Copyright (C) 1993-2014 Free Software Foundation, Inc.
+ Copyright (C) 1993-2021 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.
*/
static bfd_boolean generic_link_add_object_symbols
- (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
- (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 *, struct bfd_link_hash_entry *, const char *,
- bfd_boolean *);
+ (bfd *, struct bfd_link_info *);
static bfd_boolean generic_link_check_archive_element
(bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, const char *,
- bfd_boolean *, bfd_boolean);
+ bfd_boolean *);
static bfd_boolean generic_link_add_symbol_list
- (bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **,
- bfd_boolean);
+ (bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **);
static bfd_boolean generic_add_output_symbol
(bfd *, size_t *psymalloc, asymbol *);
static bfd_boolean default_data_link_order
if (entry == NULL)
{
entry = (struct bfd_hash_entry *)
- bfd_hash_allocate (table, sizeof (struct bfd_link_hash_entry));
+ bfd_hash_allocate (table, sizeof (struct bfd_link_hash_entry));
if (entry == NULL)
return entry;
}
/* Look up a symbol in a link hash table. If follow is TRUE, we
follow bfd_link_hash_indirect and bfd_link_hash_warning links to
- the real symbol. */
+ the real symbol.
+
+.{* Return TRUE if the symbol described by a linker hash entry H
+. is going to be absolute. Linker-script defined symbols can be
+. converted from absolute to section-relative ones late in the
+. link. Use this macro to correctly determine whether the symbol
+. will actually end up absolute in output. *}
+.#define bfd_is_abs_symbol(H) \
+. (((H)->type == bfd_link_hash_defined \
+. || (H)->type == bfd_link_hash_defweak) \
+. && bfd_is_abs_section ((H)->u.def.section) \
+. && !(H)->rel_from_abs)
+.
+*/
struct bfd_link_hash_entry *
bfd_link_hash_lookup (struct bfd_link_hash_table *table,
{
struct bfd_link_hash_entry *ret;
+ if (table == NULL || string == NULL)
+ return NULL;
+
ret = ((struct bfd_link_hash_entry *)
bfd_hash_lookup (&table->table, string, create, copy));
bfd_boolean copy,
bfd_boolean follow)
{
- bfd_size_type amt;
+ size_t amt;
if (info->wrap_hash != NULL)
{
struct bfd_link_hash_entry *h;
/* This symbol is being wrapped. We want to replace all
- references to SYM with references to __wrap_SYM. */
+ references to SYM with references to __wrap_SYM. */
amt = strlen (l) + sizeof WRAP + 1;
n = (char *) bfd_malloc (amt);
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. */
+ wrapped. We want to replace all references to __real_SYM
+ with references to SYM. */
amt = strlen (l + sizeof REAL - 1) + 2;
n = (char *) bfd_malloc (amt);
/* 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
- real symbol in a bfd_hash_travere. This traversal calls func with
+ real symbol in a bfd_hash_traverse. This traversal calls func with
the real symbol. */
void
_bfd_generic_link_hash_table_create (bfd *abfd)
{
struct generic_link_hash_table *ret;
- bfd_size_type amt = sizeof (struct generic_link_hash_table);
+ size_t amt = sizeof (struct generic_link_hash_table);
ret = (struct generic_link_hash_table *) bfd_malloc (amt);
if (ret == NULL)
symsize = bfd_get_symtab_upper_bound (abfd);
if (symsize < 0)
return FALSE;
- bfd_get_outsymbols (abfd) = (struct bfd_symbol **) bfd_alloc (abfd,
- symsize);
+ abfd->outsymbols = bfd_alloc (abfd, symsize);
if (bfd_get_outsymbols (abfd) == NULL && symsize != 0)
return FALSE;
symcount = bfd_canonicalize_symtab (abfd, bfd_get_outsymbols (abfd));
if (symcount < 0)
return FALSE;
- bfd_get_symcount (abfd) = symcount;
+ abfd->symcount = symcount;
}
return TRUE;
}
\f
-/* Generic function to add symbols to from an object file to the
- global hash table. This version does not automatically collect
- constructors by name. */
-
-bfd_boolean
-_bfd_generic_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
-{
- return generic_link_add_symbols (abfd, info, FALSE);
-}
-
-/* Generic function to add symbols from an object file to the global
- hash table. This version automatically collects constructors by
- name, as the collect2 program does. It should be used for any
- target which does not provide some other mechanism for setting up
- constructors and destructors; these are approximately those targets
- for which gcc uses collect2 and do not support stabs. */
-
-bfd_boolean
-_bfd_generic_link_add_symbols_collect (bfd *abfd, struct bfd_link_info *info)
-{
- return generic_link_add_symbols (abfd, info, TRUE);
-}
-
/* Indicate that we are only retrieving symbol values from this
section. We want the symbols to act as though the values in the
file are absolute. */
{
}
-/* Add symbols from an object file to the global hash table. */
+/* Generic function to add symbols from an object file to the
+ global hash table. */
-static bfd_boolean
-generic_link_add_symbols (bfd *abfd,
- struct bfd_link_info *info,
- bfd_boolean collect)
+bfd_boolean
+_bfd_generic_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
{
bfd_boolean ret;
switch (bfd_get_format (abfd))
{
case bfd_object:
- ret = generic_link_add_object_symbols (abfd, info, collect);
+ ret = generic_link_add_object_symbols (abfd, info);
break;
case bfd_archive:
ret = (_bfd_generic_link_add_archive_symbols
- (abfd, info,
- (collect
- ? generic_link_check_archive_element_collect
- : generic_link_check_archive_element_no_collect)));
+ (abfd, info, generic_link_check_archive_element));
break;
default:
bfd_set_error (bfd_error_wrong_format);
static bfd_boolean
generic_link_add_object_symbols (bfd *abfd,
- struct bfd_link_info *info,
- bfd_boolean collect)
+ struct bfd_link_info *info)
{
bfd_size_type symcount;
struct bfd_symbol **outsyms;
return FALSE;
symcount = _bfd_generic_link_get_symcount (abfd);
outsyms = _bfd_generic_link_get_symbols (abfd);
- return generic_link_add_symbol_list (abfd, info, symcount, outsyms, collect);
+ return generic_link_add_symbol_list (abfd, info, symcount, outsyms);
}
\f
/* Generic function to add symbols from an archive file to the global
continue;
}
+ if (arsym->name == NULL)
+ goto error_return;
+
h = bfd_link_hash_lookup (info->hash, arsym->name,
FALSE, FALSE, TRUE);
return FALSE;
}
\f
-/* See if we should include an archive element. This version is used
- when we do not want to automatically collect constructors based on
- the symbol name, presumably because we have some other mechanism
- for finding them. */
-
-static bfd_boolean
-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, h, name, pneeded,
- FALSE);
-}
-
-/* See if we should include an archive element. This version is used
- when we want to automatically collect constructors based on the
- symbol name, as collect2 does. */
-
-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, h, name, pneeded,
- TRUE);
-}
-
-/* See if we should include an archive element. Optionally collect
- constructors. */
+/* See if we should include an archive element. */
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)
+ bfd_boolean *pneeded)
{
asymbol **pp, **ppend;
return FALSE;
/* Potentially, the add_archive_element hook may have set a
substitute BFD for us. */
- return generic_link_add_object_symbols (abfd, info, collect);
+ return bfd_link_add_symbols (abfd, info);
}
/* P is a common symbol. */
/* Add the symbols from an object file to the global hash table. ABFD
is the object file. INFO is the linker information. SYMBOL_COUNT
- is the number of symbols. SYMBOLS is the list of symbols. COLLECT
- is TRUE if constructors should be automatically collected by name
- as is done by collect2. */
+ is the number of symbols. SYMBOLS is the list of symbols. */
static bfd_boolean
generic_link_add_symbol_list (bfd *abfd,
struct bfd_link_info *info,
bfd_size_type symbol_count,
- asymbol **symbols,
- bfd_boolean collect)
+ asymbol **symbols)
{
asymbol **pp, **ppend;
| BSF_GLOBAL
| BSF_CONSTRUCTOR
| BSF_WEAK)) != 0
- || bfd_is_und_section (bfd_get_section (p))
- || bfd_is_com_section (bfd_get_section (p))
- || bfd_is_ind_section (bfd_get_section (p)))
+ || bfd_is_und_section (bfd_asymbol_section (p))
+ || bfd_is_com_section (bfd_asymbol_section (p))
+ || bfd_is_ind_section (bfd_asymbol_section (p)))
{
const char *name;
const char *string;
bh = NULL;
if (! (_bfd_generic_link_add_one_symbol
- (info, abfd, name, p->flags, bfd_get_section (p),
- p->value, string, FALSE, collect, &bh)))
+ (info, abfd, name, p->flags, bfd_asymbol_section (p),
+ p->value, string, FALSE, FALSE, &bh)))
return FALSE;
h = (struct generic_link_hash_entry *) bh;
/* If this is a constructor symbol, and the linker didn't do
- anything with it, then we want to just pass the symbol
- through to the output file. This will happen when
- linking with -r. */
+ anything with it, then we want to just pass the symbol
+ through to the output file. This will happen when
+ linking with -r. */
if ((p->flags & BSF_CONSTRUCTOR) != 0
&& (h == NULL || h->root.type == bfd_link_hash_new))
{
if (info->output_bfd->xvec == abfd->xvec)
{
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)))))
+ || (! bfd_is_und_section (bfd_asymbol_section (p))
+ && (! bfd_is_com_section (bfd_asymbol_section (p))
+ || bfd_is_und_section (bfd_asymbol_section (h->sym)))))
{
h->sym = p;
/* BSF_OLD_COMMON is a hack to support COFF reloc
reading, and it should go away when the COFF
linker is switched to the new version. */
- if (bfd_is_com_section (bfd_get_section (p)))
+ if (bfd_is_com_section (bfd_asymbol_section (p)))
p->flags |= BSF_OLD_COMMON;
}
}
static const enum link_action link_action[8][8] =
{
/* current\prev new undef undefw def defw com indr warn */
- /* UNDEF_ROW */ {UND, NOACT, UND, 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 },
+ /* DEF_ROW */ {DEF, DEF, DEF, MDEF, DEF, CDEF, MIND, 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, WARN, WARN, WARN, WARN, NOACT },
else if (bfd_is_com_section (section))
{
row = COMMON_ROW;
- if (strcmp (name, "__gnu_lto_slim") == 0)
- (*_bfd_error_handler)
- (_("%s: plugin needed to handle lto object"),
- bfd_get_filename (abfd));
+ if (!bfd_link_relocatable (info)
+ && name[0] == '_'
+ && name[1] == '_'
+ && strcmp (name + (name[2] == '_'), "__gnu_lto_slim") == 0)
+ _bfd_error_handler
+ (_("%pB: plugin needed to handle lto object"), abfd);
}
else
row = DEF_ROW;
do
{
enum link_action action;
+ int prev;
+ prev = h->type;
+ /* Treat symbols defined by early linker script pass as undefined. */
+ if (h->ldscript_def)
+ prev = bfd_link_hash_undefined;
cycle = FALSE;
- action = link_action[(int) row][(int) h->type];
+ action = link_action[(int) row][prev];
switch (action)
{
case FAIL:
/* We have found a definition for a symbol which was
previously common. */
BFD_ASSERT (h->type == bfd_link_hash_common);
- if (! ((*info->callbacks->multiple_common)
- (info, h, abfd, bfd_link_hash_defined, 0)))
- return FALSE;
+ (*info->callbacks->multiple_common) (info, h, abfd,
+ bfd_link_hash_defined, 0);
/* Fall through. */
case DEF:
case DEFW:
h->u.def.section = section;
h->u.def.value = value;
h->linker_def = 0;
+ h->ldscript_def = 0;
/* If we have been asked to, we act like collect2 and
identify all functions that might be global
&& s[CONS_PREFIX_LEN] == s[CONS_PREFIX_LEN + 2])
{
/* If this is a definition of a symbol which
- was previously weakly defined, we are in
- trouble. We have already added a
- constructor entry for the weak defined
- symbol, and now we are trying to add one
- for the new symbol. Fortunately, this case
- should never arise in practice. */
+ was previously weakly defined, we are in
+ trouble. We have already added a
+ constructor entry for the weak defined
+ symbol, and now we are trying to add one
+ for the new symbol. Fortunately, this case
+ should never arise in practice. */
if (oldtype == bfd_link_hash_defweak)
abort ();
- if (! ((*info->callbacks->constructor)
- (info, c == 'I',
- h->root.string, abfd, section, value)))
- return FALSE;
+ (*info->callbacks->constructor) (info, c == 'I',
+ h->root.string, abfd,
+ section, value);
}
}
}
h->u.c.size = value;
/* Select a default alignment based on the size. This may
- be overridden by the caller. */
+ be overridden by the caller. */
{
unsigned int power;
}
/* The section of a common symbol is only used if the common
- symbol is actually allocated. It basically provides a
- hook for the linker script to decide which output section
- the common symbols should be put in. In most cases, the
- section of a common symbol will be bfd_com_section_ptr,
- the code here will choose a common symbol section named
- "COMMON", and the linker script will contain *(COMMON) in
- the appropriate place. A few targets use separate common
- sections for small symbols, and they require special
- handling. */
+ symbol is actually allocated. It basically provides a
+ hook for the linker script to decide which output section
+ the common symbols should be put in. In most cases, the
+ section of a common symbol will be bfd_com_section_ptr,
+ the code here will choose a common symbol section named
+ "COMMON", and the linker script will contain *(COMMON) in
+ the appropriate place. A few targets use separate common
+ sections for small symbols, and they require special
+ handling. */
if (section == bfd_com_section_ptr)
{
h->u.c.p->section = bfd_make_section_old_way (abfd, "COMMON");
else
h->u.c.p->section = section;
h->linker_def = 0;
+ h->ldscript_def = 0;
break;
case REF:
already had a common definition. Use the maximum of the
two sizes, and use the section required by the larger symbol. */
BFD_ASSERT (h->type == bfd_link_hash_common);
- if (! ((*info->callbacks->multiple_common)
- (info, h, abfd, bfd_link_hash_common, value)))
- return FALSE;
+ (*info->callbacks->multiple_common) (info, h, abfd,
+ bfd_link_hash_common, value);
if (value > h->u.c.size)
{
unsigned int power;
case CREF:
/* We have found a common definition for a symbol which
was already defined. */
- if (! ((*info->callbacks->multiple_common)
- (info, h, abfd, bfd_link_hash_common, value)))
- return FALSE;
+ (*info->callbacks->multiple_common) (info, h, abfd,
+ bfd_link_hash_common, value);
break;
case MIND:
/* Multiple indirect symbols. This is OK if they both point
to the same symbol. */
+ if (h->u.i.link->type == bfd_link_hash_defweak)
+ {
+ /* It is also OK to redefine a symbol that indirects to
+ a weak definition. So for sym@ver -> sym@@ver where
+ sym@@ver is weak and we have a new strong sym@ver,
+ redefine sym@@ver. Of course if there exists
+ sym -> sym@@ver then this also redefines sym. */
+ h = h->u.i.link;
+ cycle = TRUE;
+ break;
+ }
if (strcmp (h->u.i.link->root.string, string) == 0)
break;
/* Fall through. */
case MDEF:
/* Handle a multiple definition. */
- if (! ((*info->callbacks->multiple_definition)
- (info, h, abfd, section, value)))
- return FALSE;
+ (*info->callbacks->multiple_definition) (info, h,
+ abfd, section, value);
break;
case CIND:
/* Create an indirect symbol from an existing common symbol. */
BFD_ASSERT (h->type == bfd_link_hash_common);
- if (! ((*info->callbacks->multiple_common)
- (info, h, abfd, bfd_link_hash_indirect, 0)))
- return FALSE;
+ (*info->callbacks->multiple_common) (info, h, abfd,
+ bfd_link_hash_indirect, 0);
/* Fall through. */
case IND:
if (inh->type == bfd_link_hash_indirect
&& inh->u.i.link == h)
{
- (*_bfd_error_handler)
- (_("%B: indirect symbol `%s' to `%s' is a loop"),
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: indirect symbol `%s' to `%s' is a loop"),
abfd, name, string);
bfd_set_error (bfd_error_invalid_operation);
return FALSE;
case SET:
/* Add an entry to a set. */
- if (! (*info->callbacks->add_to_set) (info, h, BFD_RELOC_CTOR,
- abfd, section, value))
- return FALSE;
+ (*info->callbacks->add_to_set) (info, h, BFD_RELOC_CTOR,
+ abfd, section, value);
break;
case WARNC:
if (h->u.i.warning != NULL
&& (abfd->flags & BFD_PLUGIN) == 0)
{
- if (! (*info->callbacks->warning) (info, h->u.i.warning,
- h->root.string, abfd,
- NULL, 0))
- return FALSE;
+ (*info->callbacks->warning) (info, h->u.i.warning,
+ h->root.string, abfd, NULL, 0);
/* Only issue a warning once. */
h->u.i.warning = NULL;
}
otherwise add a warning. */
if ((!info->lto_plugin_active
&& (h->u.undef.next != NULL || info->hash->undefs_tail == h))
- || h->non_ir_ref)
+ || h->non_ir_ref_regular
+ || h->non_ir_ref_dynamic)
{
- if (! (*info->callbacks->warning) (info, string, h->root.string,
- hash_entry_bfd (h), NULL, 0))
- return FALSE;
+ (*info->callbacks->warning) (info, string, h->root.string,
+ hash_entry_bfd (h), NULL, 0);
break;
}
/* Fall through. */
size_t outsymalloc;
struct generic_write_global_symbol_info wginfo;
- bfd_get_outsymbols (abfd) = NULL;
- bfd_get_symcount (abfd) = 0;
+ abfd->outsymbols = NULL;
+ abfd->symcount = 0;
outsymalloc = 0;
/* Mark all sections which will be included in the output file. */
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)
newsyms = (asymbol **) bfd_realloc (bfd_get_outsymbols (output_bfd), amt);
if (newsyms == NULL)
return FALSE;
- bfd_get_outsymbols (output_bfd) = newsyms;
+ output_bfd->outsymbols = newsyms;
}
- bfd_get_outsymbols (output_bfd) [bfd_get_symcount (output_bfd)] = sym;
+ output_bfd->outsymbols[output_bfd->symcount] = sym;
if (sym != NULL)
- ++ bfd_get_symcount (output_bfd);
+ ++output_bfd->symcount;
return TRUE;
}
newsym = bfd_make_empty_symbol (input_bfd);
if (!newsym)
return FALSE;
- newsym->name = input_bfd->filename;
+ newsym->name = bfd_get_filename (input_bfd);
newsym->value = 0;
newsym->flags = BSF_LOCAL | BSF_FILE;
newsym->section = sec;
| BSF_GLOBAL
| BSF_CONSTRUCTOR
| BSF_WEAK)) != 0
- || bfd_is_und_section (bfd_get_section (sym))
- || bfd_is_com_section (bfd_get_section (sym))
- || bfd_is_ind_section (bfd_get_section (sym)))
+ || bfd_is_und_section (bfd_asymbol_section (sym))
+ || bfd_is_com_section (bfd_asymbol_section (sym))
+ || bfd_is_ind_section (bfd_asymbol_section (sym)))
{
if (sym->udata.p != NULL)
h = (struct generic_link_hash_entry *) sym->udata.p;
else if ((sym->flags & BSF_CONSTRUCTOR) != 0)
{
/* This case normally means that the main linker code
- deliberately ignored this constructor symbol. We
- should just pass it through. This will screw up if
- the constructor symbol is from a different,
- non-generic, object file format, but the case will
- only arise when linking with -r, which will probably
- fail anyhow, since there will be no way to represent
- the relocs in the output format being used. */
+ deliberately ignored this constructor symbol. We
+ should just pass it through. This will screw up if
+ the constructor symbol is from a different,
+ non-generic, object file format, but the case will
+ only arise when linking with -r, which will probably
+ fail anyhow, since there will be no way to represent
+ the relocs in the output format being used. */
h = NULL;
}
- else if (bfd_is_und_section (bfd_get_section (sym)))
+ else if (bfd_is_und_section (bfd_asymbol_section (sym)))
h = ((struct generic_link_hash_entry *)
bfd_wrapped_link_hash_lookup (output_bfd, info,
bfd_asymbol_name (sym),
/* 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;
}
}
- /* This switch is straight from the old code in
- 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) == NULL))
+ if ((sym->flags & BSF_KEEP) == 0
+ && (info->strip == strip_all
+ || (info->strip == strip_some
+ && bfd_hash_lookup (info->keep_hash, bfd_asymbol_name (sym),
+ FALSE, FALSE) == NULL)))
output = FALSE;
- else if ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0)
+ else if ((sym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_GNU_UNIQUE)) != 0)
{
/* If this symbol is marked as occurring now, rather
than at the end, output it now. This is used for
else
output = FALSE;
}
+ else if ((sym->flags & BSF_KEEP) != 0)
+ output = TRUE;
else if (bfd_is_ind_section (sym->section))
output = FALSE;
else if ((sym->flags & BSF_DEBUGGING) != 0)
break;
case discard_sec_merge:
output = TRUE;
- if (info->relocatable
+ if (bfd_link_relocatable (info)
|| ! (sym->section->flags & SEC_MERGE))
break;
/* FALLTHROUGH */
break;
case bfd_link_hash_new:
/* This can happen when a constructor symbol is seen but we are
- not building constructors. */
+ not building constructors. */
if (sym->section != NULL)
{
BFD_ASSERT ((sym->flags & BSF_CONSTRUCTOR) != 0);
{
arelent *r;
- if (! info->relocatable)
+ if (! bfd_link_relocatable (info))
abort ();
if (sec->orelocation == NULL)
abort ();
if (h == NULL
|| ! h->written)
{
- if (! ((*info->callbacks->unattached_reloc)
- (info, link_order->u.reloc.p->u.name, NULL, NULL, 0)))
- return FALSE;
+ (*info->callbacks->unattached_reloc)
+ (info, link_order->u.reloc.p->u.name, NULL, NULL, 0);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
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,
case bfd_reloc_outofrange:
abort ();
case bfd_reloc_overflow:
- if (! ((*info->callbacks->reloc_overflow)
- (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,
- NULL, NULL, 0)))
- {
- free (buf);
- return FALSE;
- }
+ (*info->callbacks->reloc_overflow)
+ (info, NULL,
+ (link_order->type == bfd_section_reloc_link_order
+ ? bfd_section_name (link_order->u.reloc.p->u.section)
+ : link_order->u.reloc.p->u.name),
+ r->howto->name, link_order->u.reloc.p->addend,
+ NULL, NULL, 0);
break;
}
- loc = link_order->offset * bfd_octets_per_byte (abfd);
+ loc = link_order->offset * bfd_octets_per_byte (abfd, sec);
ok = bfd_set_section_contents (abfd, sec, buf, loc, size);
free (buf);
if (! ok)
struct bfd_link_order *
bfd_new_link_order (bfd *abfd, asection *section)
{
- bfd_size_type amt = sizeof (struct bfd_link_order);
+ size_t amt = sizeof (struct bfd_link_order);
struct bfd_link_order *new_lo;
new_lo = (struct bfd_link_order *) bfd_zalloc (abfd, amt);
static bfd_boolean
default_data_link_order (bfd *abfd,
- struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info,
asection *sec,
struct bfd_link_order *link_order)
{
fill_size = link_order->u.data.size;
if (fill_size == 0)
{
- fill = abfd->arch_info->fill (size, bfd_big_endian (abfd),
+ fill = abfd->arch_info->fill (size, info->big_endian,
(sec->flags & SEC_CODE) != 0);
if (fill == NULL)
return FALSE;
}
}
- loc = link_order->offset * bfd_octets_per_byte (abfd);
+ loc = link_order->offset * bfd_octets_per_byte (abfd, sec);
result = bfd_set_section_contents (abfd, sec, fill, loc, size);
if (fill != link_order->u.data.contents)
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)
{
because somebody is attempting to link together different
types of object files. Handling this case correctly is
difficult, and sometimes impossible. */
- (*_bfd_error_handler)
- (_("Attempt to do relocatable link with %s input and %s output"),
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("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;
| BSF_GLOBAL
| BSF_CONSTRUCTOR
| BSF_WEAK)) != 0
- || bfd_is_und_section (bfd_get_section (sym))
- || bfd_is_com_section (bfd_get_section (sym))
- || bfd_is_ind_section (bfd_get_section (sym)))
+ || bfd_is_und_section (bfd_asymbol_section (sym))
+ || bfd_is_com_section (bfd_asymbol_section (sym))
+ || bfd_is_ind_section (bfd_asymbol_section (sym)))
{
/* 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;
- else if (bfd_is_und_section (bfd_get_section (sym)))
+ else if (bfd_is_und_section (bfd_asymbol_section (sym)))
h = bfd_wrapped_link_hash_lookup (output_bfd, info,
bfd_asymbol_name (sym),
FALSE, FALSE, TRUE);
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;
}
/* Output the section contents. */
- loc = input_section->output_offset * bfd_octets_per_byte (output_bfd);
+ loc = (input_section->output_offset
+ * bfd_octets_per_byte (output_bfd, output_section));
if (! bfd_set_section_contents (output_bfd, output_section,
new_contents, loc, input_section->size))
goto error_return;
- if (contents != NULL)
- free (contents);
+ free (contents);
return TRUE;
error_return:
- if (contents != NULL)
- free (contents);
+ free (contents);
return FALSE;
}
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
reloceatable or final link.
.#define bfd_link_split_section(abfd, sec) \
-. BFD_SEND (abfd, _bfd_link_split_section, (abfd, sec))
+. BFD_SEND (abfd, _bfd_link_split_section, (abfd, sec))
.
*/
bfd_section_already_linked
SYNOPSIS
- bfd_boolean bfd_section_already_linked (bfd *abfd,
+ bfd_boolean bfd_section_already_linked (bfd *abfd,
asection *sec,
struct bfd_link_info *info);
or final link. Return TRUE if it has.
.#define bfd_section_already_linked(abfd, sec, info) \
-. BFD_SEND (abfd, _section_already_linked, (abfd, sec, info))
+. BFD_SEND (abfd, _section_already_linked, (abfd, sec, info))
.
*/
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;
case SEC_LINK_DUPLICATES_ONE_ONLY:
info->callbacks->einfo
- (_("%B: ignoring duplicate section `%A'\n"),
+ /* xgettext:c-format */
+ (_("%pB: ignoring duplicate section `%pA'\n"),
sec->owner, sec);
break;
;
else if (sec->size != l->sec->size)
info->callbacks->einfo
- (_("%B: duplicate section `%A' has different size\n"),
+ /* xgettext:c-format */
+ (_("%pB: duplicate section `%pA' has different size\n"),
sec->owner, sec);
break;
;
else if (sec->size != l->sec->size)
info->callbacks->einfo
- (_("%B: duplicate section `%A' has different size\n"),
+ /* xgettext:c-format */
+ (_("%pB: duplicate section `%pA' has different size\n"),
sec->owner, sec);
else if (sec->size != 0)
{
if (!bfd_malloc_and_get_section (sec->owner, sec, &sec_contents))
info->callbacks->einfo
- (_("%B: could not read contents of section `%A'\n"),
+ /* xgettext:c-format */
+ (_("%pB: could not read contents of section `%pA'\n"),
sec->owner, sec);
else if (!bfd_malloc_and_get_section (l->sec->owner, l->sec,
&l_sec_contents))
info->callbacks->einfo
- (_("%B: could not read contents of section `%A'\n"),
+ /* xgettext:c-format */
+ (_("%pB: could not read contents of section `%pA'\n"),
l->sec->owner, l->sec);
else if (memcmp (sec_contents, l_sec_contents, sec->size) != 0)
info->callbacks->einfo
- (_("%B: duplicate section `%A' has different contents\n"),
+ /* xgettext:c-format */
+ (_("%pB: duplicate section `%pA' has different contents\n"),
sec->owner, sec);
- if (sec_contents)
- free (sec_contents);
- if (l_sec_contents)
- free (l_sec_contents);
+ free (sec_contents);
+ free (l_sec_contents);
}
break;
}
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);
+ name = bfd_section_name (sec);
already_linked_list = bfd_section_already_linked_table_lookup (name);
Return TRUE on success and FALSE on failure.
.#define bfd_define_common_symbol(output_bfd, info, h) \
-. BFD_SEND (output_bfd, _bfd_define_common_symbol, (output_bfd, info, h))
+. BFD_SEND (output_bfd, _bfd_define_common_symbol, (output_bfd, info, h))
.
*/
section = h->u.c.p->section;
/* Increase the size of the section to align the common symbol.
- The alignment must be a power of two. */
- alignment = bfd_octets_per_byte (output_bfd) << power_of_two;
+ The alignment must be a power of two. But if the section does
+ not have any alignment requirement then do not increase the
+ alignment unnecessarily. */
+ if (power_of_two)
+ alignment = bfd_octets_per_byte (output_bfd, section) << power_of_two;
+ else
+ alignment = 1;
BFD_ASSERT (alignment != 0 && (alignment & -alignment) == alignment);
section->size += alignment - 1;
section->size &= -alignment;
/* Make sure the section is allocated in memory, and make sure that
it is no longer a common section. */
section->flags |= SEC_ALLOC;
- section->flags &= ~SEC_IS_COMMON;
+ section->flags &= ~(SEC_IS_COMMON | SEC_HAS_CONTENTS);
return TRUE;
}
+/*
+FUNCTION
+ _bfd_generic_link_hide_symbol
+
+SYNOPSIS
+ void _bfd_generic_link_hide_symbol
+ (bfd *output_bfd, struct bfd_link_info *info,
+ struct bfd_link_hash_entry *h);
+
+DESCRIPTION
+ Hide symbol @var{h}.
+ This is an internal function. It should not be called from
+ outside the BFD library.
+
+.#define bfd_link_hide_symbol(output_bfd, info, h) \
+. BFD_SEND (output_bfd, _bfd_link_hide_symbol, (output_bfd, info, h))
+.
+*/
+
+void
+_bfd_generic_link_hide_symbol (bfd *output_bfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ struct bfd_link_hash_entry *h ATTRIBUTE_UNUSED)
+{
+}
+
+/*
+FUNCTION
+ bfd_generic_define_start_stop
+
+SYNOPSIS
+ struct bfd_link_hash_entry *bfd_generic_define_start_stop
+ (struct bfd_link_info *info,
+ const char *symbol, asection *sec);
+
+DESCRIPTION
+ Define a __start, __stop, .startof. or .sizeof. symbol.
+ Return the symbol or NULL if no such undefined symbol exists.
+
+.#define bfd_define_start_stop(output_bfd, info, symbol, sec) \
+. BFD_SEND (output_bfd, _bfd_define_start_stop, (info, symbol, sec))
+.
+*/
+
+struct bfd_link_hash_entry *
+bfd_generic_define_start_stop (struct bfd_link_info *info,
+ const char *symbol, asection *sec)
+{
+ struct bfd_link_hash_entry *h;
+
+ h = bfd_link_hash_lookup (info->hash, symbol, FALSE, FALSE, TRUE);
+ if (h != NULL
+ && (h->type == bfd_link_hash_undefined
+ || h->type == bfd_link_hash_undefweak))
+ {
+ h->type = bfd_link_hash_defined;
+ h->u.def.section = sec;
+ h->u.def.value = 0;
+ return h;
+ }
+ return NULL;
+}
+
/*
FUNCTION
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;
+}
+
+/*
+FUNCTION
+ bfd_merge_private_bfd_data
+
+SYNOPSIS
+ bfd_boolean bfd_merge_private_bfd_data
+ (bfd *ibfd, struct bfd_link_info *info);
+
+DESCRIPTION
+ Merge private BFD information from the BFD @var{ibfd} to the
+ the output file BFD when linking. Return <<TRUE>> on success,
+ <<FALSE>> on error. Possible error returns are:
+
+ o <<bfd_error_no_memory>> -
+ Not enough memory exists to create private data for @var{obfd}.
+
+.#define bfd_merge_private_bfd_data(ibfd, info) \
+. BFD_SEND ((info)->output_bfd, _bfd_merge_private_bfd_data, \
+. (ibfd, info))
+*/
+
+/*
+INTERNAL_FUNCTION
+ _bfd_generic_verify_endian_match
+
+SYNOPSIS
+ bfd_boolean _bfd_generic_verify_endian_match
+ (bfd *ibfd, struct bfd_link_info *info);
+
+DESCRIPTION
+ Can be used from / for bfd_merge_private_bfd_data to check that
+ endianness matches between input and output file. Returns
+ TRUE for a match, otherwise returns FALSE and emits an error.
+*/
+
+bfd_boolean
+_bfd_generic_verify_endian_match (bfd *ibfd, struct bfd_link_info *info)
+{
+ bfd *obfd = info->output_bfd;
+
+ if (ibfd->xvec->byteorder != obfd->xvec->byteorder
+ && ibfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN
+ && obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN)
+ {
+ if (bfd_big_endian (ibfd))
+ _bfd_error_handler (_("%pB: compiled for a big endian system "
+ "and target is little endian"), ibfd);
+ else
+ _bfd_error_handler (_("%pB: compiled for a little endian system "
+ "and target is big endian"), ibfd);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+int
+_bfd_nolink_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+bfd_boolean
+_bfd_nolink_bfd_relax_section (bfd *abfd,
+ asection *section ATTRIBUTE_UNUSED,
+ struct bfd_link_info *link_info ATTRIBUTE_UNUSED,
+ bfd_boolean *again ATTRIBUTE_UNUSED)
+{
+ return _bfd_bool_bfd_false_error (abfd);
+}
+
+bfd_byte *
+_bfd_nolink_bfd_get_relocated_section_contents
+ (bfd *abfd,
+ struct bfd_link_info *link_info ATTRIBUTE_UNUSED,
+ struct bfd_link_order *link_order ATTRIBUTE_UNUSED,
+ bfd_byte *data ATTRIBUTE_UNUSED,
+ bfd_boolean relocatable ATTRIBUTE_UNUSED,
+ asymbol **symbols ATTRIBUTE_UNUSED)
+{
+ return (bfd_byte *) _bfd_ptr_bfd_null_error (abfd);
+}
+
+bfd_boolean
+_bfd_nolink_bfd_lookup_section_flags
+ (struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ struct flag_info *flaginfo ATTRIBUTE_UNUSED,
+ asection *section)
+{
+ return _bfd_bool_bfd_false_error (section->owner);
+}
+
+bfd_boolean
+_bfd_nolink_bfd_is_group_section (bfd *abfd,
+ const asection *sec ATTRIBUTE_UNUSED)
+{
+ return _bfd_bool_bfd_false_error (abfd);
+}
+
+const char *
+_bfd_nolink_bfd_group_name (bfd *abfd,
+ const asection *sec ATTRIBUTE_UNUSED)
+{
+ return _bfd_ptr_bfd_null_error (abfd);
+}
+
+bfd_boolean
+_bfd_nolink_bfd_discard_group (bfd *abfd, asection *sec ATTRIBUTE_UNUSED)
+{
+ return _bfd_bool_bfd_false_error (abfd);
+}
+
+struct bfd_link_hash_table *
+_bfd_nolink_bfd_link_hash_table_create (bfd *abfd)
+{
+ return (struct bfd_link_hash_table *) _bfd_ptr_bfd_null_error (abfd);
+}
+
+void
+_bfd_nolink_bfd_link_just_syms (asection *sec ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED)
+{
+}
+
+void
+_bfd_nolink_bfd_copy_link_hash_symbol_type
+ (bfd *abfd ATTRIBUTE_UNUSED,
+ struct bfd_link_hash_entry *from ATTRIBUTE_UNUSED,
+ struct bfd_link_hash_entry *to ATTRIBUTE_UNUSED)
+{
+}
+
+bfd_boolean
+_bfd_nolink_bfd_link_split_section (bfd *abfd, asection *sec ATTRIBUTE_UNUSED)
+{
+ return _bfd_bool_bfd_false_error (abfd);
+}
+
+bfd_boolean
+_bfd_nolink_section_already_linked (bfd *abfd,
+ asection *sec ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED)
+{
+ return _bfd_bool_bfd_false_error (abfd);
+}
+
+bfd_boolean
+_bfd_nolink_bfd_define_common_symbol
+ (bfd *abfd,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ struct bfd_link_hash_entry *h ATTRIBUTE_UNUSED)
+{
+ return _bfd_bool_bfd_false_error (abfd);
+}
+
+struct bfd_link_hash_entry *
+_bfd_nolink_bfd_define_start_stop (struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ const char *name ATTRIBUTE_UNUSED,
+ asection *sec)
+{
+ return (struct bfd_link_hash_entry *) _bfd_ptr_bfd_null_error (sec->owner);
+}