/* ELF linker code. */
+#include "safe-ctype.h"
+
static bfd_boolean elf_link_add_object_symbols (bfd *, struct bfd_link_info *);
-static bfd_boolean elf_link_add_archive_symbols (bfd *,
- struct bfd_link_info *);
static bfd_boolean elf_finalize_dynstr (bfd *, struct bfd_link_info *);
static bfd_boolean elf_collect_hash_codes (struct elf_link_hash_entry *,
void *);
case bfd_object:
return elf_link_add_object_symbols (abfd, info);
case bfd_archive:
- return elf_link_add_archive_symbols (abfd, info);
+ return _bfd_elf_link_add_archive_symbols (abfd, info);
default:
bfd_set_error (bfd_error_wrong_format);
return FALSE;
}
}
\f
-/* Return TRUE iff this is a non-common, definition of a non-function symbol. */
-static bfd_boolean
-is_global_data_symbol_definition (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;
-
- /* Function symbols do not count. */
- if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
- 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
- whose archive map contains a mention of SYMDEF, and determine if
- the symbol is defined in this element. */
-static bfd_boolean
-elf_link_is_defined_archive_symbol (bfd * abfd, carsym * symdef)
+/* Sort symbol by value and section. */
+static int
+sort_symbol (const void *arg1, const void *arg2)
{
- Elf_Internal_Shdr * hdr;
- bfd_size_type symcount;
- bfd_size_type extsymcount;
- bfd_size_type extsymoff;
- Elf_Internal_Sym *isymbuf;
- Elf_Internal_Sym *isym;
- Elf_Internal_Sym *isymend;
- bfd_boolean result;
-
- abfd = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
- if (abfd == 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;
- }
+ const struct elf_link_hash_entry *h1
+ = *(const struct elf_link_hash_entry **) arg1;
+ const struct elf_link_hash_entry *h2
+ = *(const struct elf_link_hash_entry **) arg2;
+ bfd_signed_vma vdiff = h1->root.u.def.value - h2->root.u.def.value;
+
+ if (vdiff)
+ return vdiff > 0 ? 1 : -1;
else
{
- extsymcount = symcount - hdr->sh_info;
- extsymoff = hdr->sh_info;
- }
-
- if (extsymcount == 0)
- return FALSE;
-
- /* Read in the symbol table. */
- isymbuf = bfd_elf_get_elf_syms (abfd, hdr, extsymcount, extsymoff,
- NULL, NULL, NULL);
- if (isymbuf == NULL)
- return FALSE;
-
- /* Scan the symbol table looking for SYMDEF. */
- result = FALSE;
- for (isym = isymbuf, isymend = isymbuf + extsymcount; isym < isymend; isym++)
- {
- const char *name;
-
- name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
- isym->st_name);
- if (name == NULL)
- break;
-
- if (strcmp (name, symdef->name) == 0)
- {
- result = is_global_data_symbol_definition (abfd, isym);
- break;
- }
- }
-
- free (isymbuf);
-
- 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
- problem which arises on UnixWare. The UnixWare libc.so is an
- archive which includes an entry libc.so.1 which defines a bunch of
- symbols. The libc.so archive also includes a number of other
- object files, which also define symbols, some of which are the same
- as those defined in libc.so.1. Correct linking requires that we
- consider each object file in turn, and include it if it defines any
- symbols we need. _bfd_generic_link_add_archive_symbols does not do
- this; it looks through the list of undefined symbols, and includes
- any object file which defines them. When this algorithm is used on
- UnixWare, it winds up pulling in libc.so.1 early and defining a
- bunch of symbols. This means that some of the other objects in the
- archive are not included in the link, which is incorrect since they
- precede libc.so.1 in the archive.
-
- Fortunately, ELF archive handling is simpler than that done by
- _bfd_generic_link_add_archive_symbols, which has to allow for a.out
- oddities. In ELF, if we find a symbol in the archive map, and the
- symbol is currently undefined, we know that we must pull in that
- object file.
-
- Unfortunately, we do have to make multiple passes over the symbol
- table until nothing further is resolved. */
-
-static bfd_boolean
-elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
-{
- symindex c;
- bfd_boolean *defined = NULL;
- bfd_boolean *included = NULL;
- carsym *symdefs;
- bfd_boolean loop;
- bfd_size_type amt;
-
- if (! bfd_has_map (abfd))
- {
- /* An empty archive is a special case. */
- if (bfd_openr_next_archived_file (abfd, NULL) == NULL)
- return TRUE;
- bfd_set_error (bfd_error_no_armap);
- return FALSE;
- }
-
- /* Keep track of all symbols we know to be already defined, and all
- files we know to be already included. This is to speed up the
- second and subsequent passes. */
- c = bfd_ardata (abfd)->symdef_count;
- if (c == 0)
- return TRUE;
- amt = c;
- amt *= sizeof (bfd_boolean);
- defined = bfd_zmalloc (amt);
- included = bfd_zmalloc (amt);
- if (defined == NULL || included == NULL)
- goto error_return;
-
- symdefs = bfd_ardata (abfd)->symdefs;
-
- do
- {
- file_ptr last;
- symindex i;
- carsym *symdef;
- carsym *symdefend;
-
- loop = FALSE;
- last = -1;
-
- symdef = symdefs;
- symdefend = symdef + c;
- for (i = 0; symdef < symdefend; symdef++, i++)
- {
- struct elf_link_hash_entry *h;
- bfd *element;
- struct bfd_link_hash_entry *undefs_tail;
- symindex mark;
-
- if (defined[i] || included[i])
- continue;
- if (symdef->file_offset == last)
- {
- included[i] = TRUE;
- continue;
- }
-
- h = elf_link_hash_lookup (elf_hash_table (info), symdef->name,
- FALSE, FALSE, FALSE);
-
- if (h == NULL)
- {
- char *p, *copy;
- size_t len, first;
-
- /* If this is a default version (the name contains @@),
- look up the symbol again with only one `@' as well
- as without the version. The effect is that references
- to the symbol with and without the version will be
- matched by the default symbol in the archive. */
-
- p = strchr (symdef->name, ELF_VER_CHR);
- if (p == NULL || p[1] != ELF_VER_CHR)
- continue;
-
- /* First check with only one `@'. */
- len = strlen (symdef->name);
- copy = bfd_alloc (abfd, len);
- if (copy == NULL)
- goto error_return;
- first = p - symdef->name + 1;
- memcpy (copy, symdef->name, first);
- memcpy (copy + first, symdef->name + first + 1, len - first);
-
- h = elf_link_hash_lookup (elf_hash_table (info), copy,
- FALSE, FALSE, FALSE);
-
- if (h == NULL)
- {
- /* We also need to check references to the symbol
- without the version. */
-
- copy[first - 1] = '\0';
- h = elf_link_hash_lookup (elf_hash_table (info),
- copy, FALSE, FALSE, FALSE);
- }
-
- bfd_release (abfd, copy);
- }
-
- if (h == NULL)
- continue;
-
- 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;
- continue;
- }
-
- /* We need to include this archive member. */
- element = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
- if (element == NULL)
- goto error_return;
-
- if (! bfd_check_format (element, bfd_object))
- goto error_return;
-
- /* Doublecheck that we have not included this object
- already--it should be impossible, but there may be
- something wrong with the archive. */
- if (element->archive_pass != 0)
- {
- bfd_set_error (bfd_error_bad_value);
- goto error_return;
- }
- element->archive_pass = 1;
-
- undefs_tail = info->hash->undefs_tail;
-
- if (! (*info->callbacks->add_archive_element) (info, element,
- symdef->name))
- goto error_return;
- if (! elf_link_add_object_symbols (element, info))
- goto error_return;
-
- /* If there are any new undefined symbols, we need to make
- another pass through the archive in order to see whether
- they can be defined. FIXME: This isn't perfect, because
- common symbols wind up on undefs_tail and because an
- undefined symbol which is defined later on in this pass
- does not require another pass. This isn't a bug, but it
- does make the code less efficient than it could be. */
- if (undefs_tail != info->hash->undefs_tail)
- loop = TRUE;
-
- /* Look backward to mark all symbols from this object file
- which we have already seen in this pass. */
- mark = i;
- do
- {
- included[mark] = TRUE;
- if (mark == 0)
- break;
- --mark;
- }
- while (symdefs[mark].file_offset == symdef->file_offset);
-
- /* We mark subsequent symbols from this object file as we go
- on through the loop. */
- last = symdef->file_offset;
- }
+ long sdiff = h1->root.u.def.section - h2->root.u.def.section;
+ if (sdiff)
+ return sdiff > 0 ? 1 : -1;
+ else
+ return 0;
}
- while (loop);
-
- free (defined);
- free (included);
-
- return TRUE;
-
- error_return:
- if (defined != NULL)
- free (defined);
- if (included != NULL)
- free (included);
- return FALSE;
}
/* Add symbols from an ELF object file to the linker hash table. */
/* You can't use -r against a dynamic object. Also, there's no
hope of using a dynamic object which does not exactly match
the format of the output file. */
- if (info->relocatable || info->hash->creator != abfd->xvec)
+ if (info->relocatable
+ || !is_elf_hash_table (hash_table)
+ || hash_table->root.creator != abfd->xvec)
{
bfd_set_error (bfd_error_invalid_operation);
goto error_return;
fix is to keep track of what warnings we are supposed
to emit, and then handle them all at the end of the
link. */
- if (dynamic && abfd->xvec == info->hash->creator)
+ if (dynamic)
{
struct elf_link_hash_entry *h;
format. FIXME: If there are no input BFD's of the same
format as the output, we can't make a shared library. */
if (info->shared
- && is_elf_hash_table (info)
- && ! hash_table->dynamic_sections_created
- && abfd->xvec == info->hash->creator)
+ && is_elf_hash_table (hash_table)
+ && hash_table->root.creator == abfd->xvec
+ && ! hash_table->dynamic_sections_created)
{
if (! _bfd_elf_link_create_dynamic_sections (abfd, info))
goto error_return;
}
}
- else if (! is_elf_hash_table (info))
+ else if (!is_elf_hash_table (hash_table))
goto error_return;
else
{
/* If this is the first dynamic object found in the link, create
the special sections required for dynamic linking. */
- if (! hash_table->dynamic_sections_created)
- if (! _bfd_elf_link_create_dynamic_sections (abfd, info))
- goto error_return;
+ if (! _bfd_elf_link_create_dynamic_sections (abfd, info))
+ goto error_return;
if (add_needed)
{
{
/* This should be impossible, since ELF requires that all
global symbols follow all local symbols, and that sh_info
- point to the first global symbol. Unfortunatealy, Irix 5
+ point to the first global symbol. Unfortunately, Irix 5
screws this up. */
continue;
}
old_alignment = 0;
old_bfd = NULL;
- if (info->hash->creator->flavour == bfd_target_elf_flavour)
+ if (is_elf_hash_table (hash_table))
{
Elf_Internal_Versym iver;
unsigned int vernum = 0;
&& definition
&& (flags & BSF_WEAK) != 0
&& ELF_ST_TYPE (isym->st_info) != STT_FUNC
- && info->hash->creator->flavour == bfd_target_elf_flavour
+ && is_elf_hash_table (hash_table)
&& h->weakdef == NULL)
{
/* Keep a list of all weak defined non function symbols from
h->root.u.c.p->alignment_power = old_alignment;
}
- if (info->hash->creator->flavour == bfd_target_elf_flavour)
+ if (is_elf_hash_table (hash_table))
{
int old_flags;
bfd_boolean dynsym;
int new_flag;
/* Check the alignment when a common symbol is involved. This
- can change when a common symbol is overriden by a normal
+ can change when a common symbol is overridden by a normal
definition or a common symbol is ignored due to the old
normal definition. We need to make sure the maximum
alignment is maintained. */
bfd *common_bfd;
symbol_align = ffs (h->root.u.def.value) - 1;
- if ((h->root.u.def.section->owner->flags & DYNAMIC) == 0)
+ if (h->root.u.def.section->owner != NULL
+ && (h->root.u.def.section->owner->flags & DYNAMIC) == 0)
{
normal_align = h->root.u.def.section->alignment_power;
if (normal_align > symbol_align)
/* If st_other has a processor-specific meaning, specific
code might be needed here. We never merge the visibility
attribute with the one from a dynamic object. */
+ if (bed->elf_backend_merge_symbol_attribute)
+ (*bed->elf_backend_merge_symbol_attribute) (h, isym, definition,
+ dynamic);
+
if (isym->st_other != 0 && !dynamic)
{
unsigned char hvis, symvis, other, nvis;
bfd_size_type oldsize;
bfd_size_type strindex;
- if (! is_elf_hash_table (info))
- goto error_free_vers;
-
/* 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. */
shortname[amt] = '\0';
hi = (struct elf_link_hash_entry *)
- bfd_link_hash_lookup (info->hash, shortname,
+ bfd_link_hash_lookup (&hash_table->root, shortname,
FALSE, FALSE, FALSE);
if (hi != NULL
&& hi->root.type == h->root.type
assembler code, handling it correctly would be very time
consuming, and other ELF linkers don't handle general aliasing
either. */
- while (weaks != NULL)
+ if (weaks != NULL)
{
- struct elf_link_hash_entry *hlook;
- asection *slook;
- bfd_vma vlook;
struct elf_link_hash_entry **hpp;
struct elf_link_hash_entry **hppend;
+ struct elf_link_hash_entry **sorted_sym_hash;
+ struct elf_link_hash_entry *h;
+ size_t sym_count;
- hlook = weaks;
- weaks = hlook->weakdef;
- hlook->weakdef = NULL;
-
- BFD_ASSERT (hlook->root.type == bfd_link_hash_defined
- || hlook->root.type == bfd_link_hash_defweak
- || hlook->root.type == bfd_link_hash_common
- || hlook->root.type == bfd_link_hash_indirect);
- slook = hlook->root.u.def.section;
- vlook = hlook->root.u.def.value;
-
+ /* Since we have to search the whole symbol list for each weak
+ defined symbol, search time for N weak defined symbols will be
+ O(N^2). Binary search will cut it down to O(NlogN). */
+ amt = extsymcount * sizeof (struct elf_link_hash_entry *);
+ sorted_sym_hash = bfd_malloc (amt);
+ if (sorted_sym_hash == NULL)
+ goto error_return;
+ sym_hash = sorted_sym_hash;
hpp = elf_sym_hashes (abfd);
hppend = hpp + extsymcount;
+ sym_count = 0;
for (; hpp < hppend; hpp++)
{
- struct elf_link_hash_entry *h;
-
h = *hpp;
- if (h != NULL && h != hlook
+ if (h != NULL
&& h->root.type == bfd_link_hash_defined
- && h->root.u.def.section == slook
- && h->root.u.def.value == vlook)
+ && h->type != STT_FUNC)
{
- hlook->weakdef = h;
+ *sym_hash = h;
+ sym_hash++;
+ sym_count++;
+ }
+ }
+
+ qsort (sorted_sym_hash, sym_count,
+ sizeof (struct elf_link_hash_entry *),
+ sort_symbol);
- /* If the weak definition is in the list of dynamic
- symbols, make sure the real definition is put there
- as well. */
- if (hlook->dynindx != -1
- && h->dynindx == -1)
+ while (weaks != NULL)
+ {
+ struct elf_link_hash_entry *hlook;
+ asection *slook;
+ bfd_vma vlook;
+ long ilook;
+ size_t i, j, idx;
+
+ hlook = weaks;
+ weaks = hlook->weakdef;
+ hlook->weakdef = NULL;
+
+ BFD_ASSERT (hlook->root.type == bfd_link_hash_defined
+ || hlook->root.type == bfd_link_hash_defweak
+ || hlook->root.type == bfd_link_hash_common
+ || hlook->root.type == bfd_link_hash_indirect);
+ slook = hlook->root.u.def.section;
+ vlook = hlook->root.u.def.value;
+
+ ilook = -1;
+ i = 0;
+ j = sym_count;
+ while (i < j)
+ {
+ bfd_signed_vma vdiff;
+ idx = (i + j) / 2;
+ h = sorted_sym_hash [idx];
+ vdiff = vlook - h->root.u.def.value;
+ if (vdiff < 0)
+ j = idx;
+ else if (vdiff > 0)
+ i = idx + 1;
+ else
{
- if (! _bfd_elf_link_record_dynamic_symbol (info, h))
- goto error_return;
+ long sdiff = slook - h->root.u.def.section;
+ if (sdiff < 0)
+ j = idx;
+ else if (sdiff > 0)
+ i = idx + 1;
+ else
+ {
+ ilook = idx;
+ break;
+ }
}
+ }
+
+ /* We didn't find a value/section match. */
+ if (ilook == -1)
+ continue;
+
+ for (i = ilook; i < sym_count; i++)
+ {
+ h = sorted_sym_hash [i];
- /* If the real definition is in the list of dynamic
- symbols, make sure the weak definition is put there
- as well. If we don't do this, then the dynamic
- loader might not merge the entries for the real
- definition and the weak definition. */
- if (h->dynindx != -1
- && hlook->dynindx == -1)
+ /* Stop if value or section doesn't match. */
+ if (h->root.u.def.value != vlook
+ || h->root.u.def.section != slook)
+ break;
+ else if (h != hlook)
{
- if (! _bfd_elf_link_record_dynamic_symbol (info, hlook))
- goto error_return;
+ hlook->weakdef = h;
+
+ /* If the weak definition is in the list of dynamic
+ symbols, make sure the real definition is put
+ there as well. */
+ if (hlook->dynindx != -1 && h->dynindx == -1)
+ {
+ if (! _bfd_elf_link_record_dynamic_symbol (info,
+ h))
+ goto error_return;
+ }
+
+ /* If the real definition is in the list of dynamic
+ symbols, make sure the weak definition is put
+ there as well. If we don't do this, then the
+ dynamic loader might not merge the entries for the
+ real definition and the weak definition. */
+ if (h->dynindx != -1 && hlook->dynindx == -1)
+ {
+ if (! _bfd_elf_link_record_dynamic_symbol (info,
+ hlook))
+ goto error_return;
+ }
+ break;
}
- break;
}
}
+
+ free (sorted_sym_hash);
}
/* If this object is the same format as the output object, and it is
different format. It probably can't be done. */
check_relocs = get_elf_backend_data (abfd)->check_relocs;
if (! dynamic
- && abfd->xvec == info->hash->creator
+ && is_elf_hash_table (hash_table)
+ && hash_table->root.creator == abfd->xvec
&& check_relocs != NULL)
{
asection *o;
of the .stab/.stabstr sections. */
if (! dynamic
&& ! info->traditional_format
- && info->hash->creator->flavour == bfd_target_elf_flavour
- && is_elf_hash_table (info)
+ && is_elf_hash_table (hash_table)
&& (info->strip != strip_all && info->strip != strip_debugger))
{
- asection *stab, *stabstr;
-
- stab = bfd_get_section_by_name (abfd, ".stab");
- if (stab != NULL
- && (stab->flags & SEC_MERGE) == 0
- && !bfd_is_abs_section (stab->output_section))
+ asection *stabstr;
+
+ stabstr = bfd_get_section_by_name (abfd, ".stabstr");
+ if (stabstr != NULL)
{
- stabstr = bfd_get_section_by_name (abfd, ".stabstr");
-
- if (stabstr != NULL)
- {
- struct bfd_elf_section_data *secdata;
-
- secdata = elf_section_data (stab);
- if (! _bfd_link_section_stabs (abfd,
- & hash_table->stab_info,
- stab, stabstr,
- &secdata->sec_info))
- goto error_return;
- if (secdata->sec_info)
- stab->sec_info_type = ELF_INFO_TYPE_STABS;
+ bfd_size_type string_offset = 0;
+ asection *stab;
+
+ for (stab = abfd->sections; stab; stab = stab->next)
+ if (strncmp (".stab", stab->name, 5) == 0
+ && (!stab->name[5] ||
+ (stab->name[5] == '.' && ISDIGIT (stab->name[6])))
+ && (stab->flags & SEC_MERGE) == 0
+ && !bfd_is_abs_section (stab->output_section))
+ {
+ struct bfd_elf_section_data *secdata;
+
+ secdata = elf_section_data (stab);
+ if (! _bfd_link_section_stabs (abfd,
+ & hash_table->stab_info,
+ stab, stabstr,
+ &secdata->sec_info,
+ &string_offset))
+ goto error_return;
+ if (secdata->sec_info)
+ stab->sec_info_type = ELF_INFO_TYPE_STABS;
}
}
}
- if (! info->relocatable && ! dynamic
- && is_elf_hash_table (info))
+ if (! info->relocatable
+ && ! dynamic
+ && is_elf_hash_table (hash_table))
{
asection *s;
}
}
- if (is_elf_hash_table (info))
+ if (is_elf_hash_table (hash_table))
{
/* Add this bfd to the loaded list. */
struct elf_link_loaded_list *n;
bfd_size_type newsize;
bfd_byte *newcontents;
- if (! is_elf_hash_table (info))
+ if (! is_elf_hash_table (info->hash))
return FALSE;
dynobj = elf_hash_table (info)->dynobj;
# if 1
/* Variant 1: optimize for short chains. We add the squares
- of all the chain lengths (which favous many small chain
+ of all the chain lengths (which favors many small chain
over a few long chains). */
for (j = 0; j < i; ++j)
max += counts[j] * counts[j];
soname_indx = (bfd_size_type) -1;
- if (info->hash->creator->flavour != bfd_target_elf_flavour)
- return TRUE;
-
- if (! is_elf_hash_table (info))
+ if (!is_elf_hash_table (info->hash))
return TRUE;
if (info->execstack)
bfd_boolean all_defined;
*sinterpptr = bfd_get_section_by_name (dynobj, ".interp");
- BFD_ASSERT (*sinterpptr != NULL || info->shared);
+ BFD_ASSERT (*sinterpptr != NULL || !info->executable);
if (soname != NULL)
{
return FALSE;
}
- /* Make all global versions with definiton. */
+ /* Make all global versions with definition. */
for (t = verdefs; t != NULL; t = t->next)
- for (d = t->globals; d != NULL; d = d->next)
- if (!d->symver && strchr (d->pattern, '*') == NULL)
+ for (d = t->globals.list; d != NULL; d = d->next)
+ if (!d->symver && d->symbol)
{
const char *verstr, *name;
size_t namelen, verlen, newlen;
char *newname, *p;
struct elf_link_hash_entry *newh;
- name = d->pattern;
+ name = d->symbol;
namelen = strlen (name);
verstr = t->name;
verlen = strlen (verstr);
if (!info->allow_undefined_version)
{
- /* Check if all global versions have a definiton. */
+ /* Check if all global versions have a definition. */
all_defined = TRUE;
for (t = verdefs; t != NULL; t = t->next)
- for (d = t->globals; d != NULL; d = d->next)
- if (!d->symver && !d->script
- && strchr (d->pattern, '*') == NULL)
+ for (d = t->globals.list; d != NULL; d = d->next)
+ if (!d->symver && !d->script)
{
(*_bfd_error_handler)
(_("%s: undefined version: %s"),
def.vd_version = VER_DEF_CURRENT;
def.vd_flags = 0;
- if (t->globals == NULL && t->locals == NULL && ! t->used)
+ if (t->globals.list == NULL && t->locals.list == NULL && ! t->used)
def.vd_flags |= VER_FLG_WEAK;
def.vd_ndx = t->vernum + 1;
def.vd_cnt = cdeps + 1;
if (! elf_add_dynamic_entry (info, DT_FLAGS, info->flags))
return FALSE;
}
+ else if (info->flags & DF_BIND_NOW)
+ {
+ if (! elf_add_dynamic_entry (info, DT_BIND_NOW, 0))
+ return FALSE;
+ }
if (info->flags_1)
{
asection *hash_sec;
/* symbol version section (.gnu.version). */
asection *symver_sec;
- /* first SHF_TLS section (if any). */
- asection *first_tls_sec;
/* Buffer large enough to hold contents of any section. */
bfd_byte *contents;
/* Buffer large enough to hold external relocs of any section. */
};
static bfd_boolean elf_link_output_sym
- (struct elf_final_link_info *, const char *, Elf_Internal_Sym *, asection *);
+ (struct elf_final_link_info *, const char *, Elf_Internal_Sym *, asection *,
+ struct elf_link_hash_entry *);
static bfd_boolean elf_link_flush_output_syms
(struct elf_final_link_info *);
static bfd_boolean elf_link_output_extsym
asection *reldyn = 0;
bfd_size_type amt;
- if (! is_elf_hash_table (info))
+ if (! is_elf_hash_table (info->hash))
return FALSE;
if (info->shared)
finfo.symshndxbuf = NULL;
finfo.symbuf_count = 0;
finfo.shndxbuf_size = 0;
- finfo.first_tls_sec = NULL;
- for (o = abfd->sections; o != NULL; o = o->next)
- if ((o->flags & SEC_THREAD_LOCAL) != 0
- && (o->flags & SEC_LOAD) != 0)
- {
- finfo.first_tls_sec = o;
- break;
- }
/* Count up the number of relocations we will output for each output
section, so that we know the sizes of the reloc sections. We
elfsym.st_info = 0;
elfsym.st_other = 0;
elfsym.st_shndx = SHN_UNDEF;
- if (! elf_link_output_sym (&finfo, NULL, &elfsym, bfd_und_section_ptr))
+ if (! elf_link_output_sym (&finfo, NULL, &elfsym, bfd_und_section_ptr,
+ NULL))
goto error_return;
}
elfsym.st_other = 0;
elfsym.st_shndx = SHN_ABS;
if (! elf_link_output_sym (&finfo, bfd_get_filename (abfd),
- &elfsym, bfd_abs_section_ptr))
+ &elfsym, bfd_abs_section_ptr, NULL))
goto error_return;
#endif
elfsym.st_value = 0;
else
elfsym.st_value = o->vma;
- if (! elf_link_output_sym (&finfo, NULL, &elfsym, o))
+ if (! elf_link_output_sym (&finfo, NULL, &elfsym, o, NULL))
goto error_return;
if (i == SHN_LORESERVE - 1)
i += SHN_HIRESERVE + 1 - SHN_LORESERVE;
goto error_return;
}
- if (finfo.first_tls_sec)
+ if (elf_hash_table (info)->tls_sec)
{
- unsigned int align = 0;
- bfd_vma base = finfo.first_tls_sec->vma, end = 0;
+ bfd_vma base, end = 0;
asection *sec;
- for (sec = finfo.first_tls_sec;
+ for (sec = elf_hash_table (info)->tls_sec;
sec && (sec->flags & SEC_THREAD_LOCAL);
sec = sec->next)
{
bfd_vma size = sec->_raw_size;
- if (bfd_get_section_alignment (abfd, sec) > align)
- align = bfd_get_section_alignment (abfd, sec);
- if (sec->_raw_size == 0 && (sec->flags & SEC_HAS_CONTENTS) == 0)
+ if (size == 0 && (sec->flags & SEC_HAS_CONTENTS) == 0)
{
struct bfd_link_order *o;
- size = 0;
for (o = sec->link_order_head; o != NULL; o = o->next)
if (size < o->offset + o->size)
size = o->offset + o->size;
}
end = sec->vma + size;
}
- elf_hash_table (info)->tls_segment
- = bfd_zalloc (abfd, sizeof (struct elf_link_tls_segment));
- if (elf_hash_table (info)->tls_segment == NULL)
- goto error_return;
- elf_hash_table (info)->tls_segment->start = base;
- elf_hash_table (info)->tls_segment->size = end - base;
- elf_hash_table (info)->tls_segment->align = align;
+ base = elf_hash_table (info)->tls_sec->vma;
+ end = align_power (end, elf_hash_table (info)->tls_sec->alignment_power);
+ elf_hash_table (info)->tls_size = end - base;
}
/* Since ELF permits relocations to be against local symbols, we
if (bed->elf_backend_output_arch_syms)
{
typedef bfd_boolean (*out_sym_func)
- (void *, const char *, Elf_Internal_Sym *, asection *);
+ (void *, const char *, Elf_Internal_Sym *, asection *,
+ struct elf_link_hash_entry *);
if (! ((*bed->elf_backend_output_arch_syms)
(abfd, info, &finfo, (out_sym_func) elf_link_output_sym)))
elf_link_output_sym (struct elf_final_link_info *finfo,
const char *name,
Elf_Internal_Sym *elfsym,
- asection *input_sec)
+ asection *input_sec,
+ struct elf_link_hash_entry *h)
{
Elf_External_Sym *dest;
Elf_External_Sym_Shndx *destshndx;
bfd_boolean (*output_symbol_hook)
- (bfd *, struct bfd_link_info *info, const char *,
- Elf_Internal_Sym *, asection *);
+ (struct bfd_link_info *, const char *, Elf_Internal_Sym *, asection *,
+ struct elf_link_hash_entry *);
output_symbol_hook = get_elf_backend_data (finfo->output_bfd)->
elf_backend_link_output_symbol_hook;
if (output_symbol_hook != NULL)
{
- if (! ((*output_symbol_hook)
- (finfo->output_bfd, finfo->info, name, elfsym, input_sec)))
+ if (! (*output_symbol_hook) (finfo->info, name, elfsym, input_sec, h))
return FALSE;
}
bfd *abfd;
struct elf_link_loaded_list *loaded;
- if (info->hash->creator->flavour != bfd_target_elf_flavour)
+ if (!is_elf_hash_table (info->hash))
return FALSE;
switch (h->root.type)
return TRUE;
}
- /* If we are not creating a shared library, and this symbol is
- referenced by a shared library but is not defined anywhere, then
- warn that it is undefined. If we do not do this, the runtime
- linker will complain that the symbol is undefined when the
- program is run. We don't have to worry about symbols that are
- referenced by regular files, because we will already have issued
- warnings for them. */
- if (! finfo->info->relocatable
- && (finfo->info->executable
- || ! finfo->info->allow_shlib_undefined)
- && h->root.type == bfd_link_hash_undefined
+ /* If we have an undefined symbol reference here then it must have
+ come from a shared library that is being linked in. (Undefined
+ references in regular files have already been handled). If we
+ are reporting errors for this situation then do so now. */
+ if (h->root.type == bfd_link_hash_undefined
&& (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0
&& (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0
- && ! elf_link_check_versioned_symbol (finfo->info, h))
+ && ! elf_link_check_versioned_symbol (finfo->info, h)
+ && finfo->info->unresolved_syms_in_shared_libs != RM_IGNORE)
{
if (! ((*finfo->info->callbacks->undefined_symbol)
(finfo->info, h->root.root.string, h->root.u.undef.abfd,
- NULL, 0, TRUE)))
+ NULL, 0, finfo->info->unresolved_syms_in_shared_libs == RM_GENERATE_ERROR)))
{
eoinfo->failed = TRUE;
return FALSE;
/* We should also warn if a forced local symbol is referenced from
shared libraries. */
if (! finfo->info->relocatable
- && (! finfo->info->shared || ! finfo->info->allow_shlib_undefined)
+ && (! finfo->info->shared)
&& (h->elf_link_hash_flags
- & (ELF_LINK_FORCED_LOCAL | ELF_LINK_HASH_REF_DYNAMIC
- | ELF_LINK_DYNAMIC_DEF | ELF_LINK_DYNAMIC_WEAK))
+ & (ELF_LINK_FORCED_LOCAL | ELF_LINK_HASH_REF_DYNAMIC | ELF_LINK_DYNAMIC_DEF | ELF_LINK_DYNAMIC_WEAK))
== (ELF_LINK_FORCED_LOCAL | ELF_LINK_HASH_REF_DYNAMIC)
&& ! elf_link_check_versioned_symbol (finfo->info, h))
{
{
/* STT_TLS symbols are relative to PT_TLS segment
base. */
- BFD_ASSERT (finfo->first_tls_sec != NULL);
- sym.st_value -= finfo->first_tls_sec->vma;
+ BFD_ASSERT (elf_hash_table (finfo->info)->tls_sec != NULL);
+ sym.st_value -= elf_hash_table (finfo->info)->tls_sec->vma;
}
}
}
h->indx = bfd_get_symcount (finfo->output_bfd);
- if (! elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec))
+ if (! elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec, h))
{
eoinfo->failed = TRUE;
return FALSE;
if (ELF_ST_TYPE (osym.st_info) == STT_TLS)
{
/* STT_TLS symbols are relative to PT_TLS segment base. */
- BFD_ASSERT (finfo->first_tls_sec != NULL);
- osym.st_value -= finfo->first_tls_sec->vma;
+ BFD_ASSERT (elf_hash_table (finfo->info)->tls_sec != NULL);
+ osym.st_value -= elf_hash_table (finfo->info)->tls_sec->vma;
}
}
- if (! elf_link_output_sym (finfo, name, &osym, isec))
+ if (! elf_link_output_sym (finfo, name, &osym, isec, NULL))
return FALSE;
}
{
/* STT_TLS symbols are relative to PT_TLS
segment base. */
- BFD_ASSERT (finfo->first_tls_sec != NULL);
- sym.st_value -= finfo->first_tls_sec->vma;
+ BFD_ASSERT (elf_hash_table (finfo->info)
+ ->tls_sec != NULL);
+ sym.st_value -= (elf_hash_table (finfo->info)
+ ->tls_sec->vma);
}
}
finfo->indices[r_symndx]
= bfd_get_symcount (output_bfd);
- if (! elf_link_output_sym (finfo, name, &sym, sec))
+ if (! elf_link_output_sym (finfo, name, &sym, sec,
+ NULL))
return FALSE;
}
return TRUE;
}
-/* Propogate collected vtable information. This is called through
+/* Propagate collected vtable information. This is called through
elf_link_hash_traverse. */
static bfd_boolean
struct elf_link_hash_entry *h, Elf_Internal_Sym *);
if (!get_elf_backend_data (abfd)->can_gc_sections
- || info->relocatable || info->emitrelocations
+ || info->relocatable
+ || info->emitrelocations
+ || !is_elf_hash_table (info->hash)
|| elf_hash_table (info)->dynamic_sections_created)
- return TRUE;
+ {
+ (*_bfd_error_handler)(_("Warning: gc-sections option ignored"));
+ return TRUE;
+ }
/* Apply transitive closure to the vtable entry usage info. */
elf_link_hash_traverse (elf_hash_table (info),
return TRUE;
}
\f
-/* Called from check_relocs to record the existance of a VTINHERIT reloc. */
+/* Called from check_relocs to record the existence of a VTINHERIT reloc. */
bfd_boolean
elf_gc_record_vtinherit (bfd *abfd,
return TRUE;
}
-/* Called from check_relocs to record the existance of a VTENTRY reloc. */
+/* Called from check_relocs to record the existence of a VTENTRY reloc. */
bfd_boolean
elf_gc_record_vtentry (bfd *abfd ATTRIBUTE_UNUSED,
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
bfd_vma gotoff;
+ if (! is_elf_hash_table (info->hash))
+ return FALSE;
+
/* The GOT offset is relative to the .got section, but the GOT header is
put into the .got.plt section, if the backend uses it. */
if (bed->want_got_plt)
bfd_boolean ret = FALSE;
if (info->traditional_format
- || info->hash->creator->flavour != bfd_target_elf_flavour
- || ! is_elf_hash_table (info))
+ || !is_elf_hash_table (info->hash))
return FALSE;
for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next)