hash_table = elf_hash_table (info);
if (hash_table->dynobj == NULL)
- hash_table->dynobj = abfd;
+ {
+ /* We may not set dynobj, an input file holding linker created
+ dynamic sections to abfd, which may be a dynamic object with
+ its own dynamic sections. We need to find a normal input file
+ to hold linker created sections if possible. */
+ if ((abfd->flags & (DYNAMIC | BFD_PLUGIN)) != 0)
+ {
+ bfd *ibfd;
+ for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link.next)
+ if ((ibfd->flags
+ & (DYNAMIC | BFD_LINKER_CREATED | BFD_PLUGIN)) == 0)
+ {
+ abfd = ibfd;
+ break;
+ }
+ }
+ hash_table->dynobj = abfd;
+ }
if (hash_table->dynstr == NULL)
{
elf_link_renumber_hash_table_dynsyms,
&dynsymcount);
- /* There is an unused NULL entry at the head of the table which
- we must account for in our count. We always create the dynsym
- section, even if it is empty, with dynamic sections. */
- if (elf_hash_table (info)->dynamic_sections_created)
- ++dynsymcount;
+ /* There is an unused NULL entry at the head of the table which we
+ must account for in our count even if the table is empty since it
+ is intended for the mandatory DT_SYMTAB tag (.dynsym section) in
+ .dynamic section. */
+ dynsymcount++;
elf_hash_table (info)->dynsymcount = dynsymcount;
return dynsymcount;
the old symbol override the new one as normally happens with
symbols defined in dynamic objects. */
- if (! ((*info->callbacks->multiple_common)
- (info, &h->root, abfd, bfd_link_hash_common, sym->st_size)))
- return FALSE;
-
+ (*info->callbacks->multiple_common) (info, &h->root, abfd,
+ bfd_link_hash_common, sym->st_size);
if (sym->st_size > h->size)
h->size = sym->st_size;
/* It would be best if we could set the hash table entry to a
common symbol, but we don't know what to use for the section
or the alignment. */
- if (! ((*info->callbacks->multiple_common)
- (info, &h->root, abfd, bfd_link_hash_common, sym->st_size)))
- return FALSE;
+ (*info->callbacks->multiple_common) (info, &h->root, abfd,
+ bfd_link_hash_common, sym->st_size);
/* If the presumed common symbol in the dynamic object is
larger, pretend that the new symbol has its size. */
return (*info->callbacks->notice) (info, NULL, NULL, ibfd, NULL, act, 0);
}
+/* Check relocations an ELF object file. */
+
+bfd_boolean
+_bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ struct elf_link_hash_table *htab = elf_hash_table (info);
+
+ /* If this object is the same format as the output object, and it is
+ not a shared library, then let the backend look through the
+ relocs.
+
+ This is required to build global offset table entries and to
+ arrange for dynamic relocs. It is not required for the
+ particular common case of linking non PIC code, even when linking
+ against shared libraries, but unfortunately there is no way of
+ knowing whether an object file has been compiled PIC or not.
+ Looking through the relocs is not particularly time consuming.
+ The problem is that we must either (1) keep the relocs in memory,
+ which causes the linker to require additional runtime memory or
+ (2) read the relocs twice from the input file, which wastes time.
+ This would be a good case for using mmap.
+
+ I have no idea how to handle linking PIC code into a file of a
+ different format. It probably can't be done. */
+ if ((abfd->flags & DYNAMIC) == 0
+ && is_elf_hash_table (htab)
+ && bed->check_relocs != NULL
+ && elf_object_id (abfd) == elf_hash_table_id (htab)
+ && (*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
+ {
+ asection *o;
+
+ for (o = abfd->sections; o != NULL; o = o->next)
+ {
+ Elf_Internal_Rela *internal_relocs;
+ bfd_boolean ok;
+
+ /* Don't check relocations in excluded sections. */
+ if ((o->flags & SEC_RELOC) == 0
+ || (o->flags & SEC_EXCLUDE) != 0
+ || o->reloc_count == 0
+ || ((info->strip == strip_all || info->strip == strip_debugger)
+ && (o->flags & SEC_DEBUGGING) != 0)
+ || bfd_is_abs_section (o->output_section))
+ continue;
+
+ internal_relocs = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL,
+ info->keep_memory);
+ if (internal_relocs == NULL)
+ return FALSE;
+
+ ok = (*bed->check_relocs) (abfd, info, o, internal_relocs);
+
+ if (elf_section_data (o)->relocs != internal_relocs)
+ free (internal_relocs);
+
+ if (! ok)
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
/* Add symbols from an ELF object file to the linker hash table. */
static bfd_boolean
bfd_boolean old_weak;
bfd_boolean override;
bfd_boolean common;
+ bfd_boolean discarded;
unsigned int old_alignment;
bfd *old_bfd;
bfd_boolean matched;
sec = NULL;
value = isym->st_value;
common = bed->common_definition (isym);
+ discarded = FALSE;
bind = ELF_ST_BIND (isym->st_info);
switch (bind)
/* Symbols from discarded section are undefined. We keep
its visibility. */
sec = bfd_und_section_ptr;
+ discarded = TRUE;
isym->st_shndx = SHN_UNDEF;
}
else if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0)
(struct bfd_link_hash_entry **) sym_hash)))
goto error_free_vers;
+ if ((flags & BSF_GNU_UNIQUE)
+ && (abfd->flags & DYNAMIC) == 0
+ && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
+ elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_unique;
+
h = *sym_hash;
/* We need to make sure that indirect symbol dynamic flags are
updated. */
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ /* Setting the index to -3 tells elf_link_output_extsym that
+ this symbol is defined in a discarded section. */
+ if (discarded)
+ h->indx = -3;
+
*sym_hash = h;
new_weak = (flags & BSF_WEAK) != 0;
&& !(*bed->check_directives) (abfd, info))
return FALSE;
- /* If this object is the same format as the output object, and it is
- not a shared library, then let the backend look through the
- relocs.
-
- This is required to build global offset table entries and to
- arrange for dynamic relocs. It is not required for the
- particular common case of linking non PIC code, even when linking
- against shared libraries, but unfortunately there is no way of
- knowing whether an object file has been compiled PIC or not.
- Looking through the relocs is not particularly time consuming.
- The problem is that we must either (1) keep the relocs in memory,
- which causes the linker to require additional runtime memory or
- (2) read the relocs twice from the input file, which wastes time.
- This would be a good case for using mmap.
-
- I have no idea how to handle linking PIC code into a file of a
- different format. It probably can't be done. */
- if (! dynamic
- && is_elf_hash_table (htab)
- && bed->check_relocs != NULL
- && elf_object_id (abfd) == elf_hash_table_id (htab)
- && (*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
- {
- asection *o;
-
- for (o = abfd->sections; o != NULL; o = o->next)
- {
- Elf_Internal_Rela *internal_relocs;
- bfd_boolean ok;
-
- if ((o->flags & SEC_RELOC) == 0
- || o->reloc_count == 0
- || ((info->strip == strip_all || info->strip == strip_debugger)
- && (o->flags & SEC_DEBUGGING) != 0)
- || bfd_is_abs_section (o->output_section))
- continue;
-
- internal_relocs = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL,
- info->keep_memory);
- if (internal_relocs == NULL)
- goto error_return;
-
- ok = (*bed->check_relocs) (abfd, info, o, internal_relocs);
-
- if (elf_section_data (o)->relocs != internal_relocs)
- free (internal_relocs);
-
- if (! ok)
- goto error_return;
- }
- }
+ if (!info->check_relocs_after_open_input
+ && !_bfd_elf_link_check_relocs (abfd, info))
+ return FALSE;
/* If this is a non-traditional link, try to optimize the handling
of the .stab/.stabstr sections. */
if (!(*info->callbacks
->add_archive_element) (info, element, symdef->name, &element))
- goto error_return;
+ continue;
if (!bfd_link_add_symbols (element, info))
goto error_return;
/* Work out the size of the symbol version section. */
s = bfd_get_linker_section (dynobj, ".gnu.version");
BFD_ASSERT (s != NULL);
- if (dynsymcount != 0
- && (s->flags & SEC_EXCLUDE) == 0)
+ if ((s->flags & SEC_EXCLUDE) == 0)
{
s->size = dynsymcount * sizeof (Elf_External_Versym);
s->contents = (unsigned char *) bfd_zalloc (output_bfd, s->size);
BFD_ASSERT (s != NULL);
s->size = dynsymcount * bed->s->sizeof_sym;
- if (dynsymcount != 0)
- {
- s->contents = (unsigned char *) bfd_alloc (output_bfd, s->size);
- if (s->contents == NULL)
- return FALSE;
+ s->contents = (unsigned char *) bfd_alloc (output_bfd, s->size);
+ if (s->contents == NULL)
+ return FALSE;
- /* The first entry in .dynsym is a dummy symbol.
- Clear all the section syms, in case we don't output them all. */
- ++section_sym_count;
- memset (s->contents, 0, section_sym_count * bed->s->sizeof_sym);
- }
+ /* The first entry in .dynsym is a dummy symbol. Clear all the
+ section syms, in case we don't output them all. */
+ ++section_sym_count;
+ memset (s->contents, 0, section_sym_count * bed->s->sizeof_sym);
elf_hash_table (info)->bucketcount = 0;
struct elf_link_sort_rela *sq;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
int i2e = bed->s->int_rels_per_ext_rel;
+ unsigned int opb = bfd_octets_per_byte (abfd);
void (*swap_in) (bfd *, const bfd_byte *, Elf_Internal_Rela *);
void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *);
struct bfd_link_order *lo;
bfd_boolean use_rela_initialised = FALSE;
/* This is just here to stop gcc from complaining.
- It's initialization checking code is not perfect. */
+ Its initialization checking code is not perfect. */
use_rela = TRUE;
/* Both sections are present. Examine the sizes
/* Section size is only divisible by rela. */
if (use_rela_initialised && (use_rela == FALSE))
{
- _bfd_error_handler
- (_("%B: Unable to sort relocs - they are in more than one size"), abfd);
+ _bfd_error_handler (_("%B: Unable to sort relocs - "
+ "they are in more than one size"),
+ abfd);
bfd_set_error (bfd_error_invalid_operation);
return 0;
}
/* Section size is only divisible by rel. */
if (use_rela_initialised && (use_rela == TRUE))
{
- _bfd_error_handler
- (_("%B: Unable to sort relocs - they are in more than one size"), abfd);
+ _bfd_error_handler (_("%B: Unable to sort relocs - "
+ "they are in more than one size"),
+ abfd);
bfd_set_error (bfd_error_invalid_operation);
return 0;
}
}
else
{
- /* The section size is not divisible by either - something is wrong. */
- _bfd_error_handler
- (_("%B: Unable to sort relocs - they are of an unknown size"), abfd);
+ /* The section size is not divisible by either -
+ something is wrong. */
+ _bfd_error_handler (_("%B: Unable to sort relocs - "
+ "they are of an unknown size"), abfd);
bfd_set_error (bfd_error_invalid_operation);
return 0;
}
/* Section size is only divisible by rela. */
if (use_rela_initialised && (use_rela == FALSE))
{
- _bfd_error_handler
- (_("%B: Unable to sort relocs - they are in more than one size"), abfd);
+ _bfd_error_handler (_("%B: Unable to sort relocs - "
+ "they are in more than one size"),
+ abfd);
bfd_set_error (bfd_error_invalid_operation);
return 0;
}
/* Section size is only divisible by rel. */
if (use_rela_initialised && (use_rela == TRUE))
{
- _bfd_error_handler
- (_("%B: Unable to sort relocs - they are in more than one size"), abfd);
+ _bfd_error_handler (_("%B: Unable to sort relocs - "
+ "they are in more than one size"),
+ abfd);
bfd_set_error (bfd_error_invalid_operation);
return 0;
}
}
else
{
- /* The section size is not divisible by either - something is wrong. */
- _bfd_error_handler
- (_("%B: Unable to sort relocs - they are of an unknown size"), abfd);
+ /* The section size is not divisible by either -
+ something is wrong. */
+ _bfd_error_handler (_("%B: Unable to sort relocs - "
+ "they are of an unknown size"), abfd);
bfd_set_error (bfd_error_invalid_operation);
return 0;
}
}
erel = o->contents;
erelend = o->contents + o->size;
- /* FIXME: octets_per_byte. */
- p = sort + o->output_offset / ext_size * sort_elt;
+ p = sort + o->output_offset * opb / ext_size * sort_elt;
while (erel < erelend)
{
qsort (s_non_relative, count - ret, sort_elt, elf_link_sort_cmp2);
+ struct elf_link_hash_table *htab = elf_hash_table (info);
+ if (htab->srelplt && htab->srelplt->output_section == dynamic_relocs)
+ {
+ /* We have plt relocs in .rela.dyn. */
+ sq = (struct elf_link_sort_rela *) sort;
+ for (i = 0; i < count; i++)
+ if (sq[count - i - 1].type != reloc_class_plt)
+ break;
+ if (i != 0 && htab->srelplt->size == i * ext_size)
+ {
+ struct bfd_link_order **plo;
+ /* Put srelplt link_order last. This is so the output_offset
+ set in the next loop is correct for DT_JMPREL. */
+ for (plo = &dynamic_relocs->map_head.link_order; *plo != NULL; )
+ if ((*plo)->type == bfd_indirect_link_order
+ && (*plo)->u.indirect.section == htab->srelplt)
+ {
+ lo = *plo;
+ *plo = lo->next;
+ }
+ else
+ plo = &(*plo)->next;
+ *plo = lo;
+ lo->next = NULL;
+ dynamic_relocs->map_tail.link_order = lo;
+ }
+ }
+
+ p = sort;
for (lo = dynamic_relocs->map_head.link_order; lo != NULL; lo = lo->next)
if (lo->type == bfd_indirect_link_order)
{
erel = o->contents;
erelend = o->contents + o->size;
- /* FIXME: octets_per_byte. */
- p = sort + o->output_offset / ext_size * sort_elt;
+ o->output_offset = (p - sort) / sort_elt * ext_size / opb;
while (erel < erelend)
{
struct elf_link_sort_rela *s = (struct elf_link_sort_rela *) p;
&& (!h->ref_regular || flinfo->info->gc_sections)
&& !elf_link_check_versioned_symbol (flinfo->info, bed, h)
&& flinfo->info->unresolved_syms_in_shared_libs != RM_IGNORE)
- {
- if (!(flinfo->info->callbacks->undefined_symbol
- (flinfo->info, h->root.root.string,
- h->ref_regular ? NULL : h->root.u.undef.abfd,
- NULL, 0,
- (flinfo->info->unresolved_syms_in_shared_libs
- == RM_GENERATE_ERROR))))
- {
- bfd_set_error (bfd_error_bad_value);
- eoinfo->failed = TRUE;
- return FALSE;
- }
- }
+ (*flinfo->info->callbacks->undefined_symbol)
+ (flinfo->info, h->root.root.string,
+ h->ref_regular ? NULL : h->root.u.undef.abfd,
+ NULL, 0,
+ flinfo->info->unresolved_syms_in_shared_libs == RM_GENERATE_ERROR);
+
+ /* Strip a global symbol defined in a discarded section. */
+ if (h->indx == -3)
+ return TRUE;
}
/* We should also warn if a forced local symbol is referenced from
}
else
{
- if (! ((*info->callbacks->unattached_reloc)
- (info, link_order->u.reloc.p->u.name, NULL, NULL, 0)))
- return FALSE;
+ (*info->callbacks->unattached_reloc)
+ (info, link_order->u.reloc.p->u.name, NULL, NULL, 0);
indx = 0;
}
}
link_order->u.reloc.p->u.section);
else
sym_name = link_order->u.reloc.p->u.name;
- if (! ((*info->callbacks->reloc_overflow)
- (info, NULL, sym_name, howto->name, addend, NULL,
- NULL, (bfd_vma) 0)))
- {
- free (buf);
- return FALSE;
- }
+ (*info->callbacks->reloc_overflow) (info, NULL, sym_name,
+ howto->name, addend, NULL, NULL,
+ (bfd_vma) 0);
break;
}
case DT_PREINIT_ARRAYSZ:
name = ".preinit_array";
- goto get_size;
+ goto get_out_size;
case DT_INIT_ARRAYSZ:
name = ".init_array";
- goto get_size;
+ goto get_out_size;
case DT_FINI_ARRAYSZ:
name = ".fini_array";
- get_size:
+ get_out_size:
o = bfd_get_section_by_name (abfd, name);
if (o == NULL)
{
(*_bfd_error_handler)
- (_("%B: could not find output section %s"), abfd, name);
+ (_("could not find section %s"), name);
goto error_return;
}
if (o->size == 0)
case DT_PREINIT_ARRAY:
name = ".preinit_array";
- goto get_vma;
+ goto get_out_vma;
case DT_INIT_ARRAY:
name = ".init_array";
- goto get_vma;
+ goto get_out_vma;
case DT_FINI_ARRAY:
name = ".fini_array";
- goto get_vma;
+ get_out_vma:
+ o = bfd_get_section_by_name (abfd, name);
+ goto do_vma;
case DT_HASH:
name = ".hash";
case DT_VERSYM:
name = ".gnu.version";
get_vma:
- o = bfd_get_section_by_name (abfd, name);
+ o = bfd_get_linker_section (dynobj, name);
+ do_vma:
if (o == NULL)
{
(*_bfd_error_handler)
- (_("%B: could not find output section %s"), abfd, name);
+ (_("could not find section %s"), name);
goto error_return;
}
if (elf_section_data (o->output_section)->this_hdr.sh_type == SHT_NOTE)
bfd_set_error (bfd_error_nonrepresentable_section);
goto error_return;
}
- dyn.d_un.d_ptr = o->vma;
+ dyn.d_un.d_ptr = o->output_section->vma + o->output_offset;
break;
case DT_REL:
return NULL;
}
+/* For undefined __start_<name> and __stop_<name> symbols, return the
+ first input section matching <name>. Return NULL otherwise. */
+
+asection *
+_bfd_elf_is_start_stop (const struct bfd_link_info *info,
+ struct elf_link_hash_entry *h)
+{
+ asection *s;
+ const char *sec_name;
+
+ if (h->root.type != bfd_link_hash_undefined
+ && h->root.type != bfd_link_hash_undefweak)
+ return NULL;
+
+ s = h->root.u.undef.section;
+ if (s != NULL)
+ {
+ if (s == (asection *) 0 - 1)
+ return NULL;
+ return s;
+ }
+
+ sec_name = NULL;
+ if (strncmp (h->root.root.string, "__start_", 8) == 0)
+ sec_name = h->root.root.string + 8;
+ else if (strncmp (h->root.root.string, "__stop_", 7) == 0)
+ sec_name = h->root.root.string + 7;
+
+ if (sec_name != NULL && *sec_name != '\0')
+ {
+ bfd *i;
+
+ for (i = info->input_bfds; i != NULL; i = i->link.next)
+ {
+ s = bfd_get_section_by_name (i, sec_name);
+ if (s != NULL)
+ {
+ h->root.u.undef.section = s;
+ break;
+ }
+ }
+ }
+
+ if (s == NULL)
+ h->root.u.undef.section = (asection *) 0 - 1;
+
+ return s;
+}
+
/* COOKIE->rel describes a relocation against section SEC, which is
a section we've decided to keep. Return the section that contains
the relocation symbol, or NULL if no section contains it. */
if (h->u.weakdef != NULL)
h->u.weakdef->mark = 1;
- if (start_stop != NULL
- && (h->root.type == bfd_link_hash_undefined
- || h->root.type == bfd_link_hash_undefweak))
+ if (start_stop != NULL)
{
/* To work around a glibc bug, mark all XXX input sections
when there is an as yet undefined reference to __start_XXX
or __stop_XXX symbols. The linker will later define such
symbols for orphan input sections that have a name
representable as a C identifier. */
- const char *sec_name = NULL;
- if (strncmp (h->root.root.string, "__start_", 8) == 0)
- sec_name = h->root.root.string + 8;
- else if (strncmp (h->root.root.string, "__stop_", 7) == 0)
- sec_name = h->root.root.string + 7;
+ asection *s = _bfd_elf_is_start_stop (info, h);
- if (sec_name != NULL && *sec_name != '\0')
+ if (s != NULL)
{
- bfd *i;
-
- for (i = info->input_bfds; i != NULL; i = i->link.next)
- {
- asection *s = bfd_get_section_by_name (i, sec_name);
- if (s != NULL && !s->gc_mark)
- {
- *start_stop = TRUE;
- return s;
- }
- }
+ *start_stop = !s->gc_mark;
+ return s;
}
}