if ((elf_dynverdef (abfd) != 0 && elf_tdata (abfd)->verdef == NULL)
|| (elf_dynverref (abfd) != 0 && elf_tdata (abfd)->verref == NULL))
{
- if (! _bfd_elf_slurp_version_tables (abfd))
+ if (! _bfd_elf_slurp_version_tables (abfd, FALSE))
return FALSE;
}
/* Set local fields. */
ret->indx = -1;
ret->dynindx = -1;
- ret->dynstr_index = 0;
- ret->elf_hash_value = 0;
- ret->weakdef = NULL;
- ret->verinfo.verdef = NULL;
- ret->vtable_entries_size = 0;
- ret->vtable_entries_used = NULL;
- ret->vtable_parent = NULL;
- ret->got = htab->init_refcount;
- ret->plt = htab->init_refcount;
- ret->size = 0;
- ret->type = STT_NOTYPE;
- ret->other = 0;
+ ret->got = ret->plt = htab->init_refcount;
+ memset (&ret->size, 0, (sizeof (struct elf_link_hash_entry)
+ - offsetof (struct elf_link_hash_entry, size)));
/* Assume that we have been called by a non-ELF symbol reader.
This flag is then reset by the code which reads an ELF input
file. This ensures that a symbol created by a non-ELF symbol
reader will have the flag set correctly. */
- ret->ref_regular = 0;
- ret->def_regular = 0;
- ret->ref_dynamic = 0;
- ret->def_dynamic = 0;
- ret->ref_regular_nonweak = 0;
- ret->dynamic_adjusted = 0;
- ret->needs_copy = 0;
- ret->needs_plt = 0;
ret->non_elf = 1;
- ret->hidden = 0;
- ret->forced_local = 0;
- ret->mark = 0;
- ret->non_got_ref = 0;
- ret->dynamic_def = 0;
- ret->dynamic_weak = 0;
- ret->pointer_equality_needed = 0;
}
return entry;
case SHT_INIT_ARRAY: /* .init_array section. */
case SHT_FINI_ARRAY: /* .fini_array section. */
case SHT_PREINIT_ARRAY: /* .preinit_array section. */
+ case SHT_GNU_LIBLIST: /* .gnu.liblist section. */
return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
case SHT_DYNAMIC: /* Dynamic linking information. */
{ ".rela", 5, -1, SHT_RELA, 0 },
{ ".rel", 4, -1, SHT_REL, 0 },
{ ".stabstr", 5, 3, SHT_STRTAB, 0 },
+ { ".gnu.liblist", 12, 0, SHT_GNU_LIBLIST, SHF_ALLOC },
+ { ".gnu.conflict", 13, 0, SHT_RELA, SHF_ALLOC },
{ NULL, 0, 0, 0, 0 }
};
d->this_hdr.sh_link = elf_section_data (s)->this_idx;
break;
+ case SHT_GNU_LIBLIST:
+ /* sh_link is the section header index of the prelink library
+ list
+ used for the dynamic entries, or the symbol table, or the
+ version strings. */
+ s = bfd_get_section_by_name (abfd, (sec->flags & SEC_ALLOC)
+ ? ".dynstr" : ".gnu.libstr");
+ if (s != NULL)
+ d->this_hdr.sh_link = elf_section_data (s)->this_idx;
+ break;
+
case SHT_HASH:
case SHT_GNU_versym:
/* sh_link is the section header index of the symbol table
elf_elfheader (abfd)->e_phnum = count;
if (count == 0)
- return TRUE;
+ {
+ elf_tdata (abfd)->next_file_pos = bed->s->sizeof_ehdr;
+ return TRUE;
+ }
/* If we already counted the number of program segments, make sure
that we allocated enough space. This happens when SIZEOF_HEADERS
if (alloc != 0 && count > alloc)
{
((*_bfd_error_handler)
- (_("%s: Not enough room for program headers (allocated %u, need %u)"),
- bfd_get_filename (abfd), alloc, count));
+ (_("%B: Not enough room for program headers (allocated %u, need %u)"),
+ abfd, alloc, count));
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
qsort (m->sections, (size_t) m->count, sizeof (asection *),
elf_sort_sections);
+ /* An ELF segment (described by Elf_Internal_Phdr) may contain a
+ number of sections with contents contributing to both p_filesz
+ and p_memsz, followed by a number of sections with no contents
+ that just contribute to p_memsz. In this loop, OFF tracks next
+ available file offset for PT_LOAD and PT_NOTE segments. VOFF is
+ an adjustment we use for segments that have no file contents
+ but need zero filled memory allocation. */
+ voff = 0;
p->p_type = m->p_type;
p->p_flags = m->p_flags;
if (p->p_type == PT_LOAD
- && m->count > 0
- && (m->sections[0]->flags & SEC_ALLOC) != 0)
+ && m->count > 0)
{
+ bfd_size_type align;
+ bfd_vma adjust;
+
if ((abfd->flags & D_PAGED) != 0)
- off += vma_page_aligned_bias (m->sections[0]->vma, off,
- bed->maxpagesize);
+ align = bed->maxpagesize;
else
{
- bfd_size_type align;
-
- align = 0;
+ unsigned int align_power = 0;
for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
{
- bfd_size_type secalign;
+ unsigned int secalign;
secalign = bfd_get_section_alignment (abfd, *secpp);
- if (secalign > align)
- align = secalign;
+ if (secalign > align_power)
+ align_power = secalign;
}
+ align = (bfd_size_type) 1 << align_power;
+ }
- off += vma_page_aligned_bias (m->sections[0]->vma, off,
- 1 << align);
+ adjust = vma_page_aligned_bias (m->sections[0]->vma, off, align);
+ off += adjust;
+ if (adjust != 0
+ && !m->includes_filehdr
+ && !m->includes_phdrs
+ && (ufile_ptr) off >= align)
+ {
+ /* If the first section isn't loadable, the same holds for
+ any other sections. Since the segment won't need file
+ space, we can make p_offset overlap some prior segment.
+ However, .tbss is special. If a segment starts with
+ .tbss, we need to look at the next section to decide
+ whether the segment has any loadable sections. */
+ i = 0;
+ while ((m->sections[i]->flags & SEC_LOAD) == 0)
+ {
+ if ((m->sections[i]->flags & SEC_THREAD_LOCAL) == 0
+ || ++i >= m->count)
+ {
+ off -= adjust;
+ voff = adjust - align;
+ break;
+ }
+ }
}
}
/* Make sure the .dynamic section is the first section in the
&& strcmp (m->sections[0]->name, ".dynamic") != 0)
{
_bfd_error_handler
- (_("%s: The first section in the PT_DYNAMIC segment is not the .dynamic section"),
- bfd_get_filename (abfd));
+ (_("%B: The first section in the PT_DYNAMIC segment is not the .dynamic section"),
+ abfd);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
if (p->p_vaddr < (bfd_vma) off)
{
(*_bfd_error_handler)
- (_("%s: Not enough room for program headers, try linking with -N"),
- bfd_get_filename (abfd));
+ (_("%B: Not enough room for program headers, try linking with -N"),
+ abfd);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
|| (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core))
{
if (! m->includes_filehdr && ! m->includes_phdrs)
- p->p_offset = off;
+ p->p_offset = off + voff;
else
{
file_ptr adjust;
}
}
- voff = off;
-
for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
{
asection *sec;
flags = sec->flags;
align = 1 << bfd_get_section_alignment (abfd, sec);
- /* The section may have artificial alignment forced by a
- link script. Notice this case by the gap between the
- cumulative phdr lma and the section's lma. */
- if (p->p_paddr + p->p_memsz < sec->lma)
- {
- bfd_vma adjust = sec->lma - (p->p_paddr + p->p_memsz);
-
- p->p_memsz += adjust;
- if (p->p_type == PT_LOAD
- || (p->p_type == PT_NOTE
- && bfd_get_format (abfd) == bfd_core))
- {
- off += adjust;
- voff += adjust;
- }
- if ((flags & SEC_LOAD) != 0
- || (flags & SEC_THREAD_LOCAL) != 0)
- p->p_filesz += adjust;
- }
-
- if (p->p_type == PT_LOAD)
+ if (p->p_type == PT_LOAD
+ || p->p_type == PT_TLS)
{
bfd_signed_vma adjust;
if ((flags & SEC_LOAD) != 0)
{
- adjust = sec->lma - (p->p_paddr + p->p_memsz);
+ adjust = sec->lma - (p->p_paddr + p->p_filesz);
if (adjust < 0)
- adjust = 0;
+ {
+ (*_bfd_error_handler)
+ (_("%B: section %A lma 0x%lx overlaps previous sections"),
+ abfd, sec, (unsigned long) sec->lma);
+ adjust = 0;
+ }
+ off += adjust;
+ p->p_filesz += adjust;
+ p->p_memsz += adjust;
}
- else if ((flags & SEC_ALLOC) != 0)
+ /* .tbss is special. It doesn't contribute to p_memsz of
+ normal segments. */
+ else if ((flags & SEC_THREAD_LOCAL) == 0
+ || p->p_type == PT_TLS)
{
/* The section VMA must equal the file position
- modulo the page size. FIXME: I'm not sure if
- this adjustment is really necessary. We used to
- not have the SEC_LOAD case just above, and then
- this was necessary, but now I'm not sure. */
+ modulo the page size. */
+ bfd_size_type page = align;
if ((abfd->flags & D_PAGED) != 0)
- adjust = vma_page_aligned_bias (sec->vma, voff,
- bed->maxpagesize);
- else
- adjust = vma_page_aligned_bias (sec->vma, voff,
- align);
- }
- else
- adjust = 0;
-
- if (adjust != 0)
- {
- if (i == 0)
- {
- (* _bfd_error_handler) (_("\
-Error: First section in segment (%s) starts at 0x%x whereas the segment starts at 0x%x"),
- bfd_section_name (abfd, sec),
- sec->lma,
- p->p_paddr);
- return FALSE;
- }
+ page = bed->maxpagesize;
+ adjust = vma_page_aligned_bias (sec->vma,
+ p->p_vaddr + p->p_memsz,
+ page);
p->p_memsz += adjust;
- off += adjust;
- voff += adjust;
- if ((flags & SEC_LOAD) != 0)
- p->p_filesz += adjust;
}
-
- sec->filepos = off;
-
- /* We check SEC_HAS_CONTENTS here because if NOLOAD is
- used in a linker script we may have a section with
- SEC_LOAD clear but which is supposed to have
- contents. */
- if ((flags & SEC_LOAD) != 0
- || (flags & SEC_HAS_CONTENTS) != 0)
- off += sec->size;
-
- if ((flags & SEC_ALLOC) != 0
- && ((flags & SEC_LOAD) != 0
- || (flags & SEC_THREAD_LOCAL) == 0))
- voff += sec->size;
}
if (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core)
{
- /* The actual "note" segment has i == 0.
- This is the one that actually contains everything. */
+ /* The section at i == 0 is the one that actually contains
+ everything. */
if (i == 0)
{
sec->filepos = off;
- p->p_filesz = sec->size;
off += sec->size;
- voff = off;
+ p->p_filesz = sec->size;
+ p->p_memsz = 0;
+ p->p_align = 1;
}
else
{
- /* Fake sections -- don't need to be written. */
+ /* The rest are fake sections that shouldn't be written. */
sec->filepos = 0;
sec->size = 0;
- flags = sec->flags = 0;
+ sec->flags = 0;
+ continue;
}
- p->p_memsz = 0;
- p->p_align = 1;
}
else
{
- if ((sec->flags & SEC_LOAD) != 0
- || (sec->flags & SEC_THREAD_LOCAL) == 0
- || p->p_type == PT_TLS)
- p->p_memsz += sec->size;
+ if (p->p_type == PT_LOAD)
+ {
+ sec->filepos = off;
+ /* FIXME: The SEC_HAS_CONTENTS test here dates back to
+ 1997, and the exact reason for it isn't clear. One
+ plausible explanation is that it is to work around
+ a problem we have with linker scripts using data
+ statements in NOLOAD sections. I don't think it
+ makes a great deal of sense to have such a section
+ assigned to a PT_LOAD segment, but apparently
+ people do this. The data statement results in a
+ bfd_data_link_order being built, and these need
+ section contents to write into. Eventually, we get
+ to _bfd_elf_write_object_contents which writes any
+ section with contents to the output. Make room
+ here for the write, so that following segments are
+ not trashed. */
+ if ((flags & SEC_LOAD) != 0
+ || (flags & SEC_HAS_CONTENTS) != 0)
+ off += sec->size;
+ }
if ((flags & SEC_LOAD) != 0)
- p->p_filesz += sec->size;
+ {
+ p->p_filesz += sec->size;
+ p->p_memsz += sec->size;
+ }
+ /* .tbss is special. It doesn't contribute to p_memsz of
+ normal segments. */
+ else if ((flags & SEC_THREAD_LOCAL) == 0
+ || p->p_type == PT_TLS)
+ p->p_memsz += sec->size;
if (p->p_type == PT_TLS
&& sec->size == 0
else if ((hdr->sh_flags & SHF_ALLOC) != 0)
{
((*_bfd_error_handler)
- (_("%s: warning: allocated section `%s' not in segment"),
- bfd_get_filename (abfd),
+ (_("%B: warning: allocated section `%s' not in segment"),
+ abfd,
(hdr->bfd_section == NULL
? "*unknown*"
: hdr->bfd_section->name)));
/* Read in the version information. */
bfd_boolean
-_bfd_elf_slurp_version_tables (bfd *abfd)
+_bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver)
{
bfd_byte *contents = NULL;
bfd_size_type amt;
+ unsigned int freeidx = 0;
+
+ if (elf_dynverref (abfd) != 0)
+ {
+ Elf_Internal_Shdr *hdr;
+ Elf_External_Verneed *everneed;
+ Elf_Internal_Verneed *iverneed;
+ unsigned int i;
+
+ hdr = &elf_tdata (abfd)->dynverref_hdr;
+
+ amt = (bfd_size_type) hdr->sh_info * sizeof (Elf_Internal_Verneed);
+ elf_tdata (abfd)->verref = bfd_zalloc (abfd, amt);
+ if (elf_tdata (abfd)->verref == NULL)
+ goto error_return;
+
+ elf_tdata (abfd)->cverrefs = hdr->sh_info;
+
+ contents = bfd_malloc (hdr->sh_size);
+ if (contents == NULL)
+ goto error_return;
+ if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
+ || bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size)
+ goto error_return;
+
+ everneed = (Elf_External_Verneed *) contents;
+ iverneed = elf_tdata (abfd)->verref;
+ for (i = 0; i < hdr->sh_info; i++, iverneed++)
+ {
+ Elf_External_Vernaux *evernaux;
+ Elf_Internal_Vernaux *ivernaux;
+ unsigned int j;
+
+ _bfd_elf_swap_verneed_in (abfd, everneed, iverneed);
+
+ iverneed->vn_bfd = abfd;
+
+ iverneed->vn_filename =
+ bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
+ iverneed->vn_file);
+ if (iverneed->vn_filename == NULL)
+ goto error_return;
+
+ amt = iverneed->vn_cnt;
+ amt *= sizeof (Elf_Internal_Vernaux);
+ iverneed->vn_auxptr = bfd_alloc (abfd, amt);
+
+ evernaux = ((Elf_External_Vernaux *)
+ ((bfd_byte *) everneed + iverneed->vn_aux));
+ ivernaux = iverneed->vn_auxptr;
+ for (j = 0; j < iverneed->vn_cnt; j++, ivernaux++)
+ {
+ _bfd_elf_swap_vernaux_in (abfd, evernaux, ivernaux);
+
+ ivernaux->vna_nodename =
+ bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
+ ivernaux->vna_name);
+ if (ivernaux->vna_nodename == NULL)
+ goto error_return;
+
+ if (j + 1 < iverneed->vn_cnt)
+ ivernaux->vna_nextptr = ivernaux + 1;
+ else
+ ivernaux->vna_nextptr = NULL;
+
+ evernaux = ((Elf_External_Vernaux *)
+ ((bfd_byte *) evernaux + ivernaux->vna_next));
+
+ if (ivernaux->vna_other > freeidx)
+ freeidx = ivernaux->vna_other;
+ }
+
+ if (i + 1 < hdr->sh_info)
+ iverneed->vn_nextref = iverneed + 1;
+ else
+ iverneed->vn_nextref = NULL;
+
+ everneed = ((Elf_External_Verneed *)
+ ((bfd_byte *) everneed + iverneed->vn_next));
+ }
+
+ free (contents);
+ contents = NULL;
+ }
if (elf_dynverdef (abfd) != 0)
{
((bfd_byte *) everdef + iverdefmem.vd_next));
}
+ if (default_imported_symver)
+ {
+ if (freeidx > maxidx)
+ maxidx = ++freeidx;
+ else
+ freeidx = ++maxidx;
+ }
amt = (bfd_size_type) maxidx * sizeof (Elf_Internal_Verdef);
elf_tdata (abfd)->verdef = bfd_zalloc (abfd, amt);
if (elf_tdata (abfd)->verdef == NULL)
free (contents);
contents = NULL;
}
-
- if (elf_dynverref (abfd) != 0)
+ else if (default_imported_symver)
{
- Elf_Internal_Shdr *hdr;
- Elf_External_Verneed *everneed;
- Elf_Internal_Verneed *iverneed;
- unsigned int i;
-
- hdr = &elf_tdata (abfd)->dynverref_hdr;
-
- amt = (bfd_size_type) hdr->sh_info * sizeof (Elf_Internal_Verneed);
- elf_tdata (abfd)->verref = bfd_zalloc (abfd, amt);
- if (elf_tdata (abfd)->verref == NULL)
- goto error_return;
-
- elf_tdata (abfd)->cverrefs = hdr->sh_info;
+ if (freeidx < 3)
+ freeidx = 3;
+ else
+ freeidx++;
- contents = bfd_malloc (hdr->sh_size);
- if (contents == NULL)
- goto error_return;
- if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
- || bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size)
+ amt = (bfd_size_type) freeidx * sizeof (Elf_Internal_Verdef);
+ elf_tdata (abfd)->verdef = bfd_zalloc (abfd, amt);
+ if (elf_tdata (abfd)->verdef == NULL)
goto error_return;
- everneed = (Elf_External_Verneed *) contents;
- iverneed = elf_tdata (abfd)->verref;
- for (i = 0; i < hdr->sh_info; i++, iverneed++)
- {
- Elf_External_Vernaux *evernaux;
- Elf_Internal_Vernaux *ivernaux;
- unsigned int j;
-
- _bfd_elf_swap_verneed_in (abfd, everneed, iverneed);
-
- iverneed->vn_bfd = abfd;
-
- iverneed->vn_filename =
- bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
- iverneed->vn_file);
- if (iverneed->vn_filename == NULL)
- goto error_return;
-
- amt = iverneed->vn_cnt;
- amt *= sizeof (Elf_Internal_Vernaux);
- iverneed->vn_auxptr = bfd_alloc (abfd, amt);
-
- evernaux = ((Elf_External_Vernaux *)
- ((bfd_byte *) everneed + iverneed->vn_aux));
- ivernaux = iverneed->vn_auxptr;
- for (j = 0; j < iverneed->vn_cnt; j++, ivernaux++)
- {
- _bfd_elf_swap_vernaux_in (abfd, evernaux, ivernaux);
+ elf_tdata (abfd)->cverdefs = freeidx;
+ }
- ivernaux->vna_nodename =
- bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
- ivernaux->vna_name);
- if (ivernaux->vna_nodename == NULL)
- goto error_return;
+ /* Create a default version based on the soname. */
+ if (default_imported_symver)
+ {
+ Elf_Internal_Verdef *iverdef;
+ Elf_Internal_Verdaux *iverdaux;
- if (j + 1 < iverneed->vn_cnt)
- ivernaux->vna_nextptr = ivernaux + 1;
- else
- ivernaux->vna_nextptr = NULL;
+ iverdef = &elf_tdata (abfd)->verdef[freeidx - 1];;
- evernaux = ((Elf_External_Vernaux *)
- ((bfd_byte *) evernaux + ivernaux->vna_next));
- }
+ iverdef->vd_version = VER_DEF_CURRENT;
+ iverdef->vd_flags = 0;
+ iverdef->vd_ndx = freeidx;
+ iverdef->vd_cnt = 1;
- if (i + 1 < hdr->sh_info)
- iverneed->vn_nextref = iverneed + 1;
- else
- iverneed->vn_nextref = NULL;
+ iverdef->vd_bfd = abfd;
- everneed = ((Elf_External_Verneed *)
- ((bfd_byte *) everneed + iverneed->vn_next));
- }
+ iverdef->vd_nodename = bfd_elf_get_dt_soname (abfd);
+ if (iverdef->vd_nodename == NULL)
+ goto error_return;
+ iverdef->vd_nextdef = NULL;
+ amt = (bfd_size_type) sizeof (Elf_Internal_Verdaux);
+ iverdef->vd_auxptr = bfd_alloc (abfd, amt);
- free (contents);
- contents = NULL;
+ iverdaux = iverdef->vd_auxptr;
+ iverdaux->vda_nodename = iverdef->vd_nodename;
+ iverdaux->vda_nextptr = NULL;
}
return TRUE;
q = (elf_symbol_type *) *p;
- if (bfd_get_section (&q->symbol) != section)
- continue;
-
switch (ELF_ST_TYPE (q->internal_elf_sym.st_info))
{
default:
break;
case STT_NOTYPE:
case STT_FUNC:
- if (q->symbol.section == section
+ if (bfd_get_section (&q->symbol) == section
&& q->symbol.value >= low_func
&& q->symbol.value <= offset)
{
bfd_vma
_bfd_elf_section_offset (bfd *abfd,
- struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info,
asection *sec,
bfd_vma offset)
{
return _bfd_stab_section_offset (sec, elf_section_data (sec)->sec_info,
offset);
case ELF_INFO_TYPE_EH_FRAME:
- return _bfd_elf_eh_frame_section_offset (abfd, sec, offset);
+ return _bfd_elf_eh_frame_section_offset (abfd, info, sec, offset);
default:
return offset;
}