/* 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.
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)
{
FILE *f = (FILE *) farg;
Elf_Internal_Phdr *p;
- unsigned int i, c;
+ asection *s;
+ bfd_byte *dynbuf = NULL;
p = elf_tdata (abfd)->phdr;
- if (p == NULL)
- return true;
+ if (p != NULL)
+ {
+ unsigned int i, c;
- c = elf_elfheader (abfd)->e_phnum;
- for (i = 0; i < c; i++, p++)
+ 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)
{
- const char *s;
- char buf[20];
+ int elfsec;
+ unsigned long link;
+ bfd_byte *extdyn, *extdynend;
+ size_t extdynsize;
+ void (*swap_dyn_in) PARAMS ((bfd *, const PTR, Elf_Internal_Dyn *));
- switch (p->p_type)
+ 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)
{
- 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;
+ 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");
}
- 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");
+
+ free (dynbuf);
+ dynbuf = NULL;
}
return true;
+
+ error_return:
+ if (dynbuf != NULL)
+ free (dynbuf);
+ return false;
}
/* Display ELF-specific fields of a symbol. */
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 */
}
break;
- case SHT_NOTE:
- break;
-
case SHT_SHLIB:
return true;
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);
m->sections[i - from] = *hdrpp;
m->count = to - from;
+ if (from == 0)
+ {
+ /* Include the headers in the first PT_LOAD segment. */
+ m->includes_filehdr = 1;
+ m->includes_phdrs = 1;
+ }
+
return m;
}
/* Select the allocated sections, and sort them. */
- sections = (asection **) malloc (bfd_count_sections (abfd)
- * sizeof (asection *));
+ sections = (asection **) bfd_malloc (bfd_count_sections (abfd)
+ * sizeof (asection *));
if (sections == NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- goto error_return;
- }
+ goto error_return;
i = 0;
for (s = abfd->sections; s != NULL; s = s->next)
/* 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;
*pm = m;
pm = &m->next;
unsigned int alloc;
Elf_Internal_Phdr *phdrs;
file_ptr off;
- boolean found_load;
+ bfd_vma filehdr_vaddr, filehdr_paddr;
+ bfd_vma phdrs_vaddr, phdrs_paddr;
Elf_Internal_Phdr *p;
if (elf_tdata (abfd)->segment_map == NULL)
return false;
}
+ if (bed->elf_backend_modify_segment_map)
+ {
+ if (! (*bed->elf_backend_modify_segment_map) (abfd))
+ return false;
+ }
+
count = 0;
for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
++count;
if (count == 0)
return true;
- /* 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. */
off = bed->s->sizeof_ehdr;
off += alloc * bed->s->sizeof_phdr;
- found_load = false;
+ 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)
+ 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)
else
p->p_align = 0;
+ p->p_offset = 0;
p->p_filesz = 0;
p->p_memsz = 0;
- if (p->p_type == PT_LOAD)
+ if (m->includes_filehdr)
{
- p->p_offset = off;
+ 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;
+ }
+ }
- if (! found_load)
+ if (m->includes_phdrs)
+ {
+ if (! m->p_flags_valid)
+ p->p_flags |= PF_R;
+ if (m->includes_filehdr)
{
- struct elf_segment_map *mi;
- Elf_Internal_Phdr *pi;
- struct elf_segment_map *mi_phdr;
- 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 (p->p_type == PT_LOAD)
{
- if (mi->p_type == PT_INTERP)
- {
- p->p_offset = 0;
- p->p_filesz = off;
- p->p_memsz = off;
- p->p_vaddr -= off;
- if (! m->p_paddr_valid)
- p->p_paddr -= off;
- }
- if (mi->p_type == PT_PHDR)
- {
- mi_phdr = mi;
- pi_phdr = pi;
- }
+ phdrs_vaddr = p->p_vaddr + bed->s->sizeof_ehdr;
+ phdrs_paddr = p->p_paddr + bed->s->sizeof_ehdr;
}
-
- /* Set up the PT_PHDR addresses. */
- if (pi_phdr != NULL)
+ }
+ else
+ {
+ p->p_offset = bed->s->sizeof_ehdr;
+ if (m->count > 0)
{
- pi_phdr->p_vaddr = p->p_vaddr + bed->s->sizeof_ehdr;
- if (! mi_phdr->p_paddr_valid)
- pi_phdr->p_paddr = p->p_paddr + bed->s->sizeof_ehdr;
+ 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;
+ }
+
+ if (p->p_type == PT_LOAD)
+ {
+ if (! m->includes_filehdr && ! m->includes_phdrs)
+ p->p_offset = off;
+ else
+ {
+ file_ptr adjust;
- found_load = true;
+ adjust = off - (p->p_offset + p->p_filesz);
+ p->p_filesz += adjust;
+ p->p_memsz += adjust;
}
}
- if (! m->p_flags_valid)
- p->p_flags = PF_R;
for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
{
asection *sec;
/* The section VMA must equal the file position modulo
the page size. */
- adjust = (sec->vma - off) % bed->maxpagesize;
- if (adjust != 0)
+ if ((flags & SEC_LOAD) != 0)
{
- if (i == 0)
- abort ();
- p->p_memsz += adjust;
- if ((flags & SEC_LOAD) != 0)
- p->p_filesz += adjust;
- off += adjust;
+ 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 (! m->p_flags_valid)
{
+ p->p_flags |= PF_R;
if ((flags & SEC_CODE) != 0)
p->p_flags |= PF_X;
if ((flags & SEC_READONLY) == 0)
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)
{
- p->p_offset = bed->s->sizeof_ehdr;
- p->p_filesz = count * bed->s->sizeof_phdr;
- p->p_memsz = p->p_filesz;
+ 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;
+ }
}
}
- /* 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++)
{
if (elf_tdata (abfd)->program_header_size != 0)
return elf_tdata (abfd)->program_header_size;
+ if (elf_tdata (abfd)->segment_map != NULL)
+ {
+ 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;
+ }
+
/* Assume we will need exactly two PT_LOAD segments: one for text
and one for data. */
segs = 2;
}
/* 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));
+ if (bed->elf_backend_additional_program_headers)
+ {
+ int a;
+
+ a = (*bed->elf_backend_additional_program_headers) (abfd);
+ if (a == -1)
+ abort ();
+ segs += a;
+ }
elf_tdata (abfd)->program_header_size = segs * bed->s->sizeof_phdr;
return elf_tdata (abfd)->program_header_size;
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++)
bfd *ibfd;
bfd *obfd;
{
+ Elf_Internal_Ehdr *iehdr;
struct elf_segment_map *mfirst;
struct elf_segment_map **pm;
Elf_Internal_Phdr *p;
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++)
{
- struct elf_segment_map *m;
unsigned int csecs;
+ asection *s;
+ struct elf_segment_map *m;
+ unsigned int isec;
csecs = 0;
- if (p->p_type != PT_PHDR)
- {
- asection *s;
- 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->output_section != NULL)
- ++csecs;
- }
+ /* 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,
m->p_paddr = p->p_paddr;
m->p_paddr_valid = 1;
- if (p->p_type != PT_PHDR)
- {
- asection *s;
- unsigned int isec;
+ m->includes_filehdr = (p->p_offset == 0
+ && p->p_filesz >= iehdr->e_ehsize);
- isec = 0;
- for (s = ibfd->sections; s != NULL; s = s->next)
+ 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)
{
- if (s->vma >= p->p_vaddr
- && s->vma + s->_raw_size <= p->p_vaddr + p->p_memsz
- && s->output_section != NULL)
- {
- m->sections[isec] = s->output_section;
- ++isec;
- }
+ m->sections[isec] = s->output_section;
+ ++isec;
}
- qsort (m->sections, (size_t) csecs, sizeof (asection *),
- elf_sort_sections);
- m->count = csecs;
}
+ BFD_ASSERT (isec == csecs);
+ m->count = csecs;
*pm = m;
pm = &m->next;