}
/* The first bit of the global offset table is the header. */
- s->_raw_size += bed->got_header_size + bed->got_symbol_offset;
+ s->size += bed->got_header_size + bed->got_symbol_offset;
return TRUE;
}
return TRUE;
}
+/* Return true if the dynamic symbol for a given section should be
+ omitted when creating a shared library. */
+bfd_boolean
+_bfd_elf_link_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info,
+ asection *p)
+{
+ switch (elf_section_data (p)->this_hdr.sh_type)
+ {
+ case SHT_PROGBITS:
+ case SHT_NOBITS:
+ /* If sh_type is yet undecided, assume it could be
+ SHT_PROGBITS/SHT_NOBITS. */
+ case SHT_NULL:
+ if (strcmp (p->name, ".got") == 0
+ || strcmp (p->name, ".got.plt") == 0
+ || strcmp (p->name, ".plt") == 0)
+ {
+ asection *ip;
+ bfd *dynobj = elf_hash_table (info)->dynobj;
+
+ if (dynobj != NULL
+ && (ip = bfd_get_section_by_name (dynobj, p->name))
+ != NULL
+ && (ip->flags & SEC_LINKER_CREATED)
+ && ip->output_section == p)
+ return TRUE;
+ }
+ return FALSE;
+
+ /* There shouldn't be section relative relocations
+ against any other section. */
+ default:
+ return TRUE;
+ }
+}
+
/* Assign dynsym indices. 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
if (info->shared)
{
+ const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
asection *p;
for (p = output_bfd->sections; p ; p = p->next)
- if ((p->flags & SEC_EXCLUDE) == 0)
+ if ((p->flags & SEC_EXCLUDE) == 0
+ && (p->flags & SEC_ALLOC) != 0
+ && !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p))
elf_section_data (p)->dynindx = ++dynsymcount;
}
oldweak = (h->root.type == bfd_link_hash_defweak
|| h->root.type == bfd_link_hash_undefweak);
- /* If a new weak symbol comes from a regular file and the old symbol
- comes from a dynamic library, we treat the new one as strong.
- Similarly, an old weak symbol from a regular file is treated as
- strong when the new symbol comes from a dynamic library. Further,
- an old weak symbol from a dynamic library is treated as strong if
- the new symbol is from a dynamic library. This reflects the way
- glibc's ld.so works. */
- if (!newdyn && olddyn)
+ /* If a new weak symbol definition comes from a regular file and the
+ old symbol comes from a dynamic library, we treat the new one as
+ strong. Similarly, an old weak symbol definition from a regular
+ file is treated as strong when the new symbol comes from a dynamic
+ library. Further, an old weak symbol from a dynamic library is
+ treated as strong if the new symbol is from a dynamic library.
+ This reflects the way glibc's ld.so works.
+
+ Do this before setting *type_change_ok or *size_change_ok so that
+ we warn properly when dynamic library symbols are overridden. */
+
+ if (newdef && !newdyn && olddyn)
newweak = FALSE;
- if (newdyn)
+ if (olddef && newdyn)
oldweak = FALSE;
/* It's OK to change the type if either the existing symbol or the
r_symndx >>= 24;
if ((size_t) r_symndx >= nsyms)
{
+ char *sec_name = bfd_get_section_ident (sec);
(*_bfd_error_handler)
(_("%s: bad reloc symbol index (0x%lx >= 0x%lx) for offset 0x%lx in section `%s'"),
bfd_archive_filename (abfd), (unsigned long) r_symndx,
- (unsigned long) nsyms, irela->r_offset, sec->name);
+ (unsigned long) nsyms, irela->r_offset,
+ sec_name ? sec_name : sec->name);
+ if (sec_name)
+ free (sec_name);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
}
else
{
+ char *sec_name = bfd_get_section_ident (input_section);
(*_bfd_error_handler)
(_("%s: relocation size mismatch in %s section %s"),
bfd_get_filename (output_bfd),
bfd_archive_filename (input_section->owner),
- input_section->name);
+ sec_name ? sec_name : input_section->name);
+ if (sec_name)
+ free (sec_name);
bfd_set_error (bfd_error_wrong_object_format);
return FALSE;
}
_bfd_merged_section_offset (output_bfd,
&h->root.u.def.section,
elf_section_data (sec)->sec_info,
- h->root.u.def.value, 0);
+ h->root.u.def.value);
}
return TRUE;
if (h == NULL)
return TRUE;
+ /* Common symbols that become definitions don't get the DEF_REGULAR
+ flag set, so test it first, and don't bail out. */
+ if (ELF_COMMON_DEF_P (h))
+ /* Do nothing. */;
/* If we don't have a definition in a regular file, then we can't
resolve locally. The sym is either undefined or dynamic. */
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ else if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
return FALSE;
/* Forced local symbols resolve locally. */
s = bfd_get_section_by_name (hash_table->dynobj, ".dynamic");
BFD_ASSERT (s != NULL);
- newsize = s->_raw_size + bed->s->sizeof_dyn;
+ newsize = s->size + bed->s->sizeof_dyn;
newcontents = bfd_realloc (s->contents, newsize);
if (newcontents == NULL)
return FALSE;
dyn.d_tag = tag;
dyn.d_un.d_val = val;
- bed->s->swap_dyn_out (hash_table->dynobj, &dyn, newcontents + s->_raw_size);
+ bed->s->swap_dyn_out (hash_table->dynobj, &dyn, newcontents + s->size);
- s->_raw_size = newsize;
+ s->size = newsize;
s->contents = newcontents;
return TRUE;
BFD_ASSERT (sdyn != NULL);
for (extdyn = sdyn->contents;
- extdyn < sdyn->contents + sdyn->_raw_size;
+ extdyn < sdyn->contents + sdyn->size;
extdyn += bed->s->sizeof_dyn)
{
Elf_Internal_Dyn dyn;
return vdiff > 0 ? 1 : -1;
else
{
- long sdiff = h1->root.u.def.section - h2->root.u.def.section;
+ long sdiff = h1->root.u.def.section->id - h2->root.u.def.section->id;
if (sdiff != 0)
return sdiff > 0 ? 1 : -1;
}
/* Update all .dynamic entries referencing .dynstr strings. */
for (extdyn = sdyn->contents;
- extdyn < sdyn->contents + sdyn->_raw_size;
+ extdyn < sdyn->contents + sdyn->size;
extdyn += bed->s->sizeof_dyn)
{
Elf_Internal_Dyn dyn;
const char **, flagword *, asection **, bfd_vma *);
bfd_boolean (*check_relocs)
(bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *);
+ bfd_boolean (*check_directives)
+ (bfd *, struct bfd_link_info *);
bfd_boolean collect;
Elf_Internal_Shdr *hdr;
bfd_size_type symcount;
/* We don't want to issue this warning. Clobber
the section size so that the warning does not
get copied into the output file. */
- s->_raw_size = 0;
+ s->size = 0;
continue;
}
}
- sz = bfd_section_size (abfd, s);
+ sz = s->size;
prefix_len = strlen (gnu_warning_prefix);
msg = bfd_alloc (abfd, prefix_len + sz + 1);
if (msg == NULL)
{
/* Clobber the section size so that the warning does
not get copied into the output file. */
- s->_raw_size = 0;
+ s->size = 0;
}
}
}
/* If this dynamic lib was specified on the command line with
--as-needed in effect, then we don't want to add a DT_NEEDED
tag unless the lib is actually used. Similary for libs brought
- in by another lib's DT_NEEDED. */
- add_needed = elf_dyn_lib_class (abfd) == DYN_NORMAL;
+ in by another lib's DT_NEEDED. When --no-add-needed is used
+ on a dynamic lib, we don't want to add a DT_NEEDED entry for
+ any dynamic library in DT_NEEDED tags in the dynamic lib at
+ all. */
+ add_needed = (elf_dyn_lib_class (abfd)
+ & (DYN_AS_NEEDED | DYN_DT_NEEDED
+ | DYN_NO_NEEDED)) == 0;
s = bfd_get_section_by_name (abfd, ".dynamic");
if (s != NULL)
int elfsec;
unsigned long shlink;
- dynbuf = bfd_malloc (s->_raw_size);
- if (dynbuf == NULL)
- goto error_return;
-
- if (! bfd_get_section_contents (abfd, s, dynbuf, 0, s->_raw_size))
+ if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
goto error_free_dyn;
elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
shlink = elf_elfsections (abfd)[elfsec]->sh_link;
for (extdyn = dynbuf;
- extdyn < dynbuf + s->_raw_size;
+ extdyn < dynbuf + s->size;
extdyn += bed->s->sizeof_dyn)
{
Elf_Internal_Dyn dyn;
/* A symbol from a library loaded via DT_NEEDED of some
other library is referenced by a regular object.
- Add a DT_NEEDED entry for it. */
+ Add a DT_NEEDED entry for it. Issue an error if
+ --no-add-needed is used. */
+ if ((elf_dyn_lib_class (abfd) & DYN_NO_NEEDED) != 0)
+ {
+ (*_bfd_error_handler)
+ (_("%s: invalid DSO for symbol `%s' definition"),
+ bfd_archive_filename (abfd), name);
+ bfd_set_error (bfd_error_bad_value);
+ goto error_free_vers;
+ }
+
add_needed = TRUE;
ret = elf_add_dt_needed_tag (info, soname, add_needed);
if (ret < 0)
i = idx + 1;
else
{
- long sdiff = slook - h->root.u.def.section;
+ long sdiff = slook->id - h->root.u.def.section->id;
if (sdiff < 0)
j = idx;
else if (sdiff > 0)
free (sorted_sym_hash);
}
+ check_directives = get_elf_backend_data (abfd)->check_directives;
+ if (check_directives)
+ check_directives (abfd, 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.
secdata = elf_section_data (stab);
if (! _bfd_link_section_stabs (abfd,
- & hash_table->stab_info,
+ &hash_table->stab_info,
stab, stabstr,
&secdata->sec_info,
&string_offset))
}
}
- if (! info->relocatable
- && ! dynamic
- && is_elf_hash_table (hash_table))
- {
- asection *s;
-
- for (s = abfd->sections; s != NULL; s = s->next)
- if ((s->flags & SEC_MERGE) != 0
- && !bfd_is_abs_section (s->output_section))
- {
- struct bfd_elf_section_data *secdata;
-
- secdata = elf_section_data (s);
- if (! _bfd_merge_section (abfd,
- & hash_table->merge_info,
- s, &secdata->sec_info))
- goto error_return;
- else if (secdata->sec_info)
- s->sec_info_type = ELF_INFO_TYPE_MERGE;
- }
- }
-
if (is_elf_hash_table (hash_table))
{
/* Add this bfd to the loaded list. */
if (!is_elf_hash_table (info->hash))
return TRUE;
+ elf_tdata (output_bfd)->relro = info->relro;
if (info->execstack)
elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | PF_X;
else if (info->noexecstack)
size += sizeof (Elf_External_Verdaux);
}
- s->_raw_size = size;
- s->contents = bfd_alloc (output_bfd, s->_raw_size);
- if (s->contents == NULL && s->_raw_size != 0)
+ s->size = size;
+ s->contents = bfd_alloc (output_bfd, s->size);
+ if (s->contents == NULL && s->size != 0)
return FALSE;
/* Fill in the version definition section. */
size += sizeof (Elf_External_Vernaux);
}
- s->_raw_size = size;
- s->contents = bfd_alloc (output_bfd, s->_raw_size);
+ s->size = size;
+ s->contents = bfd_alloc (output_bfd, s->size);
if (s->contents == NULL)
return FALSE;
}
else
{
- s->_raw_size = dynsymcount * sizeof (Elf_External_Versym);
- s->contents = bfd_zalloc (output_bfd, s->_raw_size);
+ s->size = dynsymcount * sizeof (Elf_External_Versym);
+ s->contents = bfd_zalloc (output_bfd, s->size);
if (s->contents == NULL)
return FALSE;
section as we went along in elf_link_add_object_symbols. */
s = bfd_get_section_by_name (dynobj, ".dynsym");
BFD_ASSERT (s != NULL);
- s->_raw_size = dynsymcount * bed->s->sizeof_sym;
- s->contents = bfd_alloc (output_bfd, s->_raw_size);
- if (s->contents == NULL && s->_raw_size != 0)
+ s->size = dynsymcount * bed->s->sizeof_sym;
+ s->contents = bfd_alloc (output_bfd, s->size);
+ if (s->contents == NULL && s->size != 0)
return FALSE;
if (dynsymcount != 0)
s = bfd_get_section_by_name (dynobj, ".hash");
BFD_ASSERT (s != NULL);
hash_entry_size = elf_section_data (s)->this_hdr.sh_entsize;
- s->_raw_size = ((2 + bucketcount + dynsymcount) * hash_entry_size);
- s->contents = bfd_zalloc (output_bfd, s->_raw_size);
+ s->size = ((2 + bucketcount + dynsymcount) * hash_entry_size);
+ s->contents = bfd_zalloc (output_bfd, s->size);
if (s->contents == NULL)
return FALSE;
elf_finalize_dynstr (output_bfd, info);
- s->_raw_size = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr);
+ s->size = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr);
for (dtagcount = 0; dtagcount <= info->spare_dynamic_tags; ++dtagcount)
if (!_bfd_elf_add_dynamic_entry (info, DT_NULL, 0))
bfd_vma r_sym_mask;
reldyn = bfd_get_section_by_name (abfd, ".rela.dyn");
- if (reldyn == NULL || reldyn->_raw_size == 0)
+ if (reldyn == NULL || reldyn->size == 0)
{
reldyn = bfd_get_section_by_name (abfd, ".rel.dyn");
- if (reldyn == NULL || reldyn->_raw_size == 0)
+ if (reldyn == NULL || reldyn->size == 0)
return 0;
ext_size = bed->s->sizeof_rel;
swap_in = bed->s->swap_reloc_in;
swap_in = bed->s->swap_reloca_in;
swap_out = bed->s->swap_reloca_out;
}
- count = reldyn->_raw_size / ext_size;
+ count = reldyn->size / ext_size;
size = 0;
for (lo = reldyn->link_order_head; lo != NULL; lo = lo->next)
if (lo->type == bfd_indirect_link_order)
{
asection *o = lo->u.indirect.section;
- size += o->_raw_size;
+ size += o->size;
}
- if (size != reldyn->_raw_size)
+ if (size != reldyn->size)
return 0;
sort_elt = (sizeof (struct elf_link_sort_rela)
asection *o = lo->u.indirect.section;
erel = o->contents;
- erelend = o->contents + o->_raw_size;
+ erelend = o->contents + o->size;
p = sort + o->output_offset / ext_size * sort_elt;
while (erel < erelend)
{
asection *o = lo->u.indirect.section;
erel = o->contents;
- erelend = o->contents + o->_raw_size;
+ erelend = o->contents + o->size;
p = sort + o->output_offset / ext_size * sort_elt;
while (erel < erelend)
{
case bfd_link_hash_undefweak:
abfd = h->root.u.undef.abfd;
if ((abfd->flags & DYNAMIC) == 0
- || elf_dyn_lib_class (abfd) != DYN_DT_NEEDED)
+ || (elf_dyn_lib_class (abfd) & DYN_DT_NEEDED) == 0)
return FALSE;
break;
input_sec->output_section);
if (sym.st_shndx == SHN_BAD)
{
+ char *sec_name = bfd_get_section_ident (input_sec);
(*_bfd_error_handler)
(_("%s: could not find output section %s for input section %s"),
bfd_get_filename (finfo->output_bfd),
input_sec->output_section->name,
- input_sec->name);
+ sec_name ? sec_name : input_sec->name);
+ if (sec_name)
+ free (sec_name);
eoinfo->failed = TRUE;
return FALSE;
}
return TRUE;
}
+/* Return TRUE if special handling is done for relocs in SEC against
+ symbols defined in discarded sections. */
+
static bfd_boolean
elf_section_ignore_discarded_relocs (asection *sec)
{
return FALSE;
}
+/* Return TRUE if we should complain about a reloc in SEC against a
+ symbol defined in a discarded section. */
+
+static bfd_boolean
+elf_section_complain_discarded (asection *sec)
+{
+ if (strncmp (".stab", sec->name, 5) == 0
+ && (!sec->name[5] ||
+ (sec->name[5] == '.' && ISDIGIT (sec->name[6]))))
+ return FALSE;
+
+ if (strcmp (".eh_frame", sec->name) == 0)
+ return FALSE;
+
+ if (strcmp (".gcc_except_table", sec->name) == 0)
+ return FALSE;
+
+ if (strcmp (".PARISC.unwind", sec->name) == 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Find a match between a section and a member of a section group. */
+
+static asection *
+match_group_member (asection *sec, asection *group)
+{
+ asection *first = elf_next_in_group (group);
+ asection *s = first;
+
+ while (s != NULL)
+ {
+ if (bfd_elf_match_symbols_in_sections (s, sec))
+ return s;
+
+ if (s == first)
+ break;
+ }
+
+ return NULL;
+}
+
/* Link an input file into the linker output file. This function
handles all the sections and relocations of the input file at once.
This is so that we only have to read the local symbols once, and
isym->st_value =
_bfd_merged_section_offset (output_bfd, &isec,
elf_section_data (isec)->sec_info,
- isym->st_value, 0);
+ isym->st_value);
}
else if (isym->st_shndx == SHN_ABS)
isec = bfd_abs_section_ptr;
}
if ((o->flags & SEC_HAS_CONTENTS) == 0
- || (o->_raw_size == 0 && (o->flags & SEC_RELOC) == 0))
+ || (o->size == 0 && (o->flags & SEC_RELOC) == 0))
continue;
if ((o->flags & SEC_LINKER_CREATED) != 0)
contents = elf_section_data (o)->this_hdr.contents;
else
{
+ bfd_size_type amt = o->rawsize ? o->rawsize : o->size;
+
contents = finfo->contents;
- if (! bfd_get_section_contents (input_bfd, o, contents, 0,
- o->_raw_size))
+ if (! bfd_get_section_contents (input_bfd, o, contents, 0, amt))
return FALSE;
}
if (!elf_section_ignore_discarded_relocs (o))
{
Elf_Internal_Rela *rel, *relend;
+ bfd_boolean complain = elf_section_complain_discarded (o);
rel = internal_relocs;
relend = rel + o->reloc_count * bed->s->int_rels_per_ext_rel;
for ( ; rel < relend; rel++)
{
unsigned long r_symndx = rel->r_info >> r_sym_shift;
- asection *sec;
+ asection **ps, *sec;
+ struct elf_link_hash_entry *h = NULL;
+ const char *sym_name;
if (r_symndx >= locsymcount
|| (elf_bad_symtab (input_bfd)
&& finfo->sections[r_symndx] == NULL))
{
- struct elf_link_hash_entry *h;
-
h = sym_hashes[r_symndx - extsymoff];
while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
- /* Complain if the definition comes from a
- discarded section. */
- sec = h->root.u.def.section;
- if ((h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- && elf_discarded_section (sec))
- {
- if ((o->flags & SEC_DEBUGGING) != 0)
- {
- BFD_ASSERT (r_symndx != 0);
- /* Try to preserve debug information. */
- if ((o->flags & SEC_DEBUGGING) != 0
- && sec->kept_section != NULL
- && sec->_raw_size == sec->kept_section->_raw_size)
- h->root.u.def.section
- = sec->kept_section;
- else
- memset (rel, 0, sizeof (*rel));
- }
- else
- finfo->info->callbacks->error_handler
- (LD_DEFINITION_IN_DISCARDED_SECTION,
- _("%T: discarded in section `%s' from %s\n"),
- h->root.root.string,
- h->root.root.string,
- h->root.u.def.section->name,
- bfd_archive_filename (h->root.u.def.section->owner));
- }
+ if (h->root.type != bfd_link_hash_defined
+ && h->root.type != bfd_link_hash_defweak)
+ continue;
+
+ ps = &h->root.u.def.section;
+ sym_name = h->root.root.string;
}
else
{
- sec = finfo->sections[r_symndx];
+ Elf_Internal_Sym *sym = isymbuf + r_symndx;
+ ps = &finfo->sections[r_symndx];
+ sym_name = bfd_elf_local_sym_name (input_bfd, sym);
+ }
- if (sec != NULL && elf_discarded_section (sec))
+ /* Complain if the definition comes from a
+ discarded section. */
+ if ((sec = *ps) != NULL && elf_discarded_section (sec))
+ {
+ if ((o->flags & SEC_DEBUGGING) != 0)
{
- if ((o->flags & SEC_DEBUGGING) != 0
- || (sec->flags & SEC_LINK_ONCE) != 0)
+ BFD_ASSERT (r_symndx != 0);
+
+ /* Try to preserve debug information.
+ FIXME: This is quite broken. Modifying
+ the symbol here means we will be changing
+ all uses of the symbol, not just those in
+ debug sections. The only thing that makes
+ this half reasonable is that debug sections
+ tend to come after other sections. Of
+ course, that doesn't help with globals.
+ ??? All link-once sections of the same name
+ ought to define the same set of symbols, so
+ it would seem that globals ought to always
+ be defined in the kept section. */
+ if (sec->kept_section != NULL)
{
- BFD_ASSERT (r_symndx != 0);
- /* Try to preserve debug information. */
- if ((o->flags & SEC_DEBUGGING) != 0
- && sec->kept_section != NULL
- && sec->_raw_size == sec->kept_section->_raw_size)
- finfo->sections[r_symndx]
- = sec->kept_section;
- else
+ asection *member;
+
+ /* Check if it is a linkonce section or
+ member of a comdat group. */
+ if (elf_sec_group (sec) == NULL
+ && sec->size == sec->kept_section->size)
{
- rel->r_info &= r_type_mask;
- rel->r_addend = 0;
+ *ps = sec->kept_section;
+ continue;
+ }
+ else if (elf_sec_group (sec) != NULL
+ && (member = match_group_member (sec, sec->kept_section))
+ && sec->size == member->size)
+ {
+ *ps = member;
+ continue;
}
}
- else
- {
- static int count;
- int ok;
- char *buf;
-
- ok = asprintf (&buf, "local symbol %d",
- count++);
- if (ok <= 0)
- buf = (char *) "local symbol";
- finfo->info->callbacks->error_handler
- (LD_DEFINITION_IN_DISCARDED_SECTION,
- _("%T: discarded in section `%s' from %s\n"),
- buf, buf, sec->name,
- bfd_archive_filename (input_bfd));
- if (ok != -1)
- free (buf);
- }
}
+ else if (complain)
+ {
+ char *r_sec
+ = bfd_get_section_ident (o);
+ char *d_sec
+ = bfd_get_section_ident (sec);
+ finfo->info->callbacks->error_handler
+ (LD_DEFINITION_IN_DISCARDED_SECTION,
+ _("`%T' referenced in section `%s' of %B: "
+ "defined in discarded section `%s' of %B\n"),
+ sym_name, sym_name,
+ r_sec ? r_sec : o->name, input_bfd,
+ d_sec ? d_sec : sec->name, sec->owner);
+ if (r_sec)
+ free (r_sec);
+ if (d_sec)
+ free (d_sec);
+ }
+
+ /* Remove the symbol reference from the reloc, but
+ don't kill the reloc completely. This is so that
+ a zero value will be written into the section,
+ which may have non-zero contents put there by the
+ assembler. Zero in things like an eh_frame fde
+ pc_begin allows stack unwinders to recognize the
+ fde as bogus. */
+ rel->r_info &= r_type_mask;
+ rel->r_addend = 0;
}
}
}
{
/* I suppose the backend ought to fill in the
section of any STT_SECTION symbol against a
- processor specific section. If we have
- discarded a section, the output_section will
- be the absolute section. */
- if (bfd_is_abs_section (sec)
- || (sec != NULL
- && bfd_is_abs_section (sec->output_section)))
- r_symndx = 0;
+ processor specific section. */
+ r_symndx = 0;
+ if (bfd_is_abs_section (sec))
+ ;
else if (sec == NULL || sec->owner == NULL)
{
bfd_set_error (bfd_error_bad_value);
}
else
{
- r_symndx = sec->output_section->target_index;
- BFD_ASSERT (r_symndx != 0);
+ asection *osec = sec->output_section;
+
+ /* If we have discarded a section, the output
+ section will be the absolute section. In
+ case of discarded link-once and discarded
+ SEC_MERGE sections, use the kept section. */
+ if (bfd_is_abs_section (osec)
+ && sec->kept_section != NULL
+ && sec->kept_section->output_section != NULL)
+ {
+ osec = sec->kept_section->output_section;
+ irela->r_addend -= osec->vma;
+ }
+
+ if (!bfd_is_abs_section (osec))
+ {
+ r_symndx = osec->target_index;
+ BFD_ASSERT (r_symndx != 0);
+ }
}
/* Adjust the addend according to where the
break;
default:
{
- bfd_size_type sec_size;
-
- sec_size = (o->_cooked_size != 0 ? o->_cooked_size : o->_raw_size);
if (! (o->flags & SEC_EXCLUDE)
&& ! bfd_set_section_contents (output_bfd, o->output_section,
contents,
(file_ptr) o->output_offset,
- sec_size))
+ o->size))
return FALSE;
}
break;
return TRUE;
}
+
+/* Get the output vma of the section pointed to by the sh_link field. */
+
+static bfd_vma
+elf_get_linked_section_vma (struct bfd_link_order *p)
+{
+ Elf_Internal_Shdr **elf_shdrp;
+ asection *s;
+ int elfsec;
+
+ s = p->u.indirect.section;
+ elf_shdrp = elf_elfsections (s->owner);
+ elfsec = _bfd_elf_section_from_bfd_section (s->owner, s);
+ elfsec = elf_shdrp[elfsec]->sh_link;
+ s = elf_shdrp[elfsec]->bfd_section;
+ return s->output_section->vma + s->output_offset;
+}
+
+
+/* Compare two sections based on the locations of the sections they are
+ linked to. Used by elf_fixup_link_order. */
+
+static int
+compare_link_order (const void * a, const void * b)
+{
+ bfd_vma apos;
+ bfd_vma bpos;
+
+ apos = elf_get_linked_section_vma (*(struct bfd_link_order **)a);
+ bpos = elf_get_linked_section_vma (*(struct bfd_link_order **)b);
+ if (apos < bpos)
+ return -1;
+ return apos > bpos;
+}
+
+
+/* Looks for sections with SHF_LINK_ORDER set. Rearranges them into the same
+ order as their linked sections. Returns false if this could not be done
+ because an output section includes both ordered and unordered
+ sections. Ideally we'd do this in the linker proper. */
+
+static bfd_boolean
+elf_fixup_link_order (bfd *abfd, asection *o)
+{
+ int seen_linkorder;
+ int seen_other;
+ int n;
+ struct bfd_link_order *p;
+ bfd *sub;
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ int elfsec;
+ struct bfd_link_order **sections;
+ asection *s;
+ bfd_vma offset;
+
+ seen_other = 0;
+ seen_linkorder = 0;
+ for (p = o->link_order_head; p != NULL; p = p->next)
+ {
+ if (p->type == bfd_indirect_link_order
+ && (bfd_get_flavour ((sub = p->u.indirect.section->owner))
+ == bfd_target_elf_flavour)
+ && elf_elfheader (sub)->e_ident[EI_CLASS] == bed->s->elfclass)
+ {
+ s = p->u.indirect.section;
+ elfsec = _bfd_elf_section_from_bfd_section (sub, s);
+ if (elfsec != -1
+ && elf_elfsections (sub)[elfsec]->sh_flags & SHF_LINK_ORDER)
+ seen_linkorder++;
+ else
+ seen_other++;
+ }
+ else
+ seen_other++;
+ }
+
+ if (!seen_linkorder)
+ return TRUE;
+
+ if (seen_other && seen_linkorder)
+ {
+ (*_bfd_error_handler) (_("%s: has both ordered and unordered sections"),
+ o->name);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
+ sections = (struct bfd_link_order **)
+ xmalloc (seen_linkorder * sizeof (struct bfd_link_order *));
+ seen_linkorder = 0;
+
+ for (p = o->link_order_head; p != NULL; p = p->next)
+ {
+ sections[seen_linkorder++] = p;
+ }
+ /* Sort the input sections in the order of their linked section. */
+ qsort (sections, seen_linkorder, sizeof (struct bfd_link_order *),
+ compare_link_order);
+
+ /* Change the offsets of the sections. */
+ offset = 0;
+ for (n = 0; n < seen_linkorder; n++)
+ {
+ s = sections[n]->u.indirect.section;
+ offset &= ~(bfd_vma)((1 << s->alignment_power) - 1);
+ s->output_offset = offset;
+ sections[n]->offset = offset;
+ offset += sections[n]->size;
+ }
+
+ return TRUE;
+}
+
+
/* Do the final step of an ELF link. */
bfd_boolean
free (relocs);
}
- if (sec->_raw_size > max_contents_size)
- max_contents_size = sec->_raw_size;
- if (sec->_cooked_size > max_contents_size)
- max_contents_size = sec->_cooked_size;
+ if (sec->rawsize > max_contents_size)
+ max_contents_size = sec->rawsize;
+ if (sec->size > max_contents_size)
+ max_contents_size = sec->size;
/* We are interested in just local symbols, not all
symbols. */
sec && (sec->flags & SEC_THREAD_LOCAL);
sec = sec->next)
{
- bfd_vma size = sec->_raw_size;
+ bfd_vma size = sec->size;
if (size == 0 && (sec->flags & SEC_HAS_CONTENTS) == 0)
{
elf_hash_table (info)->tls_size = end - base;
}
+ /* Reorder SHF_LINK_ORDER sections. */
+ for (o = abfd->sections; o != NULL; o = o->next)
+ {
+ if (!elf_fixup_link_order (abfd, o))
+ return FALSE;
+ }
+
/* Since ELF permits relocations to be against local symbols, we
must have the local symbols available when we do the relocations.
Since we would rather only read the local symbols once, and we
bfd_byte *dest;
long dynindx;
- indx = elf_section_data (s)->this_idx;
dynindx = elf_section_data (s)->dynindx;
+ if (dynindx <= 0)
+ continue;
+ indx = elf_section_data (s)->this_idx;
BFD_ASSERT (indx > 0);
sym.st_shndx = indx;
sym.st_value = s->vma;
dest = dynsym + dynindx * bed->s->sizeof_sym;
+ if (last_local < dynindx)
+ last_local = dynindx;
bed->s->swap_symbol_out (abfd, &sym, dest, 0);
}
-
- last_local = bfd_count_sections (abfd);
}
/* Write out the local dynsyms. */
BFD_ASSERT (o != NULL);
dyncon = o->contents;
- dynconend = o->contents + o->_raw_size;
+ dynconend = o->contents + o->size;
for (; dyncon < dynconend; dyncon += bed->s->sizeof_dyn)
{
Elf_Internal_Dyn dyn;
bfd_get_filename (abfd), name);
goto error_return;
}
- if (o->_raw_size == 0)
+ if (o->size == 0)
(*_bfd_error_handler)
(_("warning: %s section has zero size"), name);
- dyn.d_un.d_val = o->_raw_size;
+ dyn.d_un.d_val = o->size;
break;
case DT_PREINIT_ARRAY:
for (o = dynobj->sections; o != NULL; o = o->next)
{
if ((o->flags & SEC_HAS_CONTENTS) == 0
- || o->_raw_size == 0
+ || o->size == 0
|| o->output_section == bfd_abs_section_ptr)
continue;
if ((o->flags & SEC_LINKER_CREATED) == 0)
created by _bfd_elf_link_create_dynamic_sections. */
continue;
}
+ if (elf_hash_table (info)->stab_info.stabstr == o)
+ continue;
+ if (elf_hash_table (info)->eh_info.hdr_sec == o)
+ continue;
if ((elf_section_data (o->output_section)->this_hdr.sh_type
!= SHT_STRTAB)
|| strcmp (bfd_get_section_name (abfd, o), ".dynstr") != 0)
if (! bfd_set_section_contents (abfd, o->output_section,
o->contents,
(file_ptr) o->output_offset,
- o->_raw_size))
+ o->size))
goto error_return;
}
else
}
/* If we have optimized stabs strings, output them. */
- if (elf_hash_table (info)->stab_info != NULL)
+ if (elf_hash_table (info)->stab_info.stabstr != NULL)
{
if (! _bfd_write_stab_strings (abfd, &elf_hash_table (info)->stab_info))
goto error_return;
|| ELF_ST_BIND (isym[r_symndx].st_info) != STB_LOCAL)
{
h = sym_hashes[r_symndx - extsymoff];
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
rsec = (*gc_mark_hook) (sec, info, rel, h, NULL);
}
else
return TRUE;
}
+/* Mark sections containing dynamically referenced symbols. This is called
+ through elf_link_hash_traverse. */
+
+static bfd_boolean
+elf_gc_mark_dynamic_ref_symbol (struct elf_link_hash_entry *h,
+ void *okp ATTRIBUTE_UNUSED)
+{
+ if (h->root.type == bfd_link_hash_warning)
+ 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_DYNAMIC))
+ h->root.u.def.section->flags |= SEC_KEEP;
+
+ return TRUE;
+}
+
/* Do mark and sweep of unused sections. */
bfd_boolean
if (!get_elf_backend_data (abfd)->can_gc_sections
|| info->relocatable
|| info->emitrelocations
- || !is_elf_hash_table (info->hash)
- || elf_hash_table (info)->dynamic_sections_created)
+ || info->shared
+ || !is_elf_hash_table (info->hash))
{
(*_bfd_error_handler)(_("Warning: gc-sections option ignored"));
return TRUE;
if (!ok)
return FALSE;
- /* Grovel through relocs to find out who stays ... */
+ /* Mark dynamically referenced symbols. */
+ if (elf_hash_table (info)->dynamic_sections_created)
+ elf_link_hash_traverse (elf_hash_table (info),
+ elf_gc_mark_dynamic_ref_symbol,
+ &ok);
+ if (!ok)
+ return FALSE;
+ /* Grovel through relocs to find out who stays ... */
gc_mark_hook = get_elf_backend_data (abfd)->gc_mark_hook;
for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
{
for (o = sub->sections; o != NULL; o = o->next)
{
if (o->flags & SEC_KEEP)
- if (!elf_gc_mark (info, o, gc_mark_hook))
- return FALSE;
+ {
+ /* _bfd_elf_discard_section_eh_frame knows how to discard
+ orphaned FDEs so don't mark sections referenced by the
+ EH frame section. */
+ if (strcmp (o->name, ".eh_frame") == 0)
+ o->gc_mark = 1;
+ else if (!elf_gc_mark (info, o, gc_mark_hook))
+ return FALSE;
+ }
}
}
struct elf_link_hash_entry **search, *child;
bfd_size_type extsymcount;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ char *sec_name;
/* The sh_info field of the symtab header tells us where the
external symbols start. We don't care about the local symbols at
goto win;
}
+ sec_name = bfd_get_section_ident (sec);
(*_bfd_error_handler) ("%s: %s+%lu: No symbol found for INHERIT",
- bfd_archive_filename (abfd), sec->name,
+ bfd_archive_filename (abfd),
+ sec_name ? sec_name : sec->name,
(unsigned long) offset);
bfd_set_error (bfd_error_invalid_operation);
return FALSE;
eh = bfd_get_section_by_name (abfd, ".eh_frame");
if (info->relocatable
|| (eh != NULL
- && (eh->_raw_size == 0
+ && (eh->size == 0
|| bfd_is_abs_section (eh->output_section))))
eh = NULL;
stab = bfd_get_section_by_name (abfd, ".stab");
if (stab != NULL
- && (stab->_raw_size == 0
+ && (stab->size == 0
|| bfd_is_abs_section (stab->output_section)
|| stab->sec_info_type != ELF_INFO_TYPE_STABS))
stab = NULL;
return ret;
}
+
+struct already_linked_section
+{
+ asection *sec;
+ asection *linked;
+};
+
+/* Check if the member of a single member comdat group matches a
+ linkonce section and vice versa. */
+static bfd_boolean
+try_match_symbols_in_sections
+ (struct bfd_section_already_linked_hash_entry *h, void *info)
+{
+ struct bfd_section_already_linked *l;
+ struct already_linked_section *s
+ = (struct already_linked_section *) info;
+
+ if (elf_sec_group (s->sec) == NULL)
+ {
+ /* It is a linkonce section. Try to match it with the member of a
+ single member comdat group. */
+ for (l = h->entry; l != NULL; l = l->next)
+ if ((l->sec->flags & SEC_GROUP))
+ {
+ asection *first = elf_next_in_group (l->sec);
+
+ if (first != NULL
+ && elf_next_in_group (first) == first
+ && bfd_elf_match_symbols_in_sections (first, s->sec))
+ {
+ s->linked = first;
+ return FALSE;
+ }
+ }
+ }
+ else
+ {
+ /* It is the member of a single member comdat group. Try to match
+ it with a linkonce section. */
+ for (l = h->entry; l != NULL; l = l->next)
+ if ((l->sec->flags & SEC_GROUP) == 0
+ && bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL
+ && bfd_elf_match_symbols_in_sections (l->sec, s->sec))
+ {
+ s->linked = l->sec;
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static bfd_boolean
+already_linked (asection *sec, asection *group)
+{
+ struct already_linked_section result;
+
+ result.sec = sec;
+ result.linked = NULL;
+
+ bfd_section_already_linked_table_traverse
+ (try_match_symbols_in_sections, &result);
+
+ if (result.linked)
+ {
+ sec->output_section = bfd_abs_section_ptr;
+ sec->kept_section = result.linked;
+
+ /* Also discard the group section. */
+ if (group)
+ group->output_section = bfd_abs_section_ptr;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void
+_bfd_elf_section_already_linked (bfd *abfd, struct bfd_section * sec)
+{
+ flagword flags;
+ const char *name;
+ struct bfd_section_already_linked *l;
+ struct bfd_section_already_linked_hash_entry *already_linked_list;
+ asection *group;
+
+ /* A single member comdat group section may be discarded by a
+ linkonce section. See below. */
+ if (sec->output_section == bfd_abs_section_ptr)
+ return;
+
+ flags = sec->flags;
+
+ /* Check if it belongs to a section group. */
+ group = elf_sec_group (sec);
+
+ /* Return if it isn't a linkonce section nor a member of a group. A
+ comdat group section also has SEC_LINK_ONCE set. */
+ if ((flags & SEC_LINK_ONCE) == 0 && group == NULL)
+ return;
+
+ if (group)
+ {
+ /* If this is the member of a single member comdat group, check if
+ the group should be discarded. */
+ if (elf_next_in_group (sec) == sec
+ && (group->flags & SEC_LINK_ONCE) != 0)
+ sec = group;
+ else
+ return;
+ }
+
+ /* FIXME: When doing a relocatable link, we may have trouble
+ copying relocations in other sections that refer to local symbols
+ in the section being discarded. Those relocations will have to
+ be converted somehow; as of this writing I'm not sure that any of
+ the backends handle that correctly.
+
+ It is tempting to instead not discard link once sections when
+ doing a relocatable link (technically, they should be discarded
+ whenever we are building constructors). However, that fails,
+ because the linker winds up combining all the link once sections
+ into a single large link once section, which defeats the purpose
+ of having link once sections in the first place.
+
+ Also, not merging link once sections in a relocatable link
+ causes trouble for MIPS ELF, which relies on link once semantics
+ to handle the .reginfo section correctly. */
+
+ name = bfd_get_section_name (abfd, sec);
+
+ already_linked_list = bfd_section_already_linked_table_lookup (name);
+
+ for (l = already_linked_list->entry; l != NULL; l = l->next)
+ {
+ /* We may have 3 different sections on the list: group section,
+ comdat section and linkonce section. SEC may be a linkonce or
+ group section. We match a group section with a group section,
+ a linkonce section with a linkonce section, and ignore comdat
+ section. */
+ if ((flags & SEC_GROUP) == (l->sec->flags & SEC_GROUP)
+ && bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL)
+ {
+ /* The section has already been linked. See if we should
+ issue a warning. */
+ switch (flags & SEC_LINK_DUPLICATES)
+ {
+ default:
+ abort ();
+
+ case SEC_LINK_DUPLICATES_DISCARD:
+ break;
+
+ case SEC_LINK_DUPLICATES_ONE_ONLY:
+ (*_bfd_error_handler)
+ (_("%s: %s: warning: ignoring duplicate section `%s'\n"),
+ bfd_archive_filename (abfd), name);
+ break;
+
+ case SEC_LINK_DUPLICATES_SAME_SIZE:
+ if (sec->size != l->sec->size)
+ (*_bfd_error_handler)
+ (_("%s: %s: warning: duplicate section `%s' has different size\n"),
+ bfd_archive_filename (abfd), name);
+ break;
+ }
+
+ /* Set the output_section field so that lang_add_section
+ does not create a lang_input_section structure for this
+ section. Since there might be a symbol in the section
+ being discarded, we must retain a pointer to the section
+ which we are really going to use. */
+ sec->output_section = bfd_abs_section_ptr;
+ sec->kept_section = l->sec;
+
+ if (flags & SEC_GROUP)
+ {
+ asection *first = elf_next_in_group (sec);
+ asection *s = first;
+
+ while (s != NULL)
+ {
+ s->output_section = bfd_abs_section_ptr;
+ /* Record which group discards it. */
+ s->kept_section = l->sec;
+ s = elf_next_in_group (s);
+ /* These lists are circular. */
+ if (s == first)
+ break;
+ }
+ }
+
+ return;
+ }
+ }
+
+ if (group)
+ {
+ /* If this is the member of a single member comdat group and the
+ group hasn't be discarded, we check if it matches a linkonce
+ section. We only record the discarded comdat group. Otherwise
+ the undiscarded group will be discarded incorrectly later since
+ itself has been recorded. */
+ if (! already_linked (elf_next_in_group (sec), group))
+ return;
+ }
+ else
+ /* There is no direct match. But for linkonce section, we should
+ check if there is a match with comdat group member. We always
+ record the linkonce section, discarded or not. */
+ already_linked (sec, group);
+
+ /* This is the first section with this name. Record it. */
+ bfd_section_already_linked_table_insert (already_linked_list, sec);
+}