/* ELF linking support for BFD.
- Copyright (C) 1995-2015 Free Software Foundation, Inc.
+ Copyright (C) 1995-2016 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
if ((info->dynamic_data
&& (h->type == STT_OBJECT
+ || h->type == STT_COMMON
|| (sym != NULL
- && ELF_ST_TYPE (sym->st_info) == STT_OBJECT)))
+ && (ELF_ST_TYPE (sym->st_info) == STT_OBJECT
+ || ELF_ST_TYPE (sym->st_info) == STT_COMMON))))
|| (d != NULL
&& h->root.type == bfd_link_hash_new
&& (*d->match) (&d->head, NULL, h->root.root.string)))
if (h == NULL)
return provide;
+ if (h->versioned == unknown)
+ {
+ /* Set versioned if symbol version is unknown. */
+ char *version = strrchr (name, ELF_VER_CHR);
+ if (version)
+ {
+ if (version > name && version[-1] != ELF_VER_CHR)
+ h->versioned = versioned_hidden;
+ else
+ h->versioned = versioned;
+ }
+ }
+
switch (h->root.type)
{
case bfd_link_hash_defined:
if ((h->def_dynamic
|| h->ref_dynamic
- || bfd_link_pic (info)
- || (bfd_link_pde (info)
- && elf_hash_table (info)->is_relocatable_executable))
+ || bfd_link_dll (info)
+ || elf_hash_table (info)->is_relocatable_executable)
&& h->dynindx == -1)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
&dynsymcount);
/* There is an unused NULL entry at the head of the table which
- we must account for in our count. Unless there weren't any
- symbols, which means we'll have no table at all. */
- if (dynsymcount != 0)
+ we must account for in our count. We always create the dynsym
+ section, even if it is empty, with dynamic sections. */
+ if (elf_hash_table (info)->dynamic_sections_created)
++dynsymcount;
elf_hash_table (info)->dynsymcount = dynsymcount;
*matched = TRUE;
else
{
- /* OLD_HIDDEN is true if the existing symbol is only visibile
+ /* OLD_HIDDEN is true if the existing symbol is only visible
to the symbol with the same symbol version. NEW_HIDDEN is
- true if the new symbol is only visibile to the symbol with
+ true if the new symbol is only visible to the symbol with
the same symbol version. */
bfd_boolean old_hidden = h->versioned == versioned_hidden;
bfd_boolean new_hidden = hi->versioned == versioned_hidden;
represent variables; this can cause confusion in principle, but
any such confusion would seem to indicate an erroneous program or
shared library. We also permit a common symbol in a regular
- object to override a weak symbol in a shared object. */
+ object to override a weak symbol in a shared object. A common
+ symbol in executable also overrides a symbol in a shared object. */
if (newdyn
&& newdef
&& (olddef
|| (h->root.type == bfd_link_hash_common
- && (newweak || newfunc))))
+ && (newweak
+ || newfunc
+ || (!olddyn && bfd_link_executable (info))))))
{
*override = TRUE;
newdef = FALSE;
h->versioned = versioned;
}
}
+ else
+ {
+ /* PR ld/19073: We may see an unversioned definition after the
+ default version. */
+ if (p == NULL)
+ return TRUE;
+ }
bed = get_elf_backend_data (abfd);
collect = bed->collect;
return 0;
}
+/* Return true if SONAME is on the needed list between NEEDED and STOP
+ (or the end of list if STOP is NULL), and needed by a library that
+ will be loaded. */
+
static bfd_boolean
-on_needed_list (const char *soname, struct bfd_link_needed_list *needed)
-{
- for (; needed != NULL; needed = needed->next)
- if ((elf_dyn_lib_class (needed->by) & DYN_AS_NEEDED) == 0
- && strcmp (soname, needed->name) == 0)
+on_needed_list (const char *soname,
+ struct bfd_link_needed_list *needed,
+ struct bfd_link_needed_list *stop)
+{
+ struct bfd_link_needed_list *look;
+ for (look = needed; look != stop; look = look->next)
+ if (strcmp (soname, look->name) == 0
+ && ((elf_dyn_lib_class (look->by) & DYN_AS_NEEDED) == 0
+ /* If needed by a library that itself is not directly
+ needed, recursively check whether that library is
+ indirectly needed. Since we add DT_NEEDED entries to
+ the end of the list, library dependencies appear after
+ the library. Therefore search prior to the current
+ LOOK, preventing possible infinite recursion. */
+ || on_needed_list (elf_dt_name (look->by), needed, look)))
return TRUE;
return FALSE;
/* If we are creating a shared library, create all the dynamic
sections immediately. We need to attach them to something,
so we attach them to this BFD, provided it is the right
- format and is not from ld --just-symbols. FIXME: If there
+ format and is not from ld --just-symbols. Always create the
+ dynamic sections for -E/--dynamic-list. FIXME: If there
are no input BFD's of the same format as the output, we can't
make a shared library. */
if (!just_syms
- && bfd_link_pic (info)
+ && (bfd_link_pic (info)
+ || (!bfd_link_relocatable (info)
+ && (info->export_dynamic || info->dynamic)))
&& is_elf_hash_table (htab)
&& info->output_bfd->xvec == abfd->xvec
&& !htab->dynamic_sections_created)
goto error_free_vers;
}
}
- else if (dynsym && h->dynindx != -1)
+ else if (h->dynindx != -1)
/* If the symbol already has a dynamic index, but
visibility says it should not be visible, turn it into
a local symbol. */
break;
}
- /* Don't add DT_NEEDED for references from the dummy bfd. */
+ /* Don't add DT_NEEDED for references from the dummy bfd nor
+ for unmatched symbol. */
if (!add_needed
+ && matched
&& definition
&& ((dynsym
&& h->ref_regular_nonweak
|| (old_bfd->flags & BFD_PLUGIN) == 0))
|| (h->ref_dynamic_nonweak
&& (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0
- && !on_needed_list (elf_dt_name (abfd), htab->needed))))
+ && !on_needed_list (elf_dt_name (abfd),
+ htab->needed, NULL))))
{
int ret;
const char *soname = elf_dt_name (abfd);
return FALSE;
}
+/* Looks up NAME in SECTIONS. If found sets RESULT to NAME's address (in
+ bytes) and returns TRUE, otherwise returns FALSE. Accepts pseudo-section
+ names like "foo.end" which is the end address of section "foo". */
+
static bfd_boolean
resolve_section (const char *name,
asection *sections,
- bfd_vma *result)
+ bfd_vma *result,
+ bfd * abfd)
{
asection *curr;
unsigned int len;
}
/* Hmm. still haven't found it. try pseudo-section names. */
+ /* FIXME: This could be coded more efficiently... */
for (curr = sections; curr; curr = curr->next)
{
len = strlen (curr->name);
{
if (strncmp (".end", name + len, 4) == 0)
{
- *result = curr->vma + curr->size;
+ *result = curr->vma + curr->size / bfd_octets_per_byte (abfd);
return TRUE;
}
if (symbol_is_section)
{
- if (!resolve_section (symbuf, flinfo->output_bfd->sections, result)
+ if (!resolve_section (symbuf, flinfo->output_bfd->sections, result, input_bfd)
&& !resolve_symbol (symbuf, input_bfd, flinfo, result,
isymbuf, locsymcount))
{
if (!resolve_symbol (symbuf, input_bfd, flinfo, result,
isymbuf, locsymcount)
&& !resolve_section (symbuf, flinfo->output_bfd->sections,
- result))
+ result, input_bfd))
{
undefined_reference ("symbol", symbuf);
return FALSE;
else
shift = (8 * wordsz) - (start + len);
- /* FIXME: octets_per_byte. */
- x = get_value (wordsz, chunksz, input_bfd, contents + rel->r_offset);
+ x = get_value (wordsz, chunksz, input_bfd,
+ contents + rel->r_offset * bfd_octets_per_byte (input_bfd));
#ifdef DEBUG
printf ("Doing complex reloc: "
(unsigned long) relocation, (unsigned long) (mask << shift),
(unsigned long) ((relocation & mask) << shift), (unsigned long) x);
#endif
- /* FIXME: octets_per_byte. */
- put_value (wordsz, chunksz, input_bfd, x, contents + rel->r_offset);
+ put_value (wordsz, chunksz, input_bfd, x,
+ contents + rel->r_offset * bfd_octets_per_byte (input_bfd));
return r;
}
return FALSE;
}
+/* Convert ELF common symbol TYPE. */
+
+static int
+elf_link_convert_common_type (struct bfd_link_info *info, int type)
+{
+ /* Commom symbol can only appear in relocatable link. */
+ if (!bfd_link_relocatable (info))
+ abort ();
+ switch (info->elf_stt_common)
+ {
+ case unchanged:
+ break;
+ case elf_stt_common:
+ type = STT_COMMON;
+ break;
+ case no_elf_stt_common:
+ type = STT_OBJECT;
+ break;
+ }
+ return type;
+}
+
/* Add an external symbol to the symbol table. This is called from
the hash table traversal routine. When generating a shared object,
we go through the symbol table twice. The first time we output
const struct elf_backend_data *bed;
long indx;
int ret;
+ unsigned int type;
/* A symbol is bound locally if it is forced local or it is locally
defined, hidden versioned, not referenced by shared library and
not exported when linking executable. */
&& (h->root.u.undef.abfd->flags & BFD_PLUGIN) != 0)
strip = TRUE;
+ type = h->type;
+
/* If we're stripping it, and it's not a dynamic symbol, there's
nothing else to do. However, if it is a forced local symbol or
an ifunc symbol we need to give the backend finish_dynamic_symbol
function a chance to make it dynamic. */
if (strip
&& h->dynindx == -1
- && h->type != STT_GNU_IFUNC
+ && type != STT_GNU_IFUNC
&& !h->forced_local)
return TRUE;
sym.st_value = 0;
sym.st_size = h->size;
sym.st_other = h->other;
- if (local_bind)
- {
- sym.st_info = ELF_ST_INFO (STB_LOCAL, h->type);
- /* Turn off visibility on local symbol. */
- sym.st_other &= ~ELF_ST_VISIBILITY (-1);
- }
- /* Set STB_GNU_UNIQUE only if symbol is defined in regular object. */
- else if (h->unique_global && h->def_regular)
- 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);
- else
- sym.st_info = ELF_ST_INFO (STB_GLOBAL, h->type);
- sym.st_target_internal = h->target_internal;
-
switch (h->root.type)
{
default:
return TRUE;
}
+ if (type == STT_COMMON || type == STT_OBJECT)
+ switch (h->root.type)
+ {
+ case bfd_link_hash_common:
+ type = elf_link_convert_common_type (flinfo->info, type);
+ break;
+ case bfd_link_hash_defined:
+ case bfd_link_hash_defweak:
+ if (bed->common_definition (&sym))
+ type = elf_link_convert_common_type (flinfo->info, type);
+ else
+ type = STT_OBJECT;
+ break;
+ case bfd_link_hash_undefined:
+ case bfd_link_hash_undefweak:
+ break;
+ default:
+ abort ();
+ }
+
+ if (local_bind)
+ {
+ sym.st_info = ELF_ST_INFO (STB_LOCAL, type);
+ /* Turn off visibility on local symbol. */
+ sym.st_other &= ~ELF_ST_VISIBILITY (-1);
+ }
+ /* Set STB_GNU_UNIQUE only if symbol is defined in regular object. */
+ else if (h->unique_global && h->def_regular)
+ sym.st_info = ELF_ST_INFO (STB_GNU_UNIQUE, 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, type);
+ else
+ sym.st_info = ELF_ST_INFO (STB_GLOBAL, type);
+ sym.st_target_internal = h->target_internal;
+
/* 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
|| ELF_ST_BIND (sym.st_info) == STB_WEAK))
{
int bindtype;
- unsigned int type = ELF_ST_TYPE (sym.st_info);
+ type = ELF_ST_TYPE (sym.st_info);
/* Turn an undefined IFUNC symbol into a normal FUNC symbol. */
if (type == STT_GNU_IFUNC)
break;
default:
{
- /* FIXME: octets_per_byte. */
if (! (o->flags & SEC_EXCLUDE))
{
file_ptr offset = (file_ptr) o->output_offset;
bfd_size_type todo = o->size;
+
+ offset *= bfd_octets_per_byte (output_bfd);
+
if ((o->flags & SEC_ELF_REVERSE_COPY))
{
/* Reverse-copy input section to output. */
}
break;
}
+
ok = bfd_set_section_contents (output_bfd, output_section, buf,
- link_order->offset, size);
+ link_order->offset
+ * bfd_octets_per_byte (output_bfd),
+ size);
free (buf);
if (! ok)
return FALSE;
{
s = sections[n]->u.indirect.section;
offset &= ~(bfd_vma) 0 << s->alignment_power;
- s->output_offset = offset;
+ s->output_offset = offset / bfd_octets_per_byte (abfd);
sections[n]->offset = offset;
- /* FIXME: octets_per_byte. */
offset += sections[n]->size;
}
for (p = o->map_head.link_order; p != NULL; p = p->next)
{
unsigned int reloc_count = 0;
+ unsigned int additional_reloc_count = 0;
struct bfd_elf_section_data *esdi = NULL;
if (p->type == bfd_section_reloc_link_order
reloc sections themselves can't have relocations. */
reloc_count = 0;
else if (emit_relocs)
- reloc_count = sec->reloc_count;
+ {
+ reloc_count = sec->reloc_count;
+ if (bed->elf_backend_count_additional_relocs)
+ {
+ int c;
+ c = (*bed->elf_backend_count_additional_relocs) (sec);
+ additional_reloc_count += c;
+ }
+ }
else if (bed->elf_backend_count_relocs)
reloc_count = (*bed->elf_backend_count_relocs) (info, sec);
if (reloc_count == 0)
continue;
+ reloc_count += additional_reloc_count;
o->reloc_count += reloc_count;
if (p->type == bfd_indirect_link_order && emit_relocs)
{
if (esdi->rel.hdr)
- esdo->rel.count += NUM_SHDR_ENTRIES (esdi->rel.hdr);
+ {
+ esdo->rel.count += NUM_SHDR_ENTRIES (esdi->rel.hdr);
+ esdo->rel.count += additional_reloc_count;
+ }
if (esdi->rela.hdr)
- esdo->rela.count += NUM_SHDR_ENTRIES (esdi->rela.hdr);
+ {
+ esdo->rela.count += NUM_SHDR_ENTRIES (esdi->rela.hdr);
+ esdo->rela.count += additional_reloc_count;
+ }
}
else
{
{
const char *iclass, *oclass;
- if (bed->s->elfclass == ELFCLASS64)
+ switch (bed->s->elfclass)
{
- iclass = "ELFCLASS32";
- oclass = "ELFCLASS64";
+ case ELFCLASS64: oclass = "ELFCLASS64"; break;
+ case ELFCLASS32: oclass = "ELFCLASS32"; break;
+ case ELFCLASSNONE: oclass = "ELFCLASSNONE"; break;
+ default: abort ();
}
- else
+
+ switch (elf_elfheader (sub)->e_ident[EI_CLASS])
{
- iclass = "ELFCLASS64";
- oclass = "ELFCLASS32";
+ case ELFCLASS64: iclass = "ELFCLASS64"; break;
+ case ELFCLASS32: iclass = "ELFCLASS32"; break;
+ case ELFCLASSNONE: iclass = "ELFCLASSNONE"; break;
+ default: abort ();
}
bfd_set_error (bfd_error_wrong_format);
symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr;
/* sh_name was set in prep_headers. */
symstrtab_hdr->sh_type = SHT_STRTAB;
- symstrtab_hdr->sh_flags = 0;
+ symstrtab_hdr->sh_flags = bed->elf_strtab_flags;
symstrtab_hdr->sh_addr = 0;
symstrtab_hdr->sh_size = _bfd_elf_strtab_size (flinfo.symstrtab);
symstrtab_hdr->sh_entsize = 0;
continue;
if (strcmp (o->name, ".dynstr") != 0)
{
- /* FIXME: octets_per_byte. */
if (! bfd_set_section_contents (abfd, o->output_section,
o->contents,
- (file_ptr) o->output_offset,
+ (file_ptr) o->output_offset
+ * bfd_octets_per_byte (abfd),
o->size))
goto error_return;
}
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;
}
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)
+ struct elf_reloc_cookie *cookie,
+ bfd_boolean *start_stop)
{
unsigned long r_symndx;
struct elf_link_hash_entry *h;
handling copy relocs. */
if (h->u.weakdef != NULL)
h->u.weakdef->mark = 1;
+
+ if (start_stop != NULL
+ && (h->root.type == bfd_link_hash_undefined
+ || h->root.type == bfd_link_hash_undefweak))
+ {
+ /* To work around a glibc bug, mark 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. */
+ const char *sec_name = NULL;
+ 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;
+
+ if (sec_name != NULL && *sec_name != '\0')
+ {
+ bfd *i;
+
+ for (i = info->input_bfds; i != NULL; i = i->link.next)
+ {
+ asection *s = bfd_get_section_by_name (i, sec_name);
+ if (s != NULL && !s->gc_mark)
+ {
+ *start_stop = TRUE;
+ return s;
+ }
+ }
+ }
+ }
+
return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL);
}
struct elf_reloc_cookie *cookie)
{
asection *rsec;
+ bfd_boolean start_stop = FALSE;
- rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie);
- if (rsec && !rsec->gc_mark)
+ rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie, &start_stop);
+ while (rsec != NULL)
{
- if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour
- || (rsec->owner->flags & DYNAMIC) != 0)
- rsec->gc_mark = 1;
- else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
- return FALSE;
+ if (!rsec->gc_mark)
+ {
+ if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour
+ || (rsec->owner->flags & DYNAMIC) != 0)
+ rsec->gc_mark = 1;
+ else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
+ return FALSE;
+ }
+ if (!start_stop)
+ break;
+ rsec = bfd_get_next_section_by_name (rsec->owner, rsec);
}
return TRUE;
}
&& (sec->flags & SEC_LINKER_CREATED) == 0)
elf_eh_frame_section (sub) = sec;
fini_reloc_cookie_for_section (&cookie, sec);
- sec = bfd_get_next_section_by_name (sec);
+ sec = bfd_get_next_section_by_name (NULL, sec);
}
}