This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
-#include "bfd.h"
#include "sysdep.h"
+#include "bfd.h"
#include "bfdlink.h"
#include "libbfd.h"
#define ARCH_SIZE 0
bfd_boolean provide,
bfd_boolean hidden)
{
- struct elf_link_hash_entry *h;
+ struct elf_link_hash_entry *h, *hv;
struct elf_link_hash_table *htab;
+ const struct elf_backend_data *bed;
if (!is_elf_hash_table (info->hash))
return TRUE;
if (h == NULL)
return provide;
- /* Since we're defining the symbol, don't let it seem to have not
- been defined. record_dynamic_symbol and size_dynamic_sections
- may depend on this. */
- if (h->root.type == bfd_link_hash_undefweak
- || h->root.type == bfd_link_hash_undefined)
+ switch (h->root.type)
{
+ case bfd_link_hash_defined:
+ case bfd_link_hash_defweak:
+ case bfd_link_hash_common:
+ break;
+ case bfd_link_hash_undefweak:
+ case bfd_link_hash_undefined:
+ /* Since we're defining the symbol, don't let it seem to have not
+ been defined. record_dynamic_symbol and size_dynamic_sections
+ may depend on this. */
h->root.type = bfd_link_hash_new;
if (h->root.u.undef.next != NULL || htab->root.undefs_tail == &h->root)
bfd_link_repair_undef_list (&htab->root);
- }
-
- if (h->root.type == bfd_link_hash_new)
- {
+ break;
+ case bfd_link_hash_new:
bfd_elf_link_mark_dynamic_symbol (info, h, NULL);
h->non_elf = 0;
+ break;
+ case bfd_link_hash_indirect:
+ /* We had a versioned symbol in a dynamic library. We make the
+ the versioned symbol point to this one. */
+ bed = get_elf_backend_data (output_bfd);
+ hv = h;
+ while (hv->root.type == bfd_link_hash_indirect
+ || hv->root.type == bfd_link_hash_warning)
+ hv = (struct elf_link_hash_entry *) hv->root.u.i.link;
+ /* We don't need to update h->root.u since linker will set them
+ later. */
+ h->root.type = bfd_link_hash_undefined;
+ hv->root.type = bfd_link_hash_indirect;
+ hv->root.u.i.link = (struct bfd_link_hash_entry *) h;
+ (*bed->elf_backend_copy_indirect_symbol) (info, h, hv);
+ break;
+ case bfd_link_hash_warning:
+ abort ();
+ break;
}
/* If this symbol is being provided by the linker script, and it is
&& h->root.type != bfd_link_hash_undefweak
&& h->root.type != bfd_link_hash_common);
+ bed = get_elf_backend_data (abfd);
/* When we try to create a default indirect symbol from the dynamic
definition with the default version, we skip it if its type and
the type of existing regular definition mismatch. We only do it
&& (olddef || h->root.type == bfd_link_hash_common)
&& ELF_ST_TYPE (sym->st_info) != h->type
&& ELF_ST_TYPE (sym->st_info) != STT_NOTYPE
- && h->type != STT_NOTYPE)
+ && h->type != STT_NOTYPE
+ && !(bed->is_function_type (ELF_ST_TYPE (sym->st_info))
+ && bed->is_function_type (h->type)))
{
*skip = TRUE;
return TRUE;
if (olddef && newdyn)
oldweak = FALSE;
+ /* Allow changes between different types of funciton symbol. */
+ if (bed->is_function_type (ELF_ST_TYPE (sym->st_info))
+ && bed->is_function_type (h->type))
+ *type_change_ok = TRUE;
+
/* It's OK to change the type if either the existing symbol or the
new symbol is weak. A type change is also OK if the old symbol
is undefined and the new symbol is defined. */
&& (sec->flags & SEC_ALLOC) != 0
&& (sec->flags & SEC_LOAD) == 0
&& sym->st_size > 0
- && ELF_ST_TYPE (sym->st_info) != STT_FUNC)
+ && !bed->is_function_type (ELF_ST_TYPE (sym->st_info)))
newdyncommon = TRUE;
else
newdyncommon = FALSE;
&& (h->root.u.def.section->flags & SEC_ALLOC) != 0
&& (h->root.u.def.section->flags & SEC_LOAD) == 0
&& h->size > 0
- && h->type != STT_FUNC)
+ && !bed->is_function_type (h->type))
olddyncommon = TRUE;
else
olddyncommon = FALSE;
/* We now know everything about the old and new symbols. We ask the
backend to check if we can merge them. */
- bed = get_elf_backend_data (abfd);
if (bed->merge_symbol
&& !bed->merge_symbol (info, sym_hash, h, sym, psec, pvalue,
pold_alignment, skip, override,
&& (olddef
|| (h->root.type == bfd_link_hash_common
&& (newweak
- || ELF_ST_TYPE (sym->st_info) == STT_FUNC))))
+ || bed->is_function_type (ELF_ST_TYPE (sym->st_info))))))
{
*override = TRUE;
newdef = FALSE;
&& (newdef
|| (bfd_is_com_section (sec)
&& (oldweak
- || h->type == STT_FUNC)))
+ || bed->is_function_type (h->type))))
&& olddyn
&& olddef
&& h->def_dynamic)
case, we make the versioned symbol point to the normal one. */
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
flip->root.type = h->root.type;
+ flip->root.u.undef.abfd = h->root.u.undef.abfd;
h->root.type = bfd_link_hash_indirect;
h->root.u.i.link = (struct bfd_link_hash_entry *) flip;
(*bed->elf_backend_copy_indirect_symbol) (info, flip, h);
- flip->root.u.undef.abfd = h->root.u.undef.abfd;
if (h->def_dynamic)
{
h->def_dynamic = 0;
hi = h;
}
+ /* Check if HI is a warning symbol. */
+ if (hi->root.type == bfd_link_hash_warning)
+ hi = (struct elf_link_hash_entry *) hi->root.u.i.link;
+
/* If there is a duplicate definition somewhere, then HI may not
point to an indirect symbol. We will have reported an error to
the user in that case. */
/* We could not find the version for a symbol when
generating a shared archive. Return an error. */
(*_bfd_error_handler)
- (_("%B: undefined versioned symbol name %s"),
+ (_("%B: version node not found for symbol %s"),
sinfo->output_bfd, h->root.root.string);
bfd_set_error (bfd_error_bad_value);
sinfo->failed = TRUE;
_bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h,
struct elf_info_failed *eif)
{
- const struct elf_backend_data *bed = NULL;
+ const struct elf_backend_data *bed;
/* If this symbol was mentioned in a non-ELF file, try to set
DEF_REGULAR and REF_REGULAR correctly. This is the only way to
}
/* Backend specific symbol fixup. */
- if (elf_hash_table (eif->info)->dynobj)
- {
- bed = get_elf_backend_data (elf_hash_table (eif->info)->dynobj);
- if (bed->elf_backend_fixup_symbol
- && !(*bed->elf_backend_fixup_symbol) (eif->info, h))
- return FALSE;
- }
+ bed = get_elf_backend_data (elf_hash_table (eif->info)->dynobj);
+ if (bed->elf_backend_fixup_symbol
+ && !(*bed->elf_backend_fixup_symbol) (eif->info, h))
+ return FALSE;
/* If this is a final link, and the symbol was defined as a common
symbol in a regular object file, and there was no definition in
hide it from the dynamic linker. */
if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
&& h->root.type == bfd_link_hash_undefweak)
- {
- const struct elf_backend_data *bed;
- bed = get_elf_backend_data (elf_hash_table (eif->info)->dynobj);
- (*bed->elf_backend_hide_symbol) (eif->info, h, TRUE);
- }
+ (*bed->elf_backend_hide_symbol) (eif->info, h, TRUE);
/* If this is a weak defined symbol in a dynamic object, and we know
the real definition in the dynamic object, copy interesting flags
BFD_ASSERT (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak);
- BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined
- || weakdef->root.type == bfd_link_hash_defweak);
BFD_ASSERT (weakdef->def_dynamic);
/* If the real definition is defined by a regular object file,
if (weakdef->def_regular)
h->u.weakdef = NULL;
else
- (*bed->elf_backend_copy_indirect_symbol) (eif->info, weakdef,
- h);
+ {
+ BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined
+ || weakdef->root.type == bfd_link_hash_defweak);
+ (*bed->elf_backend_copy_indirect_symbol) (eif->info, weakdef, h);
+ }
}
return TRUE;
return TRUE;
}
+/* Adjust the dynamic symbol, H, for copy in the dynamic bss section,
+ DYNBSS. */
+
+bfd_boolean
+_bfd_elf_adjust_dynamic_copy (struct elf_link_hash_entry *h,
+ asection *dynbss)
+{
+ unsigned int power_of_two;
+ bfd_vma mask;
+ asection *sec = h->root.u.def.section;
+
+ /* The section aligment of definition is the maximum alignment
+ requirement of symbols defined in the section. Since we don't
+ know the symbol alignment requirement, we start with the
+ maximum alignment and check low bits of the symbol address
+ for the minimum alignment. */
+ power_of_two = bfd_get_section_alignment (sec->owner, sec);
+ mask = ((bfd_vma) 1 << power_of_two) - 1;
+ while ((h->root.u.def.value & mask) != 0)
+ {
+ mask >>= 1;
+ --power_of_two;
+ }
+
+ if (power_of_two > bfd_get_section_alignment (dynbss->owner,
+ dynbss))
+ {
+ /* Adjust the section alignment if needed. */
+ if (! bfd_set_section_alignment (dynbss->owner, dynbss,
+ power_of_two))
+ return FALSE;
+ }
+
+ /* We make sure that the symbol will be aligned properly. */
+ dynbss->size = BFD_ALIGN (dynbss->size, mask + 1);
+
+ /* Define the symbol as being at this point in DYNBSS. */
+ h->root.u.def.section = dynbss;
+ h->root.u.def.value = dynbss->size;
+
+ /* Increment the size of DYNBSS to make room for the symbol. */
+ dynbss->size += h->size;
+
+ return TRUE;
+}
+
/* Adjust all external symbols pointing into SEC_MERGE sections
to reflect the object merging within the sections. */
bfd_boolean ignore_protected)
{
bfd_boolean binding_stays_local_p;
+ const struct elf_backend_data *bed;
+ struct elf_link_hash_table *hash_table;
if (h == NULL)
return FALSE;
return FALSE;
case STV_PROTECTED:
+ hash_table = elf_hash_table (info);
+ if (!is_elf_hash_table (hash_table))
+ return FALSE;
+
+ bed = get_elf_backend_data (hash_table->dynobj);
+
/* Proper resolution for function pointer equality may require
that these symbols perhaps be resolved dynamically, even though
we should be resolving them to the current module. */
- if (!ignore_protected || h->type != STT_FUNC)
+ if (!ignore_protected || !bed->is_function_type (h->type))
binding_stays_local_p = TRUE;
break;
struct bfd_link_info *info,
bfd_boolean local_protected)
{
+ const struct elf_backend_data *bed;
+ struct elf_link_hash_table *hash_table;
+
/* If it's a local sym, of course we resolve locally. */
if (h == NULL)
return TRUE;
if (ELF_ST_VISIBILITY (h->other) != STV_PROTECTED)
return TRUE;
+ hash_table = elf_hash_table (info);
+ if (!is_elf_hash_table (hash_table))
+ return TRUE;
+
+ bed = get_elf_backend_data (hash_table->dynobj);
+
/* STV_PROTECTED non-function symbols are local. */
- if (h->type != STT_FUNC)
+ if (!bed->is_function_type (h->type))
return TRUE;
/* Function pointer equality tests may require that STV_PROTECTED
&& ELF_ST_BIND (sym->st_info) < STB_LOOS)
return FALSE;
+ bed = get_elf_backend_data (abfd);
/* Function symbols do not count. */
- if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
+ if (bed->is_function_type (ELF_ST_TYPE (sym->st_info)))
return FALSE;
/* If the section is undefined, then so is the symbol. */
/* If the symbol is defined in the common section, then
it is a common definition and so does not count. */
- bed = get_elf_backend_data (abfd);
if (bed->common_definition (sym))
return FALSE;
tell it that we are about to handle an as-needed lib. */
if (!(*info->callbacks->notice) (info, NULL, abfd, NULL,
notice_as_needed))
- return FALSE;
-
+ goto error_free_vers;
/* Clone the symbol table and sym hashes. Remember some
pointers into the symbol table, and dynamic symbol count. */
if it is not a function, because it might be the version
symbol itself. FIXME: What if it isn't? */
if ((iver.vs_vers & VERSYM_HIDDEN) != 0
- || (vernum > 1 && (! bfd_is_abs_section (sec)
- || ELF_ST_TYPE (isym->st_info) == STT_FUNC)))
+ || (vernum > 1
+ && (!bfd_is_abs_section (sec)
+ || bed->is_function_type (ELF_ST_TYPE (isym->st_info)))))
{
const char *verstr;
size_t namelen, verlen, newlen;
if (dynamic
&& definition
&& (flags & BSF_WEAK) != 0
- && ELF_ST_TYPE (isym->st_info) != STT_FUNC
+ && !bed->is_function_type (ELF_ST_TYPE (isym->st_info))
&& is_elf_hash_table (htab)
&& h->u.weakdef == NULL)
{
to be the size of the common symbol. The code just above
won't fix the size if a common symbol becomes larger. We
don't warn about a size change here, because that is
- covered by --warn-common. */
+ covered by --warn-common. Allow changed between different
+ function types. */
if (h->root.type == bfd_link_hash_common)
h->size = h->root.u.c.size;
tell it that symbols added for crefs may need to be removed. */
if (!(*info->callbacks->notice) (info, NULL, abfd, NULL,
notice_not_needed))
- return FALSE;
+ goto error_free_vers;
free (old_tab);
objalloc_free_block ((struct objalloc *) htab->root.table.memory,
{
if (!(*info->callbacks->notice) (info, NULL, abfd, NULL,
notice_needed))
- return FALSE;
+ goto error_free_vers;
free (old_tab);
old_tab = NULL;
}
h = *hpp;
if (h != NULL
&& h->root.type == bfd_link_hash_defined
- && h->type != STT_FUNC)
+ && !bed->is_function_type (h->type))
{
*sym_hash = h;
sym_hash++;
if (!is_elf_hash_table (info->hash))
return TRUE;
+ bed = get_elf_backend_data (output_bfd);
elf_tdata (output_bfd)->relro = info->relro;
if (info->execstack)
elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | PF_X;
exec = PF_X;
notesec = s;
}
- else
+ else if (bed->default_execstack)
exec = PF_X;
}
if (notesec)
/* The backend may have to create some sections regardless of whether
we're dynamic or not. */
- bed = get_elf_backend_data (output_bfd);
if (bed->elf_backend_always_size_sections
&& ! (*bed->elf_backend_always_size_sections) (output_bfd, info))
return FALSE;
for (sub = info->input_bfds; sub != NULL;
sub = sub->link_next)
- for (o = sub->sections; o != NULL; o = o->next)
- if (elf_section_data (o)->this_hdr.sh_type
- == SHT_PREINIT_ARRAY)
- {
- (*_bfd_error_handler)
- (_("%B: .preinit_array section is not allowed in DSO"),
- sub);
- break;
- }
+ if (bfd_get_flavour (sub) == bfd_target_elf_flavour)
+ for (o = sub->sections; o != NULL; o = o->next)
+ if (elf_section_data (o)->this_hdr.sh_type
+ == SHT_PREINIT_ARRAY)
+ {
+ (*_bfd_error_handler)
+ (_("%B: .preinit_array section is not allowed in DSO"),
+ sub);
+ break;
+ }
bfd_set_error (bfd_error_nonrepresentable_section);
return FALSE;
return TRUE;
}
+\f
+/* Indicate that we are only retrieving symbol values from this
+ section. */
+
+void
+_bfd_elf_link_just_syms (asection *sec, struct bfd_link_info *info)
+{
+ if (is_elf_hash_table (info->hash))
+ sec->sec_info_type = ELF_INFO_TYPE_JUST_SYMS;
+ _bfd_generic_link_just_syms (sec, info);
+}
+
+/* Make sure sec_info_type is cleared if sec_info is cleared too. */
+
+static void
+merge_sections_remove_hook (bfd *abfd ATTRIBUTE_UNUSED,
+ asection *sec)
+{
+ BFD_ASSERT (sec->sec_info_type == ELF_INFO_TYPE_MERGE);
+ sec->sec_info_type = ELF_INFO_TYPE_NONE;
+}
+
+/* Finish SHF_MERGE section merging. */
+
+bfd_boolean
+_bfd_elf_merge_sections (bfd *abfd, struct bfd_link_info *info)
+{
+ bfd *ibfd;
+ asection *sec;
+
+ if (!is_elf_hash_table (info->hash))
+ return FALSE;
+
+ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+ if ((ibfd->flags & DYNAMIC) == 0)
+ for (sec = ibfd->sections; sec != NULL; sec = sec->next)
+ if ((sec->flags & SEC_MERGE) != 0
+ && !bfd_is_abs_section (sec->output_section))
+ {
+ struct bfd_elf_section_data *secdata;
+
+ secdata = elf_section_data (sec);
+ if (! _bfd_add_merge_section (abfd,
+ &elf_hash_table (info)->merge_info,
+ sec, &secdata->sec_info))
+ return FALSE;
+ else if (secdata->sec_info)
+ sec->sec_info_type = ELF_INFO_TYPE_MERGE;
+ }
+
+ if (elf_hash_table (info)->merge_info != NULL)
+ _bfd_merge_sections (abfd, info, elf_hash_table (info)->merge_info,
+ merge_sections_remove_hook);
+ return TRUE;
+}
+
+/* Create an entry in an ELF linker hash table. */
+
+struct bfd_hash_entry *
+_bfd_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
+ struct bfd_hash_table *table,
+ const char *string)
+{
+ /* Allocate the structure if it has not already been allocated by a
+ subclass. */
+ if (entry == NULL)
+ {
+ entry = bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry));
+ if (entry == NULL)
+ return entry;
+ }
+
+ /* Call the allocation method of the superclass. */
+ entry = _bfd_link_hash_newfunc (entry, table, string);
+ if (entry != NULL)
+ {
+ struct elf_link_hash_entry *ret = (struct elf_link_hash_entry *) entry;
+ struct elf_link_hash_table *htab = (struct elf_link_hash_table *) table;
+
+ /* Set local fields. */
+ ret->indx = -1;
+ ret->dynindx = -1;
+ ret->got = htab->init_got_refcount;
+ ret->plt = htab->init_plt_refcount;
+ memset (&ret->size, 0, (sizeof (struct elf_link_hash_entry)
+ - offsetof (struct elf_link_hash_entry, size)));
+ /* Assume that we have been called by a non-ELF symbol reader.
+ This flag is then reset by the code which reads an ELF input
+ file. This ensures that a symbol created by a non-ELF symbol
+ reader will have the flag set correctly. */
+ ret->non_elf = 1;
+ }
+
+ return entry;
+}
+
+/* Copy data from an indirect symbol to its direct symbol, hiding the
+ old indirect symbol. Also used for copying flags to a weakdef. */
+
+void
+_bfd_elf_link_hash_copy_indirect (struct bfd_link_info *info,
+ struct elf_link_hash_entry *dir,
+ struct elf_link_hash_entry *ind)
+{
+ struct elf_link_hash_table *htab;
+
+ /* Copy down any references that we may have already seen to the
+ symbol which just became indirect. */
+
+ dir->ref_dynamic |= ind->ref_dynamic;
+ dir->ref_regular |= ind->ref_regular;
+ dir->ref_regular_nonweak |= ind->ref_regular_nonweak;
+ dir->non_got_ref |= ind->non_got_ref;
+ dir->needs_plt |= ind->needs_plt;
+ dir->pointer_equality_needed |= ind->pointer_equality_needed;
+
+ if (ind->root.type != bfd_link_hash_indirect)
+ return;
+
+ /* Copy over the global and procedure linkage table refcount entries.
+ These may have been already set up by a check_relocs routine. */
+ htab = elf_hash_table (info);
+ if (ind->got.refcount > htab->init_got_refcount.refcount)
+ {
+ if (dir->got.refcount < 0)
+ dir->got.refcount = 0;
+ dir->got.refcount += ind->got.refcount;
+ ind->got.refcount = htab->init_got_refcount.refcount;
+ }
+
+ if (ind->plt.refcount > htab->init_plt_refcount.refcount)
+ {
+ if (dir->plt.refcount < 0)
+ dir->plt.refcount = 0;
+ dir->plt.refcount += ind->plt.refcount;
+ ind->plt.refcount = htab->init_plt_refcount.refcount;
+ }
+
+ if (ind->dynindx != -1)
+ {
+ if (dir->dynindx != -1)
+ _bfd_elf_strtab_delref (htab->dynstr, dir->dynstr_index);
+ dir->dynindx = ind->dynindx;
+ dir->dynstr_index = ind->dynstr_index;
+ ind->dynindx = -1;
+ ind->dynstr_index = 0;
+ }
+}
+
+void
+_bfd_elf_link_hash_hide_symbol (struct bfd_link_info *info,
+ struct elf_link_hash_entry *h,
+ bfd_boolean force_local)
+{
+ h->plt = elf_hash_table (info)->init_plt_offset;
+ h->needs_plt = 0;
+ if (force_local)
+ {
+ h->forced_local = 1;
+ if (h->dynindx != -1)
+ {
+ h->dynindx = -1;
+ _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+ h->dynstr_index);
+ }
+ }
+}
+
+/* Initialize an ELF linker hash table. */
+bfd_boolean
+_bfd_elf_link_hash_table_init
+ (struct elf_link_hash_table *table,
+ bfd *abfd,
+ struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *,
+ struct bfd_hash_table *,
+ const char *),
+ unsigned int entsize)
+{
+ bfd_boolean ret;
+ int can_refcount = get_elf_backend_data (abfd)->can_refcount;
+
+ memset (table, 0, sizeof * table);
+ table->init_got_refcount.refcount = can_refcount - 1;
+ table->init_plt_refcount.refcount = can_refcount - 1;
+ table->init_got_offset.offset = -(bfd_vma) 1;
+ table->init_plt_offset.offset = -(bfd_vma) 1;
+ /* The first dynamic symbol is a dummy. */
+ table->dynsymcount = 1;
+
+ ret = _bfd_link_hash_table_init (&table->root, abfd, newfunc, entsize);
+ table->root.type = bfd_link_elf_hash_table;
+
+ return ret;
+}
+
+/* Create an ELF linker hash table. */
+
+struct bfd_link_hash_table *
+_bfd_elf_link_hash_table_create (bfd *abfd)
+{
+ struct elf_link_hash_table *ret;
+ bfd_size_type amt = sizeof (struct elf_link_hash_table);
+
+ ret = bfd_malloc (amt);
+ if (ret == NULL)
+ return NULL;
+
+ if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc,
+ sizeof (struct elf_link_hash_entry)))
+ {
+ free (ret);
+ return NULL;
+ }
+
+ return &ret->root;
+}
+
+/* This is a hook for the ELF emulation code in the generic linker to
+ tell the backend linker what file name to use for the DT_NEEDED
+ entry for a dynamic object. */
+
+void
+bfd_elf_set_dt_needed_name (bfd *abfd, const char *name)
+{
+ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+ && bfd_get_format (abfd) == bfd_object)
+ elf_dt_name (abfd) = name;
+}
+
+int
+bfd_elf_get_dyn_lib_class (bfd *abfd)
+{
+ int lib_class;
+ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+ && bfd_get_format (abfd) == bfd_object)
+ lib_class = elf_dyn_lib_class (abfd);
+ else
+ lib_class = 0;
+ return lib_class;
+}
+
+void
+bfd_elf_set_dyn_lib_class (bfd *abfd, enum dynamic_lib_link_class lib_class)
+{
+ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+ && bfd_get_format (abfd) == bfd_object)
+ elf_dyn_lib_class (abfd) = lib_class;
+}
+
+/* Get the list of DT_NEEDED entries for a link. This is a hook for
+ the linker ELF emulation code. */
+
+struct bfd_link_needed_list *
+bfd_elf_get_needed_list (bfd *abfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info)
+{
+ if (! is_elf_hash_table (info->hash))
+ return NULL;
+ return elf_hash_table (info)->needed;
+}
+
+/* Get the list of DT_RPATH/DT_RUNPATH entries for a link. This is a
+ hook for the linker ELF emulation code. */
+
+struct bfd_link_needed_list *
+bfd_elf_get_runpath_list (bfd *abfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info)
+{
+ if (! is_elf_hash_table (info->hash))
+ return NULL;
+ return elf_hash_table (info)->runpath;
+}
+
+/* Get the name actually used for a dynamic object for a link. This
+ is the SONAME entry if there is one. Otherwise, it is the string
+ passed to bfd_elf_set_dt_needed_name, or it is the filename. */
+
+const char *
+bfd_elf_get_dt_soname (bfd *abfd)
+{
+ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+ && bfd_get_format (abfd) == bfd_object)
+ return elf_dt_name (abfd);
+ return NULL;
+}
+
+/* Get the list of DT_NEEDED entries from a BFD. This is a hook for
+ the ELF linker emulation code. */
+
+bfd_boolean
+bfd_elf_get_bfd_needed_list (bfd *abfd,
+ struct bfd_link_needed_list **pneeded)
+{
+ asection *s;
+ bfd_byte *dynbuf = NULL;
+ int elfsec;
+ unsigned long shlink;
+ bfd_byte *extdyn, *extdynend;
+ size_t extdynsize;
+ void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *);
+
+ *pneeded = NULL;
+
+ if (bfd_get_flavour (abfd) != bfd_target_elf_flavour
+ || bfd_get_format (abfd) != bfd_object)
+ return TRUE;
+
+ s = bfd_get_section_by_name (abfd, ".dynamic");
+ if (s == NULL || s->size == 0)
+ return TRUE;
+
+ if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
+ goto error_return;
+
+ elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
+ if (elfsec == -1)
+ goto error_return;
+
+ shlink = elf_elfsections (abfd)[elfsec]->sh_link;
+
+ extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
+ swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
+
+ extdyn = dynbuf;
+ extdynend = extdyn + s->size;
+ for (; extdyn < extdynend; extdyn += extdynsize)
+ {
+ Elf_Internal_Dyn dyn;
+
+ (*swap_dyn_in) (abfd, extdyn, &dyn);
+
+ if (dyn.d_tag == DT_NULL)
+ break;
+
+ if (dyn.d_tag == DT_NEEDED)
+ {
+ const char *string;
+ struct bfd_link_needed_list *l;
+ unsigned int tagv = dyn.d_un.d_val;
+ bfd_size_type amt;
+
+ string = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
+ if (string == NULL)
+ goto error_return;
+
+ amt = sizeof *l;
+ l = bfd_alloc (abfd, amt);
+ if (l == NULL)
+ goto error_return;
+
+ l->by = abfd;
+ l->name = string;
+ l->next = *pneeded;
+ *pneeded = l;
+ }
+ }
+
+ free (dynbuf);
+
+ return TRUE;
+
+ error_return:
+ if (dynbuf != NULL)
+ free (dynbuf);
+ return FALSE;
+}
+
+struct elf_symbuf_symbol
+{
+ unsigned long st_name; /* Symbol name, index in string tbl */
+ unsigned char st_info; /* Type and binding attributes */
+ unsigned char st_other; /* Visibilty, and target specific */
+};
+
+struct elf_symbuf_head
+{
+ struct elf_symbuf_symbol *ssym;
+ bfd_size_type count;
+ unsigned int st_shndx;
+};
+
+struct elf_symbol
+{
+ union
+ {
+ Elf_Internal_Sym *isym;
+ struct elf_symbuf_symbol *ssym;
+ } u;
+ const char *name;
+};
+
+/* Sort references to symbols by ascending section number. */
+
+static int
+elf_sort_elf_symbol (const void *arg1, const void *arg2)
+{
+ const Elf_Internal_Sym *s1 = *(const Elf_Internal_Sym **) arg1;
+ const Elf_Internal_Sym *s2 = *(const Elf_Internal_Sym **) arg2;
+
+ return s1->st_shndx - s2->st_shndx;
+}
+
+static int
+elf_sym_name_compare (const void *arg1, const void *arg2)
+{
+ const struct elf_symbol *s1 = (const struct elf_symbol *) arg1;
+ const struct elf_symbol *s2 = (const struct elf_symbol *) arg2;
+ return strcmp (s1->name, s2->name);
+}
+
+static struct elf_symbuf_head *
+elf_create_symbuf (bfd_size_type symcount, Elf_Internal_Sym *isymbuf)
+{
+ Elf_Internal_Sym **ind, **indbufend, **indbuf
+ = bfd_malloc2 (symcount, sizeof (*indbuf));
+ struct elf_symbuf_symbol *ssym;
+ struct elf_symbuf_head *ssymbuf, *ssymhead;
+ bfd_size_type i, shndx_count;
+
+ if (indbuf == NULL)
+ return NULL;
+
+ for (ind = indbuf, i = 0; i < symcount; i++)
+ if (isymbuf[i].st_shndx != SHN_UNDEF)
+ *ind++ = &isymbuf[i];
+ indbufend = ind;
+
+ qsort (indbuf, indbufend - indbuf, sizeof (Elf_Internal_Sym *),
+ elf_sort_elf_symbol);
+
+ shndx_count = 0;
+ if (indbufend > indbuf)
+ for (ind = indbuf, shndx_count++; ind < indbufend - 1; ind++)
+ if (ind[0]->st_shndx != ind[1]->st_shndx)
+ shndx_count++;
+
+ ssymbuf = bfd_malloc ((shndx_count + 1) * sizeof (*ssymbuf)
+ + (indbufend - indbuf) * sizeof (*ssymbuf));
+ if (ssymbuf == NULL)
+ {
+ free (indbuf);
+ return NULL;
+ }
+
+ ssym = (struct elf_symbuf_symbol *) (ssymbuf + shndx_count);
+ ssymbuf->ssym = NULL;
+ ssymbuf->count = shndx_count;
+ ssymbuf->st_shndx = 0;
+ for (ssymhead = ssymbuf, ind = indbuf; ind < indbufend; ssym++, ind++)
+ {
+ if (ind == indbuf || ssymhead->st_shndx != (*ind)->st_shndx)
+ {
+ ssymhead++;
+ ssymhead->ssym = ssym;
+ ssymhead->count = 0;
+ ssymhead->st_shndx = (*ind)->st_shndx;
+ }
+ ssym->st_name = (*ind)->st_name;
+ ssym->st_info = (*ind)->st_info;
+ ssym->st_other = (*ind)->st_other;
+ ssymhead->count++;
+ }
+ BFD_ASSERT ((bfd_size_type) (ssymhead - ssymbuf) == shndx_count);
+
+ free (indbuf);
+ return ssymbuf;
+}
+
+/* Check if 2 sections define the same set of local and global
+ symbols. */
+
+bfd_boolean
+bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2,
+ struct bfd_link_info *info)
+{
+ bfd *bfd1, *bfd2;
+ const struct elf_backend_data *bed1, *bed2;
+ Elf_Internal_Shdr *hdr1, *hdr2;
+ bfd_size_type symcount1, symcount2;
+ Elf_Internal_Sym *isymbuf1, *isymbuf2;
+ struct elf_symbuf_head *ssymbuf1, *ssymbuf2;
+ Elf_Internal_Sym *isym, *isymend;
+ struct elf_symbol *symtable1 = NULL, *symtable2 = NULL;
+ bfd_size_type count1, count2, i;
+ int shndx1, shndx2;
+ bfd_boolean result;
+
+ bfd1 = sec1->owner;
+ bfd2 = sec2->owner;
+
+ /* If both are .gnu.linkonce sections, they have to have the same
+ section name. */
+ if (CONST_STRNEQ (sec1->name, ".gnu.linkonce")
+ && CONST_STRNEQ (sec2->name, ".gnu.linkonce"))
+ return strcmp (sec1->name + sizeof ".gnu.linkonce",
+ sec2->name + sizeof ".gnu.linkonce") == 0;
+
+ /* Both sections have to be in ELF. */
+ if (bfd_get_flavour (bfd1) != bfd_target_elf_flavour
+ || bfd_get_flavour (bfd2) != bfd_target_elf_flavour)
+ return FALSE;
+
+ if (elf_section_type (sec1) != elf_section_type (sec2))
+ return FALSE;
+
+ if ((elf_section_flags (sec1) & SHF_GROUP) != 0
+ && (elf_section_flags (sec2) & SHF_GROUP) != 0)
+ {
+ /* If both are members of section groups, they have to have the
+ same group name. */
+ if (strcmp (elf_group_name (sec1), elf_group_name (sec2)) != 0)
+ return FALSE;
+ }
+
+ shndx1 = _bfd_elf_section_from_bfd_section (bfd1, sec1);
+ shndx2 = _bfd_elf_section_from_bfd_section (bfd2, sec2);
+ if (shndx1 == -1 || shndx2 == -1)
+ return FALSE;
+
+ bed1 = get_elf_backend_data (bfd1);
+ bed2 = get_elf_backend_data (bfd2);
+ hdr1 = &elf_tdata (bfd1)->symtab_hdr;
+ symcount1 = hdr1->sh_size / bed1->s->sizeof_sym;
+ hdr2 = &elf_tdata (bfd2)->symtab_hdr;
+ symcount2 = hdr2->sh_size / bed2->s->sizeof_sym;
+
+ if (symcount1 == 0 || symcount2 == 0)
+ return FALSE;
+
+ result = FALSE;
+ isymbuf1 = NULL;
+ isymbuf2 = NULL;
+ ssymbuf1 = elf_tdata (bfd1)->symbuf;
+ ssymbuf2 = elf_tdata (bfd2)->symbuf;
+
+ if (ssymbuf1 == NULL)
+ {
+ isymbuf1 = bfd_elf_get_elf_syms (bfd1, hdr1, symcount1, 0,
+ NULL, NULL, NULL);
+ if (isymbuf1 == NULL)
+ goto done;
+
+ if (!info->reduce_memory_overheads)
+ elf_tdata (bfd1)->symbuf = ssymbuf1
+ = elf_create_symbuf (symcount1, isymbuf1);
+ }
+
+ if (ssymbuf1 == NULL || ssymbuf2 == NULL)
+ {
+ isymbuf2 = bfd_elf_get_elf_syms (bfd2, hdr2, symcount2, 0,
+ NULL, NULL, NULL);
+ if (isymbuf2 == NULL)
+ goto done;
+
+ if (ssymbuf1 != NULL && !info->reduce_memory_overheads)
+ elf_tdata (bfd2)->symbuf = ssymbuf2
+ = elf_create_symbuf (symcount2, isymbuf2);
+ }
+
+ if (ssymbuf1 != NULL && ssymbuf2 != NULL)
+ {
+ /* Optimized faster version. */
+ bfd_size_type lo, hi, mid;
+ struct elf_symbol *symp;
+ struct elf_symbuf_symbol *ssym, *ssymend;
+
+ lo = 0;
+ hi = ssymbuf1->count;
+ ssymbuf1++;
+ count1 = 0;
+ while (lo < hi)
+ {
+ mid = (lo + hi) / 2;
+ if ((unsigned int) shndx1 < ssymbuf1[mid].st_shndx)
+ hi = mid;
+ else if ((unsigned int) shndx1 > ssymbuf1[mid].st_shndx)
+ lo = mid + 1;
+ else
+ {
+ count1 = ssymbuf1[mid].count;
+ ssymbuf1 += mid;
+ break;
+ }
+ }
+
+ lo = 0;
+ hi = ssymbuf2->count;
+ ssymbuf2++;
+ count2 = 0;
+ while (lo < hi)
+ {
+ mid = (lo + hi) / 2;
+ if ((unsigned int) shndx2 < ssymbuf2[mid].st_shndx)
+ hi = mid;
+ else if ((unsigned int) shndx2 > ssymbuf2[mid].st_shndx)
+ lo = mid + 1;
+ else
+ {
+ count2 = ssymbuf2[mid].count;
+ ssymbuf2 += mid;
+ break;
+ }
+ }
+
+ if (count1 == 0 || count2 == 0 || count1 != count2)
+ goto done;
+
+ symtable1 = bfd_malloc (count1 * sizeof (struct elf_symbol));
+ symtable2 = bfd_malloc (count2 * sizeof (struct elf_symbol));
+ if (symtable1 == NULL || symtable2 == NULL)
+ goto done;
+
+ symp = symtable1;
+ for (ssym = ssymbuf1->ssym, ssymend = ssym + count1;
+ ssym < ssymend; ssym++, symp++)
+ {
+ symp->u.ssym = ssym;
+ symp->name = bfd_elf_string_from_elf_section (bfd1,
+ hdr1->sh_link,
+ ssym->st_name);
+ }
+
+ symp = symtable2;
+ for (ssym = ssymbuf2->ssym, ssymend = ssym + count2;
+ ssym < ssymend; ssym++, symp++)
+ {
+ symp->u.ssym = ssym;
+ symp->name = bfd_elf_string_from_elf_section (bfd2,
+ hdr2->sh_link,
+ ssym->st_name);
+ }
+
+ /* Sort symbol by name. */
+ qsort (symtable1, count1, sizeof (struct elf_symbol),
+ elf_sym_name_compare);
+ qsort (symtable2, count1, sizeof (struct elf_symbol),
+ elf_sym_name_compare);
+
+ for (i = 0; i < count1; i++)
+ /* Two symbols must have the same binding, type and name. */
+ if (symtable1 [i].u.ssym->st_info != symtable2 [i].u.ssym->st_info
+ || symtable1 [i].u.ssym->st_other != symtable2 [i].u.ssym->st_other
+ || strcmp (symtable1 [i].name, symtable2 [i].name) != 0)
+ goto done;
+
+ result = TRUE;
+ goto done;
+ }
+
+ symtable1 = bfd_malloc (symcount1 * sizeof (struct elf_symbol));
+ symtable2 = bfd_malloc (symcount2 * sizeof (struct elf_symbol));
+ if (symtable1 == NULL || symtable2 == NULL)
+ goto done;
+
+ /* Count definitions in the section. */
+ count1 = 0;
+ for (isym = isymbuf1, isymend = isym + symcount1; isym < isymend; isym++)
+ if (isym->st_shndx == (unsigned int) shndx1)
+ symtable1[count1++].u.isym = isym;
+
+ count2 = 0;
+ for (isym = isymbuf2, isymend = isym + symcount2; isym < isymend; isym++)
+ if (isym->st_shndx == (unsigned int) shndx2)
+ symtable2[count2++].u.isym = isym;
+
+ if (count1 == 0 || count2 == 0 || count1 != count2)
+ goto done;
+
+ for (i = 0; i < count1; i++)
+ symtable1[i].name
+ = bfd_elf_string_from_elf_section (bfd1, hdr1->sh_link,
+ symtable1[i].u.isym->st_name);
+
+ for (i = 0; i < count2; i++)
+ symtable2[i].name
+ = bfd_elf_string_from_elf_section (bfd2, hdr2->sh_link,
+ symtable2[i].u.isym->st_name);
+
+ /* Sort symbol by name. */
+ qsort (symtable1, count1, sizeof (struct elf_symbol),
+ elf_sym_name_compare);
+ qsort (symtable2, count1, sizeof (struct elf_symbol),
+ elf_sym_name_compare);
+
+ for (i = 0; i < count1; i++)
+ /* Two symbols must have the same binding, type and name. */
+ if (symtable1 [i].u.isym->st_info != symtable2 [i].u.isym->st_info
+ || symtable1 [i].u.isym->st_other != symtable2 [i].u.isym->st_other
+ || strcmp (symtable1 [i].name, symtable2 [i].name) != 0)
+ goto done;
+
+ result = TRUE;
+
+done:
+ if (symtable1)
+ free (symtable1);
+ if (symtable2)
+ free (symtable2);
+ if (isymbuf1)
+ free (isymbuf1);
+ if (isymbuf2)
+ free (isymbuf2);
+
+ return result;
+}
+
+/* Return TRUE if 2 section types are compatible. */
+
+bfd_boolean
+_bfd_elf_match_sections_by_type (bfd *abfd, const asection *asec,
+ bfd *bbfd, const asection *bsec)
+{
+ if (asec == NULL
+ || bsec == NULL
+ || abfd->xvec->flavour != bfd_target_elf_flavour
+ || bbfd->xvec->flavour != bfd_target_elf_flavour)
+ return TRUE;
+
+ return elf_section_type (asec) == elf_section_type (bsec);
+}
+\f
/* Final phase of ELF linker. */
/* A structure we use to avoid passing large numbers of arguments. */
{
Elf_Internal_Rela * rel;
char * sym_name;
- unsigned long index;
+ bfd_vma index;
Elf_Internal_Sym * sym;
bfd_vma result;
bfd_vma section_offset;
Elf_Internal_Shdr * symtab_hdr;
asection * sec;
bfd_vma relocation = 0, shift, x;
- unsigned long r_symndx;
+ bfd_vma r_symndx;
bfd_vma mask;
unsigned long start, oplen, len, wordsz,
chunksz, lsb0_p, signed_p, trunc_p;
static size_t
elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
{
- asection *reldyn;
+ asection *dynamic_relocs;
+ asection *rela_dyn;
+ asection *rel_dyn;
bfd_size_type count, size;
size_t i, ret, sort_elt, ext_size;
bfd_byte *sort, *s_non_relative, *p;
void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *);
struct bfd_link_order *lo;
bfd_vma r_sym_mask;
+ bfd_boolean use_rela;
- reldyn = bfd_get_section_by_name (abfd, ".rela.dyn");
- if (reldyn == NULL || reldyn->size == 0)
+ /* Find a dynamic reloc section. */
+ rela_dyn = bfd_get_section_by_name (abfd, ".rela.dyn");
+ rel_dyn = bfd_get_section_by_name (abfd, ".rel.dyn");
+ if (rela_dyn != NULL && rela_dyn->size > 0
+ && rel_dyn != NULL && rel_dyn->size > 0)
{
- reldyn = bfd_get_section_by_name (abfd, ".rel.dyn");
- if (reldyn == NULL || reldyn->size == 0)
- return 0;
- ext_size = bed->s->sizeof_rel;
- swap_in = bed->s->swap_reloc_in;
- swap_out = bed->s->swap_reloc_out;
+ bfd_boolean use_rela_initialised = FALSE;
+
+ /* This is just here to stop gcc from complaining.
+ It's initialization checking code is not perfect. */
+ use_rela = TRUE;
+
+ /* Both sections are present. Examine the sizes
+ of the indirect sections to help us choose. */
+ for (lo = rela_dyn->map_head.link_order; lo != NULL; lo = lo->next)
+ if (lo->type == bfd_indirect_link_order)
+ {
+ asection *o = lo->u.indirect.section;
+
+ if ((o->size % bed->s->sizeof_rela) == 0)
+ {
+ if ((o->size % bed->s->sizeof_rel) == 0)
+ /* Section size is divisible by both rel and rela sizes.
+ It is of no help to us. */
+ ;
+ else
+ {
+ /* Section size is only divisible by rela. */
+ if (use_rela_initialised && (use_rela == FALSE))
+ {
+ _bfd_error_handler
+ (_("%B: Unable to sort relocs - they are in more than one size"), abfd);
+ bfd_set_error (bfd_error_invalid_operation);
+ return 0;
+ }
+ else
+ {
+ use_rela = TRUE;
+ use_rela_initialised = TRUE;
+ }
+ }
+ }
+ else if ((o->size % bed->s->sizeof_rel) == 0)
+ {
+ /* Section size is only divisible by rel. */
+ if (use_rela_initialised && (use_rela == TRUE))
+ {
+ _bfd_error_handler
+ (_("%B: Unable to sort relocs - they are in more than one size"), abfd);
+ bfd_set_error (bfd_error_invalid_operation);
+ return 0;
+ }
+ else
+ {
+ use_rela = FALSE;
+ use_rela_initialised = TRUE;
+ }
+ }
+ else
+ {
+ /* The section size is not divisible by either - something is wrong. */
+ _bfd_error_handler
+ (_("%B: Unable to sort relocs - they are of an unknown size"), abfd);
+ bfd_set_error (bfd_error_invalid_operation);
+ return 0;
+ }
+ }
+
+ for (lo = rel_dyn->map_head.link_order; lo != NULL; lo = lo->next)
+ if (lo->type == bfd_indirect_link_order)
+ {
+ asection *o = lo->u.indirect.section;
+
+ if ((o->size % bed->s->sizeof_rela) == 0)
+ {
+ if ((o->size % bed->s->sizeof_rel) == 0)
+ /* Section size is divisible by both rel and rela sizes.
+ It is of no help to us. */
+ ;
+ else
+ {
+ /* Section size is only divisible by rela. */
+ if (use_rela_initialised && (use_rela == FALSE))
+ {
+ _bfd_error_handler
+ (_("%B: Unable to sort relocs - they are in more than one size"), abfd);
+ bfd_set_error (bfd_error_invalid_operation);
+ return 0;
+ }
+ else
+ {
+ use_rela = TRUE;
+ use_rela_initialised = TRUE;
+ }
+ }
+ }
+ else if ((o->size % bed->s->sizeof_rel) == 0)
+ {
+ /* Section size is only divisible by rel. */
+ if (use_rela_initialised && (use_rela == TRUE))
+ {
+ _bfd_error_handler
+ (_("%B: Unable to sort relocs - they are in more than one size"), abfd);
+ bfd_set_error (bfd_error_invalid_operation);
+ return 0;
+ }
+ else
+ {
+ use_rela = FALSE;
+ use_rela_initialised = TRUE;
+ }
+ }
+ else
+ {
+ /* The section size is not divisible by either - something is wrong. */
+ _bfd_error_handler
+ (_("%B: Unable to sort relocs - they are of an unknown size"), abfd);
+ bfd_set_error (bfd_error_invalid_operation);
+ return 0;
+ }
+ }
+
+ if (! use_rela_initialised)
+ /* Make a guess. */
+ use_rela = TRUE;
}
+ else if (rela_dyn != NULL && rela_dyn->size > 0)
+ use_rela = TRUE;
+ else if (rel_dyn != NULL && rel_dyn->size > 0)
+ use_rela = FALSE;
else
+ return 0;
+
+ if (use_rela)
{
+ dynamic_relocs = rela_dyn;
ext_size = bed->s->sizeof_rela;
swap_in = bed->s->swap_reloca_in;
swap_out = bed->s->swap_reloca_out;
}
- count = reldyn->size / ext_size;
+ else
+ {
+ dynamic_relocs = rel_dyn;
+ ext_size = bed->s->sizeof_rel;
+ swap_in = bed->s->swap_reloc_in;
+ swap_out = bed->s->swap_reloc_out;
+ }
size = 0;
- for (lo = reldyn->map_head.link_order; lo != NULL; lo = lo->next)
+ for (lo = dynamic_relocs->map_head.link_order; lo != NULL; lo = lo->next)
if (lo->type == bfd_indirect_link_order)
- {
- asection *o = lo->u.indirect.section;
- size += o->size;
- }
+ size += lo->u.indirect.section->size;
- if (size != reldyn->size)
+ if (size != dynamic_relocs->size)
return 0;
sort_elt = (sizeof (struct elf_link_sort_rela)
+ (i2e - 1) * sizeof (Elf_Internal_Rela));
+
+ count = dynamic_relocs->size / ext_size;
sort = bfd_zmalloc (sort_elt * count);
+
if (sort == NULL)
{
(*info->callbacks->warning)
else
r_sym_mask = ~(bfd_vma) 0xffffffff;
- for (lo = reldyn->map_head.link_order; lo != NULL; lo = lo->next)
+ for (lo = dynamic_relocs->map_head.link_order; lo != NULL; lo = lo->next)
if (lo->type == bfd_indirect_link_order)
{
bfd_byte *erel, *erelend;
erel = o->contents;
erelend = o->contents + o->size;
p = sort + o->output_offset / ext_size * sort_elt;
+
while (erel < erelend)
{
struct elf_link_sort_rela *s = (struct elf_link_sort_rela *) p;
+
(*swap_in) (abfd, erel, s->rela);
s->type = (*bed->elf_backend_reloc_type_class) (s->rela);
s->u.sym_mask = r_sym_mask;
qsort (s_non_relative, count - ret, sort_elt, elf_link_sort_cmp2);
- for (lo = reldyn->map_head.link_order; lo != NULL; lo = lo->next)
+ for (lo = dynamic_relocs->map_head.link_order; lo != NULL; lo = lo->next)
if (lo->type == bfd_indirect_link_order)
{
bfd_byte *erel, *erelend;
}
free (sort);
- *psec = reldyn;
+ *psec = dynamic_relocs;
return ret;
}
static bfd_boolean
elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
{
- bfd_boolean (*relocate_section)
+ int (*relocate_section)
(bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
Elf_Internal_Rela *, Elf_Internal_Sym *, asection **);
bfd *output_bfd;
asection **ppsection;
asection *o;
const struct elf_backend_data *bed;
- bfd_boolean emit_relocs;
struct elf_link_hash_entry **sym_hashes;
output_bfd = finfo->output_bfd;
if ((input_bfd->flags & DYNAMIC) != 0)
return TRUE;
- emit_relocs = (finfo->info->relocatable
- || finfo->info->emitrelocations);
-
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
if (elf_bad_symtab (input_bfd))
{
Elf_Internal_Rela *internal_relocs;
bfd_vma r_type_mask;
int r_sym_shift;
+ int ret;
/* Get the swapped relocs. */
internal_relocs
continue;
}
}
-
- /* Remove the symbol reference from the reloc, but
- don't kill the reloc completely. This is so that
- a zero value will be written into the section,
- which may have non-zero contents put there by the
- assembler. Zero in things like an eh_frame fde
- pc_begin allows stack unwinders to recognize the
- fde as bogus. */
- rel->r_info &= r_type_mask;
- rel->r_addend = 0;
}
}
}
corresponding to the output section, which will require
the addend to be adjusted. */
- if (! (*relocate_section) (output_bfd, finfo->info,
+ ret = (*relocate_section) (output_bfd, finfo->info,
input_bfd, o, contents,
internal_relocs,
isymbuf,
- finfo->sections))
+ finfo->sections);
+ if (!ret)
return FALSE;
- if (emit_relocs)
+ if (ret == 2
+ || finfo->info->relocatable
+ || finfo->info->emitrelocations)
{
Elf_Internal_Rela *irela;
Elf_Internal_Rela *irelaend;
/* If we have discarded a section, the output
section will be the absolute section. In
- case of discarded link-once and discarded
- SEC_MERGE sections, use the kept section. */
+ case of discarded SEC_MERGE sections, use
+ the kept section. relocate_section should
+ have already handled discarded linkonce
+ sections. */
if (bfd_is_abs_section (osec)
&& sec->kept_section != NULL
&& sec->kept_section->output_section != NULL)
size_t relativecount = 0;
asection *reldyn = 0;
bfd_size_type amt;
+ asection *attr_section = NULL;
+ bfd_vma attr_size = 0;
+ const char *std_attrs_section;
if (! is_elf_hash_table (info->hash))
return FALSE;
finfo.symbuf_count = 0;
finfo.shndxbuf_size = 0;
+ /* The object attributes have been merged. Remove the input
+ sections from the link, and set the contents of the output
+ secton. */
+ std_attrs_section = get_elf_backend_data (abfd)->obj_attrs_section;
+ for (o = abfd->sections; o != NULL; o = o->next)
+ {
+ if ((std_attrs_section && strcmp (o->name, std_attrs_section) == 0)
+ || strcmp (o->name, ".gnu.attributes") == 0)
+ {
+ for (p = o->map_head.link_order; p != NULL; p = p->next)
+ {
+ asection *input_section;
+
+ if (p->type != bfd_indirect_link_order)
+ continue;
+ input_section = p->u.indirect.section;
+ /* Hack: reset the SEC_HAS_CONTENTS flag so that
+ elf_link_input_bfd ignores this section. */
+ input_section->flags &= ~SEC_HAS_CONTENTS;
+ }
+
+ attr_size = bfd_elf_obj_attr_size (abfd);
+ if (attr_size)
+ {
+ bfd_set_section_size (abfd, o, attr_size);
+ attr_section = o;
+ /* Skip this section later on. */
+ o->map_head.link_order = NULL;
+ }
+ else
+ o->flags |= SEC_EXCLUDE;
+ }
+ }
+
/* Count up the number of relocations we will output for each output
section, so that we know the sizes of the reloc sections. We
also figure out some maximum sizes. */
{
Elf_Internal_Rela * relocs;
- relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
+ relocs = _bfd_elf_link_read_relocs (sec->owner, sec,
+ NULL, NULL,
info->keep_memory);
- reloc_count = (*bed->elf_backend_count_relocs) (sec, relocs);
+ if (relocs != NULL)
+ {
+ reloc_count
+ = (*bed->elf_backend_count_relocs) (sec, relocs);
- if (elf_section_data (o)->relocs != relocs)
- free (relocs);
+ if (elf_section_data (sec)->relocs != relocs)
+ free (relocs);
+ }
}
if (sec->rawsize > max_contents_size)
if (!info->reduce_memory_overheads)
{
for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
- if (elf_tdata (sub)->symbuf)
+ if (bfd_get_flavour (sub) == bfd_target_elf_flavour
+ && elf_tdata (sub)->symbuf)
{
free (elf_tdata (sub)->symbuf);
elf_tdata (sub)->symbuf = NULL;
if (dyn.d_tag == DT_TEXTREL)
{
- _bfd_error_handler
- (_("warning: creating a DT_TEXTREL in a shared object."));
+ info->callbacks->einfo
+ (_("%P: warning: creating a DT_TEXTREL in a shared object.\n"));
break;
}
}
elf_tdata (abfd)->linker = TRUE;
+ if (attr_section)
+ {
+ bfd_byte *contents = bfd_malloc (attr_size);
+ if (contents == NULL)
+ return FALSE; /* Bail out and fail. */
+ bfd_elf_set_obj_attr_contents (abfd, contents, attr_size);
+ bfd_set_section_contents (abfd, attr_section, contents, 0, attr_size);
+ free (contents);
+ }
+
return TRUE;
error_return:
\f
/* Garbage collect unused sections. */
-typedef asection * (*gc_mark_hook_fn)
- (asection *, struct bfd_link_info *, Elf_Internal_Rela *,
- struct elf_link_hash_entry *, Elf_Internal_Sym *);
-
/* Default gc_mark_hook. */
asection *
bfd_boolean
_bfd_elf_gc_mark (struct bfd_link_info *info,
asection *sec,
- gc_mark_hook_fn gc_mark_hook)
+ elf_gc_mark_hook_fn gc_mark_hook)
{
bfd_boolean ret;
bfd_boolean is_eh;
to remove a section from the output. */
o->flags |= SEC_EXCLUDE;
- if (info->print_gc_sections == TRUE)
+ if (info->print_gc_sections && o->size != 0)
_bfd_error_handler (_("Removing unused section '%s' in file '%B'"), sub, o->name);
/* But we also have to update some of the relocation
{
bfd_boolean ok = TRUE;
bfd *sub;
- asection * (*gc_mark_hook)
- (asection *, struct bfd_link_info *, Elf_Internal_Rela *,
- struct elf_link_hash_entry *h, Elf_Internal_Sym *);
+ elf_gc_mark_hook_fn gc_mark_hook;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
if (!bed->can_gc_sections
return FALSE;
}
+ /* Allow the backend to mark additional target specific sections. */
+ if (bed->gc_mark_extra_sections)
+ bed->gc_mark_extra_sections(info, gc_mark_hook);
+
/* ... again for sections marked from eh_frame. */
for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
{
cookie.locsymcount, 0,
NULL, NULL, NULL);
if (cookie.locsyms == NULL)
- return FALSE;
+ {
+ info->callbacks->einfo (_("%P%X: can not read symbols: %E\n"));
+ return FALSE;
+ }
}
if (stab != NULL)
}
/* This is the first section with this name. Record it. */
- bfd_section_already_linked_table_insert (already_linked_list, sec);
+ if (! bfd_section_already_linked_table_insert (already_linked_list, sec))
+ info->callbacks->einfo (_("%F%P: already_linked_table: %E"));
}
bfd_boolean