aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf.c
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@airs.com>1995-11-28 22:02:13 +0000
committerIan Lance Taylor <ian@airs.com>1995-11-28 22:02:13 +0000
commitfd0198f02371c0d604ec7c3162cf60a0a84c0ef0 (patch)
tree7f92823e70416a077c31b4db5ce30fa9cee0084f /bfd/elf.c
parent6d2d98d31340d6a5e8eca291a70c59d507a8125e (diff)
downloadgdb-fd0198f02371c0d604ec7c3162cf60a0a84c0ef0.zip
gdb-fd0198f02371c0d604ec7c3162cf60a0a84c0ef0.tar.gz
gdb-fd0198f02371c0d604ec7c3162cf60a0a84c0ef0.tar.bz2
* elf-bfd.h (struct elf_obj_tdata): Add segment_map field.
* elf.c (make_mapping): New static function. (map_sections_to_segments): New static function. (elf_sort_sections): New static function. (assign_file_positions_for_segments): New static function. (map_program_segments): Remove. (get_program_header_size): Remove sorted_hdrs, count, and maxpagesize parameters. Simplify. (assign_file_positions_except_relocs): When generating an executable, use assign_file_positions_for_segments. (elf_sort_hdrs): Remove. (_bfd_elf_sizeof_headers): Remove eliminated parameters from call to get_program_header_size.
Diffstat (limited to 'bfd/elf.c')
-rw-r--r--bfd/elf.c1214
1 files changed, 698 insertions, 516 deletions
diff --git a/bfd/elf.c b/bfd/elf.c
index 95245f5..083f8d2 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -38,11 +38,11 @@ SECTION
#define ARCH_SIZE 0
#include "elf-bfd.h"
-static file_ptr map_program_segments PARAMS ((bfd *, file_ptr,
- Elf_Internal_Shdr *,
- Elf_Internal_Shdr **,
- bfd_size_type));
-static boolean assign_file_positions_except_relocs PARAMS ((bfd *, boolean));
+static INLINE struct elf_segment_map *make_mapping
+ PARAMS ((bfd *, asection **, unsigned int, unsigned int));
+static int elf_sort_sections PARAMS ((const PTR, const PTR));
+static boolean assign_file_positions_for_segments PARAMS ((bfd *));
+static boolean assign_file_positions_except_relocs PARAMS ((bfd *));
static boolean prep_headers PARAMS ((bfd *));
static boolean swap_out_syms PARAMS ((bfd *, struct bfd_strtab_hash **));
@@ -219,6 +219,26 @@ _bfd_elf_make_section_from_shdr (abfd, hdr, name)
if (! bfd_set_section_flags (abfd, newsect, flags))
return false;
+ if ((flags & SEC_ALLOC) != 0)
+ {
+ Elf_Internal_Phdr *phdr;
+ unsigned int i;
+
+ /* Look through the phdrs to see if we need to adjust the lma. */
+ phdr = elf_tdata (abfd)->phdr;
+ for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
+ {
+ if (phdr->p_type == PT_LOAD
+ && phdr->p_vaddr != phdr->p_paddr
+ && phdr->p_vaddr <= hdr->sh_addr
+ && phdr->p_vaddr + phdr->p_memsz >= hdr->sh_addr + hdr->sh_size)
+ {
+ newsect->lma += phdr->p_paddr - phdr->p_vaddr;
+ break;
+ }
+ }
+ }
+
hdr->bfd_section = newsect;
elf_section_data (newsect)->this_hdr = *hdr;
@@ -521,7 +541,7 @@ bfd_section_from_shdr (abfd, shindex)
BFD_ASSERT (elf_onesymtab (abfd) == 0);
elf_onesymtab (abfd) = shindex;
elf_tdata (abfd)->symtab_hdr = *hdr;
- elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->symtab_hdr;
+ elf_elfsections (abfd)[shindex] = hdr = &elf_tdata (abfd)->symtab_hdr;
abfd->flags |= HAS_SYMS;
/* Sometimes a shared object will map in the symbol table. If
@@ -545,7 +565,7 @@ bfd_section_from_shdr (abfd, shindex)
BFD_ASSERT (elf_dynsymtab (abfd) == 0);
elf_dynsymtab (abfd) = shindex;
elf_tdata (abfd)->dynsymtab_hdr = *hdr;
- elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->dynsymtab_hdr;
+ elf_elfsections (abfd)[shindex] = hdr = &elf_tdata (abfd)->dynsymtab_hdr;
abfd->flags |= HAS_SYMS;
/* Besides being a symbol table, we also treat this as a regular
@@ -581,7 +601,7 @@ bfd_section_from_shdr (abfd, shindex)
if (elf_dynsymtab (abfd) == i)
{
elf_tdata (abfd)->dynstrtab_hdr = *hdr;
- elf_elfsections (abfd)[shindex] =
+ elf_elfsections (abfd)[shindex] = hdr =
&elf_tdata (abfd)->dynstrtab_hdr;
/* We also treat this as a regular section, so
that objcopy can handle it. */
@@ -867,27 +887,17 @@ elf_fake_sections (abfd, asect, failedptrarg)
this_hdr->sh_flags = 0;
- /* FIXME: This should really use vma, rather than lma. However,
- that would mean that the lma information was lost, which would
- mean that the AT keyword in linker scripts would not work.
- Fortunately, native scripts do not use the AT keyword, so we can
- get away with using lma here. The right way to handle this is to
- 1) read the program headers as well as the section headers, and
- set the lma fields of the BFD sections based on the p_paddr
- fields of the program headers, and 2) set the p_paddr fields of
- the program headers based on the section lma fields when writing
- them out. */
if ((asect->flags & SEC_ALLOC) != 0)
- this_hdr->sh_addr = asect->lma;
+ this_hdr->sh_addr = asect->vma;
else
this_hdr->sh_addr = 0;
this_hdr->sh_offset = 0;
this_hdr->sh_size = asect->_raw_size;
this_hdr->sh_link = 0;
- this_hdr->sh_info = 0;
this_hdr->sh_addralign = 1 << asect->alignment_power;
- this_hdr->sh_entsize = 0;
+ /* The sh_entsize and sh_info fields may have been set already by
+ copy_private_section_data. */
this_hdr->bfd_section = asect;
this_hdr->contents = NULL;
@@ -1220,7 +1230,7 @@ elf_map_symbols (abfd)
for (idx = 0; idx < symcount; idx++)
{
if ((syms[idx]->flags & BSF_SECTION_SYM) != 0
- && syms[idx]->value == 0)
+ && (syms[idx]->value + syms[idx]->section->vma) == 0)
{
asection *sec;
@@ -1333,6 +1343,43 @@ elf_map_symbols (abfd)
return true;
}
+/* Align to the maximum file alignment that could be required for any
+ ELF data structure. */
+
+static INLINE file_ptr align_file_position PARAMS ((file_ptr, int));
+static INLINE file_ptr
+align_file_position (off, align)
+ file_ptr off;
+ int align;
+{
+ return (off + align - 1) & ~(align - 1);
+}
+
+/* Assign a file position to a section, optionally aligning to the
+ required section alignment. */
+
+INLINE file_ptr
+_bfd_elf_assign_file_position_for_section (i_shdrp, offset, align)
+ Elf_Internal_Shdr *i_shdrp;
+ file_ptr offset;
+ boolean align;
+{
+ if (align)
+ {
+ unsigned int al;
+
+ al = i_shdrp->sh_addralign;
+ if (al > 1)
+ offset = BFD_ALIGN (offset, al);
+ }
+ i_shdrp->sh_offset = offset;
+ if (i_shdrp->bfd_section != NULL)
+ i_shdrp->bfd_section->filepos = offset;
+ if (i_shdrp->sh_type != SHT_NOBITS)
+ offset += i_shdrp->sh_size;
+ return offset;
+}
+
/* Compute the file positions we are going to put the sections at, and
otherwise prepare to begin writing out the ELF file. If LINK_INFO
is not NULL, this is being called by the ELF backend linker. */
@@ -1366,7 +1413,7 @@ _bfd_elf_compute_section_file_positions (abfd, link_info)
return false;
/* The backend linker builds symbol table information itself. */
- if (link_info == NULL)
+ if (link_info == NULL && abfd->symcount > 0)
{
if (! swap_out_syms (abfd, &strtab))
return false;
@@ -1381,19 +1428,30 @@ _bfd_elf_compute_section_file_positions (abfd, link_info)
shstrtab_hdr->sh_entsize = 0;
shstrtab_hdr->sh_link = 0;
shstrtab_hdr->sh_info = 0;
- /* sh_offset is set in assign_file_positions_for_symtabs_and_strtabs. */
+ /* sh_offset is set in assign_file_positions_except_relocs. */
shstrtab_hdr->sh_addralign = 1;
- if (!assign_file_positions_except_relocs (abfd,
- link_info == NULL ? true : false))
+ if (!assign_file_positions_except_relocs (abfd))
return false;
- if (link_info == NULL)
+ if (link_info == NULL && abfd->symcount > 0)
{
+ file_ptr off;
+ Elf_Internal_Shdr *hdr;
+
+ off = elf_tdata (abfd)->next_file_pos;
+
+ hdr = &elf_tdata (abfd)->symtab_hdr;
+ off = _bfd_elf_assign_file_position_for_section (hdr, off, true);
+
+ hdr = &elf_tdata (abfd)->strtab_hdr;
+ off = _bfd_elf_assign_file_position_for_section (hdr, off, true);
+
+ elf_tdata (abfd)->next_file_pos = off;
+
/* Now that we know where the .strtab section goes, write it
out. */
- if ((bfd_seek (abfd, elf_tdata (abfd)->strtab_hdr.sh_offset, SEEK_SET)
- != 0)
+ if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
|| ! _bfd_stringtab_emit (abfd, strtab))
return false;
_bfd_stringtab_free (strtab);
@@ -1404,428 +1462,542 @@ _bfd_elf_compute_section_file_positions (abfd, link_info)
return true;
}
+/* Create a mapping from a set of sections to a program segment. */
-/* Align to the maximum file alignment that could be required for any
- ELF data structure. */
-
-static INLINE file_ptr align_file_position PARAMS ((file_ptr, int));
-static INLINE file_ptr
-align_file_position (off, align)
- file_ptr off;
- int align;
+static INLINE struct elf_segment_map *
+make_mapping (abfd, sections, from, to)
+ bfd *abfd;
+ asection **sections;
+ unsigned int from;
+ unsigned int to;
{
- return (off + align - 1) & ~(align - 1);
+ struct elf_segment_map *m;
+ unsigned int i;
+ asection **hdrpp;
+
+ m = ((struct elf_segment_map *)
+ bfd_zalloc (abfd,
+ (sizeof (struct elf_segment_map)
+ + (to - from - 1) * sizeof (asection *))));
+ if (m == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+ m->next = NULL;
+ m->p_type = PT_LOAD;
+ for (i = from, hdrpp = sections + from; i < to; i++, hdrpp++)
+ m->sections[i - from] = *hdrpp;
+ m->count = to - from;
+
+ return m;
}
-/* Assign a file position to a section, optionally aligning to the
- required section alignment. */
+/* Set up a mapping from BFD sections to program segments. */
-INLINE file_ptr
-_bfd_elf_assign_file_position_for_section (i_shdrp, offset, align)
- Elf_Internal_Shdr *i_shdrp;
- file_ptr offset;
- boolean align;
+static boolean
+map_sections_to_segments (abfd)
+ bfd *abfd;
{
- if (align)
+ asection **sections = NULL;
+ asection *s;
+ unsigned int i;
+ unsigned int count;
+ struct elf_segment_map *mfirst;
+ struct elf_segment_map **pm;
+ struct elf_segment_map *m;
+ asection *last_hdr;
+ unsigned int phdr_index;
+ bfd_vma maxpagesize;
+ asection **hdrpp;
+
+ if (elf_tdata (abfd)->segment_map != NULL)
+ return true;
+
+ if (bfd_count_sections (abfd) == 0)
+ return true;
+
+ /* Select the allocated sections, and sort them. */
+
+ sections = (asection **) malloc (bfd_count_sections (abfd)
+ * sizeof (asection *));
+ if (sections == NULL)
{
- unsigned int al;
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
- al = i_shdrp->sh_addralign;
- if (al > 1)
- offset = BFD_ALIGN (offset, al);
+ i = 0;
+ for (s = abfd->sections; s != NULL; s = s->next)
+ {
+ if ((s->flags & SEC_ALLOC) != 0)
+ {
+ sections[i] = s;
+ ++i;
+ }
}
- i_shdrp->sh_offset = offset;
- if (i_shdrp->bfd_section != NULL)
- i_shdrp->bfd_section->filepos = offset;
- if (i_shdrp->sh_type != SHT_NOBITS)
- offset += i_shdrp->sh_size;
- return offset;
-}
+ BFD_ASSERT (i <= bfd_count_sections (abfd));
+ count = i;
-/* Get the size of the program header.
+ qsort (sections, (size_t) count, sizeof (asection *), elf_sort_sections);
- SORTED_HDRS, if non-NULL, is an array of COUNT pointers to headers sorted
- by VMA. Non-allocated sections (!SHF_ALLOC) must appear last. All
- section VMAs and sizes are known so we can compute the correct value.
- (??? This may not be perfectly true. What cases do we miss?)
+ /* Build the mapping. */
- If SORTED_HDRS is NULL we assume there are two segments: text and data
- (exclusive of .interp and .dynamic).
+ mfirst = NULL;
+ pm = &mfirst;
- If this is called by the linker before any of the section VMA's are set, it
- can't calculate the correct value for a strange memory layout. This only
- happens when SIZEOF_HEADERS is used in a linker script. In this case,
- SORTED_HDRS is NULL and we assume the normal scenario of one text and one
- data segment (exclusive of .interp and .dynamic).
+ /* If we have a .interp section, then create a PT_PHDR segment for
+ the program headers and a PT_INTERP segment for the .interp
+ section. */
+ s = bfd_get_section_by_name (abfd, ".interp");
+ if (s != NULL && (s->flags & SEC_LOAD) != 0)
+ {
+ m = ((struct elf_segment_map *)
+ bfd_zalloc (abfd, sizeof (struct elf_segment_map)));
+ if (m == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+ m->next = NULL;
+ m->p_type = PT_PHDR;
+ /* FIXME: UnixWare and Solaris set PF_X, Irix 5 does not. */
+ m->p_flags = PF_R | PF_X;
+ m->p_flags_valid = 1;
- ??? User written scripts must either not use SIZEOF_HEADERS, or assume there
- will be two segments. */
+ *pm = m;
+ pm = &m->next;
-static bfd_size_type
-get_program_header_size (abfd, sorted_hdrs, count, maxpagesize)
- bfd *abfd;
- Elf_Internal_Shdr **sorted_hdrs;
- unsigned int count;
- bfd_vma maxpagesize;
-{
- size_t segs;
- asection *s;
- struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ m = ((struct elf_segment_map *)
+ bfd_zalloc (abfd, sizeof (struct elf_segment_map)));
+ if (m == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+ m->next = NULL;
+ m->p_type = PT_INTERP;
+ m->count = 1;
+ m->sections[0] = s;
- /* We can't return a different result each time we're called. */
- if (elf_tdata (abfd)->program_header_size != 0)
- return elf_tdata (abfd)->program_header_size;
+ *pm = m;
+ pm = &m->next;
+ }
- if (sorted_hdrs != NULL)
+ /* Look through the sections. We put sections in the same program
+ segment when the start of the second section can be placed within
+ a few bytes of the end of the first section. */
+ last_hdr = NULL;
+ phdr_index = 0;
+ maxpagesize = get_elf_backend_data (abfd)->maxpagesize;
+ for (i = 0, hdrpp = sections; i < count; i++, hdrpp++)
{
- unsigned int i;
- unsigned int last_type;
- Elf_Internal_Shdr **hdrpp;
- /* What we think the current segment's offset is. */
- bfd_vma p_offset;
- /* What we think the current segment's address is. */
- bfd_vma p_vaddr;
- /* How big we think the current segment is. */
- bfd_vma p_memsz;
- /* What we think the current file offset is. */
- bfd_vma file_offset;
- bfd_vma next_offset;
-
- /* Scan the headers and compute the number of segments required. This
- code is intentionally similar to the code in map_program_segments.
-
- The `sh_offset' field isn't valid at this point, so we keep our own
- running total in `file_offset'.
-
- This works because section VMAs are already known. */
-
- segs = 1;
- /* Make sure the first section goes in the first segment. */
- file_offset = p_offset = sorted_hdrs[0]->sh_addr % maxpagesize;
- p_vaddr = sorted_hdrs[0]->sh_addr;
- p_memsz = 0;
- last_type = SHT_PROGBITS;
-
- for (i = 0, hdrpp = sorted_hdrs; i < count; i++, hdrpp++)
- {
- Elf_Internal_Shdr *hdr;
+ asection *hdr;
- hdr = *hdrpp;
+ hdr = *hdrpp;
- /* Ignore any section which will not be part of the process
- image. */
- if ((hdr->sh_flags & SHF_ALLOC) == 0)
- continue;
-
- /* Keep track of where this and the next sections go.
- The section VMA must equal the file position modulo
- the page size. */
- file_offset += (hdr->sh_addr - file_offset) % maxpagesize;
- next_offset = file_offset;
- if (hdr->sh_type != SHT_NOBITS)
- next_offset = file_offset + hdr->sh_size;
-
- /* If this section fits in the segment we are constructing, add
- it in. */
- if ((file_offset - (p_offset + p_memsz)
- == hdr->sh_addr - (p_vaddr + p_memsz))
- && (last_type != SHT_NOBITS || hdr->sh_type == SHT_NOBITS))
- {
- bfd_size_type adjust;
+ /* See if this section and the last one will fit in the same
+ segment. */
+ if (last_hdr == NULL
+ || ((BFD_ALIGN (last_hdr->lma + last_hdr->_raw_size, maxpagesize)
+ >= hdr->lma)
+ && ((last_hdr->flags & SEC_LOAD) != 0
+ || (hdr->flags & SEC_LOAD) == 0)))
+ {
+ last_hdr = hdr;
+ continue;
+ }
- adjust = hdr->sh_addr - (p_vaddr + p_memsz);
- p_memsz += hdr->sh_size + adjust;
- file_offset = next_offset;
- last_type = hdr->sh_type;
- continue;
- }
+ /* This section won't fit in the program segment. We must
+ create a new program header holding all the sections from
+ phdr_index until hdr. */
- /* The section won't fit, start a new segment. */
- ++segs;
+ m = make_mapping (abfd, sections, phdr_index, i);
+ if (m == NULL)
+ goto error_return;
- /* Initialize the segment. */
- p_vaddr = hdr->sh_addr;
- p_memsz = hdr->sh_size;
- p_offset = file_offset;
- file_offset = next_offset;
+ *pm = m;
+ pm = &m->next;
- last_type = hdr->sh_type;
- }
+ last_hdr = hdr;
+ phdr_index = i;
}
- else
+
+ /* Create a final PT_LOAD program segment. */
+ if (last_hdr != NULL)
{
- /* Assume we will need exactly two PT_LOAD segments: one for text
- and one for data. */
- segs = 2;
+ m = make_mapping (abfd, sections, phdr_index, i);
+ if (m == NULL)
+ goto error_return;
+
+ *pm = m;
+ pm = &m->next;
}
- s = bfd_get_section_by_name (abfd, ".interp");
+ /* If there is a .dynamic section, throw in a PT_DYNAMIC segment. */
+ s = bfd_get_section_by_name (abfd, ".dynamic");
if (s != NULL && (s->flags & SEC_LOAD) != 0)
{
- /* If we have a loadable interpreter section, we need a
- PT_INTERP segment. In this case, assume we also need a
- PT_PHDR segment, although that may not be true for all
- targets. */
- segs += 2;
- }
+ m = ((struct elf_segment_map *)
+ bfd_zalloc (abfd, sizeof (struct elf_segment_map)));
+ if (m == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+ m->next = NULL;
+ m->p_type = PT_DYNAMIC;
+ m->count = 1;
+ m->sections[0] = s;
- if (bfd_get_section_by_name (abfd, ".dynamic") != NULL)
- {
- /* We need a PT_DYNAMIC segment. */
- ++segs;
+ *pm = m;
+ pm = &m->next;
}
- /* Let the backend count up any program headers it might need. */
- if (bed->elf_backend_create_program_headers)
- segs = ((*bed->elf_backend_create_program_headers)
- (abfd, (Elf_Internal_Phdr *) NULL, segs));
+ free (sections);
+ sections = NULL;
- elf_tdata (abfd)->program_header_size = segs * bed->s->sizeof_phdr;
- return elf_tdata (abfd)->program_header_size;
+ elf_tdata (abfd)->segment_map = mfirst;
+ return true;
+
+ error_return:
+ if (sections != NULL)
+ free (sections);
+ return false;
}
-/* Create the program header. OFF is the file offset where the
- program header should be written. FIRST is the first loadable ELF
- section. SORTED_HDRS is the ELF sections sorted by section
- address. PHDR_SIZE is the size of the program header as returned
- by get_program_header_size. */
+/* Sort sections by VMA. */
-static file_ptr
-map_program_segments (abfd, off, first, sorted_hdrs, phdr_size)
- bfd *abfd;
- file_ptr off;
- Elf_Internal_Shdr *first;
- Elf_Internal_Shdr **sorted_hdrs;
- bfd_size_type phdr_size;
+static int
+elf_sort_sections (arg1, arg2)
+ const PTR arg1;
+ const PTR arg2;
{
- Elf_Internal_Phdr phdrs[10];
- unsigned int phdr_count;
- Elf_Internal_Phdr *phdr;
- int phdr_size_adjust;
- unsigned int i;
- Elf_Internal_Shdr **hdrpp;
- asection *sinterp, *sdyn;
- unsigned int last_type;
- Elf_Internal_Ehdr *i_ehdrp;
- struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ const asection *sec1 = *(const asection **) arg1;
+ const asection *sec2 = *(const asection **) arg2;
- BFD_ASSERT ((abfd->flags & (EXEC_P | DYNAMIC)) != 0);
- BFD_ASSERT (phdr_size / sizeof (Elf_Internal_Phdr)
- <= sizeof phdrs / sizeof (phdrs[0]));
+ if (sec1->vma < sec2->vma)
+ return -1;
+ else if (sec1->vma > sec2->vma)
+ return 1;
- phdr_count = 0;
- phdr = phdrs;
+ /* Put !SEC_LOAD sections after SEC_LOAD ones. */
- if (bed->want_hdr_in_seg)
- phdr_size_adjust = first->sh_offset - phdr_size;
- else
- phdr_size_adjust = 0;
+#define TOEND(x) (((x)->flags & SEC_LOAD) == 0)
- /* If we have a loadable .interp section, we must create a PT_INTERP
- segment which must precede all PT_LOAD segments. We assume that
- we must also create a PT_PHDR segment, although that may not be
- true for all targets. */
- sinterp = bfd_get_section_by_name (abfd, ".interp");
- if (sinterp != NULL && (sinterp->flags & SEC_LOAD) != 0)
- {
- BFD_ASSERT (first != NULL);
+ if (TOEND (sec1))
+ if (TOEND (sec2))
+ return sec1->target_index - sec2->target_index;
+ else
+ return 1;
- phdr->p_type = PT_PHDR;
+ if (TOEND (sec2))
+ return -1;
- phdr->p_offset = off;
+#undef TOEND
- /* Account for any adjustment made because of the alignment of
- the first loadable section. */
- phdr_size_adjust = (first->sh_offset - phdr_size) - off;
- BFD_ASSERT (phdr_size_adjust >= 0 && phdr_size_adjust < 128);
+ /* Sort by size, to put zero sized sections before others at the
+ same address. */
- /* The program header precedes all loadable sections. This lets
- us compute its loadable address. This depends on the linker
- script. */
- phdr->p_vaddr = first->sh_addr - (phdr_size + phdr_size_adjust);
+ if (sec1->_raw_size < sec2->_raw_size)
+ return -1;
+ if (sec1->_raw_size > sec2->_raw_size)
+ return 1;
- phdr->p_paddr = 0;
- phdr->p_filesz = phdr_size;
- phdr->p_memsz = phdr_size;
+ return sec1->target_index - sec2->target_index;
+}
- /* FIXME: UnixWare and Solaris set PF_X, Irix 5 does not. */
- phdr->p_flags = PF_R | PF_X;
+/* 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. */
- phdr->p_align = bed->s->file_align;
- BFD_ASSERT ((phdr->p_vaddr - phdr->p_offset) % bed->s->file_align == 0);
+static boolean
+assign_file_positions_for_segments (abfd)
+ bfd *abfd;
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ unsigned int count;
+ struct elf_segment_map *m;
+ unsigned int alloc;
+ Elf_Internal_Phdr *phdrs;
+ file_ptr off;
+ boolean found_load;
+ Elf_Internal_Phdr *p;
+
+ if (elf_tdata (abfd)->segment_map == NULL)
+ {
+ if (! map_sections_to_segments (abfd))
+ return false;
+ }
- /* Include the ELF header in the first loadable segment. */
- phdr_size_adjust += off;
+ count = 0;
+ for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
+ ++count;
- ++phdr_count;
- ++phdr;
+ elf_elfheader (abfd)->e_phoff = bed->s->sizeof_ehdr;
+ elf_elfheader (abfd)->e_phentsize = bed->s->sizeof_phdr;
+ elf_elfheader (abfd)->e_phnum = count;
- phdr->p_type = PT_INTERP;
- phdr->p_offset = sinterp->filepos;
- phdr->p_vaddr = sinterp->vma;
- phdr->p_paddr = 0;
- phdr->p_filesz = sinterp->_raw_size;
- phdr->p_memsz = sinterp->_raw_size;
- phdr->p_flags = PF_R;
- phdr->p_align = 1 << bfd_get_section_alignment (abfd, sinterp);
+ if (count == 0)
+ return true;
- ++phdr_count;
- ++phdr;
+ /* Let the backend count up any program headers it might need. */
+ if (bed->elf_backend_create_program_headers)
+ count = ((*bed->elf_backend_create_program_headers)
+ (abfd, (Elf_Internal_Phdr *) NULL, count));
+
+ /* If we already counted the number of program segments, make sure
+ that we allocated enough space. This happens when SIZEOF_HEADERS
+ is used in a linker script. */
+ alloc = elf_tdata (abfd)->program_header_size / bed->s->sizeof_phdr;
+ 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));
+ bfd_set_error (bfd_error_bad_value);
+ return false;
}
- /* Look through the sections to see how they will be divided into
- program segments. The sections must be arranged in order by
- sh_addr for this to work correctly. */
- phdr->p_type = PT_NULL;
- last_type = SHT_PROGBITS;
- for (i = 1, hdrpp = sorted_hdrs;
- i < elf_elfheader (abfd)->e_shnum;
- i++, hdrpp++)
+ if (alloc == 0)
+ alloc = count;
+
+ phdrs = ((Elf_Internal_Phdr *)
+ bfd_alloc (abfd, alloc * sizeof (Elf_Internal_Phdr)));
+ if (phdrs == NULL)
{
- Elf_Internal_Shdr *hdr;
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
- hdr = *hdrpp;
+ off = bed->s->sizeof_ehdr;
+ off += alloc * bed->s->sizeof_phdr;
- /* Ignore any section which will not be part of the process
- image. */
- if ((hdr->sh_flags & SHF_ALLOC) == 0)
- continue;
+ found_load = false;
+ for (m = elf_tdata (abfd)->segment_map, p = phdrs;
+ m != NULL;
+ m = m->next, p++)
+ {
+ unsigned int i;
+ asection **secpp;
+ boolean adjusted;
+
+ p->p_type = m->p_type;
+
+ if (m->p_flags_valid)
+ p->p_flags = m->p_flags;
+
+ if (m->count == 0)
+ p->p_vaddr = 0;
+ else
+ p->p_vaddr = m->sections[0]->vma;
- /* If this section fits in the segment we are constructing, add
- it in. */
- if (phdr->p_type != PT_NULL
- && (hdr->sh_offset - (phdr->p_offset + phdr->p_memsz)
- == hdr->sh_addr - (phdr->p_vaddr + phdr->p_memsz))
- && (last_type != SHT_NOBITS || hdr->sh_type == SHT_NOBITS))
+ if (m->p_paddr_valid)
+ p->p_paddr = m->p_paddr;
+ else if (m->count == 0)
+ p->p_paddr = 0;
+ else
+ p->p_paddr = m->sections[0]->lma;
+
+ if (p->p_type == PT_LOAD)
+ p->p_align = bed->maxpagesize;
+ else if (m->count == 0)
+ p->p_align = bed->s->file_align;
+ else
+ p->p_align = 0;
+
+ p->p_filesz = 0;
+ p->p_memsz = 0;
+
+ adjusted = false;
+ if (p->p_type == PT_LOAD)
{
- bfd_size_type adjust;
-
- adjust = hdr->sh_addr - (phdr->p_vaddr + phdr->p_memsz);
- phdr->p_memsz += hdr->sh_size + adjust;
- if (hdr->sh_type != SHT_NOBITS)
- phdr->p_filesz += hdr->sh_size + adjust;
- if ((hdr->sh_flags & SHF_WRITE) != 0)
- phdr->p_flags |= PF_W;
- if ((hdr->sh_flags & SHF_EXECINSTR) != 0)
- phdr->p_flags |= PF_X;
- last_type = hdr->sh_type;
- continue;
+ p->p_offset = off;
+
+ if (! found_load)
+ {
+ struct elf_segment_map *mi;
+ Elf_Internal_Phdr *pi;
+ Elf_Internal_Phdr *pi_phdr;
+
+ /* This is the first PT_LOAD segment. If there is a
+ PT_INTERP segment, adjust the offset of this segment
+ to include the program headers and the file header. */
+ pi_phdr = NULL;
+ for (mi = elf_tdata (abfd)->segment_map, pi = phdrs;
+ mi != NULL;
+ mi = mi->next, pi++)
+ {
+ if (mi->p_type == PT_INTERP)
+ {
+ p->p_offset = 0;
+ p->p_filesz = off;
+ p->p_memsz = off;
+ p->p_vaddr -= off;
+ p->p_paddr -= off;
+ adjusted = true;
+ }
+ if (mi->p_type == PT_PHDR)
+ pi_phdr = pi;
+ }
+
+ /* Set up the PT_PHDR addresses. */
+ if (pi_phdr != NULL)
+ {
+ pi_phdr->p_vaddr = p->p_vaddr + bed->s->sizeof_ehdr;
+ pi_phdr->p_paddr = p->p_paddr + bed->s->sizeof_ehdr;
+ }
+
+ found_load = true;
+ }
}
- /* The section won't fit, start a new segment. If we're already in one,
- move to the next one. */
- if (phdr->p_type != PT_NULL)
+ if (! m->p_flags_valid)
+ p->p_flags = PF_R;
+ for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
{
- ++phdr;
- ++phdr_count;
+ asection *sec;
+ flagword flags;
+ bfd_size_type align;
+
+ sec = *secpp;
+ flags = sec->flags;
+
+ if (p->p_type == PT_LOAD)
+ {
+ bfd_vma adjust;
+
+ /* The section VMA must equal the file position modulo
+ the page size. */
+ adjust = (sec->vma - off) % bed->maxpagesize;
+ if (adjust != 0)
+ {
+ if (i == 0 && ! adjusted)
+ p->p_offset += adjust;
+ else
+ {
+ p->p_memsz += adjust;
+ if ((flags & SEC_LOAD) != 0)
+ p->p_filesz += adjust;
+ }
+ off += adjust;
+ }
+
+ sec->filepos = off;
+
+ if ((flags & SEC_LOAD) != 0)
+ off += sec->_raw_size;
+ }
+
+ p->p_memsz += sec->_raw_size;
+
+ if ((flags & SEC_LOAD) != 0)
+ p->p_filesz += sec->_raw_size;
+
+ align = 1 << bfd_get_section_alignment (abfd, sec);
+ if (align > p->p_align)
+ p->p_align = align;
+
+ if (! m->p_flags_valid)
+ {
+ if ((flags & SEC_CODE) != 0)
+ p->p_flags |= PF_X;
+ if ((flags & SEC_READONLY) == 0)
+ p->p_flags |= PF_W;
+ }
}
+ }
- /* Initialize the segment. */
- phdr->p_type = PT_LOAD;
- phdr->p_offset = hdr->sh_offset;
- phdr->p_vaddr = hdr->sh_addr;
- phdr->p_paddr = 0;
- if (hdr->sh_type == SHT_NOBITS)
- phdr->p_filesz = 0;
- else
- phdr->p_filesz = hdr->sh_size;
- phdr->p_memsz = hdr->sh_size;
- phdr->p_flags = PF_R;
- if ((hdr->sh_flags & SHF_WRITE) != 0)
- phdr->p_flags |= PF_W;
- if ((hdr->sh_flags & SHF_EXECINSTR) != 0)
- phdr->p_flags |= PF_X;
- phdr->p_align = bed->maxpagesize;
-
- if (hdr == first
- && (bed->want_hdr_in_seg
- || (sinterp != NULL
- && (sinterp->flags & SEC_LOAD) != 0)))
+ /* Now that we have set the section file positions, we can set up
+ the file positions for the non PT_LOAD segments. */
+ for (m = elf_tdata (abfd)->segment_map, p = phdrs;
+ m != NULL;
+ m = m->next, p++)
+ {
+ if (p->p_type != PT_LOAD && m->count > 0)
+ p->p_offset = m->sections[0]->filepos;
+ if (p->p_type == PT_PHDR)
{
- phdr->p_offset -= phdr_size + phdr_size_adjust;
- phdr->p_vaddr -= phdr_size + phdr_size_adjust;
- phdr->p_filesz += phdr_size + phdr_size_adjust;
- phdr->p_memsz += phdr_size + phdr_size_adjust;
+ p->p_offset = bed->s->sizeof_ehdr;
+ p->p_filesz = count * bed->s->sizeof_phdr;
+ p->p_memsz = p->p_filesz;
}
-
- last_type = hdr->sh_type;
}
- if (phdr->p_type != PT_NULL)
+ /* Let the backend set up any program headers it might need. */
+ if (bed->elf_backend_create_program_headers)
+ count = ((*bed->elf_backend_create_program_headers)
+ (abfd, phdrs, count));
+
+ /* Clear out any program headers we allocated but did not use. */
+ for (; count < alloc; count++, p++)
{
- ++phdr;
- ++phdr_count;
+ memset (p, 0, sizeof *p);
+ p->p_type = PT_NULL;
}
- /* If we have a .dynamic section, create a PT_DYNAMIC segment. */
- sdyn = bfd_get_section_by_name (abfd, ".dynamic");
- if (sdyn != NULL && (sdyn->flags & SEC_LOAD) != 0)
- {
- phdr->p_type = PT_DYNAMIC;
- phdr->p_offset = sdyn->filepos;
- phdr->p_vaddr = sdyn->vma;
- phdr->p_paddr = 0;
- phdr->p_filesz = sdyn->_raw_size;
- phdr->p_memsz = sdyn->_raw_size;
- phdr->p_flags = PF_R;
- if ((sdyn->flags & SEC_READONLY) == 0)
- phdr->p_flags |= PF_W;
- if ((sdyn->flags & SEC_CODE) != 0)
- phdr->p_flags |= PF_X;
- phdr->p_align = 1 << bfd_get_section_alignment (abfd, sdyn);
+ elf_tdata (abfd)->phdr = phdrs;
- ++phdr;
- ++phdr_count;
- }
+ elf_tdata (abfd)->next_file_pos = off;
- /* Let the backend create additional program headers. */
- if (bed->elf_backend_create_program_headers)
- phdr_count = (*bed->elf_backend_create_program_headers) (abfd,
- phdrs,
- phdr_count);
+ /* Write out the program headers. */
+ if (bfd_seek (abfd, bed->s->sizeof_ehdr, SEEK_SET) != 0
+ || bed->s->write_out_phdrs (abfd, phdrs, alloc) != 0)
+ return false;
+
+ return true;
+}
+
+/* Get the size of the program header.
+
+ If this is called by the linker before any of the section VMA's are set, it
+ can't calculate the correct value for a strange memory layout. This only
+ happens when SIZEOF_HEADERS is used in a linker script. In this case,
+ SORTED_HDRS is NULL and we assume the normal scenario of one text and one
+ data segment (exclusive of .interp and .dynamic).
+
+ ??? User written scripts must either not use SIZEOF_HEADERS, or assume there
+ will be two segments. */
+
+static bfd_size_type
+get_program_header_size (abfd)
+ bfd *abfd;
+{
+ size_t segs;
+ asection *s;
+ struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+ /* We can't return a different result each time we're called. */
+ if (elf_tdata (abfd)->program_header_size != 0)
+ return elf_tdata (abfd)->program_header_size;
- /* Make sure the return value from get_program_header_size matches
- what we computed here. Actually, it's OK if we allocated too
- much space in the program header. */
- if (phdr_count > phdr_size / bed->s->sizeof_phdr)
+ /* Assume we will need exactly two PT_LOAD segments: one for text
+ and one for data. */
+ segs = 2;
+
+ s = bfd_get_section_by_name (abfd, ".interp");
+ if (s != NULL && (s->flags & SEC_LOAD) != 0)
{
- ((*_bfd_error_handler)
- ("%s: Not enough room for program headers (allocated %lu, need %u)",
- bfd_get_filename (abfd),
- (unsigned long) (phdr_size / bed->s->sizeof_phdr),
- phdr_count));
- bfd_set_error (bfd_error_bad_value);
- return (file_ptr) -1;
+ /* If we have a loadable interpreter section, we need a
+ PT_INTERP segment. In this case, assume we also need a
+ PT_PHDR segment, although that may not be true for all
+ targets. */
+ segs += 2;
}
- /* Set up program header information. */
- i_ehdrp = elf_elfheader (abfd);
- i_ehdrp->e_phentsize = bed->s->sizeof_phdr;
- i_ehdrp->e_phoff = off;
- i_ehdrp->e_phnum = phdr_count;
-
- /* Save the program headers away. I don't think anybody uses this
- information right now. */
- elf_tdata (abfd)->phdr = ((Elf_Internal_Phdr *)
- bfd_alloc (abfd,
- (phdr_count
- * sizeof (Elf_Internal_Phdr))));
- if (elf_tdata (abfd)->phdr == NULL && phdr_count != 0)
+ if (bfd_get_section_by_name (abfd, ".dynamic") != NULL)
{
- bfd_set_error (bfd_error_no_memory);
- return (file_ptr) -1;
+ /* We need a PT_DYNAMIC segment. */
+ ++segs;
}
- memcpy (elf_tdata (abfd)->phdr, phdrs,
- phdr_count * sizeof (Elf_Internal_Phdr));
- /* Write out the program headers. */
- if (bfd_seek (abfd, off, SEEK_SET) != 0)
- return (file_ptr) -1;
-
- if (bed->s->write_out_phdrs (abfd, phdrs, phdr_count) != 0)
- return (file_ptr) -1;
+ /* Let the backend count up any program headers it might need. */
+ if (bed->elf_backend_create_program_headers)
+ segs = ((*bed->elf_backend_create_program_headers)
+ (abfd, (Elf_Internal_Phdr *) NULL, segs));
- return off + phdr_count * bed->s->sizeof_phdr;
+ elf_tdata (abfd)->program_header_size = segs * bed->s->sizeof_phdr;
+ return elf_tdata (abfd)->program_header_size;
}
/* Work out the file positions of all the sections. This is called by
@@ -1837,15 +2009,11 @@ map_program_segments (abfd, off, first, sorted_hdrs, phdr_size)
positions in assign_file_positions_for_relocs, which is called by
write_object_contents and final_link.
- If DOSYMS is false, we do not assign file positions for the symbol
- table or the string table. */
-
-static int elf_sort_hdrs PARAMS ((const PTR, const PTR));
+ We also don't set the positions of the .symtab and .strtab here. */
static boolean
-assign_file_positions_except_relocs (abfd, dosyms)
+assign_file_positions_except_relocs (abfd)
bfd *abfd;
- boolean dosyms;
{
struct elf_obj_tdata * const tdata = elf_tdata (abfd);
Elf_Internal_Ehdr * const i_ehdrp = elf_elfheader (abfd);
@@ -1853,14 +2021,14 @@ assign_file_positions_except_relocs (abfd, dosyms)
file_ptr off;
struct elf_backend_data *bed = get_elf_backend_data (abfd);
- /* Start after the ELF header. */
- off = i_ehdrp->e_ehsize;
-
if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
{
Elf_Internal_Shdr **hdrpp;
unsigned int i;
+ /* Start after the ELF header. */
+ off = i_ehdrp->e_ehsize;
+
/* We are not creating an executable, which means that we are
not creating a program header, and that the actual order of
the sections in the file is unimportant. */
@@ -1874,9 +2042,8 @@ assign_file_positions_except_relocs (abfd, dosyms)
hdr->sh_offset = -1;
continue;
}
- if (! dosyms
- && (i == tdata->symtab_section
- || i == tdata->strtab_section))
+ if (i == tdata->symtab_section
+ || i == tdata->strtab_section)
{
hdr->sh_offset = -1;
continue;
@@ -1887,97 +2054,45 @@ assign_file_positions_except_relocs (abfd, dosyms)
}
else
{
- file_ptr phdr_off;
- bfd_size_type phdr_size;
- bfd_vma maxpagesize;
- size_t hdrppsize;
- Elf_Internal_Shdr **sorted_hdrs;
- Elf_Internal_Shdr **hdrpp;
unsigned int i;
- Elf_Internal_Shdr *first;
- file_ptr phdr_map;
-
- /* We are creating an executable. */
-
- maxpagesize = get_elf_backend_data (abfd)->maxpagesize;
- if (maxpagesize == 0)
- maxpagesize = 1;
-
- /* We must sort the sections. The GNU linker will always create
- the sections in an appropriate order, but the Irix 5 linker
- will not. We don't include the dummy first section in the
- sort. We sort sections which are not SHF_ALLOC to the end. */
- hdrppsize = (i_ehdrp->e_shnum - 1) * sizeof (Elf_Internal_Shdr *);
- sorted_hdrs = (Elf_Internal_Shdr **) malloc (hdrppsize);
- if (sorted_hdrs == NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ Elf_Internal_Shdr **hdrpp;
- memcpy (sorted_hdrs, i_shdrpp + 1, hdrppsize);
- qsort (sorted_hdrs, (size_t) i_ehdrp->e_shnum - 1,
- sizeof (Elf_Internal_Shdr *), elf_sort_hdrs);
-
- /* We can't actually create the program header until we have set the
- file positions for the sections, and we can't do that until we know
- how big the header is going to be. */
- off = align_file_position (off, bed->s->file_align);
- phdr_size = get_program_header_size (abfd,
- sorted_hdrs, i_ehdrp->e_shnum - 1,
- maxpagesize);
- if (phdr_size == (bfd_size_type) -1)
+ /* Assign file positions for the loaded sections based on the
+ assignment of sections to segments. */
+ if (! assign_file_positions_for_segments (abfd))
return false;
- /* Compute the file offsets of each section. */
- phdr_off = off;
- off += phdr_size;
- first = NULL;
- for (i = 1, hdrpp = sorted_hdrs; i < i_ehdrp->e_shnum; i++, hdrpp++)
+ /* Assign file positions for the other sections. */
+
+ off = elf_tdata (abfd)->next_file_pos;
+ for (i = 1, hdrpp = i_shdrpp + 1; i < i_ehdrp->e_shnum; i++, hdrpp++)
{
Elf_Internal_Shdr *hdr;
hdr = *hdrpp;
- if ((hdr->sh_flags & SHF_ALLOC) == 0)
- {
- if (hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA)
- {
- hdr->sh_offset = -1;
- continue;
- }
- if (! dosyms
- && (hdr == i_shdrpp[tdata->symtab_section]
- || hdr == i_shdrpp[tdata->strtab_section]))
- {
- hdr->sh_offset = -1;
- continue;
- }
- off = _bfd_elf_assign_file_position_for_section (hdr, off,
- true);
- }
- else
+ if (hdr->bfd_section != NULL
+ && hdr->bfd_section->filepos != 0)
+ hdr->sh_offset = hdr->bfd_section->filepos;
+ else if ((hdr->sh_flags & SHF_ALLOC) != 0)
{
- if (first == NULL)
- first = hdr;
-
- /* The section VMA must equal the file position modulo
- the page size. This is required by the program
- header. */
- off += (hdr->sh_addr - off) % maxpagesize;
+ ((*_bfd_error_handler)
+ ("%s: warning: allocated section `%s' not in segment",
+ bfd_get_filename (abfd),
+ (hdr->bfd_section == NULL
+ ? "*unknown*"
+ : hdr->bfd_section->name)));
+ off += (hdr->sh_addr - off) % bed->maxpagesize;
off = _bfd_elf_assign_file_position_for_section (hdr, off,
false);
}
- }
-
- /* Create the program header. */
- phdr_map = map_program_segments (abfd, phdr_off, first, sorted_hdrs,
- phdr_size);
- if (phdr_map == (file_ptr) -1)
- return false;
- BFD_ASSERT ((bfd_size_type) phdr_map
- <= (bfd_size_type) phdr_off + phdr_size);
-
- free (sorted_hdrs);
+ else if (hdr->sh_type == SHT_REL
+ || hdr->sh_type == SHT_RELA
+ || hdr == i_shdrpp[tdata->symtab_section]
+ || hdr == i_shdrpp[tdata->strtab_section])
+ hdr->sh_offset = -1;
+ else
+ off = _bfd_elf_assign_file_position_for_section (hdr, off, true);
+ }
}
/* Place the section headers. */
@@ -1990,47 +2105,6 @@ assign_file_positions_except_relocs (abfd, dosyms)
return true;
}
-/* Sort the ELF headers by VMA. We sort headers which are not
- SHF_ALLOC to the end. */
-static int
-elf_sort_hdrs (arg1, arg2)
- const PTR arg1;
- const PTR arg2;
-{
- int ret;
- const Elf_Internal_Shdr *hdr1 = *(const Elf_Internal_Shdr **) arg1;
- const Elf_Internal_Shdr *hdr2 = *(const Elf_Internal_Shdr **) arg2;
-
-#define TOEND(x) (((x)->sh_flags & SHF_ALLOC)==0)
-
- if (TOEND (hdr1))
- if (TOEND (hdr2))
- return 0;
- else
- return 1;
-
- if (TOEND (hdr2))
- return -1;
-
- if (hdr1->sh_addr < hdr2->sh_addr)
- return -1;
- else if (hdr1->sh_addr > hdr2->sh_addr)
- return 1;
-
- /* Put !SHT_NOBITS sections before SHT_NOBITS ones.
- The main loop in map_program_segments requires this. */
-
- ret = (hdr1->sh_type == SHT_NOBITS) - (hdr2->sh_type == SHT_NOBITS);
-
- if (ret != 0)
- return ret;
- if (hdr1->sh_size < hdr2->sh_size)
- return -1;
- if (hdr1->sh_size > hdr2->sh_size)
- return 1;
- return 0;
-}
-
static boolean
prep_headers (abfd)
bfd *abfd;
@@ -2325,6 +2399,80 @@ _bfd_elf_symbol_from_bfd_symbol (abfd, asym_ptr_ptr)
return idx;
}
+/* Copy private section information. This copies over the entsize
+ field, and sometimes the info field. */
+
+boolean
+_bfd_elf_copy_private_section_data (ibfd, isec, obfd, osec)
+ bfd *ibfd;
+ asection *isec;
+ bfd *obfd;
+ asection *osec;
+{
+ Elf_Internal_Shdr *ihdr, *ohdr;
+
+ if (ibfd->xvec->flavour != bfd_target_elf_flavour
+ || obfd->xvec->flavour != bfd_target_elf_flavour)
+ return true;
+
+ ihdr = &elf_section_data (isec)->this_hdr;
+ ohdr = &elf_section_data (osec)->this_hdr;
+
+ ohdr->sh_entsize = ihdr->sh_entsize;
+
+ if (ihdr->sh_type == SHT_SYMTAB
+ || ihdr->sh_type == SHT_DYNSYM)
+ ohdr->sh_info = ihdr->sh_info;
+
+ return true;
+}
+
+/* Copy private symbol information. If this symbol is in a section
+ which we did not map into a BFD section, try to map the section
+ index correctly. We use special macro definitions for the mapped
+ section indices; these definitions are interpreted by the
+ swap_out_syms function. */
+
+#define MAP_ONESYMTAB (SHN_LORESERVE - 1)
+#define MAP_DYNSYMTAB (SHN_LORESERVE - 2)
+#define MAP_STRTAB (SHN_LORESERVE - 3)
+#define MAP_SHSTRTAB (SHN_LORESERVE - 4)
+
+boolean
+_bfd_elf_copy_private_symbol_data (ibfd, isymarg, obfd, osymarg)
+ bfd *ibfd;
+ asymbol *isymarg;
+ bfd *obfd;
+ asymbol *osymarg;
+{
+ elf_symbol_type *isym, *osym;
+
+ isym = elf_symbol_from (ibfd, isymarg);
+ osym = elf_symbol_from (obfd, osymarg);
+
+ if (isym != NULL
+ && osym != NULL
+ && bfd_is_abs_section (isym->symbol.section))
+ {
+ unsigned int shndx;
+
+ shndx = isym->internal_elf_sym.st_shndx;
+ if (shndx == elf_onesymtab (ibfd))
+ shndx = MAP_ONESYMTAB;
+ else if (shndx == elf_dynsymtab (ibfd))
+ shndx = MAP_DYNSYMTAB;
+ else if (shndx == elf_tdata (ibfd)->strtab_section)
+ shndx = MAP_STRTAB;
+ else if (shndx == elf_tdata (ibfd)->shstrtab_section)
+ shndx = MAP_SHSTRTAB;
+ osym->internal_elf_sym.st_shndx = shndx;
+ }
+
+ return true;
+}
+
+/* Swap out the symbols. */
+
static boolean
swap_out_syms (abfd, sttp)
bfd *abfd;
@@ -2429,21 +2577,56 @@ swap_out_syms (abfd, sttp)
value += sec->vma;
sym.st_value = value;
sym.st_size = type_ptr ? type_ptr->internal_elf_sym.st_size : 0;
- sym.st_shndx = shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
- if (shndx == -1)
+
+ if (bfd_is_abs_section (sec)
+ && type_ptr != NULL
+ && type_ptr->internal_elf_sym.st_shndx != 0)
{
- asection *sec2;
- /* Writing this would be a hell of a lot easier if we had
- some decent documentation on bfd, and knew what to expect
- of the library, and what to demand of applications. For
- example, it appears that `objcopy' might not set the
- section of a symbol to be a section that is actually in
- the output file. */
- sec2 = bfd_get_section_by_name (abfd, sec->name);
- BFD_ASSERT (sec2 != 0);
- sym.st_shndx = shndx = _bfd_elf_section_from_bfd_section (abfd, sec2);
- BFD_ASSERT (shndx != -1);
+ /* This symbol is in a real ELF section which we did
+ not create as a BFD section. Undo the mapping done
+ by copy_private_symbol_data. */
+ shndx = type_ptr->internal_elf_sym.st_shndx;
+ switch (shndx)
+ {
+ case MAP_ONESYMTAB:
+ shndx = elf_onesymtab (abfd);
+ break;
+ case MAP_DYNSYMTAB:
+ shndx = elf_dynsymtab (abfd);
+ break;
+ case MAP_STRTAB:
+ shndx = elf_tdata (abfd)->strtab_section;
+ break;
+ case MAP_SHSTRTAB:
+ shndx = elf_tdata (abfd)->shstrtab_section;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
+
+ if (shndx == -1)
+ {
+ asection *sec2;
+
+ /* Writing this would be a hell of a lot easier if
+ we had some decent documentation on bfd, and
+ knew what to expect of the library, and what to
+ demand of applications. For example, it
+ appears that `objcopy' might not set the
+ section of a symbol to be a section that is
+ actually in the output file. */
+ sec2 = bfd_get_section_by_name (abfd, sec->name);
+ BFD_ASSERT (sec2 != 0);
+ shndx = _bfd_elf_section_from_bfd_section (abfd, sec2);
+ BFD_ASSERT (shndx != -1);
+ }
}
+
+ sym.st_shndx = shndx;
}
if (bfd_is_com_section (syms[idx]->section))
@@ -2713,8 +2896,7 @@ _bfd_elf_sizeof_headers (abfd, reloc)
ret = get_elf_backend_data (abfd)->s->sizeof_ehdr;
if (! reloc)
- ret += get_program_header_size (abfd, (Elf_Internal_Shdr **) NULL, 0,
- (bfd_vma) 0);
+ ret += get_program_header_size (abfd);
return ret;
}