/* linker.c -- BFD linker routines
- Copyright (C) 1993-2015 Free Software Foundation, Inc.
+ Copyright (C) 1993-2017 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
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
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;
bh = NULL;
if (! (_bfd_generic_link_add_one_symbol
(info, abfd, name, p->flags, bfd_get_section (p),
- p->value, string, FALSE, collect, &bh)))
+ p->value, string, FALSE, FALSE, &bh)))
return FALSE;
h = (struct generic_link_hash_entry *) bh;
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)
+ && strcmp (name, "__gnu_lto_slim") == 0)
+ _bfd_error_handler
+ (_("%B: plugin needed to handle lto object"), abfd);
}
else
row = DEF_ROW;
/* 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:
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);
}
}
}
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:
/* 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)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: indirect symbol `%s' to `%s' is a loop"),
abfd, name, string);
bfd_set_error (bfd_error_invalid_operation);
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. */
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)
&& 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
break;
case discard_sec_merge:
output = TRUE;
- if (info->relocatable
+ if (bfd_link_relocatable (info)
|| ! (sym->section->flags & SEC_MERGE))
break;
/* FALLTHROUGH */
{
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;
}
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 (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);
break;
}
loc = link_order->offset * bfd_octets_per_byte (abfd);
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)
+ _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);
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;
case SEC_LINK_DUPLICATES_ONE_ONLY:
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%B: ignoring duplicate section `%A'\n"),
sec->owner, sec);
break;
;
else if (sec->size != l->sec->size)
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%B: duplicate section `%A' has different size\n"),
sec->owner, sec);
break;
;
else if (sec->size != l->sec->size)
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%B: duplicate section `%A' 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
+ /* xgettext:c-format */
(_("%B: could not read contents of section `%A'\n"),
sec->owner, sec);
else if (!bfd_malloc_and_get_section (l->sec->owner, l->sec,
&l_sec_contents))
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%B: could not read contents of section `%A'\n"),
l->sec->owner, l->sec);
else if (memcmp (sec_contents, l_sec_contents, sec->size) != 0)
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%B: duplicate section `%A' has different contents\n"),
sec->owner, sec);
return TRUE;
}
+/*
+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 (_("%B: compiled for a big endian system "
+ "and target is little endian"), ibfd);
+ else
+ _bfd_error_handler (_("%B: compiled for a little endian system "
+ "and target is big endian"), ibfd);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ return TRUE;
+}