return ((vma - off) % maxpagesize);
}
+/* 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. */
+#define IS_LOADED(FLAGS) \
+ (((FLAGS) & SEC_LOAD) != 0 || ((FLAGS) & SEC_HAS_CONTENTS) != 0)
+
/* Assign file positions to the sections based on the mapping from
sections to segments. This function also sets up some fields in
the file header, and writes out the program 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 (!IS_LOADED (m->sections[i]->flags))
+ {
+ 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)
+ if (IS_LOADED (flags))
{
- 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;
+ if (IS_LOADED (flags))
+ off += sec->size;
+ }
- if ((flags & SEC_LOAD) != 0)
- p->p_filesz += sec->size;
+ if (IS_LOADED (flags))
+ {
+ 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)));