/* ELF linking support for BFD.
Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- 2005, 2006, 2007, 2008, 2009
+ 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
asection *s;
struct elf_link_hash_entry *h;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
- int ptralign;
+ struct elf_link_hash_table *htab = elf_hash_table (info);
/* This function may be called more than once. */
s = bfd_get_section_by_name (abfd, ".got");
if (s != NULL && (s->flags & SEC_LINKER_CREATED) != 0)
return TRUE;
- switch (bed->s->arch_size)
- {
- case 32:
- ptralign = 2;
- break;
-
- case 64:
- ptralign = 3;
- break;
-
- default:
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
- }
-
flags = bed->dynamic_sec_flags;
+ s = bfd_make_section_with_flags (abfd,
+ (bed->rela_plts_and_copies_p
+ ? ".rela.got" : ".rel.got"),
+ (bed->dynamic_sec_flags
+ | SEC_READONLY));
+ if (s == NULL
+ || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
+ return FALSE;
+ htab->srelgot = s;
+
s = bfd_make_section_with_flags (abfd, ".got", flags);
if (s == NULL
- || !bfd_set_section_alignment (abfd, s, ptralign))
+ || !bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
return FALSE;
+ htab->sgot = s;
if (bed->want_got_plt)
{
s = bfd_make_section_with_flags (abfd, ".got.plt", flags);
if (s == NULL
- || !bfd_set_section_alignment (abfd, s, ptralign))
+ || !bfd_set_section_alignment (abfd, s,
+ bed->s->log_file_align))
return FALSE;
+ htab->sgotplt = s;
}
+ /* The first bit of the global offset table is the header. */
+ s->size += bed->got_header_size;
+
if (bed->want_got_sym)
{
/* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got
(or .got.plt) section. We don't do this in the linker script
because we don't want to define the symbol if we are not creating
a global offset table. */
- h = _bfd_elf_define_linkage_sym (abfd, info, s, "_GLOBAL_OFFSET_TABLE_");
+ h = _bfd_elf_define_linkage_sym (abfd, info, s,
+ "_GLOBAL_OFFSET_TABLE_");
elf_hash_table (info)->hgot = h;
if (h == NULL)
return FALSE;
}
- /* The first bit of the global offset table is the header. */
- s->size += bed->got_header_size;
-
return TRUE;
}
\f
_bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
{
flagword flags;
- register asection *s;
+ asection *s;
const struct elf_backend_data *bed;
if (! is_elf_hash_table (info->hash))
struct elf_link_hash_entry *h;
asection *s;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ struct elf_link_hash_table *htab = elf_hash_table (info);
/* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and
.rel[a].bss sections. */
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
return FALSE;
+ htab->splt = s;
/* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the
.plt section. */
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
return FALSE;
+ htab->srelplt = s;
if (! _bfd_elf_create_got_section (abfd, info))
return FALSE;
if (provide && hidden)
{
- const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
-
+ bed = get_elf_backend_data (output_bfd);
h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
(*bed->elf_backend_hide_symbol) (info, h, TRUE);
}
return 1;
amt = sizeof (*entry);
- entry = bfd_alloc (input_bfd, amt);
+ entry = (struct elf_link_local_dynamic_entry *) bfd_alloc (input_bfd, amt);
if (entry == NULL)
return 0;
elf_link_renumber_hash_table_dynsyms (struct elf_link_hash_entry *h,
void *data)
{
- size_t *count = data;
+ size_t *count = (size_t *) data;
if (h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
elf_link_renumber_local_hash_table_dynsyms (struct elf_link_hash_entry *h,
void *data)
{
- size_t *count = data;
+ size_t *count = (size_t *) data;
if (h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
break;
}
+ /* Differentiate strong and weak symbols. */
+ newweak = bind == STB_WEAK;
+ oldweak = (h->root.type == bfd_link_hash_defweak
+ || h->root.type == bfd_link_hash_undefweak);
+
/* In cases involving weak versioned symbols, we may wind up trying
to merge a symbol with itself. Catch that here, to avoid the
confusion that results if we try to override a symbol with
_GLOBAL_OFFSET_TABLE_, which are regular symbols defined in a
dynamic object, which we do want to handle here. */
if (abfd == oldbfd
+ && (newweak || oldweak)
&& ((abfd->flags & DYNAMIC) == 0
|| !h->def_regular))
return TRUE;
was referenced before. */
if (h->ref_regular)
{
- const struct elf_backend_data *bed
- = get_elf_backend_data (abfd);
struct elf_link_hash_entry *vh = *sym_hash;
+
vh->root.type = h->root.type;
h->root.type = bfd_link_hash_indirect;
(*bed->elf_backend_copy_indirect_symbol) (info, vh, h);
return TRUE;
}
- /* Differentiate strong and weak symbols. */
- newweak = bind == STB_WEAK;
- oldweak = (h->root.type == bfd_link_hash_defweak
- || h->root.type == bfd_link_hash_undefweak);
+ if (bind == STB_GNU_UNIQUE)
+ h->unique_global = 1;
/* If a new weak symbol definition comes from a regular file and the
old symbol comes from a dynamic library, we treat the new one as
/* Handle the case where we had a versioned symbol in a dynamic
library and now find a definition in a normal object. In this
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;
dynamic = (abfd->flags & DYNAMIC) != 0;
shortlen = p - name;
- shortname = bfd_hash_allocate (&info->hash->table, shortlen + 1);
+ shortname = (char *) bfd_hash_allocate (&info->hash->table, shortlen + 1);
if (shortname == NULL)
return FALSE;
memcpy (shortname, name, shortlen);
{
if (! dynamic)
{
- if (info->shared
+ if (! info->executable
|| hi->ref_dynamic)
*dynsym = TRUE;
}
nondefault:
len = strlen (name);
- shortname = bfd_hash_allocate (&info->hash->table, len);
+ shortname = (char *) bfd_hash_allocate (&info->hash->table, len);
if (shortname == NULL)
return FALSE;
memcpy (shortname, name, shortlen);
{
if (! dynamic)
{
- if (info->shared
+ if (! info->executable
|| hi->ref_dynamic)
*dynsym = TRUE;
}
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. */
static bfd_boolean
_bfd_elf_export_symbol (struct elf_link_hash_entry *h, void *data)
{
- struct elf_info_failed *eif = data;
+ struct elf_info_failed *eif = (struct elf_info_failed *) data;
/* Ignore this if we won't export it. */
if (!eif->info->export_dynamic && !h->dynamic)
bfd_boolean hide;
if (eif->verdefs == NULL
- || (find_version_for_sym (eif->verdefs, h->root.root.string, &hide)
+ || (bfd_find_version_for_sym (eif->verdefs, h->root.root.string, &hide)
&& !hide))
{
if (! bfd_elf_link_record_dynamic_symbol (eif->info, h))
_bfd_elf_link_find_version_dependencies (struct elf_link_hash_entry *h,
void *data)
{
- struct elf_find_verdep_info *rinfo = data;
+ struct elf_find_verdep_info *rinfo = (struct elf_find_verdep_info *) data;
Elf_Internal_Verneed *t;
Elf_Internal_Vernaux *a;
bfd_size_type amt;
if (t == NULL)
{
amt = sizeof *t;
- t = bfd_zalloc (rinfo->info->output_bfd, amt);
+ t = (Elf_Internal_Verneed *) bfd_zalloc (rinfo->info->output_bfd, amt);
if (t == NULL)
{
rinfo->failed = TRUE;
}
amt = sizeof *a;
- a = bfd_zalloc (rinfo->info->output_bfd, amt);
+ a = (Elf_Internal_Vernaux *) bfd_zalloc (rinfo->info->output_bfd, amt);
if (a == NULL)
{
rinfo->failed = TRUE;
char *p;
bfd_size_type amt;
- sinfo = data;
+ sinfo = (struct elf_info_failed *) data;
info = sinfo->info;
if (h->root.type == bfd_link_hash_warning)
struct bfd_elf_version_expr *d;
len = p - h->root.root.string;
- alc = bfd_malloc (len);
+ alc = (char *) bfd_malloc (len);
if (alc == NULL)
{
sinfo->failed = TRUE;
return TRUE;
amt = sizeof *t;
- t = bfd_zalloc (info->output_bfd, amt);
+ t = (struct bfd_elf_version_tree *) bfd_zalloc (info->output_bfd, amt);
if (t == NULL)
{
sinfo->failed = TRUE;
{
bfd_boolean hide;
- h->verinfo.vertree = find_version_for_sym (sinfo->verdefs,
+ h->verinfo.vertree = bfd_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 FALSE;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
- nsyms = symtab_hdr->sh_size / symtab_hdr->sh_entsize;
+ nsyms = NUM_SHDR_ENTRIES (symtab_hdr);
bed = get_elf_backend_data (abfd);
return FALSE;
}
- erela = external_relocs;
+ erela = (const bfd_byte *) external_relocs;
erelaend = erela + shdr->sh_size;
irela = internal_relocs;
while (erela < erelaend)
r_symndx = ELF32_R_SYM (irela->r_info);
if (bed->s->arch_size == 64)
r_symndx >>= 24;
- if ((size_t) r_symndx >= nsyms)
+ if (nsyms > 0)
+ {
+ if ((size_t) r_symndx >= nsyms)
+ {
+ (*_bfd_error_handler)
+ (_("%B: bad reloc symbol index (0x%lx >= 0x%lx)"
+ " for offset 0x%lx in section `%A'"),
+ abfd, sec,
+ (unsigned long) r_symndx, (unsigned long) nsyms, irela->r_offset);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ }
+ else if (r_symndx != 0)
{
(*_bfd_error_handler)
- (_("%B: bad reloc symbol index (0x%lx >= 0x%lx)"
- " for offset 0x%lx in section `%A'"),
+ (_("%B: non-zero symbol index (0x%lx) for offset 0x%lx in section `%A'"
+ " when the object file has no symbol table"),
abfd, sec,
(unsigned long) r_symndx, (unsigned long) nsyms, irela->r_offset);
bfd_set_error (bfd_error_bad_value);
size = o->reloc_count;
size *= bed->s->int_rels_per_ext_rel * sizeof (Elf_Internal_Rela);
if (keep_memory)
- internal_relocs = alloc2 = bfd_alloc (abfd, size);
+ internal_relocs = alloc2 = (Elf_Internal_Rela *) bfd_alloc (abfd, size);
else
- internal_relocs = alloc2 = bfd_malloc (size);
+ internal_relocs = alloc2 = (Elf_Internal_Rela *) bfd_malloc (size);
if (internal_relocs == NULL)
goto error_return;
}
allocate it with bfd_alloc rather than malloc. Also since we
cannot be sure that the contents will actually be filled in,
we zero the allocated space. */
- rel_hdr->contents = bfd_zalloc (abfd, rel_hdr->sh_size);
+ rel_hdr->contents = (unsigned char *) bfd_zalloc (abfd, rel_hdr->sh_size);
if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0)
return FALSE;
{
struct elf_link_hash_entry **p;
- p = bfd_zmalloc (num_rel_hashes * sizeof (struct elf_link_hash_entry *));
+ p = (struct elf_link_hash_entry **)
+ bfd_zmalloc (num_rel_hashes * sizeof (struct elf_link_hash_entry *));
if (p == NULL)
return FALSE;
static bfd_boolean
_bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data)
{
- struct elf_info_failed *eif = data;
+ struct elf_info_failed *eif = (struct elf_info_failed *) data;
bfd *dynobj;
const struct elf_backend_data *bed;
about symbols which are defined by one dynamic object and
referenced by another one? */
if (!h->needs_plt
+ && h->type != STT_GNU_IFUNC
&& (h->def_regular
|| !h->def_dynamic
|| (!h->ref_regular
&& ((sec = h->root.u.def.section)->flags & SEC_MERGE)
&& sec->sec_info_type == ELF_INFO_TYPE_MERGE)
{
- bfd *output_bfd = data;
+ bfd *output_bfd = (bfd *) data;
h->root.u.def.value =
_bfd_merged_section_offset (output_bfd,
BFD_ASSERT (s != NULL);
newsize = s->size + bed->s->sizeof_dyn;
- newcontents = bfd_realloc (s->contents, newsize);
+ newcontents = (bfd_byte *) bfd_realloc (s->contents, newsize);
if (newcontents == NULL)
return FALSE;
static bfd_boolean
elf_adjust_dynstr_offsets (struct elf_link_hash_entry *h, void *data)
{
- struct elf_strtab_hash *dynstr = data;
+ struct elf_strtab_hash *dynstr = (struct elf_strtab_hash *) data;
if (h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
case DT_RUNPATH:
case DT_FILTER:
case DT_AUXILIARY:
+ case DT_AUDIT:
+ case DT_DEPAUDIT:
dyn.d_un.d_val = _bfd_elf_strtab_offset (dynstr, dyn.d_un.d_val);
break;
default:
static bfd_boolean
elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
{
+ Elf_Internal_Ehdr *ehdr;
Elf_Internal_Shdr *hdr;
bfd_size_type symcount;
bfd_size_type extsymcount;
}
}
+ ehdr = elf_elfheader (abfd);
+ if (info->warn_alternate_em
+ && bed->elf_machine_code != ehdr->e_machine
+ && ((bed->elf_machine_alt1 != 0
+ && ehdr->e_machine == bed->elf_machine_alt1)
+ || (bed->elf_machine_alt2 != 0
+ && ehdr->e_machine == bed->elf_machine_alt2)))
+ info->callbacks->einfo
+ (_("%P: alternate ELF machine code found (%d) in %B, expecting %d\n"),
+ ehdr->e_machine, abfd, bed->elf_machine_code);
+
/* As a GNU extension, any input sections which are named
.gnu.warning.SYMBOL are treated as warning symbols for the given
symbol. This differs from .gnu.warning sections, which generate
}
sz = s->size;
- msg = bfd_alloc (abfd, sz + 1);
+ msg = (char *) bfd_alloc (abfd, sz + 1);
if (msg == NULL)
goto error_return;
{
asection *s;
const char *soname = NULL;
+ char *audit = NULL;
struct bfd_link_needed_list *rpath = NULL, *runpath = NULL;
int ret;
unsigned long shlink;
if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
- goto error_free_dyn;
+ {
+error_free_dyn:
+ free (dynbuf);
+ goto error_return;
+ }
elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
if (elfsec == SHN_BAD)
unsigned int tagv = dyn.d_un.d_val;
amt = sizeof (struct bfd_link_needed_list);
- n = bfd_alloc (abfd, amt);
+ n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
if (n == NULL || fnm == NULL)
goto error_free_dyn;
amt = strlen (fnm) + 1;
- anm = bfd_alloc (abfd, amt);
+ anm = (char *) bfd_alloc (abfd, amt);
if (anm == NULL)
goto error_free_dyn;
memcpy (anm, fnm, amt);
unsigned int tagv = dyn.d_un.d_val;
amt = sizeof (struct bfd_link_needed_list);
- n = bfd_alloc (abfd, amt);
+ n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
if (n == NULL || fnm == NULL)
goto error_free_dyn;
amt = strlen (fnm) + 1;
- anm = bfd_alloc (abfd, amt);
+ anm = (char *) bfd_alloc (abfd, amt);
if (anm == NULL)
goto error_free_dyn;
memcpy (anm, fnm, amt);
unsigned int tagv = dyn.d_un.d_val;
amt = sizeof (struct bfd_link_needed_list);
- n = bfd_alloc (abfd, amt);
+ n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
if (n == NULL || fnm == NULL)
goto error_free_dyn;
amt = strlen (fnm) + 1;
- anm = bfd_alloc (abfd, amt);
+ anm = (char *) bfd_alloc (abfd, amt);
if (anm == NULL)
- {
- error_free_dyn:
- free (dynbuf);
- goto error_return;
- }
+ goto error_free_dyn;
memcpy (anm, fnm, amt);
n->name = anm;
n->by = abfd;
;
*pn = n;
}
+ if (dyn.d_tag == DT_AUDIT)
+ {
+ unsigned int tagv = dyn.d_un.d_val;
+ audit = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
+ }
}
free (dynbuf);
particular dynamic object more than once. */
if (ret > 0)
return TRUE;
+
+ /* Save the DT_AUDIT entry for the linker emulation code. */
+ elf_dt_audit (abfd) = audit;
}
/* If this is a dynamic object, we always link against the .dynsym
/* We store a pointer to the hash table entry for each external
symbol. */
amt = extsymcount * sizeof (struct elf_link_hash_entry *);
- sym_hash = bfd_alloc (abfd, amt);
+ sym_hash = (struct elf_link_hash_entry **) bfd_alloc (abfd, amt);
if (sym_hash == NULL)
goto error_free_sym;
elf_sym_hashes (abfd) = sym_hash;
Elf_Internal_Shdr *versymhdr;
versymhdr = &elf_tdata (abfd)->dynversym_hdr;
- extversym = bfd_malloc (versymhdr->sh_size);
+ extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size);
if (extversym == NULL)
goto error_free_sym;
amt = versymhdr->sh_size;
bfd_boolean common;
unsigned int old_alignment;
bfd *old_bfd;
+ bfd * undef_bfd = NULL;
override = FALSE;
common = bed->common_definition (isym);
bind = ELF_ST_BIND (isym->st_info);
- if (bind == STB_LOCAL)
+ switch (bind)
{
+ case STB_LOCAL:
/* This should be impossible, since ELF requires that all
global symbols follow all local symbols, and that sh_info
point to the first global symbol. Unfortunately, Irix 5
screws this up. */
continue;
- }
- else if (bind == STB_GLOBAL)
- {
+
+ case STB_GLOBAL:
if (isym->st_shndx != SHN_UNDEF && !common)
flags = BSF_GLOBAL;
- }
- else if (bind == STB_WEAK)
- flags = BSF_WEAK;
- else
- {
+ break;
+
+ case STB_WEAK:
+ flags = BSF_WEAK;
+ break;
+
+ case STB_GNU_UNIQUE:
+ flags = BSF_GNU_UNIQUE;
+ break;
+
+ default:
/* Leave it up to the processor backend. */
+ break;
}
if (isym->st_shndx == SHN_UNDEF)
unsigned int vernum = 0;
bfd_boolean skip;
+ /* If this is a definition of a symbol which was previously
+ referenced in a non-weak manner then make a note of the bfd
+ that contained the reference. This is used if we need to
+ refer to the source of the reference later on. */
+ if (! bfd_is_und_section (sec))
+ {
+ h = elf_link_hash_lookup (elf_hash_table (info), name, FALSE, FALSE, FALSE);
+
+ if (h != NULL
+ && h->root.type == bfd_link_hash_undefined
+ && h->root.u.undef.abfd)
+ undef_bfd = h->root.u.undef.abfd;
+ }
+
if (ever == NULL)
{
if (info->default_imported_symver)
&& isym->st_shndx != SHN_UNDEF)
++newlen;
- newname = bfd_hash_allocate (&htab->root.table, newlen);
+ newname = (char *) bfd_hash_allocate (&htab->root.table, newlen);
if (newname == NULL)
goto error_free_vers;
memcpy (newname, name, namelen);
name = newname;
}
+ /* If necessary, make a second attempt to locate the bfd
+ containing an unresolved, non-weak reference to the
+ current symbol. */
+ if (! bfd_is_und_section (sec) && undef_bfd == NULL)
+ {
+ h = elf_link_hash_lookup (elf_hash_table (info), name, FALSE, FALSE, FALSE);
+
+ if (h != NULL
+ && h->root.type == bfd_link_hash_undefined
+ && h->root.u.undef.abfd)
+ undef_bfd = h->root.u.undef.abfd;
+ }
+
if (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec,
&value, &old_alignment,
sym_hash, &skip, &override,
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;
+
*sym_hash = h;
+ h->unique_global = (flags & BSF_GNU_UNIQUE) != 0;
new_weakdef = FALSE;
if (dynamic
if (ELF_ST_TYPE (isym->st_info) != STT_NOTYPE
&& (definition || h->type == STT_NOTYPE))
{
- if (h->type != STT_NOTYPE
- && h->type != ELF_ST_TYPE (isym->st_info)
- && ! type_change_ok)
- (*_bfd_error_handler)
- (_("Warning: type of symbol `%s' changed"
- " from %d to %d in %B"),
- abfd, name, h->type, ELF_ST_TYPE (isym->st_info));
+ unsigned int type = ELF_ST_TYPE (isym->st_info);
- h->type = ELF_ST_TYPE (isym->st_info);
+ /* Turn an IFUNC symbol from a DSO into a normal FUNC
+ symbol. */
+ if (type == STT_GNU_IFUNC
+ && (abfd->flags & DYNAMIC) != 0)
+ type = STT_FUNC;
+
+ if (h->type != type)
+ {
+ if (h->type != STT_NOTYPE && ! type_change_ok)
+ (*_bfd_error_handler)
+ (_("Warning: type of symbol `%s' changed"
+ " from %d to %d in %B"),
+ abfd, name, h->type, type);
+
+ h->type = type;
+ }
}
/* Merge st_other field. */
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);
dynsym = FALSE;
}
{
amt = ((isymend - isym + 1)
* sizeof (struct elf_link_hash_entry *));
- nondeflt_vers = bfd_malloc (amt);
+ nondeflt_vers =
+ (struct elf_link_hash_entry **) bfd_malloc (amt);
if (!nondeflt_vers)
goto error_free_vers;
}
/* A symbol from a library loaded via DT_NEEDED of some
other library is referenced by a regular object.
Add a DT_NEEDED entry for it. Issue an error if
- --no-add-needed is used. */
- if ((elf_dyn_lib_class (abfd) & DYN_NO_NEEDED) != 0)
+ --no-add-needed is used and the reference was not
+ a weak one. */
+ if (undef_bfd != NULL
+ && (elf_dyn_lib_class (abfd) & DYN_NO_NEEDED) != 0)
{
(*_bfd_error_handler)
- (_("%s: invalid DSO for symbol `%s' definition"),
+ (_("%B: undefined reference to symbol '%s'"),
+ undef_bfd, name);
+ (*_bfd_error_handler)
+ (_("note: '%s' is defined in DSO %B so try adding it to the linker command line"),
abfd, name);
- bfd_set_error (bfd_error_bad_value);
+ bfd_set_error (bfd_error_invalid_operation);
goto error_free_vers;
}
- elf_dyn_lib_class (abfd) &= ~DYN_AS_NEEDED;
+ elf_dyn_lib_class (abfd) = (enum dynamic_lib_link_class)
+ (elf_dyn_lib_class (abfd) & ~DYN_AS_NEEDED);
add_needed = TRUE;
ret = elf_add_dt_needed_tag (abfd, info, soname, add_needed);
continue;
amt = p - h->root.root.string;
- shortname = bfd_malloc (amt + 1);
+ shortname = (char *) bfd_malloc (amt + 1);
if (!shortname)
goto error_free_vers;
memcpy (shortname, h->root.root.string, amt);
defined symbol, search time for N weak defined symbols will be
O(N^2). Binary search will cut it down to O(NlogN). */
amt = extsymcount * sizeof (struct elf_link_hash_entry *);
- sorted_sym_hash = bfd_malloc (amt);
+ sorted_sym_hash = (struct elf_link_hash_entry **) bfd_malloc (amt);
if (sorted_sym_hash == NULL)
goto error_return;
sym_hash = sorted_sym_hash;
/* Add this bfd to the loaded list. */
struct elf_link_loaded_list *n;
- n = bfd_alloc (abfd, sizeof (struct elf_link_loaded_list));
+ n = (struct elf_link_loaded_list *)
+ bfd_alloc (abfd, sizeof (struct elf_link_loaded_list));
if (n == NULL)
goto error_return;
n->abfd = abfd;
/* First check with only one `@'. */
len = strlen (name);
- copy = bfd_alloc (abfd, len);
+ copy = (char *) bfd_alloc (abfd, len);
if (copy == NULL)
return (struct elf_link_hash_entry *) 0 - 1;
return TRUE;
amt = c;
amt *= sizeof (bfd_boolean);
- defined = bfd_zmalloc (amt);
- included = bfd_zmalloc (amt);
+ defined = (bfd_boolean *) bfd_zmalloc (amt);
+ included = (bfd_boolean *) bfd_zmalloc (amt);
if (defined == NULL || included == NULL)
goto error_return;
static bfd_boolean
elf_collect_hash_codes (struct elf_link_hash_entry *h, void *data)
{
- struct hash_codes_info *inf = data;
+ struct hash_codes_info *inf = (struct hash_codes_info *) data;
const char *name;
char *p;
unsigned long ha;
p = strchr (name, ELF_VER_CHR);
if (p != NULL)
{
- alc = bfd_malloc (p - name + 1);
+ alc = (char *) bfd_malloc (p - name + 1);
if (alc == NULL)
{
inf->error = TRUE;
static bfd_boolean
elf_collect_gnu_hash_codes (struct elf_link_hash_entry *h, void *data)
{
- struct collect_gnu_hash_codes *s = data;
+ struct collect_gnu_hash_codes *s = (struct collect_gnu_hash_codes *) data;
const char *name;
char *p;
unsigned long ha;
p = strchr (name, ELF_VER_CHR);
if (p != NULL)
{
- alc = bfd_malloc (p - name + 1);
+ alc = (char *) bfd_malloc (p - name + 1);
if (alc == NULL)
{
s->error = TRUE;
static bfd_boolean
elf_renumber_gnu_hash_syms (struct elf_link_hash_entry *h, void *data)
{
- struct collect_gnu_hash_codes *s = data;
+ struct collect_gnu_hash_codes *s = (struct collect_gnu_hash_codes *) data;
unsigned long int bucket;
unsigned long int val;
since the size could be large. */
amt = maxsize;
amt *= sizeof (unsigned long int);
- counts = bfd_malloc (amt);
+ counts = (unsigned long int *) bfd_malloc (amt);
if (counts == NULL)
return 0;
return best_size;
}
+/* Size any SHT_GROUP section for ld -r. */
+
+bfd_boolean
+_bfd_elf_size_group_sections (struct bfd_link_info *info)
+{
+ bfd *ibfd;
+
+ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+ if (bfd_get_flavour (ibfd) == bfd_target_elf_flavour
+ && !_bfd_elf_fixup_group_sections (ibfd, bfd_abs_section_ptr))
+ return FALSE;
+ return TRUE;
+}
+
/* Set up the sizes and contents of the ELF dynamic sections. This is
called by the ELF linker emulation before_allocation routine. We
must set the sizes of the sections before the linker sets the
const char *soname,
const char *rpath,
const char *filter_shlib,
+ const char *audit,
+ const char *depaudit,
const char * const *auxiliary_filters,
struct bfd_link_info *info,
asection **sinterpptr,
elf_hash_table (info)->init_plt_refcount
= elf_hash_table (info)->init_plt_offset;
+ if (info->relocatable
+ && !_bfd_elf_size_group_sections (info))
+ return FALSE;
+
/* The backend may have to create some sections regardless of whether
we're dynamic or not. */
if (bed->elf_backend_always_size_sections
}
}
+ if (audit != NULL)
+ {
+ bfd_size_type indx;
+
+ indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, audit,
+ TRUE);
+ if (indx == (bfd_size_type) -1
+ || !_bfd_elf_add_dynamic_entry (info, DT_AUDIT, indx))
+ return FALSE;
+ }
+
+ if (depaudit != NULL)
+ {
+ bfd_size_type indx;
+
+ indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, depaudit,
+ TRUE);
+ if (indx == (bfd_size_type) -1
+ || !_bfd_elf_add_dynamic_entry (info, DT_DEPAUDIT, indx))
+ return FALSE;
+ }
+
eif.info = info;
eif.verdefs = verdefs;
eif.failed = FALSE;
verlen = strlen (verstr);
newlen = namelen + verlen + 3;
- newname = bfd_malloc (newlen);
+ newname = (char *) bfd_malloc (newlen);
if (newname == NULL)
return FALSE;
memcpy (newname, name, namelen);
{
struct bfd_elf_version_deps *n;
+ /* Don't emit base version twice. */
+ if (t->vernum == 0)
+ continue;
+
size += sizeof (Elf_External_Verdef);
size += sizeof (Elf_External_Verdaux);
++cdefs;
}
s->size = size;
- s->contents = bfd_alloc (output_bfd, s->size);
+ s->contents = (unsigned char *) bfd_alloc (output_bfd, s->size);
if (s->contents == NULL && s->size != 0)
return FALSE;
unsigned int cdeps;
struct bfd_elf_version_deps *n;
+ /* Don't emit the base version twice. */
+ if (t->vernum == 0)
+ continue;
+
cdeps = 0;
for (n = t->deps; n != NULL; n = n->next)
++cdeps;
def.vd_hash = bfd_elf_hash (t->name);
def.vd_aux = sizeof (Elf_External_Verdef);
def.vd_next = 0;
- if (t->next != NULL)
+
+ /* If a basever node is next, it *must* be the last node in
+ the chain, otherwise Verdef construction breaks. */
+ if (t->next != NULL && t->next->vernum == 0)
+ BFD_ASSERT (t->next->next == NULL);
+
+ if (t->next != NULL && t->next->vernum != 0)
def.vd_next = (sizeof (Elf_External_Verdef)
+ (cdeps + 1) * sizeof (Elf_External_Verdaux));
unsigned int crefs;
bfd_byte *p;
- /* Build the version definition section. */
+ /* Build the version dependency section. */
size = 0;
crefs = 0;
for (t = elf_tdata (output_bfd)->verref;
}
s->size = size;
- s->contents = bfd_alloc (output_bfd, s->size);
+ s->contents = (unsigned char *) bfd_alloc (output_bfd, s->size);
if (s->contents == NULL)
return FALSE;
&& (s->flags & SEC_EXCLUDE) == 0)
{
s->size = dynsymcount * sizeof (Elf_External_Versym);
- s->contents = bfd_zalloc (output_bfd, s->size);
+ s->contents = (unsigned char *) bfd_zalloc (output_bfd, s->size);
if (s->contents == NULL)
return FALSE;
if (dynsymcount != 0)
{
- s->contents = bfd_alloc (output_bfd, s->size);
+ s->contents = (unsigned char *) bfd_alloc (output_bfd, s->size);
if (s->contents == NULL)
return FALSE;
time store the values in an array so that we could use them for
optimizations. */
amt = dynsymcount * sizeof (unsigned long int);
- hashcodes = bfd_malloc (amt);
+ hashcodes = (unsigned long int *) bfd_malloc (amt);
if (hashcodes == NULL)
return FALSE;
hashinf.hashcodes = hashcodes;
BFD_ASSERT (s != NULL);
hash_entry_size = elf_section_data (s)->this_hdr.sh_entsize;
s->size = ((2 + bucketcount + dynsymcount) * hash_entry_size);
- s->contents = bfd_zalloc (output_bfd, s->size);
+ s->contents = (unsigned char *) bfd_zalloc (output_bfd, s->size);
if (s->contents == NULL)
return FALSE;
time store the values in an array so that we could use them for
optimizations. */
amt = dynsymcount * 2 * sizeof (unsigned long int);
- cinfo.hashcodes = bfd_malloc (amt);
+ cinfo.hashcodes = (long unsigned int *) bfd_malloc (amt);
if (cinfo.hashcodes == NULL)
return FALSE;
BFD_ASSERT (cinfo.min_dynindx == -1);
free (cinfo.hashcodes);
s->size = 5 * 4 + bed->s->arch_size / 8;
- contents = bfd_zalloc (output_bfd, s->size);
+ contents = (unsigned char *) bfd_zalloc (output_bfd, s->size);
if (contents == NULL)
return FALSE;
s->contents = contents;
maskwords = 1 << (maskbitslog2 - cinfo.shift1);
amt = bucketcount * sizeof (unsigned long int) * 2;
amt += maskwords * sizeof (bfd_vma);
- cinfo.bitmask = bfd_malloc (amt);
+ cinfo.bitmask = (bfd_vma *) bfd_malloc (amt);
if (cinfo.bitmask == NULL)
{
free (cinfo.hashcodes);
return FALSE;
}
- cinfo.counts = (void *) (cinfo.bitmask + maskwords);
+ cinfo.counts = (long unsigned int *) (cinfo.bitmask + maskwords);
cinfo.indx = cinfo.counts + bucketcount;
cinfo.symindx = dynsymcount - cinfo.nsyms;
memset (cinfo.bitmask, 0, maskwords * sizeof (bfd_vma));
s->size = (4 + bucketcount + cinfo.nsyms) * 4;
s->size += cinfo.maskbits / 8;
- contents = bfd_zalloc (output_bfd, s->size);
+ contents = (unsigned char *) bfd_zalloc (output_bfd, s->size);
if (contents == NULL)
{
free (cinfo.bitmask);
subclass. */
if (entry == NULL)
{
- entry = bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry));
+ entry = (struct bfd_hash_entry *)
+ bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry));
if (entry == NULL)
return entry;
}
struct elf_link_hash_entry *h,
bfd_boolean force_local)
{
- h->plt = elf_hash_table (info)->init_plt_offset;
- h->needs_plt = 0;
+ /* STT_GNU_IFUNC symbol must go through PLT. */
+ if (h->type != STT_GNU_IFUNC)
+ {
+ h->plt = elf_hash_table (info)->init_plt_offset;
+ h->needs_plt = 0;
+ }
if (force_local)
{
h->forced_local = 1;
struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *,
struct bfd_hash_table *,
const char *),
- unsigned int entsize)
+ unsigned int entsize,
+ enum elf_target_id target_id)
{
bfd_boolean ret;
int can_refcount = get_elf_backend_data (abfd)->can_refcount;
table->dynsymcount = 1;
ret = _bfd_link_hash_table_init (&table->root, abfd, newfunc, entsize);
+
table->root.type = bfd_link_elf_hash_table;
+ table->hash_table_id = target_id;
return ret;
}
struct elf_link_hash_table *ret;
bfd_size_type amt = sizeof (struct elf_link_hash_table);
- ret = bfd_malloc (amt);
+ ret = (struct elf_link_hash_table *) 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)))
+ sizeof (struct elf_link_hash_entry),
+ GENERIC_ELF_DATA))
{
free (ret);
return NULL;
goto error_return;
amt = sizeof *l;
- l = bfd_alloc (abfd, amt);
+ l = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
if (l == NULL)
goto error_return;
struct elf_symbuf_head *ssymbuf, *ssymhead;
bfd_size_type i, shndx_count, total_size;
- indbuf = bfd_malloc2 (symcount, sizeof (*indbuf));
+ indbuf = (Elf_Internal_Sym **) bfd_malloc2 (symcount, sizeof (*indbuf));
if (indbuf == NULL)
return NULL;
total_size = ((shndx_count + 1) * sizeof (*ssymbuf)
+ (indbufend - indbuf) * sizeof (*ssym));
- ssymbuf = bfd_malloc (total_size);
+ ssymbuf = (struct elf_symbuf_head *) bfd_malloc (total_size);
if (ssymbuf == NULL)
{
free (indbuf);
result = FALSE;
isymbuf1 = NULL;
isymbuf2 = NULL;
- ssymbuf1 = elf_tdata (bfd1)->symbuf;
- ssymbuf2 = elf_tdata (bfd2)->symbuf;
+ ssymbuf1 = (struct elf_symbuf_head *) elf_tdata (bfd1)->symbuf;
+ ssymbuf2 = (struct elf_symbuf_head *) elf_tdata (bfd2)->symbuf;
if (ssymbuf1 == NULL)
{
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));
+ symtable1 = (struct elf_symbol *)
+ bfd_malloc (count1 * sizeof (struct elf_symbol));
+ symtable2 = (struct elf_symbol *)
+ bfd_malloc (count2 * sizeof (struct elf_symbol));
if (symtable1 == NULL || symtable2 == NULL)
goto done;
goto done;
}
- symtable1 = bfd_malloc (symcount1 * sizeof (struct elf_symbol));
- symtable2 = bfd_malloc (symcount2 * sizeof (struct elf_symbol));
+ symtable1 = (struct elf_symbol *)
+ bfd_malloc (symcount1 * sizeof (struct elf_symbol));
+ symtable2 = (struct elf_symbol *)
+ bfd_malloc (symcount2 * sizeof (struct elf_symbol));
if (symtable1 == NULL || symtable2 == NULL)
goto done;
else
shift = (8 * wordsz) - (start + len);
+ /* FIXME: octets_per_byte. */
x = get_value (wordsz, chunksz, input_bfd, contents + rel->r_offset);
#ifdef DEBUG
relocation, (mask << shift),
((relocation & mask) << shift), x);
#endif
+ /* FIXME: octets_per_byte. */
put_value (wordsz, chunksz, input_bfd, x, contents + rel->r_offset);
return r;
}
static int
elf_link_sort_cmp1 (const void *A, const void *B)
{
- const struct elf_link_sort_rela *a = A;
- const struct elf_link_sort_rela *b = B;
+ const struct elf_link_sort_rela *a = (const struct elf_link_sort_rela *) A;
+ const struct elf_link_sort_rela *b = (const struct elf_link_sort_rela *) B;
int relativea, relativeb;
relativea = a->type == reloc_class_relative;
static int
elf_link_sort_cmp2 (const void *A, const void *B)
{
- const struct elf_link_sort_rela *a = A;
- const struct elf_link_sort_rela *b = B;
+ const struct elf_link_sort_rela *a = (const struct elf_link_sort_rela *) A;
+ const struct elf_link_sort_rela *b = (const struct elf_link_sort_rela *) B;
int copya, copyb;
if (a->u.offset < b->u.offset)
+ (i2e - 1) * sizeof (Elf_Internal_Rela));
count = dynamic_relocs->size / ext_size;
- sort = bfd_zmalloc (sort_elt * count);
+ if (count == 0)
+ return 0;
+ sort = (bfd_byte *) bfd_zmalloc (sort_elt * count);
if (sort == NULL)
{
}
erel = o->contents;
erelend = o->contents + o->size;
+ /* FIXME: octets_per_byte. */
p = sort + o->output_offset / ext_size * sort_elt;
while (erel < erelend)
erel = o->contents;
erelend = o->contents + o->size;
+ /* FIXME: octets_per_byte. */
p = sort + o->output_offset / ext_size * sort_elt;
while (erel < erelend)
{
/* Add a symbol to the output symbol table. */
-static bfd_boolean
+static int
elf_link_output_sym (struct elf_final_link_info *finfo,
const char *name,
Elf_Internal_Sym *elfsym,
{
bfd_byte *dest;
Elf_External_Sym_Shndx *destshndx;
- bfd_boolean (*output_symbol_hook)
+ int (*output_symbol_hook)
(struct bfd_link_info *, const char *, Elf_Internal_Sym *, asection *,
struct elf_link_hash_entry *);
const struct elf_backend_data *bed;
output_symbol_hook = bed->elf_backend_link_output_symbol_hook;
if (output_symbol_hook != NULL)
{
- if (! (*output_symbol_hook) (finfo->info, name, elfsym, input_sec, h))
- return FALSE;
+ int ret = (*output_symbol_hook) (finfo->info, name, elfsym, input_sec, h);
+ if (ret != 1)
+ return ret;
}
if (name == NULL || *name == '\0')
elfsym->st_name = (unsigned long) _bfd_stringtab_add (finfo->symstrtab,
name, TRUE, FALSE);
if (elfsym->st_name == (unsigned long) -1)
- return FALSE;
+ return 0;
}
if (finfo->symbuf_count >= finfo->symbuf_size)
{
if (! elf_link_flush_output_syms (finfo, bed))
- return FALSE;
+ return 0;
}
dest = finfo->symbuf + finfo->symbuf_count * bed->s->sizeof_sym;
bfd_size_type amt;
amt = finfo->shndxbuf_size * sizeof (Elf_External_Sym_Shndx);
- destshndx = bfd_realloc (destshndx, amt * 2);
+ destshndx = (Elf_External_Sym_Shndx *) bfd_realloc (destshndx,
+ amt * 2);
if (destshndx == NULL)
- return FALSE;
+ return 0;
finfo->symshndxbuf = destshndx;
memset ((char *) destshndx + amt, 0, amt);
finfo->shndxbuf_size *= 2;
finfo->symbuf_count += 1;
bfd_get_symcount (finfo->output_bfd) += 1;
- return TRUE;
+ return 1;
}
/* Return TRUE if the dynamic symbol SYM in ABFD is supported. */
/* Read in any version definitions. */
versymhdr = &elf_tdata (input)->dynversym_hdr;
- extversym = bfd_malloc (versymhdr->sh_size);
+ extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size);
if (extversym == NULL)
goto error_ret;
_bfd_elf_swap_versym_in (input, ever, &iver);
- if ((iver.vs_vers & VERSYM_HIDDEN) == 0)
+ if ((iver.vs_vers & VERSYM_HIDDEN) == 0
+ && !(h->def_regular
+ && h->forced_local))
{
/* If we have a non-hidden versioned sym, then it should
- have provided a definition for the undefined sym. */
+ have provided a definition for the undefined sym unless
+ it is defined in a non-shared object and forced local.
+ */
abort ();
}
static bfd_boolean
elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
{
- struct elf_outext_info *eoinfo = data;
+ struct elf_outext_info *eoinfo = (struct elf_outext_info *) data;
struct elf_final_link_info *finfo = eoinfo->finfo;
bfd_boolean strip;
Elf_Internal_Sym sym;
asection *input_sec;
const struct elf_backend_data *bed;
+ long indx;
+ int ret;
if (h->root.type == bfd_link_hash_warning)
{
{
/* If we have an undefined symbol reference here then it must have
come from a shared library that is being linked in. (Undefined
- references in regular files have already been handled). */
+ references in regular files have already been handled unless
+ they are in unreferenced sections which are removed by garbage
+ collection). */
bfd_boolean ignore_undef = FALSE;
/* Some symbols may be special in that the fact that they're
/* If we are reporting errors for this situation then do so now. */
if (ignore_undef == FALSE
&& h->ref_dynamic
- && ! h->ref_regular
+ && (!h->ref_regular || finfo->info->gc_sections)
&& ! elf_link_check_versioned_symbol (finfo->info, bed, h)
&& finfo->info->unresolved_syms_in_shared_libs != RM_IGNORE)
{
if (! (finfo->info->callbacks->undefined_symbol
- (finfo->info, h->root.root.string, h->root.u.undef.abfd,
+ (finfo->info, h->root.root.string,
+ h->ref_regular ? NULL : h->root.u.undef.abfd,
NULL, 0, finfo->info->unresolved_syms_in_shared_libs == RM_GENERATE_ERROR)))
{
eoinfo->failed = TRUE;
strip = FALSE;
/* If we're stripping it, and it's not a dynamic symbol, there's
- nothing else to do unless it is a forced local symbol. */
+ nothing else to do unless it is a forced local symbol or a
+ STT_GNU_IFUNC symbol. */
if (strip
&& h->dynindx == -1
+ && h->type != STT_GNU_IFUNC
&& !h->forced_local)
return TRUE;
sym.st_size = h->size;
sym.st_other = h->other;
if (h->forced_local)
- sym.st_info = ELF_ST_INFO (STB_LOCAL, h->type);
+ {
+ sym.st_info = ELF_ST_INFO (STB_LOCAL, h->type);
+ /* Turn off visibility on local symbol. */
+ sym.st_other &= ~ELF_ST_VISIBILITY (-1);
+ }
+ else if (h->unique_global)
+ sym.st_info = ELF_ST_INFO (STB_GNU_UNIQUE, h->type);
else if (h->root.type == bfd_link_hash_undefweak
|| h->root.type == bfd_link_hash_defweak)
sym.st_info = ELF_ST_INFO (STB_WEAK, h->type);
/* Give the processor backend a chance to tweak the symbol value,
and also to finish up anything that needs to be done for this
symbol. FIXME: Not calling elf_backend_finish_dynamic_symbol for
- forced local syms when non-shared is due to a historical quirk. */
- if ((h->dynindx != -1
- || h->forced_local)
- && ((finfo->info->shared
- && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
- || h->root.type != bfd_link_hash_undefweak))
- || !h->forced_local)
- && elf_hash_table (finfo->info)->dynamic_sections_created)
+ forced local syms when non-shared is due to a historical quirk.
+ STT_GNU_IFUNC symbol must go through PLT. */
+ if ((h->type == STT_GNU_IFUNC
+ && h->def_regular
+ && !finfo->info->relocatable)
+ || ((h->dynindx != -1
+ || h->forced_local)
+ && ((finfo->info->shared
+ && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak))
+ || !h->forced_local)
+ && elf_hash_table (finfo->info)->dynamic_sections_created))
{
if (! ((*bed->elf_backend_finish_dynamic_symbol)
(finfo->output_bfd, finfo->info, h, &sym)))
|| ELF_ST_BIND (sym.st_info) == STB_WEAK))
{
int bindtype;
+ unsigned int type = ELF_ST_TYPE (sym.st_info);
+
+ /* Turn an undefined IFUNC symbol into a normal FUNC symbol. */
+ if (type == STT_GNU_IFUNC)
+ type = STT_FUNC;
if (h->ref_regular_nonweak)
bindtype = STB_GLOBAL;
else
bindtype = STB_WEAK;
- sym.st_info = ELF_ST_INFO (bindtype, ELF_ST_TYPE (sym.st_info));
+ sym.st_info = ELF_ST_INFO (bindtype, type);
}
/* If this is a symbol defined in a dynamic library, don't use the
if (strip || (input_sec->flags & SEC_EXCLUDE) != 0)
return TRUE;
- h->indx = bfd_get_symcount (finfo->output_bfd);
-
- if (! elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec, h))
+ indx = bfd_get_symcount (finfo->output_bfd);
+ ret = elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec, h);
+ if (ret == 0)
{
eoinfo->failed = TRUE;
return FALSE;
}
+ else if (ret == 1)
+ h->indx = indx;
+ else if (h->indx == -2)
+ abort();
return TRUE;
}
asection *isec;
const char *name;
Elf_Internal_Sym osym;
+ long indx;
+ int ret;
*pindex = -1;
&& bfd_is_local_label_name (input_bfd, name)))
continue;
- /* If we get here, we are going to output this symbol. */
-
osym = *isym;
/* Adjust the section index for the output file. */
if (osym.st_shndx == SHN_BAD)
return FALSE;
- *pindex = bfd_get_symcount (output_bfd);
-
/* ELF symbols in relocatable files are section relative, but
in executable files they are virtual addresses. Note that
this code assumes that all ELF sections have an associated
}
}
- if (! elf_link_output_sym (finfo, name, &osym, isec, NULL))
+ indx = bfd_get_symcount (output_bfd);
+ ret = elf_link_output_sym (finfo, name, &osym, isec, NULL);
+ if (ret == 0)
return FALSE;
+ else if (ret == 1)
+ *pindex = indx;
}
/* Relocate the contents of each section. */
Elf_Internal_Sym sym = isymbuf[symndx];
asection *sec = finfo->sections[symndx]->output_section;
const char *name;
+ long indx;
+ int ret;
name = bfd_elf_string_from_elf_section (input_bfd,
symtab_hdr->sh_link,
sym.st_value += o->output_offset;
- finfo->indices[symndx] = bfd_get_symcount (output_bfd);
- if (! elf_link_output_sym (finfo, name, &sym, o, NULL))
+ indx = bfd_get_symcount (output_bfd);
+ ret = elf_link_output_sym (finfo, name, &sym, o, NULL);
+ if (ret == 0)
return FALSE;
+ else if (ret == 1)
+ finfo->indices[symndx] = indx;
+ else
+ abort ();
}
elf_section_data (osec)->this_hdr.sh_info
= finfo->indices[symndx];
sym, *ps);
}
- if (s_type == STT_RELC || s_type == STT_SRELC)
+ if ((s_type == STT_RELC || s_type == STT_SRELC)
+ && !finfo->info->relocatable)
{
bfd_vma val;
bfd_vma dot = (rel->r_offset
unsigned long shlink;
const char *name;
asection *osec;
+ long indx;
if (finfo->info->strip == strip_all)
{
}
}
- finfo->indices[r_symndx]
- = bfd_get_symcount (output_bfd);
-
- if (! elf_link_output_sym (finfo, name, &sym, sec,
- NULL))
+ indx = bfd_get_symcount (output_bfd);
+ ret = elf_link_output_sym (finfo, name, &sym, sec,
+ NULL);
+ if (ret == 0)
return FALSE;
+ else if (ret == 1)
+ finfo->indices[r_symndx] = indx;
+ else
+ abort ();
}
r_symndx = finfo->indices[r_symndx];
break;
default:
{
+ /* FIXME: octets_per_byte. */
if (! (o->flags & SEC_EXCLUDE)
&& ! (o->output_section->flags & SEC_NEVER_LOAD)
&& ! bfd_set_section_contents (output_bfd, o->output_section,
bfd_boolean ok;
const char *sym_name;
- size = bfd_get_reloc_size (howto);
- buf = bfd_zmalloc (size);
+ size = (bfd_size_type) bfd_get_reloc_size (howto);
+ buf = (bfd_byte *) bfd_zmalloc (size);
if (buf == NULL)
return FALSE;
rstat = _bfd_relocate_contents (howto, output_bfd, addend, buf);
offset &= ~(bfd_vma) 0 << s->alignment_power;
s->output_offset = offset;
sections[n]->offset = offset;
+ /* FIXME: octets_per_byte. */
offset += sections[n]->size;
}
bfd_boolean emit_relocs;
bfd *dynobj;
struct elf_final_link_info finfo;
- register asection *o;
- register struct bfd_link_order *p;
- register bfd *sub;
+ asection *o;
+ struct bfd_link_order *p;
+ bfd *sub;
bfd_size_type max_contents_size;
bfd_size_type max_external_reloc_size;
bfd_size_type max_internal_reloc_count;
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)
finfo.symbuf_size = max_sym_count;
amt = finfo.symbuf_size;
amt *= bed->s->sizeof_sym;
- finfo.symbuf = bfd_malloc (amt);
+ finfo.symbuf = (bfd_byte *) bfd_malloc (amt);
if (finfo.symbuf == NULL)
goto error_return;
if (elf_numsections (abfd) > (SHN_LORESERVE & 0xFFFF))
amt = 2 * max_sym_count + elf_numsections (abfd) + 1000;
finfo.shndxbuf_size = amt;
amt *= sizeof (Elf_External_Sym_Shndx);
- finfo.symshndxbuf = bfd_zmalloc (amt);
+ finfo.symshndxbuf = (Elf_External_Sym_Shndx *) bfd_zmalloc (amt);
if (finfo.symshndxbuf == NULL)
goto error_return;
}
elfsym.st_info = 0;
elfsym.st_other = 0;
elfsym.st_shndx = SHN_UNDEF;
- if (! elf_link_output_sym (&finfo, NULL, &elfsym, bfd_und_section_ptr,
- NULL))
+ if (elf_link_output_sym (&finfo, NULL, &elfsym, bfd_und_section_ptr,
+ NULL) != 1)
goto error_return;
}
elfsym.st_shndx = i;
if (!info->relocatable)
elfsym.st_value = o->vma;
- if (!elf_link_output_sym (&finfo, NULL, &elfsym, o, NULL))
+ if (elf_link_output_sym (&finfo, NULL, &elfsym, o, NULL) != 1)
goto error_return;
}
}
files. */
if (max_contents_size != 0)
{
- finfo.contents = bfd_malloc (max_contents_size);
+ finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size);
if (finfo.contents == NULL)
goto error_return;
}
{
amt = max_internal_reloc_count * bed->s->int_rels_per_ext_rel;
amt *= sizeof (Elf_Internal_Rela);
- finfo.internal_relocs = bfd_malloc (amt);
+ finfo.internal_relocs = (Elf_Internal_Rela *) bfd_malloc (amt);
if (finfo.internal_relocs == NULL)
goto error_return;
}
if (max_sym_count != 0)
{
amt = max_sym_count * bed->s->sizeof_sym;
- finfo.external_syms = bfd_malloc (amt);
+ finfo.external_syms = (bfd_byte *) bfd_malloc (amt);
if (finfo.external_syms == NULL)
goto error_return;
amt = max_sym_count * sizeof (Elf_Internal_Sym);
- finfo.internal_syms = bfd_malloc (amt);
+ finfo.internal_syms = (Elf_Internal_Sym *) bfd_malloc (amt);
if (finfo.internal_syms == NULL)
goto error_return;
amt = max_sym_count * sizeof (long);
- finfo.indices = bfd_malloc (amt);
+ finfo.indices = (long int *) bfd_malloc (amt);
if (finfo.indices == NULL)
goto error_return;
amt = max_sym_count * sizeof (asection *);
- finfo.sections = bfd_malloc (amt);
+ finfo.sections = (asection **) bfd_malloc (amt);
if (finfo.sections == NULL)
goto error_return;
}
if (max_sym_shndx_count != 0)
{
amt = max_sym_shndx_count * sizeof (Elf_External_Sym_Shndx);
- finfo.locsym_shndx = bfd_malloc (amt);
+ finfo.locsym_shndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
if (finfo.locsym_shndx == NULL)
goto error_return;
}
if (size == 0
&& (sec->flags & SEC_HAS_CONTENTS) == 0)
{
- struct bfd_link_order *o = sec->map_tail.link_order;
- if (o != NULL)
- size = o->offset + o->size;
+ struct bfd_link_order *ord = sec->map_tail.link_order;
+
+ if (ord != NULL)
+ size = ord->offset + ord->size;
}
end = sec->vma + size;
}
table, do it now. */
if (bed->elf_backend_output_arch_local_syms)
{
- typedef bfd_boolean (*out_sym_func)
+ typedef int (*out_sym_func)
(void *, const char *, Elf_Internal_Sym *, asection *,
struct elf_link_hash_entry *);
asection *s;
bfd_byte *dest;
- sym.st_size = e->isym.st_size;
- sym.st_other = e->isym.st_other;
-
- /* Copy the internal symbol as is.
+ /* Copy the internal symbol and turn off visibility.
Note that we saved a word of storage and overwrote
the original st_name with the dynstr_index. */
sym = e->isym;
+ sym.st_other &= ~ELF_ST_VISIBILITY (-1);
s = bfd_section_from_elf_index (e->input_bfd,
e->isym.st_shndx);
table, do it now. */
if (bed->elf_backend_output_arch_syms)
{
- typedef bfd_boolean (*out_sym_func)
+ typedef int (*out_sym_func)
(void *, const char *, Elf_Internal_Sym *, asection *,
struct elf_link_hash_entry *);
!= SHT_STRTAB)
|| strcmp (bfd_get_section_name (abfd, o), ".dynstr") != 0)
{
+ /* FIXME: octets_per_byte. */
if (! bfd_set_section_contents (abfd, o->output_section,
o->contents,
(file_ptr) o->output_offset,
if (attr_section)
{
- bfd_byte *contents = bfd_malloc (attr_size);
+ bfd_byte *contents = (bfd_byte *) bfd_malloc (attr_size);
if (contents == NULL)
return FALSE; /* Bail out and fail. */
bfd_elf_set_obj_attr_contents (abfd, contents, attr_size);
struct elf_link_hash_entry *h,
Elf_Internal_Sym *sym)
{
+ const char *sec_name;
+
if (h != NULL)
{
switch (h->root.type)
case bfd_link_hash_common:
return h->root.u.c.p->section;
+ case bfd_link_hash_undefined:
+ case bfd_link_hash_undefweak:
+ /* To work around a glibc bug, keep all XXX input sections
+ when there is an as yet undefined reference to __start_XXX
+ or __stop_XXX symbols. The linker will later define such
+ symbols for orphan input sections that have a name
+ representable as a C identifier. */
+ if (strncmp (h->root.root.string, "__start_", 8) == 0)
+ sec_name = h->root.root.string + 8;
+ else if (strncmp (h->root.root.string, "__stop_", 7) == 0)
+ sec_name = h->root.root.string + 7;
+ else
+ sec_name = NULL;
+
+ if (sec_name && *sec_name != '\0')
+ {
+ bfd *i;
+
+ for (i = info->input_bfds; i; i = i->link_next)
+ {
+ sec = bfd_get_section_by_name (i, sec_name);
+ if (sec)
+ sec->flags |= SEC_KEEP;
+ }
+ }
+ break;
+
default:
break;
}
&& !h->root.u.def.section->gc_mark
&& !(h->root.u.def.section->owner->flags & DYNAMIC))
{
- struct elf_gc_sweep_symbol_info *inf = data;
+ struct elf_gc_sweep_symbol_info *inf =
+ (struct elf_gc_sweep_symbol_info *) data;
(*inf->hide_symbol) (inf->info, h, TRUE);
}
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)
+ || (o->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0
+ || elf_section_data (o)->this_hdr.sh_type == SHT_NOTE)
{
- /* Keep debug and special sections. */
+ /* Keep debug, special and SHT_NOTE sections. */
o->gc_mark = 1;
}
win:
if (!child->vtable)
{
- child->vtable = bfd_zalloc (abfd, sizeof (*child->vtable));
+ child->vtable = (struct elf_link_virtual_table_entry *)
+ bfd_zalloc (abfd, sizeof (*child->vtable));
if (!child->vtable)
return FALSE;
}
if (!h->vtable)
{
- h->vtable = bfd_zalloc (abfd, sizeof (*h->vtable));
+ h->vtable = (struct elf_link_virtual_table_entry *)
+ bfd_zalloc (abfd, sizeof (*h->vtable));
if (!h->vtable)
return FALSE;
}
if (ptr)
{
- ptr = bfd_realloc (ptr - 1, bytes);
+ ptr = (bfd_boolean *) bfd_realloc (ptr - 1, bytes);
if (ptr != NULL)
{
}
}
else
- ptr = bfd_zmalloc (bytes);
+ ptr = (bfd_boolean *) bfd_zmalloc (bytes);
if (ptr == NULL)
return FALSE;
static bfd_boolean
elf_gc_allocate_got_offsets (struct elf_link_hash_entry *h, void *arg)
{
- struct alloc_got_off_arg *gofarg = arg;
+ struct alloc_got_off_arg *gofarg = (struct alloc_got_off_arg *) arg;
bfd *obfd = gofarg->info->output_bfd;
const struct elf_backend_data *bed = get_elf_backend_data (obfd);
bfd_boolean
bfd_elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie)
{
- struct elf_reloc_cookie *rcookie = cookie;
+ struct elf_reloc_cookie *rcookie = (struct elf_reloc_cookie *) cookie;
if (rcookie->bad_symtab)
rcookie->rel = rcookie->rels;
/* 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"));
+ info->callbacks->einfo (_("%F%P: already_linked_table: %E\n"));
}
bfd_boolean
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
return reloc_sec;
}
+
+/* Copy the ELF symbol type associated with a linker hash entry. */
+void
+_bfd_elf_copy_link_hash_symbol_type (bfd *abfd ATTRIBUTE_UNUSED,
+ struct bfd_link_hash_entry * hdest,
+ struct bfd_link_hash_entry * hsrc)
+{
+ struct elf_link_hash_entry *ehdest = (struct elf_link_hash_entry *)hdest;
+ struct elf_link_hash_entry *ehsrc = (struct elf_link_hash_entry *)hsrc;
+
+ ehdest->type = ehsrc->type;
+}