char *fnm, *anm;
/* When we see DT_RPATH before DT_RUNPATH, we have
- to free runpath. */
+ to clear runpath. Do _NOT_ bfd_release, as that
+ frees all more recently bfd_alloc'd blocks as
+ well. */
if (rpath && elf_hash_table (info)->runpath)
- {
- struct bfd_link_needed_list *nn;
- for (n = elf_hash_table (info)->runpath;
- n != NULL; n = nn)
- {
- nn = n->next;
- bfd_release (abfd, n);
- }
- bfd_release (abfd, elf_hash_table (info)->runpath);
- elf_hash_table (info)->runpath = NULL;
- }
+ elf_hash_table (info)->runpath = NULL;
n = ((struct bfd_link_needed_list *)
bfd_alloc (abfd, sizeof (struct bfd_link_needed_list)));
if (sym.st_shndx != SHN_UNDEF
&& sym.st_shndx != SHN_COMMON)
flags = BSF_GLOBAL;
- else
- flags = 0;
}
else if (bind == STB_WEAK)
flags = BSF_WEAK;
unsigned int align;
align = bfd_log2 (sym.st_value);
- if (align > old_alignment)
+ if (align > old_alignment
+ /* Permit an alignment power of zero if an alignment of one
+ is specified and no other alignments have been specified. */
+ || (sym.st_value == 1 && old_alignment == 0))
h->root.u.c.p->alignment_power = align;
}
name to the fully decorated name. This will cause
external references which do not specify a version to be
bound to this version of the symbol. */
- if (definition)
+ if (definition || h->root.type == bfd_link_hash_common)
{
char *p;
{
struct elf_info_failed eif;
struct elf_link_hash_entry *h;
- bfd_size_type strsize;
+ asection *dynstr;
*sinterpptr = bfd_get_section_by_name (dynobj, ".interp");
BFD_ASSERT (*sinterpptr != NULL || info->shared);
return false;
}
- strsize = _bfd_stringtab_size (elf_hash_table (info)->dynstr);
- if (! elf_add_dynamic_entry (info, DT_HASH, 0)
- || ! elf_add_dynamic_entry (info, DT_STRTAB, 0)
- || ! elf_add_dynamic_entry (info, DT_SYMTAB, 0)
- || ! elf_add_dynamic_entry (info, DT_STRSZ, strsize)
- || ! elf_add_dynamic_entry (info, DT_SYMENT,
- sizeof (Elf_External_Sym)))
- return false;
+ dynstr = bfd_get_section_by_name (dynobj, ".dynstr");
+ /* If .dynstr is excluded from the link, we don't want any of
+ these tags. Strictly, we should be checking each section
+ individually; This quick check covers for the case where
+ someone does a /DISCARD/ : { *(*) }. */
+ if (dynstr != NULL && dynstr->output_section != bfd_abs_section_ptr)
+ {
+ bfd_size_type strsize;
+
+ strsize = _bfd_stringtab_size (elf_hash_table (info)->dynstr);
+ if (! elf_add_dynamic_entry (info, DT_HASH, 0)
+ || ! elf_add_dynamic_entry (info, DT_STRTAB, 0)
+ || ! elf_add_dynamic_entry (info, DT_SYMTAB, 0)
+ || ! elf_add_dynamic_entry (info, DT_STRSZ, strsize)
+ || ! elf_add_dynamic_entry (info, DT_SYMENT,
+ sizeof (Elf_External_Sym)))
+ return false;
+ }
}
/* The backend must work out the sizes of all the other dynamic
size_t dynsymcount;
asection *s;
size_t bucketcount = 0;
- Elf_Internal_Sym isym;
size_t hash_entry_size;
/* Set up the version definition section. */
if (s->contents == NULL && s->_raw_size != 0)
return false;
- /* The first entry in .dynsym is a dummy symbol. */
- isym.st_value = 0;
- isym.st_size = 0;
- isym.st_name = 0;
- isym.st_info = 0;
- isym.st_other = 0;
- isym.st_shndx = 0;
- elf_swap_symbol_out (output_bfd, &isym,
- (PTR) (Elf_External_Sym *) s->contents);
+ if (dynsymcount != 0)
+ {
+ Elf_Internal_Sym isym;
+
+ /* The first entry in .dynsym is a dummy symbol. */
+ isym.st_value = 0;
+ isym.st_size = 0;
+ isym.st_name = 0;
+ isym.st_info = 0;
+ isym.st_other = 0;
+ isym.st_shndx = 0;
+ elf_swap_symbol_out (output_bfd, &isym,
+ (PTR) (Elf_External_Sym *) s->contents);
+ }
/* Compute the size of the hashing table. As a side effect this
computes the hash values for all the names we export. */
/* The sh_info field records the index of the first non local symbol. */
symtab_hdr->sh_info = bfd_get_symcount (abfd);
- if (dynamic)
+ if (dynamic
+ && finfo.dynsym_sec->output_section != bfd_abs_section_ptr)
{
Elf_Internal_Sym sym;
Elf_External_Sym *dynsym =
for (o = dynobj->sections; o != NULL; o = o->next)
{
if ((o->flags & SEC_HAS_CONTENTS) == 0
- || o->_raw_size == 0)
+ || o->_raw_size == 0
+ || o->output_section == bfd_abs_section_ptr)
continue;
if ((o->flags & SEC_LINKER_CREATED) == 0)
{
if (esym == external_syms)
continue;
+ if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
+ {
+ asection *ksec;
+
+ /* Save away all section symbol values. */
+ if (isec != NULL)
+ isec->symbol->value = isym->st_value;
+
+ /* If this is a discarded link-once section symbol, update
+ it's value to that of the kept section symbol. The
+ linker will keep the first of any matching link-once
+ sections, so we should have already seen it's section
+ symbol. I trust no-one will have the bright idea of
+ re-ordering the bfd list... */
+ if (isec != NULL
+ && (bfd_get_section_flags (input_bfd, isec) & SEC_LINK_ONCE) != 0
+ && (ksec = isec->kept_section) != NULL)
+ {
+ isym->st_value = ksec->symbol->value;
+
+ /* That put the value right, but the section info is all
+ wrong. I hope this works. */
+ isec->output_offset = ksec->output_offset;
+ isec->output_section = ksec->output_section;
+ }
+
+ /* We never output section symbols. Instead, we use the
+ section symbol of the corresponding section in the output
+ file. */
+ continue;
+ }
+
/* If we are stripping all symbols, we don't want to output this
one. */
if (finfo->info->strip == strip_all)
continue;
- /* We never output section symbols. Instead, we use the section
- symbol of the corresponding section in the output file. */
- if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
- continue;
-
/* If we are discarding all local symbols, we don't want to
output this one. If we are generating a relocateable output
file, then some of the local symbols may be required by