/* ELF linker support.
- Copyright 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
+ Copyright 1995, 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
static boolean elf_merge_symbol
PARAMS ((bfd *, struct bfd_link_info *, const char *, Elf_Internal_Sym *,
asection **, bfd_vma *, struct elf_link_hash_entry **,
- boolean *, boolean *, boolean *));
+ boolean *, boolean *, boolean *, boolean));
static boolean elf_export_symbol
PARAMS ((struct elf_link_hash_entry *, PTR));
static boolean elf_fix_symbol_flags
PARAMS ((struct elf_link_hash_entry *, PTR));
static boolean elf_link_assign_sym_version
PARAMS ((struct elf_link_hash_entry *, PTR));
-static boolean elf_link_renumber_dynsyms
- PARAMS ((struct elf_link_hash_entry *, PTR));
static boolean elf_collect_hash_codes
PARAMS ((struct elf_link_hash_entry *, PTR));
static boolean elf_link_read_relocs_from_section
PARAMS ((bfd *, Elf_Internal_Shdr *, PTR, Elf_Internal_Rela *));
-static void elf_link_remove_section_and_adjust_dynindices
- PARAMS ((struct bfd_link_info *, asection *));
static void elf_link_output_relocs
PARAMS ((bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *));
static boolean elf_link_size_reloc_section
PARAMS ((bfd *, Elf_Internal_Shdr *, asection *));
+static void elf_link_adjust_relocs
+ PARAMS ((bfd *, Elf_Internal_Shdr *, unsigned int,
+ struct elf_link_hash_entry **));
/* Given an ELF BFD, add symbols to the global hash table as
appropriate. */
}
}
\f
+/* Return true iff this is a non-common definition of a symbol. */
+static boolean
+is_global_symbol_definition (abfd, sym)
+ bfd * abfd ATTRIBUTE_UNUSED;
+ Elf_Internal_Sym * sym;
+{
+ /* Local symbols do not count, but target specific ones might. */
+ if (ELF_ST_BIND (sym->st_info) != STB_GLOBAL
+ && ELF_ST_BIND (sym->st_info) < STB_LOOS)
+ return false;
+
+ /* If the section is undefined, then so is the symbol. */
+ if (sym->st_shndx == SHN_UNDEF)
+ return false;
+
+ /* If the symbol is defined in the common section, then
+ it is a common definition and so does not count. */
+ if (sym->st_shndx == SHN_COMMON)
+ return false;
+
+ /* If the symbol is in a target specific section then we
+ must rely upon the backend to tell us what it is. */
+ if (sym->st_shndx >= SHN_LORESERVE && sym->st_shndx < SHN_ABS)
+ /* FIXME - this function is not coded yet:
+
+ return _bfd_is_global_symbol_definition (abfd, sym);
+
+ Instead for now assume that the definition is not global,
+ Even if this is wrong, at least the linker will behave
+ in the same way that it used to do. */
+ return false;
+
+ return true;
+}
+
+
+/* Search the symbol table of the archive element of the archive ABFD
+ whoes archove map contains a mention of SYMDEF, and determine if
+ the symbol is defined in this element. */
+static boolean
+elf_link_is_defined_archive_symbol (abfd, symdef)
+ bfd * abfd;
+ carsym * symdef;
+{
+ Elf_Internal_Shdr * hdr;
+ Elf_External_Sym * esym;
+ Elf_External_Sym * esymend;
+ Elf_External_Sym * buf = NULL;
+ size_t symcount;
+ size_t extsymcount;
+ size_t extsymoff;
+ boolean result = false;
+
+ abfd = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
+ if (abfd == (bfd *) NULL)
+ return false;
+
+ if (! bfd_check_format (abfd, bfd_object))
+ return false;
+
+ /* If we have already included the element containing this symbol in the
+ link then we do not need to include it again. Just claim that any symbol
+ it contains is not a definition, so that our caller will not decide to
+ (re)include this element. */
+ if (abfd->archive_pass)
+ return false;
+
+ /* Select the appropriate symbol table. */
+ if ((abfd->flags & DYNAMIC) == 0 || elf_dynsymtab (abfd) == 0)
+ hdr = &elf_tdata (abfd)->symtab_hdr;
+ else
+ hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+
+ symcount = hdr->sh_size / sizeof (Elf_External_Sym);
+
+ /* The sh_info field of the symtab header tells us where the
+ external symbols start. We don't care about the local symbols. */
+ if (elf_bad_symtab (abfd))
+ {
+ extsymcount = symcount;
+ extsymoff = 0;
+ }
+ else
+ {
+ extsymcount = symcount - hdr->sh_info;
+ extsymoff = hdr->sh_info;
+ }
+
+ buf = ((Elf_External_Sym *)
+ bfd_malloc (extsymcount * sizeof (Elf_External_Sym)));
+ if (buf == NULL && extsymcount != 0)
+ return false;
+
+ /* Read in the symbol table.
+ FIXME: This ought to be cached somewhere. */
+ if (bfd_seek (abfd,
+ hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym),
+ SEEK_SET) != 0
+ || (bfd_read ((PTR) buf, sizeof (Elf_External_Sym), extsymcount, abfd)
+ != extsymcount * sizeof (Elf_External_Sym)))
+ {
+ free (buf);
+ return false;
+ }
+
+ /* Scan the symbol table looking for SYMDEF. */
+ esymend = buf + extsymcount;
+ for (esym = buf;
+ esym < esymend;
+ esym++)
+ {
+ Elf_Internal_Sym sym;
+ const char * name;
+
+ elf_swap_symbol_in (abfd, esym, & sym);
+
+ name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link, sym.st_name);
+ if (name == (const char *) NULL)
+ break;
+
+ if (strcmp (name, symdef->name) == 0)
+ {
+ result = is_global_symbol_definition (abfd, & sym);
+ break;
+ }
+ }
+
+ free (buf);
+
+ return result;
+}
+\f
/* Add symbols from an ELF archive file to the linker hash table. We
don't use _bfd_generic_link_add_archive_symbols because of a
if (h == NULL)
continue;
- if (h->root.type != bfd_link_hash_undefined)
+ if (h->root.type == bfd_link_hash_common)
+ {
+ /* We currently have a common symbol. The archive map contains
+ a reference to this symbol, so we may want to include it. We
+ only want to include it however, if this archive element
+ contains a definition of the symbol, not just another common
+ declaration of it.
+
+ Unfortunately some archivers (including GNU ar) will put
+ declarations of common symbols into their archive maps, as
+ well as real definitions, so we cannot just go by the archive
+ map alone. Instead we must read in the element's symbol
+ table and check that to see what kind of symbol definition
+ this is. */
+ if (! elf_link_is_defined_archive_symbol (abfd, symdef))
+ continue;
+ }
+ else if (h->root.type != bfd_link_hash_undefined)
{
if (h->root.type != bfd_link_hash_undefweak)
defined[i] = true;
}
/* We need to include this archive member. */
-
element = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
if (element == (bfd *) NULL)
goto error_return;
TYPE_CHANGE_OK if it is OK for the type to change. We set
SIZE_CHANGE_OK if it is OK for the size to change. By OK to
change, we mean that we shouldn't warn if the type or size does
- change. */
+ change. DT_NEEDED indicates if it comes from a DT_NEEDED entry of
+ a shared object. */
static boolean
elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
- override, type_change_ok, size_change_ok)
+ override, type_change_ok, size_change_ok, dt_needed)
bfd *abfd;
struct bfd_link_info *info;
const char *name;
boolean *override;
boolean *type_change_ok;
boolean *size_change_ok;
+ boolean dt_needed;
{
asection *sec;
struct elf_link_hash_entry *h;
/* 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
- itself. */
- if (abfd == oldbfd)
+ itself. The additional tests catch cases like
+ _GLOBAL_OFFSET_TABLE_, which are regular symbols defined in a
+ dynamic object, which we do want to handle here. */
+ if (abfd == oldbfd
+ && ((abfd->flags & DYNAMIC) == 0
+ || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0))
return true;
/* NEWDYN and OLDDYN indicate whether the new or old symbol,
else
newdyn = false;
- if (oldbfd == NULL || (oldbfd->flags & DYNAMIC) == 0)
- olddyn = false;
+ if (oldbfd != NULL)
+ olddyn = (oldbfd->flags & DYNAMIC) != 0;
else
- olddyn = true;
+ {
+ asection *hsec;
+
+ /* This code handles the special SHN_MIPS_{TEXT,DATA} section
+ indices used by MIPS ELF. */
+ switch (h->root.type)
+ {
+ default:
+ hsec = NULL;
+ break;
+
+ case bfd_link_hash_defined:
+ case bfd_link_hash_defweak:
+ hsec = h->root.u.def.section;
+ break;
+
+ case bfd_link_hash_common:
+ hsec = h->root.u.c.p->section;
+ break;
+ }
+
+ if (hsec == NULL)
+ olddyn = false;
+ else
+ olddyn = (hsec->symbol->flags & BSF_DYNAMIC) != 0;
+ }
/* NEWDEF and OLDDEF indicate whether the new or old symbol,
respectively, appear to be a definition rather than reference. */
olddyncommon = false;
/* It's OK to change the type if either the existing symbol or the
- new symbol is weak. */
+ new symbol is weak unless it comes from a DT_NEEDED entry of
+ a shared object, in which case, the DT_NEEDED entry may not be
+ required at the run time. */
- if (h->root.type == bfd_link_hash_defweak
+ if ((! dt_needed && h->root.type == bfd_link_hash_defweak)
|| h->root.type == bfd_link_hash_undefweak
|| bind == STB_WEAK)
*type_change_ok = true;
object to override a weak symbol in a shared object.
We prefer a non-weak definition in a shared library to a weak
- definition in the executable. */
+ definition in the executable unless it comes from a DT_NEEDED
+ entry of a shared object, in which case, the DT_NEEDED entry
+ may not be required at the run time. */
if (newdyn
&& newdef
|| (h->root.type == bfd_link_hash_common
&& (bind == STB_WEAK
|| ELF_ST_TYPE (sym->st_info) == STT_FUNC)))
- && (h->root.type != bfd_link_hash_defweak
+ && (h->root.type != bfd_link_hash_defweak
+ || dt_needed
|| bind == STB_WEAK))
{
*override = true;
/* Handle the special case of a weak definition in a regular object
followed by a non-weak definition in a shared object. In this
- case, we prefer the definition in the shared object. */
+ case, we prefer the definition in the shared object unless it
+ comes from a DT_NEEDED entry of a shared object, in which case,
+ the DT_NEEDED entry may not be required at the run time. */
if (olddef
+ && ! dt_needed
&& h->root.type == bfd_link_hash_defweak
&& newdef
&& newdyn
/* To make this work we have to frob the flags so that the rest
of the code does not think we are using the regular
definition. */
- h->elf_link_hash_flags &= ~ ELF_LINK_HASH_DEF_REGULAR;
- h->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR;
+ if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
+ h->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR;
+ else if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0)
+ h->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC;
+ h->elf_link_hash_flags &= ~ (ELF_LINK_HASH_DEF_REGULAR
+ | ELF_LINK_HASH_DEF_DYNAMIC);
/* If H is the target of an indirection, we want the caller to
use H rather than the indirect symbol. Otherwise if we are
struct elf_link_hash_entry *weaks;
Elf_External_Sym *esym;
Elf_External_Sym *esymend;
+ struct elf_backend_data *bed;
+ boolean dt_needed;
- add_symbol_hook = get_elf_backend_data (abfd)->elf_add_symbol_hook;
- collect = get_elf_backend_data (abfd)->collect;
+ bed = get_elf_backend_data (abfd);
+ add_symbol_hook = bed->elf_add_symbol_hook;
+ collect = bed->collect;
if ((abfd->flags & DYNAMIC) == 0)
dynamic = false;
goto error_return;
elf_sym_hashes (abfd) = sym_hash;
+ dt_needed = false;
+
if (! dynamic)
{
/* If we are creating a shared library, create all the dynamic
{
name = elf_dt_name (abfd);
if (*name == '\0')
- add_needed = false;
+ {
+ if (elf_dt_soname (abfd) != NULL)
+ dt_needed = true;
+
+ add_needed = false;
+ }
}
s = bfd_get_section_by_name (abfd, ".dynamic");
if (s != NULL)
Elf_External_Dyn *extdynend;
int elfsec;
unsigned long link;
+ int rpath;
+ int runpath;
dynbuf = (Elf_External_Dyn *) bfd_malloc ((size_t) s->_raw_size);
if (dynbuf == NULL)
goto error_return;
link = elf_elfsections (abfd)[elfsec]->sh_link;
+ {
+ /* The shared libraries distributed with hpux11 have a bogus
+ sh_link field for the ".dynamic" section. This code detects
+ when LINK refers to a section that is not a string table and
+ tries to find the string table for the ".dynsym" section
+ instead. */
+ Elf_Internal_Shdr *hdr = elf_elfsections (abfd)[link];
+ if (hdr->sh_type != SHT_STRTAB)
+ {
+ asection *s = bfd_get_section_by_name (abfd, ".dynsym");
+ int elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
+ if (elfsec == -1)
+ goto error_return;
+ link = elf_elfsections (abfd)[elfsec]->sh_link;
+ }
+ }
+
extdyn = dynbuf;
extdynend = extdyn + s->_raw_size / sizeof (Elf_External_Dyn);
+ rpath = 0;
+ runpath = 0;
for (; extdyn < extdynend; extdyn++)
{
Elf_Internal_Dyn dyn;
;
*pn = n;
}
+ if (dyn.d_tag == DT_RUNPATH)
+ {
+ struct bfd_link_needed_list *n, **pn;
+ char *fnm, *anm;
+
+ /* When we see DT_RPATH before DT_RUNPATH, we have
+ 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)
+ elf_hash_table (info)->runpath = NULL;
+
+ n = ((struct bfd_link_needed_list *)
+ bfd_alloc (abfd, sizeof (struct bfd_link_needed_list)));
+ fnm = bfd_elf_string_from_elf_section (abfd, link,
+ dyn.d_un.d_val);
+ if (n == NULL || fnm == NULL)
+ goto error_return;
+ anm = bfd_alloc (abfd, strlen (fnm) + 1);
+ if (anm == NULL)
+ goto error_return;
+ strcpy (anm, fnm);
+ n->name = anm;
+ n->by = abfd;
+ n->next = NULL;
+ for (pn = &elf_hash_table (info)->runpath;
+ *pn != NULL;
+ pn = &(*pn)->next)
+ ;
+ *pn = n;
+ runpath = 1;
+ rpath = 0;
+ }
+ /* Ignore DT_RPATH if we have seen DT_RUNPATH. */
+ if (!runpath && dyn.d_tag == DT_RPATH)
+ {
+ struct bfd_link_needed_list *n, **pn;
+ char *fnm, *anm;
+
+ n = ((struct bfd_link_needed_list *)
+ bfd_alloc (abfd, sizeof (struct bfd_link_needed_list)));
+ fnm = bfd_elf_string_from_elf_section (abfd, link,
+ dyn.d_un.d_val);
+ if (n == NULL || fnm == NULL)
+ goto error_return;
+ anm = bfd_alloc (abfd, strlen (fnm) + 1);
+ if (anm == NULL)
+ goto error_return;
+ strcpy (anm, fnm);
+ n->name = anm;
+ n->by = abfd;
+ n->next = NULL;
+ for (pn = &elf_hash_table (info)->runpath;
+ *pn != NULL;
+ pn = &(*pn)->next)
+ ;
+ *pn = n;
+ rpath = 1;
+ }
}
free (dynbuf);
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;
strcpy (newname, name);
p = newname + namelen;
*p++ = ELF_VER_CHR;
- if ((iver.vs_vers & VERSYM_HIDDEN) == 0)
+ /* If this is a defined non-hidden version symbol,
+ we add another @ to the name. This indicates the
+ default version of the symbol. */
+ if ((iver.vs_vers & VERSYM_HIDDEN) == 0
+ && sym.st_shndx != SHN_UNDEF)
*p++ = ELF_VER_CHR;
strcpy (p, verstr);
if (! elf_merge_symbol (abfd, info, name, &sym, &sec, &value,
sym_hash, &override, &type_change_ok,
- &size_change_ok))
+ &size_change_ok, dt_needed))
goto error_return;
if (override)
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;
}
h->type = ELF_ST_TYPE (sym.st_info);
}
- if (sym.st_other != 0
- && (definition || h->other == 0))
- h->other = sym.st_other;
+ /* If st_other has a processor-specific meaning, specific code
+ might be needed here. */
+ if (sym.st_other != 0)
+ {
+ /* Combine visibilities, using the most constraining one. */
+ unsigned char hvis = ELF_ST_VISIBILITY (h->other);
+ unsigned char symvis = ELF_ST_VISIBILITY (sym.st_other);
+
+ if (symvis && (hvis > symvis || hvis == 0))
+ h->other = sym.st_other;
+
+ /* If neither has visibility, use the st_other of the
+ definition. This is an arbitrary choice, since the
+ other bits have no general meaning. */
+ if (!symvis && !hvis
+ && (definition || h->other == 0))
+ h->other = sym.st_other;
+ }
/* Set a flag in the hash table entry indicating the type of
reference or definition we just found. Keep a count of
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;
size_change_ok = false;
if (! elf_merge_symbol (abfd, info, shortname, &sym, &sec,
&value, &hi, &override,
- &type_change_ok, &size_change_ok))
+ &type_change_ok,
+ &size_change_ok, dt_needed))
goto error_return;
if (! override)
== 0);
ht = (struct elf_link_hash_entry *) hi->root.u.i.link;
-
- /* Copy down any references that we may have
- already seen to the symbol which just became
- indirect. */
- ht->elf_link_hash_flags |=
- (hi->elf_link_hash_flags
- & (ELF_LINK_HASH_REF_DYNAMIC
- | ELF_LINK_HASH_REF_REGULAR
- | ELF_LINK_HASH_REF_REGULAR_NONWEAK));
-
- /* Copy over the global and procedure linkage table
- offset entries. These may have been already set
- up by a check_relocs routine. */
- if (ht->got.offset == (bfd_vma) -1)
- {
- ht->got.offset = hi->got.offset;
- hi->got.offset = (bfd_vma) -1;
- }
- BFD_ASSERT (hi->got.offset == (bfd_vma) -1);
-
- if (ht->plt.offset == (bfd_vma) -1)
- {
- ht->plt.offset = hi->plt.offset;
- hi->plt.offset = (bfd_vma) -1;
- }
- BFD_ASSERT (hi->plt.offset == (bfd_vma) -1);
-
- if (ht->dynindx == -1)
- {
- ht->dynindx = hi->dynindx;
- ht->dynstr_index = hi->dynstr_index;
- hi->dynindx = -1;
- hi->dynstr_index = 0;
- }
- BFD_ASSERT (hi->dynindx == -1);
-
- /* FIXME: There may be other information to copy
- over for particular targets. */
+ (*bed->elf_backend_copy_indirect_symbol) (ht, hi);
/* See if the new flags lead us to realize that
the symbol must be dynamic. */
size_change_ok = false;
if (! elf_merge_symbol (abfd, info, shortname, &sym, &sec,
&value, &hi, &override,
- &type_change_ok, &size_change_ok))
+ &type_change_ok,
+ &size_change_ok, dt_needed))
goto error_return;
if (override)
| ELF_LINK_HASH_DEF_REGULAR))
== 0);
- /* Copy down any references that we may have
- already seen to the symbol which just
- became indirect. */
- h->elf_link_hash_flags |=
- (hi->elf_link_hash_flags
- & (ELF_LINK_HASH_REF_DYNAMIC
- | ELF_LINK_HASH_REF_REGULAR
- | ELF_LINK_HASH_REF_REGULAR_NONWEAK));
-
- /* Copy over the global and procedure linkage
- table offset entries. These may have been
- already set up by a check_relocs routine. */
- if (h->got.offset == (bfd_vma) -1)
- {
- h->got.offset = hi->got.offset;
- hi->got.offset = (bfd_vma) -1;
- }
- BFD_ASSERT (hi->got.offset == (bfd_vma) -1);
-
- if (h->plt.offset == (bfd_vma) -1)
- {
- h->plt.offset = hi->plt.offset;
- hi->plt.offset = (bfd_vma) -1;
- }
- BFD_ASSERT (hi->got.offset == (bfd_vma) -1);
-
- if (h->dynindx == -1)
- {
- h->dynindx = hi->dynindx;
- h->dynstr_index = hi->dynstr_index;
- hi->dynindx = -1;
- hi->dynstr_index = 0;
- }
- BFD_ASSERT (hi->dynindx == -1);
-
- /* FIXME: There may be other information to
- copy over for particular targets. */
+ (*bed->elf_backend_copy_indirect_symbol) (h, hi);
/* See if the new flags lead us to realize
that the symbol must be dynamic. */
goto error_return;
}
}
+ else if (dynsym && 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. */
+ switch (ELF_ST_VISIBILITY (h->other))
+ {
+ case STV_INTERNAL:
+ case STV_HIDDEN:
+ h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
+ (*bed->elf_backend_hide_symbol) (info, h);
+ break;
+ }
+
+ if (dt_needed && definition
+ && (h->elf_link_hash_flags
+ & ELF_LINK_HASH_REF_REGULAR) != 0)
+ {
+ bfd_size_type oldsize;
+ bfd_size_type strindex;
+
+ /* The symbol from a DT_NEEDED object is referenced from
+ the regular object to create a dynamic executable. We
+ have to make sure there is a DT_NEEDED entry for it. */
+
+ dt_needed = false;
+ oldsize = _bfd_stringtab_size (elf_hash_table (info)->dynstr);
+ strindex = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
+ elf_dt_soname (abfd),
+ true, false);
+ if (strindex == (bfd_size_type) -1)
+ goto error_return;
+
+ if (oldsize
+ == _bfd_stringtab_size (elf_hash_table (info)->dynstr))
+ {
+ asection *sdyn;
+ Elf_External_Dyn *dyncon, *dynconend;
+
+ sdyn = bfd_get_section_by_name (elf_hash_table (info)->dynobj,
+ ".dynamic");
+ BFD_ASSERT (sdyn != NULL);
+
+ dyncon = (Elf_External_Dyn *) sdyn->contents;
+ dynconend = (Elf_External_Dyn *) (sdyn->contents +
+ sdyn->_raw_size);
+ for (; dyncon < dynconend; dyncon++)
+ {
+ Elf_Internal_Dyn dyn;
+
+ elf_swap_dyn_in (elf_hash_table (info)->dynobj,
+ dyncon, &dyn);
+ BFD_ASSERT (dyn.d_tag != DT_NEEDED ||
+ dyn.d_un.d_val != strindex);
+ }
+ }
+
+ if (! elf_add_dynamic_entry (info, DT_NEEDED, strindex))
+ goto error_return;
+ }
}
}
return true;
}
+
+/* Record a new local dynamic symbol. */
+
+boolean
+elf_link_record_local_dynamic_symbol (info, input_bfd, input_indx)
+ struct bfd_link_info *info;
+ bfd *input_bfd;
+ long input_indx;
+{
+ struct elf_link_local_dynamic_entry *entry;
+ struct elf_link_hash_table *eht;
+ struct bfd_strtab_hash *dynstr;
+ Elf_External_Sym esym;
+ unsigned long dynstr_index;
+ char *name;
+
+ /* See if the entry exists already. */
+ for (entry = elf_hash_table (info)->dynlocal; entry ; entry = entry->next)
+ if (entry->input_bfd == input_bfd && entry->input_indx == input_indx)
+ return true;
+
+ entry = (struct elf_link_local_dynamic_entry *)
+ bfd_alloc (input_bfd, sizeof (*entry));
+ if (entry == NULL)
+ return false;
+
+ /* Go find the symbol, so that we can find it's name. */
+ if (bfd_seek (input_bfd,
+ (elf_tdata (input_bfd)->symtab_hdr.sh_offset
+ + input_indx * sizeof (Elf_External_Sym)),
+ SEEK_SET) != 0
+ || (bfd_read (&esym, sizeof (Elf_External_Sym), 1, input_bfd)
+ != sizeof (Elf_External_Sym)))
+ return false;
+ elf_swap_symbol_in (input_bfd, &esym, &entry->isym);
+
+ name = (bfd_elf_string_from_elf_section
+ (input_bfd, elf_tdata (input_bfd)->symtab_hdr.sh_link,
+ entry->isym.st_name));
+
+ dynstr = elf_hash_table (info)->dynstr;
+ if (dynstr == NULL)
+ {
+ /* Create a strtab to hold the dynamic symbol names. */
+ elf_hash_table (info)->dynstr = dynstr = _bfd_elf_stringtab_init ();
+ if (dynstr == NULL)
+ return false;
+ }
+
+ dynstr_index = _bfd_stringtab_add (dynstr, name, true, false);
+ if (dynstr_index == (unsigned long) -1)
+ return false;
+ entry->isym.st_name = dynstr_index;
+
+ eht = elf_hash_table (info);
+
+ entry->next = eht->dynlocal;
+ eht->dynlocal = entry;
+ entry->input_bfd = input_bfd;
+ entry->input_indx = input_indx;
+ eht->dynsymcount++;
+
+ /* Whatever binding the symbol had before, it's now local. */
+ entry->isym.st_info
+ = ELF_ST_INFO (STB_LOCAL, ELF_ST_TYPE (entry->isym.st_info));
+
+ /* The dynindx will be set at the end of size_dynamic_sections. */
+
+ return true;
+}
\f
/* Read and swap the relocs from the section indicated by SHDR. This
/*ARGSUSED*/
boolean
NAME(bfd_elf,record_link_assignment) (output_bfd, info, name, provide)
- bfd *output_bfd;
+ bfd *output_bfd ATTRIBUTE_UNUSED;
struct bfd_link_info *info;
const char *name;
boolean provide;
h->verinfo.verdef = NULL;
h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
- h->type = STT_OBJECT;
+
+ /* When possible, keep the original type of the symbol */
+ if (h->type == STT_NOTYPE)
+ h->type = STT_OBJECT;
if (((h->elf_link_hash_flags & (ELF_LINK_HASH_DEF_DYNAMIC
| ELF_LINK_HASH_REF_DYNAMIC)) != 0
struct bfd_elf_version_tree *verdefs;
/* Whether we are exporting all dynamic symbols. */
boolean export_dynamic;
- /* Whether we removed any symbols from the dynamic symbol table. */
- boolean removed_dynamic;
/* Whether we had a failure. */
boolean failed;
};
struct bfd_link_info *info;
{
size_t dynsymcount = elf_hash_table (info)->dynsymcount;
- size_t best_size;
+ size_t best_size = 0;
unsigned long int *hashcodes;
unsigned long int *hashcodesp;
unsigned long int i;
return best_size;
}
-/* Remove SECTION from the BFD. If a symbol for SECTION was going to
- be put into the dynamic symbol table, remove it, and renumber
- subsequent entries. */
-
-static void
-elf_link_remove_section_and_adjust_dynindices (info, section)
- struct bfd_link_info *info;
- asection *section;
-{
- /* Remove the section from the output list. */
- _bfd_strip_section_from_output (section);
-
- if (elf_section_data (section->output_section)->dynindx)
- {
- asection *s;
- int increment = -1;
-
- /* We were going to output an entry in the dynamic symbol table
- for the symbol corresponding to this section. Now, the
- section is gone. So, we must renumber the dynamic indices of
- all subsequent sections and all other entries in the dynamic
- symbol table. */
- elf_section_data (section->output_section)->dynindx = 0;
- for (s = section->output_section->next; s; s = s->next)
- if (elf_section_data (s)->dynindx)
- --elf_section_data (s)->dynindx;
-
- elf_link_hash_traverse (elf_hash_table (info),
- _bfd_elf_link_adjust_dynindx,
- &increment);
-
- /* There is one less dynamic symbol than there was before. */
- --elf_hash_table (info)->dynsymcount;
- }
-}
-
/* 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
bfd_size_type soname_indx;
bfd *dynobj;
struct elf_backend_data *bed;
- bfd_size_type old_dynsymcount;
struct elf_assign_sym_version_info asvinfo;
*sinterpptr = NULL;
if (dynobj == NULL)
return true;
- /* If we are supposed to export all symbols into the dynamic symbol
- table (this is not the normal case), then do so. */
- if (export_dynamic)
- {
- struct elf_info_failed eif;
-
- eif.failed = false;
- eif.info = info;
- elf_link_hash_traverse (elf_hash_table (info), elf_export_symbol,
- (PTR) &eif);
- if (eif.failed)
- return false;
- }
-
if (elf_hash_table (info)->dynamic_sections_created)
{
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);
{
if (! elf_add_dynamic_entry (info, DT_SYMBOLIC, 0))
return false;
+ info->flags |= DF_SYMBOLIC;
}
if (rpath != NULL)
indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr, rpath,
true, true);
if (indx == (bfd_size_type) -1
- || ! elf_add_dynamic_entry (info, DT_RPATH, indx))
+ || ! elf_add_dynamic_entry (info, DT_RPATH, indx)
+ || (info->new_dtags
+ && ! elf_add_dynamic_entry (info, DT_RUNPATH, indx)))
return false;
}
}
}
+ /* If we are supposed to export all symbols into the dynamic symbol
+ table (this is not the normal case), then do so. */
+ if (export_dynamic)
+ {
+ struct elf_info_failed eif;
+
+ eif.failed = false;
+ eif.info = info;
+ elf_link_hash_traverse (elf_hash_table (info), elf_export_symbol,
+ (PTR) &eif);
+ if (eif.failed)
+ return false;
+ }
+
/* Attach all the symbols to their version information. */
asvinfo.output_bfd = output_bfd;
asvinfo.info = info;
asvinfo.verdefs = verdefs;
asvinfo.export_dynamic = export_dynamic;
- asvinfo.removed_dynamic = false;
asvinfo.failed = false;
elf_link_hash_traverse (elf_hash_table (info),
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
sections. */
- old_dynsymcount = elf_hash_table (info)->dynsymcount;
if (bed->elf_backend_size_dynamic_sections
&& ! (*bed->elf_backend_size_dynamic_sections) (output_bfd, info))
return false;
size_t dynsymcount;
asection *s;
size_t bucketcount = 0;
- Elf_Internal_Sym isym;
size_t hash_entry_size;
/* Set up the version definition section. */
verdefs = asvinfo.verdefs;
if (verdefs == NULL)
- elf_link_remove_section_and_adjust_dynindices (info, s);
+ _bfd_strip_section_from_output (info, s);
else
{
unsigned int cdefs;
Elf_Internal_Verdef def;
Elf_Internal_Verdaux defaux;
- if (asvinfo.removed_dynamic)
- {
- /* Some dynamic symbols were changed to be local
- symbols. In this case, we renumber all of the
- dynamic symbols, so that we don't have a hole. If
- the backend changed dynsymcount, then assume that the
- new symbols are at the start. This is the case on
- the MIPS. FIXME: The names of the removed symbols
- will still be in the dynamic string table, wasting
- space. */
- elf_hash_table (info)->dynsymcount =
- 1 + (elf_hash_table (info)->dynsymcount - old_dynsymcount);
- elf_link_hash_traverse (elf_hash_table (info),
- elf_link_renumber_dynsyms,
- (PTR) info);
- }
-
cdefs = 0;
size = 0;
if (soname_indx != (bfd_size_type) -1)
{
- def.vd_hash = bfd_elf_hash ((const unsigned char *) soname);
+ def.vd_hash = bfd_elf_hash (soname);
defaux.vda_name = soname_indx;
}
else
bfd_size_type indx;
name = output_bfd->filename;
- def.vd_hash = bfd_elf_hash ((const unsigned char *) name);
+ def.vd_hash = bfd_elf_hash (name);
indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
name, true, false);
if (indx == (bfd_size_type) -1)
def.vd_flags |= VER_FLG_WEAK;
def.vd_ndx = t->vernum + 1;
def.vd_cnt = cdeps + 1;
- def.vd_hash = bfd_elf_hash ((const unsigned char *) t->name);
+ def.vd_hash = bfd_elf_hash (t->name);
def.vd_aux = sizeof (Elf_External_Verdef);
if (t->next != NULL)
def.vd_next = (sizeof (Elf_External_Verdef)
elf_tdata (output_bfd)->cverdefs = cdefs;
}
+ if (info->new_dtags && info->flags)
+ {
+ if (! elf_add_dynamic_entry (info, DT_FLAGS, info->flags))
+ return false;
+ }
+
+ if (info->flags_1)
+ {
+ if (! info->shared)
+ info->flags_1 &= ~ (DF_1_INITFIRST
+ | DF_1_NODELETE
+ | DF_1_NOOPEN);
+ if (! elf_add_dynamic_entry (info, DT_FLAGS_1, info->flags_1))
+ return false;
+ }
+
/* Work out the size of the version reference section. */
s = bfd_get_section_by_name (dynobj, ".gnu.version_r");
(PTR) &sinfo);
if (elf_tdata (output_bfd)->verref == NULL)
- elf_link_remove_section_and_adjust_dynindices (info, s);
+ _bfd_strip_section_from_output (info, s);
else
{
Elf_Internal_Verneed *t;
for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
{
- a->vna_hash = bfd_elf_hash ((const unsigned char *)
- a->vna_nodename);
+ a->vna_hash = bfd_elf_hash (a->vna_nodename);
indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
a->vna_nodename, true, false);
if (indx == (bfd_size_type) -1)
}
}
- dynsymcount = elf_hash_table (info)->dynsymcount;
+ /* Assign dynsym indicies. In a shared library we generate a
+ section symbol for each output section, which come first.
+ Next come all of the back-end allocated local dynamic syms,
+ followed by the rest of the global symbols. */
+
+ dynsymcount = _bfd_elf_link_renumber_dynsyms (output_bfd, info);
/* Work out the size of the symbol version section. */
s = bfd_get_section_by_name (dynobj, ".gnu.version");
if (dynsymcount == 0
|| (verdefs == NULL && elf_tdata (output_bfd)->verref == NULL))
{
- elf_link_remove_section_and_adjust_dynindices (info, s);
+ _bfd_strip_section_from_output (info, s);
/* The DYNSYMCOUNT might have changed if we were going to
output a dynamic symbol table entry for S. */
- dynsymcount = elf_hash_table (info)->dynsymcount;
+ dynsymcount = _bfd_elf_link_renumber_dynsyms (output_bfd, info);
}
else
{
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. */
an ELF dynamic object. */
if ((h->elf_link_hash_flags & ELF_LINK_NON_ELF) != 0)
{
+ while (h->root.type == bfd_link_hash_indirect)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
if (h->root.type != bfd_link_hash_defined
&& h->root.type != bfd_link_hash_defweak)
h->elf_link_hash_flags |= (ELF_LINK_HASH_REF_REGULAR
/* If -Bsymbolic was used (which means to bind references to global
symbols to the definition within the shared object), and this
symbol was defined in a regular object, then it actually doesn't
- need a PLT entry. */
+ need a PLT entry. Likewise, if the symbol has any kind of
+ visibility (internal, hidden, or protected), it doesn't need a
+ PLT. */
if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0
&& eif->info->shared
- && eif->info->symbolic
+ && (eif->info->symbolic || ELF_ST_VISIBILITY (h->other))
&& (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
{
h->elf_link_hash_flags &=~ ELF_LINK_HASH_NEEDS_PLT;
h->plt.offset = (bfd_vma) -1;
}
+ /* If this is a weak defined symbol in a dynamic object, and we know
+ the real definition in the dynamic object, copy interesting flags
+ over to the real definition. */
+ if (h->weakdef != NULL)
+ {
+ struct elf_link_hash_entry *weakdef;
+
+ BFD_ASSERT (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak);
+ weakdef = h->weakdef;
+ BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined
+ || weakdef->root.type == bfd_link_hash_defweak);
+ BFD_ASSERT (weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC);
+
+ /* If the real definition is defined by a regular object file,
+ don't do anything special. See the longer description in
+ elf_adjust_dynamic_symbol, below. */
+ if ((weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
+ h->weakdef = NULL;
+ else
+ weakdef->elf_link_hash_flags |=
+ (h->elf_link_hash_flags
+ & (ELF_LINK_HASH_REF_REGULAR
+ | ELF_LINK_HASH_REF_REGULAR_NONWEAK
+ | ELF_LINK_NON_GOT_REF));
+ }
+
return true;
}
if (h->weakdef != NULL)
{
- struct elf_link_hash_entry *weakdef;
+ /* If we get to this point, we know there is an implicit
+ reference by a regular object file via the weak symbol H.
+ FIXME: Is this really true? What if the traversal finds
+ H->WEAKDEF before it finds H? */
+ h->weakdef->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR;
- BFD_ASSERT (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak);
- weakdef = h->weakdef;
- BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined
- || weakdef->root.type == bfd_link_hash_defweak);
- BFD_ASSERT (weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC);
- if ((weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
- {
- /* This symbol is defined by a regular object file, so we
- will not do anything special. Clear weakdef for the
- convenience of the processor backend. */
- h->weakdef = NULL;
- }
- else
- {
- /* There is an implicit reference by a regular object file
- via the weak symbol. */
- weakdef->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR;
- if (h->weakdef->elf_link_hash_flags
- & ELF_LINK_HASH_REF_REGULAR_NONWEAK)
- weakdef->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR_NONWEAK;
- if (! elf_adjust_dynamic_symbol (weakdef, (PTR) eif))
- return false;
- }
+ if (! elf_adjust_dynamic_symbol (h->weakdef, (PTR) eif))
+ return false;
}
/* If a symbol has no type and no size and does not require a PLT
struct elf_assign_sym_version_info *sinfo =
(struct elf_assign_sym_version_info *) data;
struct bfd_link_info *info = sinfo->info;
+ struct elf_backend_data *bed;
struct elf_info_failed eif;
char *p;
if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
return true;
+ bed = get_elf_backend_data (sinfo->output_bfd);
p = strchr (h->root.root.string, ELF_VER_CHR);
if (p != NULL && h->verinfo.vertree == NULL)
{
&& info->shared
&& ! sinfo->export_dynamic)
{
- sinfo->removed_dynamic = true;
h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
- h->elf_link_hash_flags &=~
- ELF_LINK_HASH_NEEDS_PLT;
- h->dynindx = -1;
- h->plt.offset = (bfd_vma) -1;
+ (*bed->elf_backend_hide_symbol) (info, h);
/* FIXME: The name of the symbol has
already been recorded in the dynamic
string table section. */
&& info->shared
&& ! sinfo->export_dynamic)
{
- sinfo->removed_dynamic = true;
h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
- h->elf_link_hash_flags &=~ ELF_LINK_HASH_NEEDS_PLT;
- h->dynindx = -1;
- h->plt.offset = (bfd_vma) -1;
+ (*bed->elf_backend_hide_symbol) (info, h);
/* FIXME: The name of the symbol has already
been recorded in the dynamic string table
section. */
&& info->shared
&& ! sinfo->export_dynamic)
{
- sinfo->removed_dynamic = true;
h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
- h->elf_link_hash_flags &=~ ELF_LINK_HASH_NEEDS_PLT;
- h->dynindx = -1;
- h->plt.offset = (bfd_vma) -1;
+ (*bed->elf_backend_hide_symbol) (info, h);
/* FIXME: The name of the symbol has already been
recorded in the dynamic string table section. */
}
return true;
}
-
-/* This function is used to renumber the dynamic symbols, if some of
- them are removed because they are marked as local. This is called
- via elf_link_hash_traverse. */
-
-static boolean
-elf_link_renumber_dynsyms (h, data)
- struct elf_link_hash_entry *h;
- PTR data;
-{
- struct bfd_link_info *info = (struct bfd_link_info *) data;
-
- if (h->dynindx != -1)
- {
- h->dynindx = elf_hash_table (info)->dynsymcount;
- ++elf_hash_table (info)->dynsymcount;
- }
-
- return true;
-}
\f
/* Final phase of ELF linker. */
asection *o;
{
register struct elf_link_hash_entry **p, **pend;
+ unsigned reloc_count;
- /* We are overestimating the size required for the relocation
- sections, in the case that we are using both REL and RELA
- relocations for a single section. In that case, RELOC_COUNT will
- be the total number of relocations required, and we allocate
- space for that many REL relocations as well as that many RELA
- relocations. This approximation is wasteful of disk space.
- However, until we keep track of how many of each kind of
- relocation is required, it's difficult to calculate the right
- value. */
- rel_hdr->sh_size = rel_hdr->sh_entsize * o->reloc_count;
+ /* Figure out how many relocations there will be. */
+ if (rel_hdr == &elf_section_data (o)->rel_hdr)
+ reloc_count = elf_section_data (o)->rel_count;
+ else
+ reloc_count = elf_section_data (o)->rel_count2;
+
+ /* That allows us to calculate the size of the section. */
+ rel_hdr->sh_size = rel_hdr->sh_entsize * reloc_count;
/* The contents field must last into write_object_contents, so we
- allocate it with bfd_alloc rather than malloc. */
- rel_hdr->contents = (PTR) bfd_alloc (abfd, rel_hdr->sh_size);
+ 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 = (PTR) bfd_zalloc (abfd, rel_hdr->sh_size);
if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0)
return false;
+
+ /* We only allocate one set of hash entries, so we only do it the
+ first time we are called. */
+ if (elf_section_data (o)->rel_hashes == NULL)
+ {
+ p = ((struct elf_link_hash_entry **)
+ bfd_malloc (o->reloc_count
+ * sizeof (struct elf_link_hash_entry *)));
+ if (p == NULL && o->reloc_count != 0)
+ return false;
- p = ((struct elf_link_hash_entry **)
- bfd_malloc (o->reloc_count
- * sizeof (struct elf_link_hash_entry *)));
- if (p == NULL && o->reloc_count != 0)
- return false;
-
- elf_section_data (o)->rel_hashes = p;
- pend = p + o->reloc_count;
- for (; p < pend; p++)
- *p = NULL;
+ elf_section_data (o)->rel_hashes = p;
+ pend = p + o->reloc_count;
+ for (; p < pend; p++)
+ *p = NULL;
+ }
return true;
}
+/* When performing a relocateable link, the input relocations are
+ preserved. But, if they reference global symbols, the indices
+ referenced must be updated. Update all the relocations in
+ REL_HDR (there are COUNT of them), using the data in REL_HASH. */
+
+static void
+elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash)
+ bfd *abfd;
+ Elf_Internal_Shdr *rel_hdr;
+ unsigned int count;
+ struct elf_link_hash_entry **rel_hash;
+{
+ unsigned int i;
+ struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+ for (i = 0; i < count; i++, rel_hash++)
+ {
+ if (*rel_hash == NULL)
+ continue;
+
+ BFD_ASSERT ((*rel_hash)->indx >= 0);
+
+ if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
+ {
+ Elf_External_Rel *erel;
+ Elf_Internal_Rel irel;
+
+ erel = (Elf_External_Rel *) rel_hdr->contents + i;
+ if (bed->s->swap_reloc_in)
+ (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel, &irel);
+ else
+ elf_swap_reloc_in (abfd, erel, &irel);
+ irel.r_info = ELF_R_INFO ((*rel_hash)->indx,
+ ELF_R_TYPE (irel.r_info));
+ if (bed->s->swap_reloc_out)
+ (*bed->s->swap_reloc_out) (abfd, &irel, (bfd_byte *) erel);
+ else
+ elf_swap_reloc_out (abfd, &irel, erel);
+ }
+ else
+ {
+ Elf_External_Rela *erela;
+ Elf_Internal_Rela irela;
+
+ BFD_ASSERT (rel_hdr->sh_entsize
+ == sizeof (Elf_External_Rela));
+
+ erela = (Elf_External_Rela *) rel_hdr->contents + i;
+ if (bed->s->swap_reloca_in)
+ (*bed->s->swap_reloca_in) (abfd, (bfd_byte *) erela, &irela);
+ else
+ elf_swap_reloca_in (abfd, erela, &irela);
+ irela.r_info = ELF_R_INFO ((*rel_hash)->indx,
+ ELF_R_TYPE (irela.r_info));
+ if (bed->s->swap_reloca_out)
+ (*bed->s->swap_reloca_out) (abfd, &irela, (bfd_byte *) erela);
+ else
+ elf_swap_reloca_out (abfd, &irela, erela);
+ }
+ }
+}
+
/* Do the final step of an ELF link. */
boolean
the linker has decided to not include. */
sec->linker_mark = true;
- if (info->relocateable)
+ if (info->relocateable || info->emitrelocations)
o->reloc_count += sec->reloc_count;
if (sec->_raw_size > max_contents_size)
if (! _bfd_elf_compute_section_file_positions (abfd, info))
goto error_return;
+ /* Figure out how many relocations we will have in each section.
+ Just using RELOC_COUNT isn't good enough since that doesn't
+ maintain a separate value for REL vs. RELA relocations. */
+ if (info->relocateable || info->emitrelocations)
+ for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+ for (o = sub->sections; o != NULL; o = o->next)
+ {
+ asection *output_section;
+
+ if (! o->linker_mark)
+ {
+ /* This section was omitted from the link. */
+ continue;
+ }
+
+ output_section = o->output_section;
+
+ if (output_section != NULL
+ && (o->flags & SEC_RELOC) != 0)
+ {
+ struct bfd_elf_section_data *esdi
+ = elf_section_data (o);
+ struct bfd_elf_section_data *esdo
+ = elf_section_data (output_section);
+ unsigned int *rel_count;
+ unsigned int *rel_count2;
+
+ /* We must be careful to add the relocation froms the
+ input section to the right output count. */
+ if (esdi->rel_hdr.sh_entsize == esdo->rel_hdr.sh_entsize)
+ {
+ rel_count = &esdo->rel_count;
+ rel_count2 = &esdo->rel_count2;
+ }
+ else
+ {
+ rel_count = &esdo->rel_count2;
+ rel_count2 = &esdo->rel_count;
+ }
+
+ *rel_count += (esdi->rel_hdr.sh_size
+ / esdi->rel_hdr.sh_entsize);
+ if (esdi->rel_hdr2)
+ *rel_count2 += (esdi->rel_hdr2->sh_size
+ / esdi->rel_hdr2->sh_entsize);
+ }
+ }
+
/* That created the reloc sections. Set their sizes, and assign
them file positions, and allocate some buffers. */
for (o = abfd->sections; o != NULL; o = o->next)
o))
goto error_return;
}
+
+ /* Now, reset REL_COUNT and REL_COUNT2 so that we can use them
+ to count upwards while actually outputting the relocations. */
+ elf_section_data (o)->rel_count = 0;
+ elf_section_data (o)->rel_count2 = 0;
}
_bfd_elf_assign_file_positions_for_relocs (abfd);
/* Start writing out the symbol table. The first symbol is always a
dummy symbol. */
- if (info->strip != strip_all || info->relocateable)
+ if (info->strip != strip_all || info->relocateable || info->emitrelocations)
{
elfsym.st_value = 0;
elfsym.st_size = 0;
symbols have no names. We store the index of each one in the
index field of the section, so that we can find it again when
outputting relocs. */
- if (info->strip != strip_all || info->relocateable)
+ if (info->strip != strip_all || info->relocateable || info->emitrelocations)
{
elfsym.st_size = 0;
elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
}
/* That wrote out all the local symbols. Finish up the symbol table
- with the global symbols. */
+ with the global symbols. Even if we want to strip everything we
+ can, we still need to deal with those global symbols that got
+ converted to local in a version script. */
- if (info->strip != strip_all && info->shared)
+ if (info->shared)
{
/* Output any global symbols that got converted to local in a
version script. We do this in a separate step since ELF
return false;
}
- /* The sh_info field records the index of the first non local
- symbol. */
+ /* The sh_info field records the index of the first non local symbol. */
symtab_hdr->sh_info = bfd_get_symcount (abfd);
- if (dynamic)
- elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info = 1;
+
+ if (dynamic
+ && finfo.dynsym_sec->output_section != bfd_abs_section_ptr)
+ {
+ Elf_Internal_Sym sym;
+ Elf_External_Sym *dynsym =
+ (Elf_External_Sym *)finfo.dynsym_sec->contents;
+ long last_local = 0;
+
+ /* Write out the section symbols for the output sections. */
+ if (info->shared)
+ {
+ asection *s;
+
+ sym.st_size = 0;
+ sym.st_name = 0;
+ sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
+ sym.st_other = 0;
+
+ for (s = abfd->sections; s != NULL; s = s->next)
+ {
+ int indx;
+ indx = elf_section_data (s)->this_idx;
+ BFD_ASSERT (indx > 0);
+ sym.st_shndx = indx;
+ sym.st_value = s->vma;
+
+ elf_swap_symbol_out (abfd, &sym,
+ dynsym + elf_section_data (s)->dynindx);
+ }
+
+ last_local = bfd_count_sections (abfd);
+ }
+
+ /* Write out the local dynsyms. */
+ if (elf_hash_table (info)->dynlocal)
+ {
+ struct elf_link_local_dynamic_entry *e;
+ for (e = elf_hash_table (info)->dynlocal; e ; e = e->next)
+ {
+ asection *s;
+
+ sym.st_size = e->isym.st_size;
+ sym.st_other = e->isym.st_other;
+
+ /* Copy the internal symbol as is.
+ Note that we saved a word of storage and overwrote
+ the original st_name with the dynstr_index. */
+ sym = e->isym;
+
+ if (e->isym.st_shndx > 0 && e->isym.st_shndx < SHN_LORESERVE)
+ {
+ s = bfd_section_from_elf_index (e->input_bfd,
+ e->isym.st_shndx);
+
+ sym.st_shndx =
+ elf_section_data (s->output_section)->this_idx;
+ sym.st_value = (s->output_section->vma
+ + s->output_offset
+ + e->isym.st_value);
+ }
+
+ if (last_local < e->dynindx)
+ last_local = e->dynindx;
+
+ elf_swap_symbol_out (abfd, &sym, dynsym + e->dynindx);
+ }
+ }
+
+ elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info =
+ last_local + 1;
+ }
/* We get the global symbols from the hash table. */
eoinfo.failed = false;
if (eoinfo.failed)
return false;
+ /* If backend needs to output some symbols not present in the hash
+ table, do it now. */
+ if (bed->elf_backend_output_arch_syms)
+ {
+ if (! (*bed->elf_backend_output_arch_syms)
+ (abfd, info, (PTR) &finfo,
+ (boolean (*) PARAMS ((PTR, const char *,
+ Elf_Internal_Sym *, asection *)))
+ elf_link_output_sym))
+ return false;
+ }
+
/* Flush all symbols to the file. */
if (! elf_link_flush_output_syms (&finfo))
return false;
/* Adjust the relocs to have the correct symbol indices. */
for (o = abfd->sections; o != NULL; o = o->next)
{
- struct elf_link_hash_entry **rel_hash;
- Elf_Internal_Shdr *rel_hdr;
-
if ((o->flags & SEC_RELOC) == 0)
continue;
- rel_hash = elf_section_data (o)->rel_hashes;
- rel_hdr = &elf_section_data (o)->rel_hdr;
- BFD_ASSERT (elf_section_data (o)->rel_count == o->reloc_count);
- for (i = 0; i < o->reloc_count; i++, rel_hash++)
- {
- if (*rel_hash == NULL)
- continue;
-
- BFD_ASSERT ((*rel_hash)->indx >= 0);
-
- if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
- {
- Elf_External_Rel *erel;
- Elf_Internal_Rel irel;
-
- erel = (Elf_External_Rel *) rel_hdr->contents + i;
- elf_swap_reloc_in (abfd, erel, &irel);
- irel.r_info = ELF_R_INFO ((*rel_hash)->indx,
- ELF_R_TYPE (irel.r_info));
- elf_swap_reloc_out (abfd, &irel, erel);
- }
- else
- {
- Elf_External_Rela *erela;
- Elf_Internal_Rela irela;
-
- BFD_ASSERT (rel_hdr->sh_entsize
- == sizeof (Elf_External_Rela));
-
- erela = (Elf_External_Rela *) rel_hdr->contents + i;
- elf_swap_reloca_in (abfd, erela, &irela);
- irela.r_info = ELF_R_INFO ((*rel_hash)->indx,
- ELF_R_TYPE (irela.r_info));
- elf_swap_reloca_out (abfd, &irela, erela);
- }
- }
+ elf_link_adjust_relocs (abfd, &elf_section_data (o)->rel_hdr,
+ elf_section_data (o)->rel_count,
+ elf_section_data (o)->rel_hashes);
+ if (elf_section_data (o)->rel_hdr2 != NULL)
+ elf_link_adjust_relocs (abfd, elf_section_data (o)->rel_hdr2,
+ elf_section_data (o)->rel_count2,
+ (elf_section_data (o)->rel_hashes
+ + elf_section_data (o)->rel_count));
/* Set the reloc_count field to 0 to prevent write_relocs from
trying to swap the relocs out itself. */
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 (! ((*finfo->info->callbacks->undefined_symbol)
(finfo->info, h->root.root.string, h->root.u.undef.abfd,
- (asection *) NULL, 0)))
+ (asection *) NULL, 0, true)))
{
eoinfo->failed = true;
return false;
strip = false;
/* If we're stripping it, and it's not a dynamic symbol, there's
- nothing else to do. */
- if (strip && h->dynindx == -1)
+ nothing else to do unless it is a forced local symbol. */
+ if (strip
+ && h->dynindx == -1
+ && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
return true;
sym.st_value = 0;
symbol foo@@GNU_1.2 is the default, which should be used when
foo is used with no version, then we add an indirect symbol
foo which points to foo@@GNU_1.2. We ignore these symbols,
- since the indirected symbol is already in the hash table. If
- the indirect symbol is non-ELF, fall through and output it. */
- if ((h->elf_link_hash_flags & ELF_LINK_NON_ELF) == 0)
- return true;
+ since the indirected symbol is already in the hash table. */
+ return true;
- /* Fall through. */
case bfd_link_hash_warning:
/* We can't represent these symbols in ELF, although a warning
symbol may have come from a .gnu.warning.SYMBOL section. We
/* If we are marking the symbol as undefined, and there are no
non-weak references to this symbol from a regular object, then
- mark the symbol as weak undefined. We can't do this earlier,
+ mark the symbol as weak undefined; if there are non-weak
+ references, mark the symbol as strong. We can't do this earlier,
because it might not be marked as undefined until the
finish_dynamic_symbol routine gets through with it. */
if (sym.st_shndx == SHN_UNDEF
- && sym.st_info == ELF_ST_INFO (STB_GLOBAL, h->type)
&& (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) != 0
- && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK) == 0)
- sym.st_info = ELF_ST_INFO (STB_WEAK, h->type);
+ && (ELF_ST_BIND(sym.st_info) == STB_GLOBAL
+ || ELF_ST_BIND(sym.st_info) == STB_WEAK))
+ {
+ int bindtype;
+
+ if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK) != 0)
+ bindtype = STB_GLOBAL;
+ else
+ bindtype = STB_WEAK;
+ sym.st_info = ELF_ST_INFO (bindtype, ELF_ST_TYPE (sym.st_info));
+ }
+
+ /* If a symbol is not defined locally, we clear the visibility
+ field. */
+ if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ sym.st_other ^= ELF_ST_VISIBILITY(sym.st_other);
/* If this symbol should be put in the .dynsym section, then put it
there now. We have already know the symbol index. We also fill
Elf_Internal_Rela *irelaend;
Elf_Internal_Shdr *output_rel_hdr;
asection *output_section;
- unsigned int *rel_countp;
+ unsigned int *rel_countp = NULL;
+ struct elf_backend_data *bed;
output_section = input_section->output_section;
output_rel_hdr = NULL;
}
BFD_ASSERT (output_rel_hdr != NULL);
-
+
+ bed = get_elf_backend_data (output_bfd);
irela = internal_relocs;
irelaend = irela + input_rel_hdr->sh_size / input_rel_hdr->sh_entsize;
if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
irel.r_offset = irela->r_offset;
irel.r_info = irela->r_info;
BFD_ASSERT (irela->r_addend == 0);
- elf_swap_reloc_out (output_bfd, &irel, erel);
+ if (bed->s->swap_reloc_out)
+ (*bed->s->swap_reloc_out) (output_bfd, &irel, (PTR) erel);
+ else
+ elf_swap_reloc_out (output_bfd, &irel, erel);
}
}
else
== sizeof (Elf_External_Rela));
erela = ((Elf_External_Rela *) output_rel_hdr->contents + *rel_countp);
for (; irela < irelaend; irela++, erela++)
- elf_swap_reloca_out (output_bfd, irela, erela);
+ if (bed->s->swap_reloca_out)
+ (*bed->s->swap_reloca_out) (output_bfd, irela, (PTR) erela);
+ else
+ elf_swap_reloca_out (output_bfd, irela, erela);
}
/* Bump the counter, so that we know where to add the next set of
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
finfo->sections))
return false;
- if (finfo->info->relocateable)
+ if (finfo->info->relocateable || finfo->info->emitrelocations)
{
Elf_Internal_Rela *irela;
Elf_Internal_Rela *irelaend;
irelaend =
irela + o->reloc_count * bed->s->int_rels_per_ext_rel;
rel_hash = (elf_section_data (o->output_section)->rel_hashes
- + elf_section_data (o->output_section)->rel_count);
+ + elf_section_data (o->output_section)->rel_count
+ + elf_section_data (o->output_section)->rel_count2);
for (; irela < irelaend; irela++, rel_hash++)
{
unsigned long r_symndx;
irela->r_offset += o->output_offset;
+ /* Relocs in an executable have to be virtual addresses. */
+ if (finfo->info->emitrelocations)
+ irela->r_offset += o->output_section->vma;
+
r_symndx = ELF_R_SYM (irela->r_info);
if (r_symndx == 0)
bfd_vma addend;
struct elf_link_hash_entry **rel_hash_ptr;
Elf_Internal_Shdr *rel_hdr;
+ struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc);
if (howto == NULL)
/* Figure out the symbol index. */
rel_hash_ptr = (elf_section_data (output_section)->rel_hashes
- + elf_section_data (output_section)->rel_count);
+ + elf_section_data (output_section)->rel_count
+ + elf_section_data (output_section)->rel_count2);
if (link_order->type == bfd_section_reloc_link_order)
{
indx = link_order->u.reloc.p->u.section->target_index;
irel.r_info = ELF_R_INFO (indx, howto->type);
erel = ((Elf_External_Rel *) rel_hdr->contents
+ elf_section_data (output_section)->rel_count);
- elf_swap_reloc_out (output_bfd, &irel, erel);
+ if (bed->s->swap_reloc_out)
+ (*bed->s->swap_reloc_out) (output_bfd, &irel, (bfd_byte *) erel);
+ else
+ elf_swap_reloc_out (output_bfd, &irel, erel);
}
else
{
irela.r_addend = addend;
erela = ((Elf_External_Rela *) rel_hdr->contents
+ elf_section_data (output_section)->rel_count);
- elf_swap_reloca_out (output_bfd, &irela, erela);
+ if (bed->s->swap_reloca_out)
+ (*bed->s->swap_reloca_out) (output_bfd, &irela, (bfd_byte *) erela);
+ else
+ elf_swap_reloca_out (output_bfd, &irela, erela);
}
++elf_section_data (output_section)->rel_count;
{
asection *o;
+ if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
+ continue;
+
for (o = sub->sections; o != NULL; o = o->next)
{
/* Keep special sections. Keep .debug sections. */
struct elf_link_hash_entry *h, Elf_Internal_Sym *));
if (!get_elf_backend_data (abfd)->can_gc_sections
- || info->relocateable
+ || info->relocateable || info->emitrelocations
|| elf_hash_table (info)->dynamic_sections_created)
return true;
for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
{
asection *o;
+
+ if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
+ continue;
+
for (o = sub->sections; o != NULL; o = o->next)
{
if (o->flags & SEC_KEEP)
boolean
elf_gc_record_vtentry (abfd, sec, h, addend)
- bfd *abfd;
- asection *sec;
+ bfd *abfd ATTRIBUTE_UNUSED;
+ asection *sec ATTRIBUTE_UNUSED;
struct elf_link_hash_entry *h;
bfd_vma addend;
{
/* Allocate one extra entry for use as a "done" flag for the
consolidation pass. */
- bytes = (size / FILE_ALIGN + 1) * sizeof(boolean);
+ bytes = (size / FILE_ALIGN + 1) * sizeof (boolean);
if (ptr)
{
- size_t oldbytes;
-
- ptr = realloc (ptr-1, bytes);
- if (ptr == NULL)
- return false;
+ ptr = bfd_realloc (ptr - 1, bytes);
+
+ if (ptr != NULL)
+ {
+ size_t oldbytes;
- oldbytes = (h->vtable_entries_size/FILE_ALIGN + 1) * sizeof(boolean);
- memset (ptr + oldbytes, 0, bytes - oldbytes);
+ oldbytes = (h->vtable_entries_size/FILE_ALIGN + 1) * sizeof (boolean);
+ memset (((char *)ptr) + oldbytes, 0, bytes - oldbytes);
+ }
}
else
- {
- ptr = calloc (1, bytes);
- if (ptr == NULL)
- return false;
- }
+ ptr = bfd_zmalloc (bytes);
+ if (ptr == NULL)
+ return false;
+
/* And arrange for that done flag to be at index -1. */
- h->vtable_entries_used = ptr+1;
+ h->vtable_entries_used = ptr + 1;
h->vtable_entries_size = size;
}
+
h->vtable_entries_used[addend / FILE_ALIGN] = true;
return true;
/* Do the local .got entries first. */
for (i = info->input_bfds; i; i = i->link_next)
{
- bfd_signed_vma *local_got = elf_local_got_refcounts (i);
+ bfd_signed_vma *local_got;
bfd_size_type j, locsymcount;
Elf_Internal_Shdr *symtab_hdr;
+ if (bfd_get_flavour (i) != bfd_target_elf_flavour)
+ continue;
+
+ local_got = elf_local_got_refcounts (i);
if (!local_got)
continue;
}
}
- /* Then the global .got and .plt entries. */
+ /* Then the global .got entries. .plt refcounts are handled by
+ adjust_dynamic_symbol */
elf_link_hash_traverse (elf_hash_table (info),
elf_gc_allocate_got_offsets,
(PTR) &gotoff);