/* ELF linking support for BFD.
Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- 2005, 2006, 2007 Free Software Foundation, Inc.
+ 2005, 2006, 2007, 2008, 2009
+ Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
#include "libiberty.h"
#include "objalloc.h"
+/* This struct is used to pass information to routines called via
+ elf_link_hash_traverse which must return failure. */
+
+struct elf_info_failed
+{
+ struct bfd_link_info *info;
+ struct bfd_elf_version_tree *verdefs;
+ bfd_boolean failed;
+};
+
+/* This structure is used to pass information to
+ _bfd_elf_link_find_version_dependencies. */
+
+struct elf_find_verdep_info
+{
+ /* General link information. */
+ struct bfd_link_info *info;
+ /* The number of dependencies. */
+ unsigned int vers;
+ /* Whether we had a failure. */
+ bfd_boolean failed;
+};
+
+static bfd_boolean _bfd_elf_fix_symbol_flags
+ (struct elf_link_hash_entry *, struct elf_info_failed *);
+
/* Define a symbol in a dynamic linkage section. */
struct elf_link_hash_entry *
}
s = bfd_make_section_with_flags (abfd,
- (bed->default_use_rela_p
+ (bed->rela_plts_and_copies_p
? ".rela.plt" : ".rel.plt"),
flags | SEC_READONLY);
if (s == NULL
if (! info->shared)
{
s = bfd_make_section_with_flags (abfd,
- (bed->default_use_rela_p
+ (bed->rela_plts_and_copies_p
? ".rela.bss" : ".rel.bss"),
flags | SEC_READONLY);
if (s == NULL
\f
/* Mark a symbol dynamic. */
-void
+static void
bfd_elf_link_mark_dynamic_symbol (struct bfd_link_info *info,
struct elf_link_hash_entry *h,
Elf_Internal_Sym *sym)
}
if (entry->isym.st_shndx != SHN_UNDEF
- && (entry->isym.st_shndx < SHN_LORESERVE
- || entry->isym.st_shndx > SHN_HIRESERVE))
+ && entry->isym.st_shndx < SHN_LORESERVE)
{
asection *s;
return dynsymcount;
}
+/* Merge st_other field. */
+
+static void
+elf_merge_st_other (bfd *abfd, struct elf_link_hash_entry *h,
+ Elf_Internal_Sym *isym, bfd_boolean definition,
+ bfd_boolean dynamic)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+ /* If st_other has a processor-specific meaning, specific
+ code might be needed here. We never merge the visibility
+ attribute with the one from a dynamic object. */
+ if (bed->elf_backend_merge_symbol_attribute)
+ (*bed->elf_backend_merge_symbol_attribute) (h, isym, definition,
+ dynamic);
+
+ /* If this symbol has default visibility and the user has requested
+ we not re-export it, then mark it as hidden. */
+ if (definition
+ && !dynamic
+ && (abfd->no_export
+ || (abfd->my_archive && abfd->my_archive->no_export))
+ && ELF_ST_VISIBILITY (isym->st_other) != STV_INTERNAL)
+ isym->st_other = (STV_HIDDEN
+ | (isym->st_other & ~ELF_ST_VISIBILITY (-1)));
+
+ if (!dynamic && ELF_ST_VISIBILITY (isym->st_other) != 0)
+ {
+ unsigned char hvis, symvis, other, nvis;
+
+ /* Only merge the visibility. Leave the remainder of the
+ st_other field to elf_backend_merge_symbol_attribute. */
+ other = h->other & ~ELF_ST_VISIBILITY (-1);
+
+ /* Combine visibilities, using the most constraining one. */
+ hvis = ELF_ST_VISIBILITY (h->other);
+ symvis = ELF_ST_VISIBILITY (isym->st_other);
+ if (! hvis)
+ nvis = symvis;
+ else if (! symvis)
+ nvis = hvis;
+ else
+ nvis = hvis < symvis ? hvis : symvis;
+
+ h->other = other | nvis;
+ }
+}
+
/* This function is called when we want to define a new symbol. It
handles the various cases which arise when we find a definition in
a dynamic object, or when there is already a definition in a
int bind;
bfd *oldbfd;
bfd_boolean newdyn, olddyn, olddef, newdef, newdyncommon, olddyncommon;
- bfd_boolean newweak, oldweak;
+ bfd_boolean newweak, oldweak, newfunc, oldfunc;
const struct elf_backend_data *bed;
*skip = FALSE;
return FALSE;
*sym_hash = h;
+ bed = get_elf_backend_data (abfd);
+
/* This code is for coping with dynamic objects, and is only useful
if we are doing an ELF link. */
- if (info->hash->creator != abfd->xvec)
+ if (!(*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
return TRUE;
/* For merging, we only care about real symbols. */
&& h->root.type != bfd_link_hash_undefweak
&& h->root.type != bfd_link_hash_common);
- bed = get_elf_backend_data (abfd);
+ /* NEWFUNC and OLDFUNC indicate whether the new or old symbol,
+ respectively, appear to be a function. */
+
+ newfunc = (ELF_ST_TYPE (sym->st_info) != STT_NOTYPE
+ && bed->is_function_type (ELF_ST_TYPE (sym->st_info)));
+
+ oldfunc = (h->type != STT_NOTYPE
+ && bed->is_function_type (h->type));
+
/* 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
&& ELF_ST_TYPE (sym->st_info) != h->type
&& ELF_ST_TYPE (sym->st_info) != STT_NOTYPE
&& h->type != STT_NOTYPE
- && !(bed->is_function_type (ELF_ST_TYPE (sym->st_info))
- && bed->is_function_type (h->type)))
+ && !(newfunc && oldfunc))
{
*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))
+ /* Allow changes between different types of function symbol. */
+ if (newfunc && oldfunc)
*type_change_ok = TRUE;
/* It's OK to change the type if either the existing symbol or the
&& (sec->flags & SEC_ALLOC) != 0
&& (sec->flags & SEC_LOAD) == 0
&& sym->st_size > 0
- && !bed->is_function_type (ELF_ST_TYPE (sym->st_info)))
+ && !newfunc)
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
- && !bed->is_function_type (h->type))
+ && !oldfunc)
olddyncommon = TRUE;
else
olddyncommon = FALSE;
&& newdef
&& (olddef
|| (h->root.type == bfd_link_hash_common
- && (newweak
- || bed->is_function_type (ELF_ST_TYPE (sym->st_info))))))
+ && (newweak || newfunc))))
{
*override = TRUE;
newdef = FALSE;
/* Skip weak definitions of symbols that are already defined. */
if (newdef && olddef && newweak)
- *skip = TRUE;
+ {
+ *skip = TRUE;
+
+ /* Merge st_other. If the symbol already has a dynamic index,
+ but visibility says it should not be visible, turn it into a
+ local symbol. */
+ elf_merge_st_other (abfd, h, sym, newdef, newdyn);
+ if (h->dynindx != -1)
+ switch (ELF_ST_VISIBILITY (h->other))
+ {
+ case STV_INTERNAL:
+ case STV_HIDDEN:
+ (*bed->elf_backend_hide_symbol) (info, h, TRUE);
+ break;
+ }
+ }
/* If the old symbol is from a dynamic object, and the new symbol is
a definition which is not from a dynamic object, then the new
if (!newdyn
&& (newdef
|| (bfd_is_com_section (sec)
- && (oldweak
- || bed->is_function_type (h->type))))
+ && (oldweak || oldfunc)))
&& olddyn
&& olddef
&& h->def_dynamic)
overriding a function. */
if (bfd_is_com_section (sec))
- *type_change_ok = TRUE;
+ {
+ if (oldfunc)
+ {
+ /* If a common symbol overrides a function, make sure
+ that it isn't defined dynamically nor has type
+ function. */
+ h->def_dynamic = 0;
+ h->type = STT_NOTYPE;
+ }
+ *type_change_ok = TRUE;
+ }
if ((*sym_hash)->root.type == bfd_link_hash_indirect)
flip = *sym_hash;
symbol is described by H, NAME, SYM, PSEC, VALUE, and OVERRIDE. We
set DYNSYM if the new indirect symbol is dynamic. */
-bfd_boolean
+static bfd_boolean
_bfd_elf_add_default_symbol (bfd *abfd,
struct bfd_link_info *info,
struct elf_link_hash_entry *h,
return TRUE;
}
\f
+static struct bfd_elf_version_tree *
+find_version_for_sym (struct bfd_elf_version_tree *verdefs,
+ const char *sym_name,
+ bfd_boolean *hide)
+{
+ struct bfd_elf_version_tree *t;
+ struct bfd_elf_version_tree *local_ver, *global_ver, *exist_ver;
+
+ local_ver = NULL;
+ global_ver = NULL;
+ exist_ver = NULL;
+ for (t = verdefs; t != NULL; t = t->next)
+ {
+ if (t->globals.list != NULL)
+ {
+ struct bfd_elf_version_expr *d = NULL;
+
+ while ((d = (*t->match) (&t->globals, d, sym_name)) != NULL)
+ {
+ global_ver = t;
+ if (d->symver)
+ exist_ver = t;
+ d->script = 1;
+ /* If the match is a wildcard pattern, keep looking for
+ a more explicit, perhaps even local, match. */
+ if (d->literal)
+ break;
+ }
+
+ if (d != NULL)
+ break;
+ }
+
+ if (t->locals.list != NULL)
+ {
+ struct bfd_elf_version_expr *d = NULL;
+
+ while ((d = (*t->match) (&t->locals, d, sym_name)) != NULL)
+ {
+ local_ver = t;
+ /* If the match is a wildcard pattern, keep looking for
+ a more explicit, perhaps even global, match. */
+ if (d->literal)
+ {
+ /* An exact match overrides a global wildcard. */
+ global_ver = NULL;
+ break;
+ }
+ }
+
+ if (d != NULL)
+ break;
+ }
+ }
+
+ if (global_ver != NULL)
+ {
+ /* If we already have a versioned symbol that matches the
+ node for this symbol, then we don't want to create a
+ duplicate from the unversioned symbol. Instead hide the
+ unversioned symbol. */
+ *hide = exist_ver == global_ver;
+ return global_ver;
+ }
+
+ if (local_ver != NULL)
+ {
+ *hide = TRUE;
+ return local_ver;
+ }
+
+ return NULL;
+}
+
/* This routine is used to export all defined symbols into the dynamic
symbol table. It is called via elf_link_hash_traverse. */
-bfd_boolean
+static bfd_boolean
_bfd_elf_export_symbol (struct elf_link_hash_entry *h, void *data)
{
struct elf_info_failed *eif = data;
&& (h->def_regular
|| h->ref_regular))
{
- struct bfd_elf_version_tree *t;
- struct bfd_elf_version_expr *d;
-
- for (t = eif->verdefs; t != NULL; t = t->next)
- {
- if (t->globals.list != NULL)
- {
- d = (*t->match) (&t->globals, NULL, h->root.root.string);
- if (d != NULL)
- goto doit;
- }
+ bfd_boolean hide;
- if (t->locals.list != NULL)
- {
- d = (*t->match) (&t->locals, NULL, h->root.root.string);
- if (d != NULL)
- return TRUE;
- }
- }
-
- if (!eif->verdefs)
+ if (eif->verdefs == NULL
+ || (find_version_for_sym (eif->verdefs, h->root.root.string, &hide)
+ && !hide))
{
- doit:
if (! bfd_elf_link_record_dynamic_symbol (eif->info, h))
{
eif->failed = TRUE;
dependencies. This will be put into the .gnu.version_r section.
This function is called via elf_link_hash_traverse. */
-bfd_boolean
+static bfd_boolean
_bfd_elf_link_find_version_dependencies (struct elf_link_hash_entry *h,
void *data)
{
return TRUE;
/* See if we already know about this version. */
- for (t = elf_tdata (rinfo->output_bfd)->verref; t != NULL; t = t->vn_nextref)
+ for (t = elf_tdata (rinfo->info->output_bfd)->verref;
+ t != NULL;
+ t = t->vn_nextref)
{
if (t->vn_bfd != h->verinfo.verdef->vd_bfd)
continue;
if (t == NULL)
{
amt = sizeof *t;
- t = bfd_zalloc (rinfo->output_bfd, amt);
+ t = bfd_zalloc (rinfo->info->output_bfd, amt);
if (t == NULL)
{
rinfo->failed = TRUE;
}
t->vn_bfd = h->verinfo.verdef->vd_bfd;
- t->vn_nextref = elf_tdata (rinfo->output_bfd)->verref;
- elf_tdata (rinfo->output_bfd)->verref = t;
+ t->vn_nextref = elf_tdata (rinfo->info->output_bfd)->verref;
+ elf_tdata (rinfo->info->output_bfd)->verref = t;
}
amt = sizeof *a;
- a = bfd_zalloc (rinfo->output_bfd, amt);
+ a = bfd_zalloc (rinfo->info->output_bfd, amt);
if (a == NULL)
{
rinfo->failed = TRUE;
files, so until that point we don't know which symbols should be
local. This function is called via elf_link_hash_traverse. */
-bfd_boolean
+static bfd_boolean
_bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
{
- struct elf_assign_sym_version_info *sinfo;
+ struct elf_info_failed *sinfo;
struct bfd_link_info *info;
const struct elf_backend_data *bed;
struct elf_info_failed eif;
if (!h->def_regular)
return TRUE;
- bed = get_elf_backend_data (sinfo->output_bfd);
+ bed = get_elf_backend_data (info->output_bfd);
p = strchr (h->root.root.string, ELF_VER_CHR);
if (p != NULL && h->verinfo.vertree == NULL)
{
return TRUE;
amt = sizeof *t;
- t = bfd_zalloc (sinfo->output_bfd, amt);
+ t = bfd_zalloc (info->output_bfd, amt);
if (t == NULL)
{
sinfo->failed = TRUE;
generating a shared archive. Return an error. */
(*_bfd_error_handler)
(_("%B: version node not found for symbol %s"),
- sinfo->output_bfd, h->root.root.string);
+ info->output_bfd, h->root.root.string);
bfd_set_error (bfd_error_bad_value);
sinfo->failed = TRUE;
return FALSE;
something. */
if (h->verinfo.vertree == NULL && sinfo->verdefs != NULL)
{
- struct bfd_elf_version_tree *t;
- struct bfd_elf_version_tree *local_ver;
- struct bfd_elf_version_expr *d;
-
- /* See if can find what version this symbol is in. If the
- symbol is supposed to be local, then don't actually register
- it. */
- local_ver = NULL;
- for (t = sinfo->verdefs; t != NULL; t = t->next)
- {
- if (t->globals.list != NULL)
- {
- bfd_boolean matched;
-
- matched = FALSE;
- d = NULL;
- while ((d = (*t->match) (&t->globals, d,
- h->root.root.string)) != NULL)
- if (d->symver)
- matched = TRUE;
- else
- {
- /* There is a version without definition. Make
- the symbol the default definition for this
- version. */
- h->verinfo.vertree = t;
- local_ver = NULL;
- d->script = 1;
- break;
- }
- if (d != NULL)
- break;
- else if (matched)
- /* There is no undefined version for this symbol. Hide the
- default one. */
- (*bed->elf_backend_hide_symbol) (info, h, TRUE);
- }
+ bfd_boolean hide;
- if (t->locals.list != NULL)
- {
- d = NULL;
- while ((d = (*t->match) (&t->locals, d,
- h->root.root.string)) != NULL)
- {
- local_ver = t;
- /* If the match is "*", keep looking for a more
- explicit, perhaps even global, match.
- XXX: Shouldn't this be !d->wildcard instead? */
- if (d->pattern[0] != '*' || d->pattern[1] != '\0')
- break;
- }
-
- if (d != NULL)
- break;
- }
- }
-
- if (local_ver != NULL)
- {
- h->verinfo.vertree = local_ver;
- if (h->dynindx != -1
- && ! info->export_dynamic)
- {
- (*bed->elf_backend_hide_symbol) (info, h, TRUE);
- }
- }
+ h->verinfo.vertree = find_version_for_sym (sinfo->verdefs,
+ h->root.root.string, &hide);
+ if (h->verinfo.vertree != NULL && hide)
+ (*bed->elf_backend_hide_symbol) (info, h, TRUE);
}
return TRUE;
size = o->reloc_count;
size *= bed->s->int_rels_per_ext_rel * sizeof (Elf_Internal_Rela);
if (keep_memory)
- internal_relocs = bfd_alloc (abfd, size);
+ internal_relocs = alloc2 = bfd_alloc (abfd, size);
else
internal_relocs = alloc2 = bfd_malloc (size);
if (internal_relocs == NULL)
if (alloc1 != NULL)
free (alloc1);
if (alloc2 != NULL)
- free (alloc2);
+ {
+ if (keep_memory)
+ bfd_release (abfd, alloc2);
+ else
+ free (alloc2);
+ }
return NULL;
}
/* Compute the size of, and allocate space for, REL_HDR which is the
section header for a section containing relocations for O. */
-bfd_boolean
+static bfd_boolean
_bfd_elf_link_size_reloc_section (bfd *abfd,
Elf_Internal_Shdr *rel_hdr,
asection *o)
(*_bfd_error_handler)
(_("%B: relocation size mismatch in %B section %A"),
output_bfd, input_section->owner, input_section);
- bfd_set_error (bfd_error_wrong_object_format);
+ bfd_set_error (bfd_error_wrong_format);
return FALSE;
}
assign_sym_version, which is unnecessary but perhaps more robust in
the face of future changes. */
-bfd_boolean
+static bfd_boolean
_bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h,
struct elf_info_failed *eif)
{
called via elf_link_hash_traverse, and also calls itself
recursively. */
-bfd_boolean
+static bfd_boolean
_bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data)
{
struct elf_info_failed *eif = data;
dynobj = elf_hash_table (eif->info)->dynobj;
bed = get_elf_backend_data (dynobj);
+
if (! (*bed->elf_backend_adjust_dynamic_symbol) (eif->info, h))
{
eif->failed = TRUE;
/* Adjust all external symbols pointing into SEC_MERGE sections
to reflect the object merging within the sections. */
-bfd_boolean
+static bfd_boolean
_bfd_elf_link_sec_merge_syms (struct elf_link_hash_entry *h, void *data)
{
asection *sec;
if (h == NULL)
return TRUE;
+ /* STV_HIDDEN or STV_INTERNAL ones must be local. */
+ if (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
+ || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL)
+ return TRUE;
+
/* Common symbols that become definitions don't get the DEF_REGULAR
flag set, so test it first, and don't bail out. */
if (ELF_COMMON_DEF_P (h))
if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
return FALSE;
- /* However, STV_HIDDEN or STV_INTERNAL ones must be local. */
- 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;
return 0;
}
+static bfd_boolean
+on_needed_list (const char *soname, struct bfd_link_needed_list *needed)
+{
+ for (; needed != NULL; needed = needed->next)
+ if (strcmp (soname, needed->name) == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
/* Sort symbol by value and section. */
static int
elf_sort_symbol (const void *arg1, const void *arg2)
return TRUE;
}
\f
+/* Return TRUE iff relocations for INPUT are compatible with OUTPUT.
+ The default is to only match when the INPUT and OUTPUT are exactly
+ the same target. */
+
+bfd_boolean
+_bfd_elf_default_relocs_compatible (const bfd_target *input,
+ const bfd_target *output)
+{
+ return input == output;
+}
+
+/* Return TRUE iff relocations for INPUT are compatible with OUTPUT.
+ This version is used when different targets for the same architecture
+ are virtually identical. */
+
+bfd_boolean
+_bfd_elf_relocs_compatible (const bfd_target *input,
+ const bfd_target *output)
+{
+ const struct elf_backend_data *obed, *ibed;
+
+ if (input == output)
+ return TRUE;
+
+ ibed = xvec_get_elf_backend_data (input);
+ obed = xvec_get_elf_backend_data (output);
+
+ if (ibed->arch != obed->arch)
+ return FALSE;
+
+ /* If both backends are using this function, deem them compatible. */
+ return ibed->relocs_compatible == obed->relocs_compatible;
+}
+
/* Add symbols from an ELF object file to the linker hash table. */
static bfd_boolean
the format of the output file. */
if (info->relocatable
|| !is_elf_hash_table (htab)
- || htab->root.creator != abfd->xvec)
+ || info->output_bfd->xvec != abfd->xvec)
{
if (info->relocatable)
bfd_set_error (bfd_error_invalid_operation);
format as the output, we can't make a shared library. */
if (info->shared
&& is_elf_hash_table (htab)
- && htab->root.creator == abfd->xvec
+ && info->output_bfd->xvec == abfd->xvec
&& !htab->dynamic_sections_created)
{
if (! _bfd_elf_link_create_dynamic_sections (abfd, info))
{
bfd_byte *dynbuf;
bfd_byte *extdyn;
- int elfsec;
+ unsigned int elfsec;
unsigned long shlink;
if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
goto error_free_dyn;
elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
- if (elfsec == -1)
+ if (elfsec == SHN_BAD)
goto error_free_dyn;
shlink = elf_elfsections (abfd)[elfsec]->sh_link;
if (isym->st_shndx == SHN_UNDEF)
sec = bfd_und_section_ptr;
- else if (isym->st_shndx < SHN_LORESERVE
- || isym->st_shndx > SHN_HIRESERVE)
+ else if (isym->st_shndx == SHN_ABS)
+ sec = bfd_abs_section_ptr;
+ else if (isym->st_shndx == SHN_COMMON)
+ {
+ sec = bfd_com_section_ptr;
+ /* What ELF calls the size we call the value. What ELF
+ calls the value we call the alignment. */
+ value = isym->st_size;
+ }
+ else
{
sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
if (sec == NULL)
else if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0)
value -= sec->vma;
}
- else if (isym->st_shndx == SHN_ABS)
- sec = bfd_abs_section_ptr;
- else if (isym->st_shndx == SHN_COMMON)
- {
- sec = bfd_com_section_ptr;
- /* What ELF calls the size we call the value. What ELF
- calls the value we call the alignment. */
- value = isym->st_size;
- }
- else
- {
- /* Leave it up to the processor backend. */
- }
name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
isym->st_name);
h->type = ELF_ST_TYPE (isym->st_info);
}
- /* If st_other has a processor-specific meaning, specific
- code might be needed here. We never merge the visibility
- attribute with the one from a dynamic object. */
- if (bed->elf_backend_merge_symbol_attribute)
- (*bed->elf_backend_merge_symbol_attribute) (h, isym, definition,
- dynamic);
-
- /* If this symbol has default visibility and the user has requested
- we not re-export it, then mark it as hidden. */
- if (definition && !dynamic
- && (abfd->no_export
- || (abfd->my_archive && abfd->my_archive->no_export))
- && ELF_ST_VISIBILITY (isym->st_other) != STV_INTERNAL)
- isym->st_other = (STV_HIDDEN
- | (isym->st_other & ~ELF_ST_VISIBILITY (-1)));
-
- if (ELF_ST_VISIBILITY (isym->st_other) != 0 && !dynamic)
- {
- unsigned char hvis, symvis, other, nvis;
-
- /* Only merge the visibility. Leave the remainder of the
- st_other field to elf_backend_merge_symbol_attribute. */
- other = h->other & ~ELF_ST_VISIBILITY (-1);
-
- /* Combine visibilities, using the most constraining one. */
- hvis = ELF_ST_VISIBILITY (h->other);
- symvis = ELF_ST_VISIBILITY (isym->st_other);
- if (! hvis)
- nvis = symvis;
- else if (! symvis)
- nvis = hvis;
- else
- nvis = hvis < symvis ? hvis : symvis;
-
- h->other = other | nvis;
- }
+ /* Merge st_other field. */
+ elf_merge_st_other (abfd, h, isym, definition, dynamic);
/* Set a flag in the hash table entry indicating the type of
reference or definition we just found. Keep a count of
h->ref_regular_nonweak = 1;
}
else
- h->def_regular = 1;
+ {
+ h->def_regular = 1;
+ if (h->def_dynamic)
+ {
+ h->def_dynamic = 0;
+ h->ref_dynamic = 1;
+ h->dynamic_def = 1;
+ }
+ }
if (! info->executable
|| h->def_dynamic
|| h->ref_dynamic)
dynsym = TRUE;
}
- if (definition && (sec->flags & SEC_DEBUGGING))
+ if (definition && (sec->flags & SEC_DEBUGGING) && !info->relocatable)
{
/* We don't want to make debug symbol dynamic. */
(*bed->elf_backend_hide_symbol) (info, h, TRUE);
if (!add_needed
&& definition
- && dynsym
- && h->ref_regular)
+ && ((dynsym
+ && h->ref_regular)
+ || (h->ref_dynamic
+ && (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0
+ && !on_needed_list (elf_dt_name (abfd), htab->needed))))
{
int ret;
const char *soname = elf_dt_name (abfd);
if (hlook->dynindx != -1 && h->dynindx == -1)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
- goto error_return;
+ {
+ err_free_sym_hash:
+ free (sorted_sym_hash);
+ goto error_return;
+ }
}
/* If the real definition is in the list of dynamic
if (h->dynindx != -1 && hlook->dynindx == -1)
{
if (! bfd_elf_link_record_dynamic_symbol (info, hlook))
- goto error_return;
+ goto err_free_sym_hash;
}
break;
}
free (sorted_sym_hash);
}
- if (bed->check_directives)
- (*bed->check_directives) (abfd, info);
+ if (bed->check_directives
+ && !(*bed->check_directives) (abfd, info))
+ return FALSE;
/* If this object is the same format as the output object, and it is
not a shared library, then let the backend look through the
different format. It probably can't be done. */
if (! dynamic
&& is_elf_hash_table (htab)
- && htab->root.creator == abfd->xvec
- && bed->check_relocs != NULL)
+ && bed->check_relocs != NULL
+ && (*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
{
asection *o;
Therefore the result is always a good payoff between few collisions
(= short chain lengths) and table size. */
static size_t
-compute_bucket_count (struct bfd_link_info *info, unsigned long int *hashcodes,
- unsigned long int nsyms, int gnu_hash)
+compute_bucket_count (struct bfd_link_info *info,
+ unsigned long int *hashcodes ATTRIBUTE_UNUSED,
+ unsigned long int nsyms,
+ int gnu_hash)
{
- size_t dynsymcount = elf_hash_table (info)->dynsymcount;
size_t best_size = 0;
unsigned long int i;
- bfd_size_type amt;
/* We have a problem here. The following code to optimize the table
size requires an integer type with more the 32 bits. If
size_t maxsize;
BFD_HOST_U_64_BIT best_chlen = ~((BFD_HOST_U_64_BIT) 0);
bfd *dynobj = elf_hash_table (info)->dynobj;
+ size_t dynsymcount = elf_hash_table (info)->dynsymcount;
const struct elf_backend_data *bed = get_elf_backend_data (dynobj);
unsigned long int *counts;
+ bfd_size_type amt;
/* Possible optimization parameters: if we have NSYMS symbols we say
that the hashing table must at least have NSYMS/4 and at most
bfd_size_type soname_indx;
bfd *dynobj;
const struct elf_backend_data *bed;
- struct elf_assign_sym_version_info asvinfo;
+ struct elf_info_failed asvinfo;
*sinterpptr = NULL;
{
asection *s;
- if (inputobj->flags & (DYNAMIC | BFD_LINKER_CREATED))
+ if (inputobj->flags & (DYNAMIC | EXEC_P | BFD_LINKER_CREATED))
continue;
s = bfd_get_section_by_name (inputobj, ".note.GNU-stack");
if (s)
/* Make all global versions with definition. */
for (t = verdefs; t != NULL; t = t->next)
for (d = t->globals.list; d != NULL; d = d->next)
- if (!d->symver && d->symbol)
+ if (!d->symver && d->literal)
{
const char *verstr, *name;
size_t namelen, verlen, newlen;
char *newname, *p;
struct elf_link_hash_entry *newh;
- name = d->symbol;
+ name = d->pattern;
namelen = strlen (name);
verstr = t->name;
verlen = strlen (verstr);
}
/* Attach all the symbols to their version information. */
- asvinfo.output_bfd = output_bfd;
asvinfo.info = info;
asvinfo.verdefs = verdefs;
asvinfo.failed = FALSE;
all_defined = TRUE;
for (t = verdefs; t != NULL; t = t->next)
for (d = t->globals.list; d != NULL; d = d->next)
- if (!d->symver && !d->script)
+ if (d->literal && !d->symver && !d->script)
{
(*_bfd_error_handler)
(_("%s: undefined version: %s"),
{
struct elf_find_verdep_info sinfo;
- sinfo.output_bfd = output_bfd;
sinfo.info = info;
sinfo.vers = elf_tdata (output_bfd)->cverdefs;
if (sinfo.vers == 0)
{
asection *s;
+ /* Data first, since setting text_index_section changes
+ _bfd_elf_link_omit_section_dynsym. */
for (s = output_bfd->sections; s != NULL; s = s->next)
- if (((s->flags & (SEC_EXCLUDE | SEC_ALLOC | SEC_READONLY))
- == (SEC_ALLOC | SEC_READONLY))
+ if (((s->flags & (SEC_EXCLUDE | SEC_ALLOC | SEC_READONLY)) == SEC_ALLOC)
&& !_bfd_elf_link_omit_section_dynsym (output_bfd, info, s))
{
- elf_hash_table (info)->text_index_section = s;
+ elf_hash_table (info)->data_index_section = s;
break;
}
for (s = output_bfd->sections; s != NULL; s = s->next)
- if (((s->flags & (SEC_EXCLUDE | SEC_ALLOC | SEC_READONLY)) == SEC_ALLOC)
+ if (((s->flags & (SEC_EXCLUDE | SEC_ALLOC | SEC_READONLY))
+ == (SEC_ALLOC | SEC_READONLY))
&& !_bfd_elf_link_omit_section_dynsym (output_bfd, info, s))
{
- elf_hash_table (info)->data_index_section = s;
+ elf_hash_table (info)->text_index_section = s;
break;
}
elf_link_hash_traverse (elf_hash_table (info),
elf_collect_hash_codes, &hashinf);
if (hashinf.error)
- return FALSE;
+ {
+ free (hashcodes);
+ return FALSE;
+ }
nsyms = hashinf.hashcodes - hashcodes;
bucketcount
elf_link_hash_traverse (elf_hash_table (info),
elf_collect_gnu_hash_codes, &cinfo);
if (cinfo.error)
- return FALSE;
+ {
+ free (cinfo.hashcodes);
+ return FALSE;
+ }
bucketcount
= compute_bucket_count (info, cinfo.hashcodes, cinfo.nsyms, 1);
{
asection *s;
bfd_byte *dynbuf = NULL;
- int elfsec;
+ unsigned int elfsec;
unsigned long shlink;
bfd_byte *extdyn, *extdynend;
size_t extdynsize;
goto error_return;
elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
- if (elfsec == -1)
+ if (elfsec == SHN_BAD)
goto error_return;
shlink = elf_elfsections (abfd)[elfsec]->sh_link;
Elf_Internal_Sym **ind, **indbufend, **indbuf;
struct elf_symbuf_symbol *ssym;
struct elf_symbuf_head *ssymbuf, *ssymhead;
- bfd_size_type i, shndx_count;
+ bfd_size_type i, shndx_count, total_size;
indbuf = bfd_malloc2 (symcount, sizeof (*indbuf));
if (indbuf == NULL)
if (ind[0]->st_shndx != ind[1]->st_shndx)
shndx_count++;
- ssymbuf = bfd_malloc ((shndx_count + 1) * sizeof (*ssymbuf)
- + (indbufend - indbuf) * sizeof (*ssymbuf));
+ total_size = ((shndx_count + 1) * sizeof (*ssymbuf)
+ + (indbufend - indbuf) * sizeof (*ssym));
+ ssymbuf = bfd_malloc (total_size);
if (ssymbuf == NULL)
{
free (indbuf);
return NULL;
}
- ssym = (struct elf_symbuf_symbol *) (ssymbuf + shndx_count);
+ ssym = (struct elf_symbuf_symbol *) (ssymbuf + shndx_count + 1);
ssymbuf->ssym = NULL;
ssymbuf->count = shndx_count;
ssymbuf->st_shndx = 0;
ssym->st_other = (*ind)->st_other;
ssymhead->count++;
}
- BFD_ASSERT ((bfd_size_type) (ssymhead - ssymbuf) == shndx_count);
+ BFD_ASSERT ((bfd_size_type) (ssymhead - ssymbuf) == shndx_count
+ && (((bfd_hostptr_t) ssym - (bfd_hostptr_t) ssymbuf)
+ == total_size));
free (indbuf);
return ssymbuf;
/* Check if 2 sections define the same set of local and global
symbols. */
-bfd_boolean
+static bfd_boolean
bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2,
struct bfd_link_info *info)
{
Elf_Internal_Sym *isym, *isymend;
struct elf_symbol *symtable1 = NULL, *symtable2 = NULL;
bfd_size_type count1, count2, i;
- int shndx1, shndx2;
+ unsigned 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)
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)
+ if (shndx1 == SHN_BAD || shndx2 == SHN_BAD)
return FALSE;
bed1 = get_elf_backend_data (bfd1);
while (lo < hi)
{
mid = (lo + hi) / 2;
- if ((unsigned int) shndx1 < ssymbuf1[mid].st_shndx)
+ if (shndx1 < ssymbuf1[mid].st_shndx)
hi = mid;
- else if ((unsigned int) shndx1 > ssymbuf1[mid].st_shndx)
+ else if (shndx1 > ssymbuf1[mid].st_shndx)
lo = mid + 1;
else
{
while (lo < hi)
{
mid = (lo + hi) / 2;
- if ((unsigned int) shndx2 < ssymbuf2[mid].st_shndx)
+ if (shndx2 < ssymbuf2[mid].st_shndx)
hi = mid;
- else if ((unsigned int) shndx2 > ssymbuf2[mid].st_shndx)
+ else if (shndx2 > ssymbuf2[mid].st_shndx)
lo = mid + 1;
else
{
/* Count definitions in the section. */
count1 = 0;
for (isym = isymbuf1, isymend = isym + symcount1; isym < isymend; isym++)
- if (isym->st_shndx == (unsigned int) shndx1)
+ if (isym->st_shndx == shndx1)
symtable1[count1++].u.isym = isym;
count2 = 0;
for (isym = isymbuf2, isymend = isym + symcount2; isym < isymend; isym++)
- if (isym->st_shndx == (unsigned int) shndx2)
+ if (isym->st_shndx == shndx2)
symtable2[count2++].u.isym = isym;
if (count1 == 0 || count2 == 0 || count1 != count2)
* trunc_p = (encoded >> 29) & 1;
}
-void
+bfd_reloc_status_type
bfd_elf_perform_complex_relocation (bfd *input_bfd,
- asection *input_section,
+ asection *input_section ATTRIBUTE_UNUSED,
bfd_byte *contents,
Elf_Internal_Rela *rel,
bfd_vma relocation)
{
bfd_vma shift, x, mask;
unsigned long start, oplen, len, wordsz, chunksz, lsb0_p, signed_p, trunc_p;
+ bfd_reloc_status_type r;
/* Perform this reloc, since it is complex.
(this is not to say that it necessarily refers to a complex
oplen, x, mask, relocation);
#endif
+ r = bfd_reloc_ok;
if (! trunc_p)
- {
- /* Now do an overflow check. */
- if (bfd_check_overflow ((signed_p
- ? complain_overflow_signed
- : complain_overflow_unsigned),
- len, 0, (8 * wordsz),
- relocation) == bfd_reloc_overflow)
- (*_bfd_error_handler)
- ("%s (%s + 0x%lx): relocation overflow: 0x%lx %sdoes not fit "
- "within 0x%lx",
- input_bfd->filename, input_section->name, rel->r_offset,
- relocation, (signed_p ? "(signed) " : ""), mask);
- }
+ /* Now do an overflow check. */
+ r = bfd_check_overflow ((signed_p
+ ? complain_overflow_signed
+ : complain_overflow_unsigned),
+ len, 0, (8 * wordsz),
+ relocation);
/* Do the deed. */
x = (x & ~(mask << shift)) | ((relocation & mask) << shift);
((relocation & mask) << shift), x);
#endif
put_value (wordsz, chunksz, input_bfd, x, contents + rel->r_offset);
+ return r;
}
/* When performing a relocatable link, the input relocations are
bfd_size_type amt;
amt = finfo->shndxbuf_size * sizeof (Elf_External_Sym_Shndx);
- finfo->symshndxbuf = destshndx = bfd_realloc (destshndx, amt * 2);
+ destshndx = bfd_realloc (destshndx, amt * 2);
if (destshndx == NULL)
return FALSE;
+ finfo->symshndxbuf = destshndx;
memset ((char *) destshndx + amt, 0, amt);
finfo->shndxbuf_size *= 2;
}
static bfd_boolean
check_dynsym (bfd *abfd, Elf_Internal_Sym *sym)
{
- if (sym->st_shndx > SHN_HIRESERVE)
+ if (sym->st_shndx >= (SHN_LORESERVE & 0xffff)
+ && sym->st_shndx < SHN_LORESERVE)
{
/* The gABI doesn't support dynamic symbols in output sections
beyond 64k. */
(*_bfd_error_handler)
(_("%B: Too many sections: %d (>= %d)"),
- abfd, bfd_count_sections (abfd), SHN_LORESERVE);
+ abfd, bfd_count_sections (abfd), SHN_LORESERVE & 0xffff);
bfd_set_error (bfd_error_nonrepresentable_section);
return FALSE;
}
sym.st_value += input_sec->output_section->vma;
if (h->type == STT_TLS)
{
- /* STT_TLS symbols are relative to PT_TLS segment
- base. */
- BFD_ASSERT (elf_hash_table (finfo->info)->tls_sec != NULL);
- sym.st_value -= elf_hash_table (finfo->info)->tls_sec->vma;
+ asection *tls_sec = elf_hash_table (finfo->info)->tls_sec;
+ if (tls_sec != NULL)
+ sym.st_value -= tls_sec->vma;
+ else
+ {
+ /* The TLS section may have been garbage collected. */
+ BFD_ASSERT (finfo->info->gc_sections
+ && !input_sec->gc_mark);
+ }
}
}
}
sym.st_info = ELF_ST_INFO (bindtype, ELF_ST_TYPE (sym.st_info));
}
+ /* If this is a symbol defined in a dynamic library, don't use the
+ symbol size from the dynamic library. Relinking an executable
+ against a new library may introduce gratuitous changes in the
+ executable's symbols if we keep the size. */
+ if (sym.st_shndx == SHN_UNDEF
+ && !h->def_regular
+ && h->def_dynamic)
+ sym.st_size = 0;
+
/* If a non-weak symbol with non-default visibility is not defined
locally, it is a fatal error. */
if (! finfo->info->relocatable
{
if ((kept->flags & SEC_GROUP) != 0)
kept = match_group_member (sec, kept, info);
- if (kept != NULL && sec->size != kept->size)
+ if (kept != NULL
+ && ((sec->rawsize != 0 ? sec->rawsize : sec->size)
+ != (kept->rawsize != 0 ? kept->rawsize : kept->size)))
kept = NULL;
sec->kept_section = kept;
}
if (isym->st_shndx == SHN_UNDEF)
isec = bfd_und_section_ptr;
- else if (isym->st_shndx < SHN_LORESERVE
- || isym->st_shndx > SHN_HIRESERVE)
+ else if (isym->st_shndx == SHN_ABS)
+ isec = bfd_abs_section_ptr;
+ else if (isym->st_shndx == SHN_COMMON)
+ isec = bfd_com_section_ptr;
+ else
{
isec = bfd_section_from_elf_index (input_bfd, isym->st_shndx);
- if (isec
- && isec->sec_info_type == ELF_INFO_TYPE_MERGE
- && ELF_ST_TYPE (isym->st_info) != STT_SECTION)
+ if (isec == NULL)
+ {
+ /* Don't attempt to output symbols with st_shnx in the
+ reserved range other than SHN_ABS and SHN_COMMON. */
+ *ppsection = NULL;
+ continue;
+ }
+ else if (isec->sec_info_type == ELF_INFO_TYPE_MERGE
+ && ELF_ST_TYPE (isym->st_info) != STT_SECTION)
isym->st_value =
_bfd_merged_section_offset (output_bfd, &isec,
elf_section_data (isec)->sec_info,
isym->st_value);
}
- else if (isym->st_shndx == SHN_ABS)
- isec = bfd_abs_section_ptr;
- else if (isym->st_shndx == SHN_COMMON)
- isec = bfd_com_section_ptr;
- else
- {
- /* Don't attempt to output symbols with st_shnx in the
- reserved range other than SHN_ABS and SHN_COMMON. */
- *ppsection = NULL;
- continue;
- }
*ppsection = isec;
/* If this symbol is defined in a section which we are
discarding, we don't need to keep it. */
if (isym->st_shndx != SHN_UNDEF
- && (isym->st_shndx < SHN_LORESERVE || isym->st_shndx > SHN_HIRESERVE)
- && (isec == NULL
- || bfd_section_removed_from_list (output_bfd,
- isec->output_section)))
+ && isym->st_shndx < SHN_LORESERVE
+ && bfd_section_removed_from_list (output_bfd,
+ isec->output_section))
continue;
/* Get the name of the symbol. */
continue;
}
+ if (finfo->info->relocatable
+ && (o->flags & (SEC_LINKER_CREATED | SEC_GROUP)) == SEC_GROUP)
+ {
+ /* Deal with the group signature symbol. */
+ struct bfd_elf_section_data *sec_data = elf_section_data (o);
+ unsigned long symndx = sec_data->this_hdr.sh_info;
+ asection *osec = o->output_section;
+
+ if (symndx >= locsymcount
+ || (elf_bad_symtab (input_bfd)
+ && finfo->sections[symndx] == NULL))
+ {
+ struct elf_link_hash_entry *h = sym_hashes[symndx - extsymoff];
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ /* Arrange for symbol to be output. */
+ h->indx = -2;
+ elf_section_data (osec)->this_hdr.sh_info = -2;
+ }
+ else if (ELF_ST_TYPE (isymbuf[symndx].st_info) == STT_SECTION)
+ {
+ /* We'll use the output section target_index. */
+ asection *sec = finfo->sections[symndx]->output_section;
+ elf_section_data (osec)->this_hdr.sh_info = sec->target_index;
+ }
+ else
+ {
+ if (finfo->indices[symndx] == -1)
+ {
+ /* Otherwise output the local symbol now. */
+ Elf_Internal_Sym sym = isymbuf[symndx];
+ asection *sec = finfo->sections[symndx]->output_section;
+ const char *name;
+
+ name = bfd_elf_string_from_elf_section (input_bfd,
+ symtab_hdr->sh_link,
+ sym.st_name);
+ if (name == NULL)
+ return FALSE;
+
+ sym.st_shndx = _bfd_elf_section_from_bfd_section (output_bfd,
+ sec);
+ if (sym.st_shndx == SHN_BAD)
+ return FALSE;
+
+ sym.st_value += o->output_offset;
+
+ finfo->indices[symndx] = bfd_get_symcount (output_bfd);
+ if (! elf_link_output_sym (finfo, name, &sym, o, NULL))
+ return FALSE;
+ }
+ elf_section_data (osec)->this_hdr.sh_info
+ = finfo->indices[symndx];
+ }
+ }
+
if ((o->flags & SEC_HAS_CONTENTS) == 0
|| (o->size == 0 && (o->flags & SEC_RELOC) == 0))
continue;
default:
{
if (! (o->flags & SEC_EXCLUDE)
+ && ! (o->output_section->flags & SEC_NEVER_LOAD)
&& ! bfd_set_section_contents (output_bfd, o->output_section,
contents,
(file_ptr) o->output_offset,
&& elf_elfheader (sub)->e_ident[EI_CLASS] == bed->s->elfclass
&& (elfsec = _bfd_elf_section_from_bfd_section (sub, s))
&& elfsec < elf_numsections (sub)
- && elf_elfsections (sub)[elfsec]->sh_flags & SHF_LINK_ORDER)
+ && elf_elfsections (sub)[elfsec]->sh_flags & SHF_LINK_ORDER
+ && elf_elfsections (sub)[elfsec]->sh_link < elf_numsections (sub))
{
seen_linkorder++;
linkorder_sec = s;
offset += sections[n]->size;
}
+ free (sections);
return TRUE;
}
if (info->relocatable || info->emitrelocations)
reloc_count = sec->reloc_count;
else if (bed->elf_backend_count_relocs)
- {
- Elf_Internal_Rela * relocs;
-
- relocs = _bfd_elf_link_read_relocs (sec->owner, sec,
- NULL, NULL,
- info->keep_memory);
-
- if (relocs != NULL)
- {
- reloc_count
- = (*bed->elf_backend_count_relocs) (sec, relocs);
-
- if (elf_section_data (sec)->relocs != relocs)
- free (relocs);
- }
- }
+ reloc_count = (*bed->elf_backend_count_relocs) (info, sec);
if (sec->rawsize > max_contents_size)
max_contents_size = sec->rawsize;
bfd_size_type entsize1;
entsize1 = esdi->rel_hdr.sh_entsize;
- BFD_ASSERT (entsize1 == bed->s->sizeof_rel
- || entsize1 == bed->s->sizeof_rela);
+ /* PR 9827: If the header size has not been set yet then
+ assume that it will match the output section's reloc type. */
+ if (entsize1 == 0)
+ entsize1 = o->use_rela_p ? bed->s->sizeof_rela : bed->s->sizeof_rel;
+ else
+ BFD_ASSERT (entsize1 == bed->s->sizeof_rel
+ || entsize1 == bed->s->sizeof_rela);
same_size = !o->use_rela_p == (entsize1 == bed->s->sizeof_rel);
if (!same_size)
/* sh_link is set in assign_section_numbers. */
/* sh_info is set below. */
/* sh_offset is set just below. */
- symtab_hdr->sh_addralign = 1 << bed->s->log_file_align;
+ symtab_hdr->sh_addralign = (bfd_vma) 1 << bed->s->log_file_align;
off = elf_tdata (abfd)->next_file_pos;
off = _bfd_elf_assign_file_position_for_section (symtab_hdr, off, TRUE);
finfo.symbuf = bfd_malloc (amt);
if (finfo.symbuf == NULL)
goto error_return;
- if (elf_numsections (abfd) > SHN_LORESERVE)
+ if (elf_numsections (abfd) > (SHN_LORESERVE & 0xFFFF))
{
/* Wild guess at number of output symbols. realloc'd as needed. */
amt = 2 * max_sym_count + elf_numsections (abfd) + 1000;
if (!elf_link_output_sym (&finfo, NULL, &elfsym, o, NULL))
goto error_return;
}
- if (i == SHN_LORESERVE - 1)
- i += SHN_HIRESERVE + 1 - SHN_LORESERVE;
}
}
the original st_name with the dynstr_index. */
sym = e->isym;
- if (e->isym.st_shndx != SHN_UNDEF
- && (e->isym.st_shndx < SHN_LORESERVE
- || e->isym.st_shndx > SHN_HIRESERVE))
+ s = bfd_section_from_elf_index (e->input_bfd,
+ e->isym.st_shndx);
+ if (s != NULL)
{
- s = bfd_section_from_elf_index (e->input_bfd,
- e->isym.st_shndx);
-
sym.st_shndx =
elf_section_data (s->output_section)->this_idx;
if (! check_dynsym (abfd, &sym))
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak))
{
- dyn.d_un.d_val = h->root.u.def.value;
+ dyn.d_un.d_ptr = h->root.u.def.value;
o = h->root.u.def.section;
if (o->output_section != NULL)
- dyn.d_un.d_val += (o->output_section->vma
+ dyn.d_un.d_ptr += (o->output_section->vma
+ o->output_offset);
else
{
/* The symbol is imported from another shared
library and does not apply to this one. */
- dyn.d_un.d_val = 0;
+ dyn.d_un.d_ptr = 0;
}
break;
}
else
type = SHT_RELA;
dyn.d_un.d_val = 0;
+ dyn.d_un.d_ptr = 0;
for (i = 1; i < elf_numsections (abfd); i++)
{
Elf_Internal_Shdr *hdr;
dyn.d_un.d_val += hdr->sh_size;
else
{
- if (dyn.d_un.d_val == 0
- || hdr->sh_addr < dyn.d_un.d_val)
- dyn.d_un.d_val = hdr->sh_addr;
+ if (dyn.d_un.d_ptr == 0
+ || hdr->sh_addr < dyn.d_un.d_ptr)
+ dyn.d_un.d_ptr = hdr->sh_addr;
}
}
}
return FALSE;
}
\f
+/* Initialize COOKIE for input bfd ABFD. */
+
+static bfd_boolean
+init_reloc_cookie (struct elf_reloc_cookie *cookie,
+ struct bfd_link_info *info, bfd *abfd)
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ const struct elf_backend_data *bed;
+
+ bed = get_elf_backend_data (abfd);
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+
+ cookie->abfd = abfd;
+ cookie->sym_hashes = elf_sym_hashes (abfd);
+ cookie->bad_symtab = elf_bad_symtab (abfd);
+ if (cookie->bad_symtab)
+ {
+ cookie->locsymcount = symtab_hdr->sh_size / bed->s->sizeof_sym;
+ cookie->extsymoff = 0;
+ }
+ else
+ {
+ cookie->locsymcount = symtab_hdr->sh_info;
+ cookie->extsymoff = symtab_hdr->sh_info;
+ }
+
+ if (bed->s->arch_size == 32)
+ cookie->r_sym_shift = 8;
+ else
+ cookie->r_sym_shift = 32;
+
+ cookie->locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (cookie->locsyms == NULL && cookie->locsymcount != 0)
+ {
+ cookie->locsyms = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+ cookie->locsymcount, 0,
+ NULL, NULL, NULL);
+ if (cookie->locsyms == NULL)
+ {
+ info->callbacks->einfo (_("%P%X: can not read symbols: %E\n"));
+ return FALSE;
+ }
+ if (info->keep_memory)
+ symtab_hdr->contents = (bfd_byte *) cookie->locsyms;
+ }
+ return TRUE;
+}
+
+/* Free the memory allocated by init_reloc_cookie, if appropriate. */
+
+static void
+fini_reloc_cookie (struct elf_reloc_cookie *cookie, bfd *abfd)
+{
+ Elf_Internal_Shdr *symtab_hdr;
+
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ if (cookie->locsyms != NULL
+ && symtab_hdr->contents != (unsigned char *) cookie->locsyms)
+ free (cookie->locsyms);
+}
+
+/* Initialize the relocation information in COOKIE for input section SEC
+ of input bfd ABFD. */
+
+static bfd_boolean
+init_reloc_cookie_rels (struct elf_reloc_cookie *cookie,
+ struct bfd_link_info *info, bfd *abfd,
+ asection *sec)
+{
+ const struct elf_backend_data *bed;
+
+ if (sec->reloc_count == 0)
+ {
+ cookie->rels = NULL;
+ cookie->relend = NULL;
+ }
+ else
+ {
+ bed = get_elf_backend_data (abfd);
+
+ cookie->rels = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
+ info->keep_memory);
+ if (cookie->rels == NULL)
+ return FALSE;
+ cookie->rel = cookie->rels;
+ cookie->relend = (cookie->rels
+ + sec->reloc_count * bed->s->int_rels_per_ext_rel);
+ }
+ cookie->rel = cookie->rels;
+ return TRUE;
+}
+
+/* Free the memory allocated by init_reloc_cookie_rels,
+ if appropriate. */
+
+static void
+fini_reloc_cookie_rels (struct elf_reloc_cookie *cookie,
+ asection *sec)
+{
+ if (cookie->rels && elf_section_data (sec)->relocs != cookie->rels)
+ free (cookie->rels);
+}
+
+/* Initialize the whole of COOKIE for input section SEC. */
+
+static bfd_boolean
+init_reloc_cookie_for_section (struct elf_reloc_cookie *cookie,
+ struct bfd_link_info *info,
+ asection *sec)
+{
+ if (!init_reloc_cookie (cookie, info, sec->owner))
+ goto error1;
+ if (!init_reloc_cookie_rels (cookie, info, sec->owner, sec))
+ goto error2;
+ return TRUE;
+
+ error2:
+ fini_reloc_cookie (cookie, sec->owner);
+ error1:
+ return FALSE;
+}
+
+/* Free the memory allocated by init_reloc_cookie_for_section,
+ if appropriate. */
+
+static void
+fini_reloc_cookie_for_section (struct elf_reloc_cookie *cookie,
+ asection *sec)
+{
+ fini_reloc_cookie_rels (cookie, sec);
+ fini_reloc_cookie (cookie, sec->owner);
+}
+\f
/* Garbage collect unused sections. */
/* Default gc_mark_hook. */
return NULL;
}
+/* COOKIE->rel describes a relocation against section SEC, which is
+ a section we've decided to keep. Return the section that contains
+ the relocation symbol, or NULL if no section contains it. */
+
+asection *
+_bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec,
+ elf_gc_mark_hook_fn gc_mark_hook,
+ struct elf_reloc_cookie *cookie)
+{
+ unsigned long r_symndx;
+ struct elf_link_hash_entry *h;
+
+ r_symndx = cookie->rel->r_info >> cookie->r_sym_shift;
+ if (r_symndx == 0)
+ return NULL;
+
+ if (r_symndx >= cookie->locsymcount
+ || ELF_ST_BIND (cookie->locsyms[r_symndx].st_info) != STB_LOCAL)
+ {
+ h = cookie->sym_hashes[r_symndx - cookie->extsymoff];
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL);
+ }
+
+ return (*gc_mark_hook) (sec, info, cookie->rel, NULL,
+ &cookie->locsyms[r_symndx]);
+}
+
+/* COOKIE->rel describes a relocation against section SEC, which is
+ a section we've decided to keep. Mark the section that contains
+ the relocation symbol. */
+
+bfd_boolean
+_bfd_elf_gc_mark_reloc (struct bfd_link_info *info,
+ asection *sec,
+ elf_gc_mark_hook_fn gc_mark_hook,
+ struct elf_reloc_cookie *cookie)
+{
+ asection *rsec;
+
+ rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie);
+ if (rsec && !rsec->gc_mark)
+ {
+ if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour)
+ rsec->gc_mark = 1;
+ else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
+ return FALSE;
+ }
+ return TRUE;
+}
+
/* The mark phase of garbage collection. For a given section, mark
it and any sections in this section's group, and all the sections
which define symbols to which it refers. */
elf_gc_mark_hook_fn gc_mark_hook)
{
bfd_boolean ret;
- bfd_boolean is_eh;
- asection *group_sec;
+ asection *group_sec, *eh_frame;
sec->gc_mark = 1;
/* Look through the section relocs. */
ret = TRUE;
- is_eh = strcmp (sec->name, ".eh_frame") == 0;
- if ((sec->flags & SEC_RELOC) != 0 && sec->reloc_count > 0)
+ eh_frame = elf_eh_frame_section (sec->owner);
+ if ((sec->flags & SEC_RELOC) != 0
+ && sec->reloc_count > 0
+ && sec != eh_frame)
{
- Elf_Internal_Rela *relstart, *rel, *relend;
- Elf_Internal_Shdr *symtab_hdr;
- struct elf_link_hash_entry **sym_hashes;
- size_t nlocsyms;
- size_t extsymoff;
- bfd *input_bfd = sec->owner;
- const struct elf_backend_data *bed = get_elf_backend_data (input_bfd);
- Elf_Internal_Sym *isym = NULL;
- int r_sym_shift;
-
- symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
- sym_hashes = elf_sym_hashes (input_bfd);
-
- /* Read the local symbols. */
- if (elf_bad_symtab (input_bfd))
- {
- nlocsyms = symtab_hdr->sh_size / bed->s->sizeof_sym;
- extsymoff = 0;
- }
- else
- extsymoff = nlocsyms = symtab_hdr->sh_info;
+ struct elf_reloc_cookie cookie;
- isym = (Elf_Internal_Sym *) symtab_hdr->contents;
- if (isym == NULL && nlocsyms != 0)
+ if (!init_reloc_cookie_for_section (&cookie, info, sec))
+ ret = FALSE;
+ else
{
- isym = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, nlocsyms, 0,
- NULL, NULL, NULL);
- if (isym == NULL)
- return FALSE;
+ for (; cookie.rel < cookie.relend; cookie.rel++)
+ if (!_bfd_elf_gc_mark_reloc (info, sec, gc_mark_hook, &cookie))
+ {
+ ret = FALSE;
+ break;
+ }
+ fini_reloc_cookie_for_section (&cookie, sec);
}
+ }
- /* Read the relocations. */
- relstart = _bfd_elf_link_read_relocs (input_bfd, sec, NULL, NULL,
- info->keep_memory);
- if (relstart == NULL)
- {
- ret = FALSE;
- goto out1;
- }
- relend = relstart + sec->reloc_count * bed->s->int_rels_per_ext_rel;
+ if (ret && eh_frame && elf_fde_list (sec))
+ {
+ struct elf_reloc_cookie cookie;
- if (bed->s->arch_size == 32)
- r_sym_shift = 8;
+ if (!init_reloc_cookie_for_section (&cookie, info, eh_frame))
+ ret = FALSE;
else
- r_sym_shift = 32;
-
- for (rel = relstart; rel < relend; rel++)
- {
- unsigned long r_symndx;
- asection *rsec;
- struct elf_link_hash_entry *h;
-
- r_symndx = rel->r_info >> r_sym_shift;
- if (r_symndx == 0)
- continue;
-
- if (r_symndx >= nlocsyms
- || ELF_ST_BIND (isym[r_symndx].st_info) != STB_LOCAL)
- {
- h = sym_hashes[r_symndx - extsymoff];
- while (h->root.type == bfd_link_hash_indirect
- || h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
- rsec = (*gc_mark_hook) (sec, info, rel, h, NULL);
- }
- else
- {
- rsec = (*gc_mark_hook) (sec, info, rel, NULL, &isym[r_symndx]);
- }
-
- if (rsec && !rsec->gc_mark)
- {
- if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour)
- rsec->gc_mark = 1;
- else if (is_eh)
- rsec->gc_mark_from_eh = 1;
- else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
- {
- ret = FALSE;
- goto out2;
- }
- }
- }
-
- out2:
- if (elf_section_data (sec)->relocs != relstart)
- free (relstart);
- out1:
- if (isym != NULL && symtab_hdr->contents != (unsigned char *) isym)
{
- if (! info->keep_memory)
- free (isym);
- else
- symtab_hdr->contents = (unsigned char *) isym;
+ if (!_bfd_elf_gc_mark_fdes (info, sec, eh_frame,
+ gc_mark_hook, &cookie))
+ ret = FALSE;
+ fini_reloc_cookie_for_section (&cookie, eh_frame);
}
}
for (o = sub->sections; o != NULL; o = o->next)
{
- /* Keep debug and special sections. */
- if ((o->flags & (SEC_DEBUGGING | SEC_LINKER_CREATED)) != 0
- || (o->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0)
- o->gc_mark = 1;
+ /* When any section in a section group is kept, we keep all
+ sections in the section group. If the first member of
+ the section group is excluded, we will also exclude the
+ group section. */
+ if (o->flags & SEC_GROUP)
+ {
+ asection *first = elf_next_in_group (o);
+ o->gc_mark = first->gc_mark;
+ }
+ else if ((o->flags & (SEC_DEBUGGING | SEC_LINKER_CREATED)) != 0
+ || (o->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0)
+ {
+ /* Keep debug and special sections. */
+ o->gc_mark = 1;
+ }
if (o->gc_mark)
continue;
return TRUE;
}
+/* Keep all sections containing symbols undefined on the command-line,
+ and the section containing the entry symbol. */
+
+void
+_bfd_elf_gc_keep (struct bfd_link_info *info)
+{
+ struct bfd_sym_chain *sym;
+
+ for (sym = info->gc_sym_list; sym != NULL; sym = sym->next)
+ {
+ struct elf_link_hash_entry *h;
+
+ h = elf_link_hash_lookup (elf_hash_table (info), sym->name,
+ FALSE, FALSE, FALSE);
+
+ if (h != NULL
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && !bfd_is_abs_section (h->root.u.def.section))
+ h->root.u.def.section->flags |= SEC_KEEP;
+ }
+}
+
/* Do mark and sweep of unused sections. */
bfd_boolean
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
if (!bed->can_gc_sections
- || info->relocatable
- || info->emitrelocations
|| !is_elf_hash_table (info->hash))
{
(*_bfd_error_handler)(_("Warning: gc-sections option ignored"));
return TRUE;
}
+ bed->gc_keep (info);
+
+ /* Try to parse each bfd's .eh_frame section. Point elf_eh_frame_section
+ at the .eh_frame section if we can mark the FDEs individually. */
+ _bfd_elf_begin_eh_frame_parsing (info);
+ for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+ {
+ asection *sec;
+ struct elf_reloc_cookie cookie;
+
+ sec = bfd_get_section_by_name (sub, ".eh_frame");
+ if (sec && init_reloc_cookie_for_section (&cookie, info, sec))
+ {
+ _bfd_elf_parse_eh_frame (sub, info, sec, &cookie);
+ if (elf_section_data (sec)->sec_info)
+ elf_eh_frame_section (sub) = sec;
+ fini_reloc_cookie_for_section (&cookie, sec);
+ }
+ }
+ _bfd_elf_end_eh_frame_parsing (info);
+
/* Apply transitive closure to the vtable entry usage info. */
elf_link_hash_traverse (elf_hash_table (info),
elf_gc_propagate_vtable_entries_used,
/* 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)
- {
- asection *o;
-
- if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
- continue;
-
- /* Keep .gcc_except_table.* if the associated .text.* (or the
- associated .gnu.linkonce.t.* if .text.* doesn't exist) is
- marked. This isn't very nice, but the proper solution,
- splitting .eh_frame up and using comdat doesn't pan out
- easily due to needing special relocs to handle the
- difference of two symbols in separate sections.
- Don't keep code sections referenced by .eh_frame. */
-#define TEXT_PREFIX ".text."
-#define TEXT_PREFIX2 ".gnu.linkonce.t."
-#define GCC_EXCEPT_TABLE_PREFIX ".gcc_except_table."
- for (o = sub->sections; o != NULL; o = o->next)
- if (!o->gc_mark && o->gc_mark_from_eh && (o->flags & SEC_CODE) == 0)
- {
- if (CONST_STRNEQ (o->name, GCC_EXCEPT_TABLE_PREFIX))
- {
- char *fn_name;
- const char *sec_name;
- asection *fn_text;
- unsigned o_name_prefix_len , fn_name_prefix_len, tmp;
-
- o_name_prefix_len = strlen (GCC_EXCEPT_TABLE_PREFIX);
- sec_name = o->name + o_name_prefix_len;
- fn_name_prefix_len = strlen (TEXT_PREFIX);
- tmp = strlen (TEXT_PREFIX2);
- if (tmp > fn_name_prefix_len)
- fn_name_prefix_len = tmp;
- fn_name
- = bfd_malloc (fn_name_prefix_len + strlen (sec_name) + 1);
- if (fn_name == NULL)
- return FALSE;
-
- /* Try the first prefix. */
- sprintf (fn_name, "%s%s", TEXT_PREFIX, sec_name);
- fn_text = bfd_get_section_by_name (sub, fn_name);
-
- /* Try the second prefix. */
- if (fn_text == NULL)
- {
- sprintf (fn_name, "%s%s", TEXT_PREFIX2, sec_name);
- fn_text = bfd_get_section_by_name (sub, fn_name);
- }
-
- free (fn_name);
- if (fn_text == NULL || !fn_text->gc_mark)
- continue;
- }
-
- /* If not using specially named exception table section,
- then keep whatever we are using. */
- if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
- return FALSE;
- }
- }
+ bed->gc_mark_extra_sections (info, gc_mark_hook);
/* ... and mark SEC_EXCLUDE for those that go. */
return elf_gc_sweep (abfd, info);
struct alloc_got_off_arg {
bfd_vma gotoff;
- unsigned int got_elt_size;
+ struct bfd_link_info *info;
};
/* We need a special top-level link routine to convert got reference counts
elf_gc_allocate_got_offsets (struct elf_link_hash_entry *h, void *arg)
{
struct alloc_got_off_arg *gofarg = arg;
+ bfd *obfd = gofarg->info->output_bfd;
+ const struct elf_backend_data *bed = get_elf_backend_data (obfd);
if (h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
if (h->got.refcount > 0)
{
h->got.offset = gofarg->gotoff;
- gofarg->gotoff += gofarg->got_elt_size;
+ gofarg->gotoff += bed->got_elt_size (obfd, gofarg->info, h, NULL, 0);
}
else
h->got.offset = (bfd_vma) -1;
bfd *i;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
bfd_vma gotoff;
- unsigned int got_elt_size = bed->s->arch_size / 8;
struct alloc_got_off_arg gofarg;
+ BFD_ASSERT (abfd == info->output_bfd);
+
if (! is_elf_hash_table (info->hash))
return FALSE;
if (local_got[j] > 0)
{
local_got[j] = gotoff;
- gotoff += got_elt_size;
+ gotoff += bed->got_elt_size (abfd, info, NULL, i, j);
}
else
local_got[j] = (bfd_vma) -1;
/* Then the global .got entries. .plt refcounts are handled by
adjust_dynamic_symbol */
gofarg.gotoff = gotoff;
- gofarg.got_elt_size = got_elt_size;
+ gofarg.info = info;
elf_link_hash_traverse (elf_hash_table (info),
elf_gc_allocate_got_offsets,
&gofarg);
/* Need to: get the symbol; get the section. */
isym = &rcookie->locsyms[r_symndx];
- if (isym->st_shndx < SHN_LORESERVE || isym->st_shndx > SHN_HIRESERVE)
- {
- isec = bfd_section_from_elf_index (rcookie->abfd, isym->st_shndx);
- if (isec != NULL && elf_discarded_section (isec))
- return TRUE;
- }
+ isec = bfd_section_from_elf_index (rcookie->abfd, isym->st_shndx);
+ if (isec != NULL && elf_discarded_section (isec))
+ return TRUE;
}
return FALSE;
}
{
struct elf_reloc_cookie cookie;
asection *stab, *eh;
- Elf_Internal_Shdr *symtab_hdr;
const struct elf_backend_data *bed;
bfd *abfd;
- unsigned int count;
bfd_boolean ret = FALSE;
if (info->traditional_format
|| !is_elf_hash_table (info->hash))
return FALSE;
+ _bfd_elf_begin_eh_frame_parsing (info);
for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next)
{
if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
&& bed->elf_backend_discard_info == NULL)
continue;
- symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
- cookie.abfd = abfd;
- cookie.sym_hashes = elf_sym_hashes (abfd);
- cookie.bad_symtab = elf_bad_symtab (abfd);
- if (cookie.bad_symtab)
- {
- cookie.locsymcount = symtab_hdr->sh_size / bed->s->sizeof_sym;
- cookie.extsymoff = 0;
- }
- else
- {
- cookie.locsymcount = symtab_hdr->sh_info;
- cookie.extsymoff = symtab_hdr->sh_info;
- }
-
- if (bed->s->arch_size == 32)
- cookie.r_sym_shift = 8;
- else
- cookie.r_sym_shift = 32;
-
- cookie.locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
- if (cookie.locsyms == NULL && cookie.locsymcount != 0)
- {
- cookie.locsyms = bfd_elf_get_elf_syms (abfd, symtab_hdr,
- cookie.locsymcount, 0,
- NULL, NULL, NULL);
- if (cookie.locsyms == NULL)
- {
- info->callbacks->einfo (_("%P%X: can not read symbols: %E\n"));
- return FALSE;
- }
- }
+ if (!init_reloc_cookie (&cookie, info, abfd))
+ return FALSE;
- if (stab != NULL)
+ if (stab != NULL
+ && stab->reloc_count > 0
+ && init_reloc_cookie_rels (&cookie, info, abfd, stab))
{
- cookie.rels = NULL;
- count = stab->reloc_count;
- if (count != 0)
- cookie.rels = _bfd_elf_link_read_relocs (abfd, stab, NULL, NULL,
- info->keep_memory);
- if (cookie.rels != NULL)
- {
- cookie.rel = cookie.rels;
- cookie.relend = cookie.rels;
- cookie.relend += count * bed->s->int_rels_per_ext_rel;
- if (_bfd_discard_section_stabs (abfd, stab,
- elf_section_data (stab)->sec_info,
- bfd_elf_reloc_symbol_deleted_p,
- &cookie))
- ret = TRUE;
- if (elf_section_data (stab)->relocs != cookie.rels)
- free (cookie.rels);
- }
+ if (_bfd_discard_section_stabs (abfd, stab,
+ elf_section_data (stab)->sec_info,
+ bfd_elf_reloc_symbol_deleted_p,
+ &cookie))
+ ret = TRUE;
+ fini_reloc_cookie_rels (&cookie, stab);
}
- if (eh != NULL)
+ if (eh != NULL
+ && init_reloc_cookie_rels (&cookie, info, abfd, eh))
{
- cookie.rels = NULL;
- count = eh->reloc_count;
- if (count != 0)
- cookie.rels = _bfd_elf_link_read_relocs (abfd, eh, NULL, NULL,
- info->keep_memory);
- cookie.rel = cookie.rels;
- cookie.relend = cookie.rels;
- if (cookie.rels != NULL)
- cookie.relend += count * bed->s->int_rels_per_ext_rel;
-
+ _bfd_elf_parse_eh_frame (abfd, info, eh, &cookie);
if (_bfd_elf_discard_section_eh_frame (abfd, info, eh,
bfd_elf_reloc_symbol_deleted_p,
&cookie))
ret = TRUE;
-
- if (cookie.rels != NULL
- && elf_section_data (eh)->relocs != cookie.rels)
- free (cookie.rels);
+ fini_reloc_cookie_rels (&cookie, eh);
}
if (bed->elf_backend_discard_info != NULL
&& (*bed->elf_backend_discard_info) (abfd, &cookie, info))
ret = TRUE;
- if (cookie.locsyms != NULL
- && symtab_hdr->contents != (unsigned char *) cookie.locsyms)
- {
- if (! info->keep_memory)
- free (cookie.locsyms);
- else
- symtab_hdr->contents = (unsigned char *) cookie.locsyms;
- }
+ fini_reloc_cookie (&cookie, abfd);
}
+ _bfd_elf_end_eh_frame_parsing (info);
if (info->eh_frame_hdr
&& !info->relocatable
return ret;
}
+/* For a SHT_GROUP section, return the group signature. For other
+ sections, return the normal section name. */
+
+static const char *
+section_signature (asection *sec)
+{
+ if ((sec->flags & SEC_GROUP) != 0
+ && elf_next_in_group (sec) != NULL
+ && elf_group_name (elf_next_in_group (sec)) != NULL)
+ return elf_group_name (elf_next_in_group (sec));
+ return sec->name;
+}
+
void
-_bfd_elf_section_already_linked (bfd *abfd, struct bfd_section *sec,
+_bfd_elf_section_already_linked (bfd *abfd, asection *sec,
struct bfd_link_info *info)
{
flagword flags;
causes trouble for MIPS ELF, which relies on link once semantics
to handle the .reginfo section correctly. */
- name = bfd_get_section_name (abfd, sec);
+ name = section_signature (sec);
if (CONST_STRNEQ (name, ".gnu.linkonce.")
&& (p = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL)
/* We may have 2 different types of sections on the list: group
sections and linkonce sections. Match like sections. */
if ((flags & SEC_GROUP) == (l->sec->flags & SEC_GROUP)
- && strcmp (name, l->sec->name) == 0
+ && strcmp (name, section_signature (l->sec)) == 0
&& bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL)
{
/* The section has already been linked. See if we should
}
}
+ /* Do not complain on unresolved relocations in `.gnu.linkonce.r.F'
+ referencing its discarded `.gnu.linkonce.t.F' counterpart - g++-3.4
+ specific as g++-4.x is using COMDAT groups (without the `.gnu.linkonce'
+ prefix) instead. `.gnu.linkonce.r.*' were the `.rodata' part of its
+ matching `.gnu.linkonce.t.*'. If `.gnu.linkonce.r.F' is not discarded
+ but its `.gnu.linkonce.t.F' is discarded means we chose one-only
+ `.gnu.linkonce.t.F' section from a different bfd not requiring any
+ `.gnu.linkonce.r.F'. Thus `.gnu.linkonce.r.F' should be discarded.
+ The reverse order cannot happen as there is never a bfd with only the
+ `.gnu.linkonce.r.F' section. The order of sections in a bfd does not
+ matter as here were are looking only for cross-bfd sections. */
+
+ if ((flags & SEC_GROUP) == 0 && CONST_STRNEQ (name, ".gnu.linkonce.r."))
+ for (l = already_linked_list->entry; l != NULL; l = l->next)
+ if ((l->sec->flags & SEC_GROUP) == 0
+ && CONST_STRNEQ (l->sec->name, ".gnu.linkonce.t."))
+ {
+ if (abfd != l->sec->owner)
+ sec->output_section = bfd_abs_section_ptr;
+ break;
+ }
+
/* This is the first section with this name. Record it. */
if (! bfd_section_already_linked_table_insert (already_linked_list, sec))
info->callbacks->einfo (_("%F%P: already_linked_table: %E"));
{
return bfd_com_section_ptr;
}
+
+bfd_vma
+_bfd_elf_default_got_elt_size (bfd *abfd,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ struct elf_link_hash_entry *h ATTRIBUTE_UNUSED,
+ bfd *ibfd ATTRIBUTE_UNUSED,
+ unsigned long symndx ATTRIBUTE_UNUSED)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ return bed->s->arch_size / 8;
+}
+
+/* Routines to support the creation of dynamic relocs. */
+
+/* Return true if NAME is a name of a relocation
+ section associated with section S. */
+
+static bfd_boolean
+is_reloc_section (bfd_boolean rela, const char * name, asection * s)
+{
+ if (rela)
+ return CONST_STRNEQ (name, ".rela")
+ && strcmp (bfd_get_section_name (NULL, s), name + 5) == 0;
+
+ return CONST_STRNEQ (name, ".rel")
+ && strcmp (bfd_get_section_name (NULL, s), name + 4) == 0;
+}
+
+/* Returns the name of the dynamic reloc section associated with SEC. */
+
+static const char *
+get_dynamic_reloc_section_name (bfd * abfd,
+ asection * sec,
+ bfd_boolean is_rela)
+{
+ const char * name;
+ unsigned int strndx = elf_elfheader (abfd)->e_shstrndx;
+ unsigned int shnam = elf_section_data (sec)->rel_hdr.sh_name;
+
+ name = bfd_elf_string_from_elf_section (abfd, strndx, shnam);
+ if (name == NULL)
+ return NULL;
+
+ if (! is_reloc_section (is_rela, name, sec))
+ {
+ static bfd_boolean complained = FALSE;
+
+ if (! complained)
+ {
+ (*_bfd_error_handler)
+ (_("%B: bad relocation section name `%s\'"), abfd, name);
+ complained = TRUE;
+ }
+ name = NULL;
+ }
+
+ return name;
+}
+
+/* Returns the dynamic reloc section associated with SEC.
+ If necessary compute the name of the dynamic reloc section based
+ on SEC's name (looked up in ABFD's string table) and the setting
+ of IS_RELA. */
+
+asection *
+_bfd_elf_get_dynamic_reloc_section (bfd * abfd,
+ asection * sec,
+ bfd_boolean is_rela)
+{
+ asection * reloc_sec = elf_section_data (sec)->sreloc;
+
+ if (reloc_sec == NULL)
+ {
+ const char * name = get_dynamic_reloc_section_name (abfd, sec, is_rela);
+
+ if (name != NULL)
+ {
+ reloc_sec = bfd_get_section_by_name (abfd, name);
+
+ if (reloc_sec != NULL)
+ elf_section_data (sec)->sreloc = reloc_sec;
+ }
+ }
+
+ return reloc_sec;
+}
+
+/* Returns the dynamic reloc section associated with SEC. If the
+ section does not exist it is created and attached to the DYNOBJ
+ bfd and stored in the SRELOC field of SEC's elf_section_data
+ structure.
+
+ ALIGNMENT is the alignment for the newly created section and
+ IS_RELA defines whether the name should be .rela.<SEC's name>
+ or .rel.<SEC's name>. The section name is looked up in the
+ string table associated with ABFD. */
+
+asection *
+_bfd_elf_make_dynamic_reloc_section (asection * sec,
+ bfd * dynobj,
+ unsigned int alignment,
+ bfd * abfd,
+ bfd_boolean is_rela)
+{
+ asection * reloc_sec = elf_section_data (sec)->sreloc;
+
+ if (reloc_sec == NULL)
+ {
+ const char * name = get_dynamic_reloc_section_name (abfd, sec, is_rela);
+
+ if (name == NULL)
+ return NULL;
+
+ reloc_sec = bfd_get_section_by_name (dynobj, name);
+
+ if (reloc_sec == NULL)
+ {
+ flagword flags;
+
+ flags = (SEC_HAS_CONTENTS | SEC_READONLY | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+ if ((sec->flags & SEC_ALLOC) != 0)
+ flags |= SEC_ALLOC | SEC_LOAD;
+
+ reloc_sec = bfd_make_section_with_flags (dynobj, name, flags);
+ if (reloc_sec != NULL)
+ {
+ if (! bfd_set_section_alignment (dynobj, reloc_sec, alignment))
+ reloc_sec = NULL;
+ }
+ }
+
+ elf_section_data (sec)->sreloc = reloc_sec;
+ }
+
+ return reloc_sec;
+}