/* 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.
}
}
\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;
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. */
/* 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)
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);
for (; extdyn < extdynend; extdyn++)
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);
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
== 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. */
| 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;
+ }
}
}
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;
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
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;
{
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;
verdefs = asvinfo.verdefs;
if (verdefs == NULL)
- _bfd_strip_section_from_output (s);
+ _bfd_strip_section_from_output (info, s);
else
{
unsigned int cdefs;
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)
- _bfd_strip_section_from_output (s);
+ _bfd_strip_section_from_output (info, s);
else
{
Elf_Internal_Verneed *t;
if (dynsymcount == 0
|| (verdefs == NULL && elf_tdata (output_bfd)->verref == NULL))
{
- _bfd_strip_section_from_output (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 = _bfd_elf_link_renumber_dynsyms (output_bfd, info);
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)
{
&& ! sinfo->export_dynamic)
{
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. */
&& ! sinfo->export_dynamic)
{
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. */
&& ! sinfo->export_dynamic)
{
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. */
}
asection *o;
{
register struct elf_link_hash_entry **p, **pend;
+ unsigned 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;
- /* 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;
+ /* 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);
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;
}
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++)
{
Elf_Internal_Rel irel;
erel = (Elf_External_Rel *) rel_hdr->contents + i;
- elf_swap_reloc_in (abfd, erel, &irel);
+ 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));
- elf_swap_reloc_out (abfd, &irel, erel);
+ 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
{
== sizeof (Elf_External_Rela));
erela = (Elf_External_Rela *) rel_hdr->contents + i;
- elf_swap_reloca_in (abfd, erela, &irela);
+ 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));
- elf_swap_reloca_out (abfd, &irela, erela);
+ if (bed->s->swap_reloca_out)
+ (*bed->s->swap_reloca_out) (abfd, &irela, (bfd_byte *) erela);
+ else
+ elf_swap_reloca_out (abfd, &irela, erela);
}
}
}
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
Elf_Internal_Sym sym;
Elf_External_Sym *dynsym =
(Elf_External_Sym *)finfo.dynsym_sec->contents;
- unsigned long last_local = 0;
+ long last_local = 0;
/* Write out the section symbols for the output sections. */
if (info->shared)
sym.st_size = e->isym.st_size;
sym.st_other = e->isym.st_other;
- /* Note that we saved a word of storage and overwrote
+ /* 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.st_name = e->isym.st_name;
-
- /* Whatever binding the symbol had before, it's now local. */
- sym.st_info = ELF_ST_INFO (STB_LOCAL,
- ELF_ST_TYPE (e->isym.st_info));
+ sym = e->isym;
- 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 (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_section_data (finfo.dynsym_sec->output_section)
- ->this_hdr.sh_info = last_local;
+ elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info =
+ last_local + 1;
}
/* We get the global symbols from the hash table. */
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;
{
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_Shdr *output_rel_hdr;
asection *output_section;
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
finfo->sections))
return false;
- if (finfo->info->relocateable)
+ if (finfo->info->relocateable || finfo->info->emitrelocations)
{
Elf_Internal_Rela *irela;
Elf_Internal_Rela *irelaend;
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)
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)
/* 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);