/* ELF executable support for BFD.
- Copyright 1993 Free Software Foundation, Inc.
+ Copyright 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
#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 **));
+static boolean copy_private_bfd_data PARAMS ((bfd *, bfd *));
/* Standard ELF hash function. Do not change this function; you will
cause invalid hash tables to be generated. (Well, you would if this
char *buf;
if ((buf = bfd_alloc (abfd, size)) == NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return NULL;
- }
+ return NULL;
if (bfd_seek (abfd, offset, SEEK_SET) == -1)
return NULL;
if (bfd_read ((PTR) buf, size, 1, abfd) != size)
elf_tdata (abfd) = (struct elf_obj_tdata *)
bfd_zalloc (abfd, sizeof (struct elf_obj_tdata));
if (elf_tdata (abfd) == 0)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
/* since everything is done at close time, do we need any
initialization? */
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_paddr != 0
+ && 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;
return bfd_reloc_continue;
}
\f
+/* Print out the program headers. */
+
+boolean
+_bfd_elf_print_private_bfd_data (abfd, farg)
+ bfd *abfd;
+ PTR farg;
+{
+ FILE *f = (FILE *) farg;
+ Elf_Internal_Phdr *p;
+ asection *s;
+ bfd_byte *dynbuf = NULL;
+
+ p = elf_tdata (abfd)->phdr;
+ if (p != NULL)
+ {
+ unsigned int i, c;
+
+ fprintf (f, "\nProgram Header:\n");
+ c = elf_elfheader (abfd)->e_phnum;
+ for (i = 0; i < c; i++, p++)
+ {
+ const char *s;
+ char buf[20];
+
+ switch (p->p_type)
+ {
+ case PT_NULL: s = "NULL"; break;
+ case PT_LOAD: s = "LOAD"; break;
+ case PT_DYNAMIC: s = "DYNAMIC"; break;
+ case PT_INTERP: s = "INTERP"; break;
+ case PT_NOTE: s = "NOTE"; break;
+ case PT_SHLIB: s = "SHLIB"; break;
+ case PT_PHDR: s = "PHDR"; break;
+ default: sprintf (buf, "0x%lx", p->p_type); s = buf; break;
+ }
+ fprintf (f, "%8s off 0x", s);
+ fprintf_vma (f, p->p_offset);
+ fprintf (f, " vaddr 0x");
+ fprintf_vma (f, p->p_vaddr);
+ fprintf (f, " paddr 0x");
+ fprintf_vma (f, p->p_paddr);
+ fprintf (f, " align 2**%u\n", bfd_log2 (p->p_align));
+ fprintf (f, " filesz 0x");
+ fprintf_vma (f, p->p_filesz);
+ fprintf (f, " memsz 0x");
+ fprintf_vma (f, p->p_memsz);
+ fprintf (f, " flags %c%c%c",
+ (p->p_flags & PF_R) != 0 ? 'r' : '-',
+ (p->p_flags & PF_W) != 0 ? 'w' : '-',
+ (p->p_flags & PF_X) != 0 ? 'x' : '-');
+ if ((p->p_flags &~ (PF_R | PF_W | PF_X)) != 0)
+ fprintf (f, " %lx", p->p_flags &~ (PF_R | PF_W | PF_X));
+ fprintf (f, "\n");
+ }
+ }
+
+ s = bfd_get_section_by_name (abfd, ".dynamic");
+ if (s != NULL)
+ {
+ int elfsec;
+ unsigned long link;
+ bfd_byte *extdyn, *extdynend;
+ size_t extdynsize;
+ void (*swap_dyn_in) PARAMS ((bfd *, const PTR, Elf_Internal_Dyn *));
+
+ fprintf (f, "\nDynamic Section:\n");
+
+ dynbuf = (bfd_byte *) bfd_malloc (s->_raw_size);
+ if (dynbuf == NULL)
+ goto error_return;
+ if (! bfd_get_section_contents (abfd, s, (PTR) dynbuf, (file_ptr) 0,
+ s->_raw_size))
+ goto error_return;
+
+ elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
+ if (elfsec == -1)
+ goto error_return;
+ link = elf_elfsections (abfd)[elfsec]->sh_link;
+
+ extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
+ swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
+
+ extdyn = dynbuf;
+ extdynend = extdyn + s->_raw_size;
+ for (; extdyn < extdynend; extdyn += extdynsize)
+ {
+ Elf_Internal_Dyn dyn;
+ const char *name;
+ char ab[20];
+ boolean stringp;
+
+ (*swap_dyn_in) (abfd, (PTR) extdyn, &dyn);
+
+ if (dyn.d_tag == DT_NULL)
+ break;
+
+ stringp = false;
+ switch (dyn.d_tag)
+ {
+ default:
+ sprintf (ab, "0x%lx", (unsigned long) dyn.d_tag);
+ name = ab;
+ break;
+
+ case DT_NEEDED: name = "NEEDED"; stringp = true; break;
+ case DT_PLTRELSZ: name = "PLTRELSZ"; break;
+ case DT_PLTGOT: name = "PLTGOT"; break;
+ case DT_HASH: name = "HASH"; break;
+ case DT_STRTAB: name = "STRTAB"; break;
+ case DT_SYMTAB: name = "SYMTAB"; break;
+ case DT_RELA: name = "RELA"; break;
+ case DT_RELASZ: name = "RELASZ"; break;
+ case DT_RELAENT: name = "RELAENT"; break;
+ case DT_STRSZ: name = "STRSZ"; break;
+ case DT_SYMENT: name = "SYMENT"; break;
+ case DT_INIT: name = "INIT"; break;
+ case DT_FINI: name = "FINI"; break;
+ case DT_SONAME: name = "SONAME"; stringp = true; break;
+ case DT_RPATH: name = "RPATH"; stringp = true; break;
+ case DT_SYMBOLIC: name = "SYMBOLIC"; break;
+ case DT_REL: name = "REL"; break;
+ case DT_RELSZ: name = "RELSZ"; break;
+ case DT_RELENT: name = "RELENT"; break;
+ case DT_PLTREL: name = "PLTREL"; break;
+ case DT_DEBUG: name = "DEBUG"; break;
+ case DT_TEXTREL: name = "TEXTREL"; break;
+ case DT_JMPREL: name = "JMPREL"; break;
+ }
+
+ fprintf (f, " %-11s ", name);
+ if (! stringp)
+ fprintf (f, "0x%lx", (unsigned long) dyn.d_un.d_val);
+ else
+ {
+ const char *string;
+
+ string = bfd_elf_string_from_elf_section (abfd, link,
+ dyn.d_un.d_val);
+ if (string == NULL)
+ goto error_return;
+ fprintf (f, "%s", string);
+ }
+ fprintf (f, "\n");
+ }
+
+ free (dynbuf);
+ dynbuf = NULL;
+ }
+
+ return true;
+
+ error_return:
+ if (dynbuf != NULL)
+ free (dynbuf);
+ return false;
+}
+
/* Display ELF-specific fields of a symbol. */
void
bfd_elf_print_symbol (ignore_abfd, filep, symbol, how)
ret = ((struct elf_link_hash_entry *)
bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry)));
if (ret == (struct elf_link_hash_entry *) NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return (struct bfd_hash_entry *) ret;
- }
+ return (struct bfd_hash_entry *) ret;
/* Call the allocation method of the superclass. */
ret = ((struct elf_link_hash_entry *)
ret = ((struct elf_link_hash_table *)
bfd_alloc (abfd, sizeof (struct elf_link_hash_table)));
if (ret == (struct elf_link_hash_table *) NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return NULL;
- }
+ return NULL;
if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc))
{
case SHT_DYNAMIC: /* Dynamic linking information. */
case SHT_NOBITS: /* .bss section. */
case SHT_HASH: /* .hash section. */
+ case SHT_NOTE: /* .note section. */
return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
case SHT_SYMTAB: /* A symbol table */
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
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
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. */
}
break;
- case SHT_NOTE:
- break;
-
case SHT_SHLIB:
return true;
sdata = (struct bfd_elf_section_data *) bfd_alloc (abfd, sizeof (*sdata));
if (!sdata)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
sec->used_by_bfd = (PTR) sdata;
memset (sdata, 0, sizeof (*sdata));
return true;
sprintf (namebuf, split ? "segment%da" : "segment%d", index);
name = bfd_alloc (abfd, strlen (namebuf) + 1);
if (!name)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
strcpy (name, namebuf);
newsect = bfd_make_section (abfd, name);
if (newsect == NULL)
sprintf (namebuf, "segment%db", index);
name = bfd_alloc (abfd, strlen (namebuf) + 1);
if (!name)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
strcpy (name, namebuf);
newsect = bfd_make_section (abfd, name);
if (newsect == NULL)
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;
name = bfd_alloc (abfd, sizeof ".rela" + strlen (asect->name));
if (name == NULL)
{
- bfd_set_error (bfd_error_no_memory);
*failedptr = true;
return;
}
i_shdrp = ((Elf_Internal_Shdr **)
bfd_alloc (abfd, section_number * sizeof (Elf_Internal_Shdr *)));
if (i_shdrp == NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
i_shdrp[0] = ((Elf_Internal_Shdr *)
bfd_alloc (abfd, sizeof (Elf_Internal_Shdr)));
if (i_shdrp[0] == NULL)
{
bfd_release (abfd, i_shdrp);
- bfd_set_error (bfd_error_no_memory);
return false;
}
memset (i_shdrp[0], 0, sizeof (Elf_Internal_Shdr));
char *alc;
len = strlen (sec->name);
- alc = (char *) malloc (len - 2);
+ alc = (char *) bfd_malloc (len - 2);
if (alc == NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
strncpy (alc, sec->name, len - 3);
alc[len - 3] = '\0';
s = bfd_get_section_by_name (abfd, alc);
max_index++;
sect_syms = (asymbol **) bfd_zalloc (abfd, max_index * sizeof (asymbol *));
if (sect_syms == NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
elf_section_syms (abfd) = sect_syms;
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;
bfd_alloc (abfd,
(num_locals + num_globals) * sizeof (asymbol *)));
if (new_syms == NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
for (idx = 0; idx < symcount; idx++)
{
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. */
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;
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);
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;
-/* Assign a file position to a section, optionally aligning to the
- required section alignment. */
+ m = ((struct elf_segment_map *)
+ bfd_zalloc (abfd,
+ (sizeof (struct elf_segment_map)
+ + (to - from - 1) * sizeof (asection *))));
+ if (m == NULL)
+ 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;
-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)
+ if (from == 0)
{
- unsigned int al;
-
- al = i_shdrp->sh_addralign;
- if (al > 1)
- offset = BFD_ALIGN (offset, al);
+ /* Include the headers in the first PT_LOAD segment. */
+ m->includes_filehdr = 1;
+ m->includes_phdrs = 1;
}
- 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;
-}
-
-/* Get the size of the program header.
- 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?)
-
- If SORTED_HDRS is NULL we assume there are two segments: text and data
- (exclusive of .interp and .dynamic).
-
- 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).
+ return m;
+}
- ??? User written scripts must either not use SIZEOF_HEADERS, or assume there
- will be two segments. */
+/* Set up a mapping from BFD sections to program segments. */
-static bfd_size_type
-get_program_header_size (abfd, sorted_hdrs, count, maxpagesize)
+static boolean
+map_sections_to_segments (abfd)
bfd *abfd;
- Elf_Internal_Shdr **sorted_hdrs;
- unsigned int count;
- bfd_vma maxpagesize;
{
- size_t segs;
+ asection **sections = NULL;
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;
+ 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 (sorted_hdrs != NULL)
- {
- 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;
+ if (bfd_count_sections (abfd) == 0)
+ return true;
- hdr = *hdrpp;
+ /* Select the allocated sections, and sort them. */
- /* 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;
+ sections = (asection **) bfd_malloc (bfd_count_sections (abfd)
+ * sizeof (asection *));
+ if (sections == NULL)
+ goto error_return;
- adjust = hdr->sh_addr - (p_vaddr + p_memsz);
- p_memsz += hdr->sh_size + adjust;
- file_offset = next_offset;
- last_type = hdr->sh_type;
- continue;
- }
+ i = 0;
+ for (s = abfd->sections; s != NULL; s = s->next)
+ {
+ if ((s->flags & SEC_ALLOC) != 0)
+ {
+ sections[i] = s;
+ ++i;
+ }
+ }
+ BFD_ASSERT (i <= bfd_count_sections (abfd));
+ count = i;
- /* The section won't fit, start a new segment. */
- ++segs;
+ qsort (sections, (size_t) count, sizeof (asection *), elf_sort_sections);
- /* Initialize the segment. */
- p_vaddr = hdr->sh_addr;
- p_memsz = hdr->sh_size;
- p_offset = file_offset;
- file_offset = next_offset;
+ /* Build the mapping. */
- last_type = hdr->sh_type;
- }
- }
- else
- {
- /* Assume we will need exactly two PT_LOAD segments: one for text
- and one for data. */
- segs = 2;
- }
+ mfirst = NULL;
+ pm = &mfirst;
+ /* 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)
{
- /* 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)
+ 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;
+ m->includes_phdrs = 1;
- if (bfd_get_section_by_name (abfd, ".dynamic") != NULL)
- {
- /* We need a PT_DYNAMIC segment. */
- ++segs;
+ *pm = m;
+ pm = &m->next;
+
+ m = ((struct elf_segment_map *)
+ bfd_zalloc (abfd, sizeof (struct elf_segment_map)));
+ if (m == NULL)
+ goto error_return;
+ m->next = NULL;
+ m->p_type = PT_INTERP;
+ m->count = 1;
+ m->sections[0] = s;
+
+ *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));
+ /* 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++)
+ {
+ asection *hdr;
- elf_tdata (abfd)->program_header_size = segs * bed->s->sizeof_phdr;
- return elf_tdata (abfd)->program_header_size;
-}
+ hdr = *hdrpp;
-/* 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. */
+ /* 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;
+ }
-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;
-{
- 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);
+ /* 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. */
- BFD_ASSERT ((abfd->flags & (EXEC_P | DYNAMIC)) != 0);
- BFD_ASSERT (phdr_size / sizeof (Elf_Internal_Phdr)
- <= sizeof phdrs / sizeof (phdrs[0]));
+ m = make_mapping (abfd, sections, phdr_index, i);
+ if (m == NULL)
+ goto error_return;
- phdr_count = 0;
- phdr = phdrs;
+ *pm = m;
+ pm = &m->next;
- if (bed->want_hdr_in_seg)
- phdr_size_adjust = first->sh_offset - phdr_size;
- else
- phdr_size_adjust = 0;
+ last_hdr = hdr;
+ phdr_index = i;
+ }
- /* 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)
+ /* Create a final PT_LOAD program segment. */
+ if (last_hdr != NULL)
{
- BFD_ASSERT (first != NULL);
+ m = make_mapping (abfd, sections, phdr_index, i);
+ if (m == NULL)
+ goto error_return;
- phdr->p_type = PT_PHDR;
+ *pm = m;
+ pm = &m->next;
+ }
- phdr->p_offset = off;
+ /* 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)
+ {
+ m = ((struct elf_segment_map *)
+ bfd_zalloc (abfd, sizeof (struct elf_segment_map)));
+ if (m == NULL)
+ goto error_return;
+ m->next = NULL;
+ m->p_type = PT_DYNAMIC;
+ m->count = 1;
+ m->sections[0] = s;
- /* 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);
+ *pm = m;
+ pm = &m->next;
+ }
- /* 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);
+ free (sections);
+ sections = NULL;
- phdr->p_paddr = 0;
- phdr->p_filesz = phdr_size;
- phdr->p_memsz = phdr_size;
+ elf_tdata (abfd)->segment_map = mfirst;
+ return true;
- /* FIXME: UnixWare and Solaris set PF_X, Irix 5 does not. */
- phdr->p_flags = PF_R | PF_X;
+ error_return:
+ if (sections != NULL)
+ free (sections);
+ return false;
+}
- phdr->p_align = bed->s->file_align;
- BFD_ASSERT ((phdr->p_vaddr - phdr->p_offset) % bed->s->file_align == 0);
+/* Sort sections by VMA. */
- /* Include the ELF header in the first loadable segment. */
- phdr_size_adjust += off;
+static int
+elf_sort_sections (arg1, arg2)
+ const PTR arg1;
+ const PTR arg2;
+{
+ const asection *sec1 = *(const asection **) arg1;
+ const asection *sec2 = *(const asection **) arg2;
- ++phdr_count;
- ++phdr;
+ if (sec1->vma < sec2->vma)
+ return -1;
+ else if (sec1->vma > sec2->vma)
+ return 1;
- 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);
+ /* Put !SEC_LOAD sections after SEC_LOAD ones. */
- ++phdr_count;
- ++phdr;
- }
+#define TOEND(x) (((x)->flags & SEC_LOAD) == 0)
- /* 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 (TOEND (sec1))
+ if (TOEND (sec2))
+ return sec1->target_index - sec2->target_index;
+ else
+ return 1;
+
+ if (TOEND (sec2))
+ return -1;
+
+#undef TOEND
+
+ /* Sort by size, to put zero sized sections before others at the
+ same address. */
+
+ if (sec1->_raw_size < sec2->_raw_size)
+ return -1;
+ if (sec1->_raw_size > sec2->_raw_size)
+ return 1;
+
+ return sec1->target_index - sec2->target_index;
+}
+
+/* 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. */
+
+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;
+ bfd_vma filehdr_vaddr, filehdr_paddr;
+ bfd_vma phdrs_vaddr, phdrs_paddr;
+ Elf_Internal_Phdr *p;
+
+ if (elf_tdata (abfd)->segment_map == NULL)
{
- Elf_Internal_Shdr *hdr;
+ if (! map_sections_to_segments (abfd))
+ return false;
+ }
- hdr = *hdrpp;
+ if (bed->elf_backend_modify_segment_map)
+ {
+ if (! (*bed->elf_backend_modify_segment_map) (abfd))
+ return false;
+ }
- /* Ignore any section which will not be part of the process
- image. */
- if ((hdr->sh_flags & SHF_ALLOC) == 0)
- continue;
+ count = 0;
+ for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
+ ++count;
+
+ elf_elfheader (abfd)->e_phoff = bed->s->sizeof_ehdr;
+ elf_elfheader (abfd)->e_phentsize = bed->s->sizeof_phdr;
+ elf_elfheader (abfd)->e_phnum = count;
+
+ if (count == 0)
+ return true;
+
+ /* 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;
+ }
- /* 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 (alloc == 0)
+ alloc = count;
+
+ phdrs = ((Elf_Internal_Phdr *)
+ bfd_alloc (abfd, alloc * sizeof (Elf_Internal_Phdr)));
+ if (phdrs == NULL)
+ return false;
+
+ off = bed->s->sizeof_ehdr;
+ off += alloc * bed->s->sizeof_phdr;
+
+ filehdr_vaddr = 0;
+ filehdr_paddr = 0;
+ phdrs_vaddr = 0;
+ phdrs_paddr = 0;
+ for (m = elf_tdata (abfd)->segment_map, p = phdrs;
+ m != NULL;
+ m = m->next, p++)
+ {
+ unsigned int i;
+ asection **secpp;
+
+ /* If elf_segment_map is not from map_sections_to_segments, the
+ sections may not be correctly ordered. */
+ if (m->count > 0)
+ qsort (m->sections, (size_t) m->count, sizeof (asection *),
+ elf_sort_sections);
+
+ p->p_type = m->p_type;
+
+ if (m->p_flags_valid)
+ p->p_flags = m->p_flags;
+ else
+ p->p_flags = 0;
+
+ if (p->p_type == PT_LOAD
+ && m->count > 0
+ && (m->sections[0]->flags & SEC_LOAD) != 0)
+ off += (m->sections[0]->vma - off) % bed->maxpagesize;
+
+ if (m->count == 0)
+ p->p_vaddr = 0;
+ else
+ p->p_vaddr = m->sections[0]->vma;
+
+ 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_offset = 0;
+ p->p_filesz = 0;
+ p->p_memsz = 0;
+
+ if (m->includes_filehdr)
{
- 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;
+ if (! m->p_flags_valid)
+ p->p_flags |= PF_R;
+ p->p_offset = 0;
+ p->p_filesz = bed->s->sizeof_ehdr;
+ p->p_memsz = bed->s->sizeof_ehdr;
+ if (m->count > 0)
+ {
+ BFD_ASSERT (p->p_type == PT_LOAD);
+ p->p_vaddr -= off;
+ if (! m->p_paddr_valid)
+ p->p_paddr -= off;
+ }
+ if (p->p_type == PT_LOAD)
+ {
+ filehdr_vaddr = p->p_vaddr;
+ filehdr_paddr = p->p_paddr;
+ }
}
- /* 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->includes_phdrs)
{
- ++phdr;
- ++phdr_count;
+ if (! m->p_flags_valid)
+ p->p_flags |= PF_R;
+ if (m->includes_filehdr)
+ {
+ if (p->p_type == PT_LOAD)
+ {
+ phdrs_vaddr = p->p_vaddr + bed->s->sizeof_ehdr;
+ phdrs_paddr = p->p_paddr + bed->s->sizeof_ehdr;
+ }
+ }
+ else
+ {
+ p->p_offset = bed->s->sizeof_ehdr;
+ if (m->count > 0)
+ {
+ BFD_ASSERT (p->p_type == PT_LOAD);
+ p->p_vaddr -= off - p->p_offset;
+ if (! m->p_paddr_valid)
+ p->p_paddr -= off - p->p_offset;
+ }
+ if (p->p_type == PT_LOAD)
+ {
+ phdrs_vaddr = p->p_vaddr;
+ phdrs_paddr = p->p_paddr;
+ }
+ }
+ p->p_filesz += alloc * bed->s->sizeof_phdr;
+ p->p_memsz += alloc * bed->s->sizeof_phdr;
}
- /* 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)))
+ if (p->p_type == PT_LOAD)
{
- 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;
+ if (! m->includes_filehdr && ! m->includes_phdrs)
+ p->p_offset = off;
+ else
+ {
+ file_ptr adjust;
+
+ adjust = off - (p->p_offset + p->p_filesz);
+ p->p_filesz += adjust;
+ p->p_memsz += adjust;
+ }
}
- last_type = hdr->sh_type;
+ for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
+ {
+ 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. */
+ if ((flags & SEC_LOAD) != 0)
+ {
+ adjust = (sec->vma - off) % bed->maxpagesize;
+ if (adjust != 0)
+ {
+ if (i == 0)
+ abort ();
+ 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)
+ {
+ p->p_flags |= PF_R;
+ if ((flags & SEC_CODE) != 0)
+ p->p_flags |= PF_X;
+ if ((flags & SEC_READONLY) == 0)
+ p->p_flags |= PF_W;
+ }
+ }
}
- if (phdr->p_type != PT_NULL)
+ /* 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++)
{
- ++phdr;
- ++phdr_count;
+ if (p->p_type != PT_LOAD && m->count > 0)
+ {
+ BFD_ASSERT (! m->includes_filehdr && ! m->includes_phdrs);
+ p->p_offset = m->sections[0]->filepos;
+ }
+ if (m->count == 0)
+ {
+ if (m->includes_filehdr)
+ {
+ p->p_vaddr = filehdr_vaddr;
+ if (! m->p_paddr_valid)
+ p->p_paddr = filehdr_paddr;
+ }
+ else if (m->includes_phdrs)
+ {
+ p->p_vaddr = phdrs_vaddr;
+ if (! m->p_paddr_valid)
+ p->p_paddr = phdrs_paddr;
+ }
+ }
}
- /* 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)
+ /* Clear out any program headers we allocated but did not use. */
+ for (; count < alloc; count++, p++)
{
- 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);
-
- ++phdr;
- ++phdr_count;
+ memset (p, 0, sizeof *p);
+ p->p_type = PT_NULL;
}
- /* 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);
+ elf_tdata (abfd)->phdr = phdrs;
+
+ elf_tdata (abfd)->next_file_pos = off;
+
+ /* 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)
+ if (elf_tdata (abfd)->segment_map != NULL)
{
- ((*_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;
+ struct elf_segment_map *m;
+
+ segs = 0;
+ for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
+ ++segs;
+ elf_tdata (abfd)->program_header_size = segs * bed->s->sizeof_phdr;
+ return elf_tdata (abfd)->program_header_size;
}
- /* 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;
+ /* 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)
+ {
+ /* 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;
+ }
- /* 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;
+ /* Let the backend count up any program headers it might need. */
+ if (bed->elf_backend_additional_program_headers)
+ {
+ int a;
- if (bed->s->write_out_phdrs (abfd, phdrs, phdr_count) != 0)
- return (file_ptr) -1;
+ a = (*bed->elf_backend_additional_program_headers) (abfd);
+ if (a == -1)
+ abort ();
+ segs += a;
+ }
- 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
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);
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. */
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;
}
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. */
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;
i_ehdrp->e_ident[EI_CLASS] = bed->s->elfclass;
i_ehdrp->e_ident[EI_DATA] =
- abfd->xvec->byteorder_big_p ? ELFDATA2MSB : ELFDATA2LSB;
+ bfd_big_endian (abfd) ? ELFDATA2MSB : ELFDATA2LSB;
i_ehdrp->e_ident[EI_VERSION] = bed->s->ev_current;
for (count = EI_PAD; count < EI_NIDENT; count++)
return idx;
}
+/* Copy private BFD data. This copies any program header information. */
+
+static boolean
+copy_private_bfd_data (ibfd, obfd)
+ bfd *ibfd;
+ bfd *obfd;
+{
+ Elf_Internal_Ehdr *iehdr;
+ struct elf_segment_map *mfirst;
+ struct elf_segment_map **pm;
+ Elf_Internal_Phdr *p;
+ unsigned int i, c;
+
+ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+ || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+ return true;
+
+ if (elf_tdata (ibfd)->phdr == NULL)
+ return true;
+
+ iehdr = elf_elfheader (ibfd);
+
+ mfirst = NULL;
+ pm = &mfirst;
+
+ c = elf_elfheader (ibfd)->e_phnum;
+ for (i = 0, p = elf_tdata (ibfd)->phdr; i < c; i++, p++)
+ {
+ unsigned int csecs;
+ asection *s;
+ struct elf_segment_map *m;
+ unsigned int isec;
+
+ csecs = 0;
+
+ /* The complicated case when p_vaddr is 0 is to handle the
+ Solaris linker, which generates a PT_INTERP section with
+ p_vaddr and p_memsz set to 0. */
+ for (s = ibfd->sections; s != NULL; s = s->next)
+ if (((s->vma >= p->p_vaddr
+ && (s->vma + s->_raw_size <= p->p_vaddr + p->p_memsz
+ || s->vma + s->_raw_size <= p->p_vaddr + p->p_filesz))
+ || (p->p_vaddr == 0
+ && p->p_filesz > 0
+ && (s->flags & SEC_HAS_CONTENTS) != 0
+ && (bfd_vma) s->filepos >= p->p_offset
+ && ((bfd_vma) s->filepos + s->_raw_size
+ <= p->p_offset + p->p_filesz)))
+ && (s->flags & SEC_ALLOC) != 0
+ && s->output_section != NULL)
+ ++csecs;
+
+ m = ((struct elf_segment_map *)
+ bfd_alloc (obfd,
+ (sizeof (struct elf_segment_map)
+ + (csecs - 1) * sizeof (asection *))));
+ if (m == NULL)
+ return false;
+
+ m->next = NULL;
+ m->p_type = p->p_type;
+ m->p_flags = p->p_flags;
+ m->p_flags_valid = 1;
+ m->p_paddr = p->p_paddr;
+ m->p_paddr_valid = 1;
+
+ m->includes_filehdr = (p->p_offset == 0
+ && p->p_filesz >= iehdr->e_ehsize);
+
+ m->includes_phdrs = (p->p_offset <= (bfd_vma) iehdr->e_phoff
+ && (p->p_offset + p->p_filesz
+ >= ((bfd_vma) iehdr->e_phoff
+ + iehdr->e_phnum * iehdr->e_phentsize)));
+
+ isec = 0;
+ for (s = ibfd->sections; s != NULL; s = s->next)
+ {
+ if (((s->vma >= p->p_vaddr
+ && (s->vma + s->_raw_size <= p->p_vaddr + p->p_memsz
+ || s->vma + s->_raw_size <= p->p_vaddr + p->p_filesz))
+ || (p->p_vaddr == 0
+ && p->p_filesz > 0
+ && (s->flags & SEC_HAS_CONTENTS) != 0
+ && (bfd_vma) s->filepos >= p->p_offset
+ && ((bfd_vma) s->filepos + s->_raw_size
+ <= p->p_offset + p->p_filesz)))
+ && (s->flags & SEC_ALLOC) != 0
+ && s->output_section != NULL)
+ {
+ m->sections[isec] = s->output_section;
+ ++isec;
+ }
+ }
+ BFD_ASSERT (isec == csecs);
+ m->count = csecs;
+
+ *pm = m;
+ pm = &m->next;
+ }
+
+ elf_tdata (obfd)->segment_map = mfirst;
+
+ return true;
+}
+
+/* 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;
+
+ /* Copy over private BFD data if it has not already been copied.
+ This must be done here, rather than in the copy_private_bfd_data
+ entry point, because the latter is called after the section
+ contents have been set, which means that the program headers have
+ already been worked out. */
+ if (elf_tdata (obfd)->segment_map == NULL
+ && elf_tdata (ibfd)->phdr != NULL)
+ {
+ asection *s;
+
+ /* Only set up the segments when all the sections have been set
+ up. */
+ for (s = ibfd->sections; s != NULL; s = s->next)
+ if (s->output_section == NULL)
+ break;
+ if (s == NULL)
+ {
+ if (! copy_private_bfd_data (ibfd, obfd))
+ return false;
+ }
+ }
+
+ 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;
outbound_syms = bfd_alloc (abfd,
(1 + symcount) * bed->s->sizeof_sym);
if (outbound_syms == NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
symtab_hdr->contents = (PTR) outbound_syms;
/* now generate the data (for "contents") */
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))
newsym = (elf_symbol_type *) bfd_zalloc (abfd, sizeof (elf_symbol_type));
if (!newsym)
- {
- bfd_set_error (bfd_error_no_memory);
- return NULL;
- }
+ return NULL;
else
{
newsym->symbol.the_bfd = abfd;
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;
}