Based on patches from Ronald F. Guilmette <rfg@monkeys.com>:
[deliverable/binutils-gdb.git] / bfd / elf.c
index ba00bc8d0ce6dd3cfb4b1ea5e7a93928c5fe988c..be1cbc88e5774c0a0c353030f0ac7956cbc1e8ea 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1,5 +1,5 @@
 /* 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.
 
@@ -45,6 +45,7 @@ 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
@@ -82,10 +83,7 @@ elf_read (abfd, offset, size)
   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)
@@ -106,10 +104,7 @@ elf_mkobject (abfd)
   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? */
 
@@ -229,6 +224,7 @@ _bfd_elf_make_section_from_shdr (abfd, hdr, name)
       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)
@@ -339,50 +335,152 @@ _bfd_elf_print_private_bfd_data (abfd, farg)
 {
   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;
+
+      fprintf (f, "\nProgram Header:\n");
+      c = elf_elfheader (abfd)->e_phnum;
+      for (i = 0; i < c; i++, p++)
+       {
+         const char *s;
+         char buf[20];
 
-  c = elf_elfheader (abfd)->e_phnum;
-  for (i = 0; i < c; i++, p++)
+         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 *));
+
+      fprintf (f, "\nDynamic Section:\n");
 
-      switch (p->p_type)
+      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.  */
@@ -440,10 +538,7 @@ _bfd_elf_link_hash_newfunc (entry, table, string)
     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 *)
@@ -459,6 +554,7 @@ _bfd_elf_link_hash_newfunc (entry, table, string)
       ret->weakdef = NULL;
       ret->got_offset = (bfd_vma) -1;
       ret->plt_offset = (bfd_vma) -1;
+      ret->linker_section_pointer = (elf_linker_section_pointers_t *)0;
       ret->type = STT_NOTYPE;
       ret->elf_link_hash_flags = 0;
     }
@@ -497,10 +593,7 @@ _bfd_elf_link_hash_table_create (abfd)
   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))
     {
@@ -586,6 +679,7 @@ bfd_section_from_shdr (abfd, shindex)
     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 */
@@ -762,9 +856,6 @@ bfd_section_from_shdr (abfd, shindex)
       }
       break;
 
-    case SHT_NOTE:
-      break;
-
     case SHT_SHLIB:
       return true;
 
@@ -803,10 +894,7 @@ _bfd_elf_new_section_hook (abfd, sec)
 
   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;
@@ -851,10 +939,7 @@ bfd_section_from_phdr (abfd, hdr, index)
   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)
@@ -885,10 +970,7 @@ bfd_section_from_phdr (abfd, hdr, index)
       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)
@@ -1031,7 +1113,6 @@ elf_fake_sections (abfd, asect, failedptrarg)
       name = bfd_alloc (abfd, sizeof ".rela" + strlen (asect->name));
       if (name == NULL)
        {
-         bfd_set_error (bfd_error_no_memory);
          *failedptr = true;
          return;
        }
@@ -1100,17 +1181,13 @@ assign_section_numbers (abfd)
   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));
@@ -1182,12 +1259,9 @@ assign_section_numbers (abfd)
              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);
@@ -1276,10 +1350,7 @@ elf_map_symbols (abfd)
   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++)
@@ -1356,10 +1427,7 @@ elf_map_symbols (abfd)
              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++)
     {
@@ -1535,16 +1603,20 @@ make_mapping (abfd, sections, from, to)
                   (sizeof (struct elf_segment_map)
                    + (to - from - 1) * sizeof (asection *))));
   if (m == NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return 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;
 
+  if (from == 0)
+    {
+      /* Include the headers in the first PT_LOAD segment.  */
+      m->includes_filehdr = 1;
+      m->includes_phdrs = 1;
+    }
+
   return m;
 }
 
@@ -1574,13 +1646,10 @@ map_sections_to_segments (abfd)
 
   /* 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)
@@ -1610,15 +1679,13 @@ map_sections_to_segments (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;
-       }
+       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;
 
       *pm = m;
       pm = &m->next;
@@ -1626,10 +1693,7 @@ map_sections_to_segments (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;
-       }
+       goto error_return;
       m->next = NULL;
       m->p_type = PT_INTERP;
       m->count = 1;
@@ -1696,10 +1760,7 @@ map_sections_to_segments (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;
-       }
+       goto error_return;
       m->next = NULL;
       m->p_type = PT_DYNAMIC;
       m->count = 1;
@@ -1776,7 +1837,8 @@ assign_file_positions_for_segments (abfd)
   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)
@@ -1785,6 +1847,12 @@ assign_file_positions_for_segments (abfd)
        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;
@@ -1796,11 +1864,6 @@ assign_file_positions_for_segments (abfd)
   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.  */
@@ -1820,15 +1883,15 @@ assign_file_positions_for_segments (abfd)
   phdrs = ((Elf_Internal_Phdr *)
           bfd_alloc (abfd, alloc * sizeof (Elf_Internal_Phdr)));
   if (phdrs == NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
+    return false;
 
   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++)
@@ -1836,12 +1899,22 @@ assign_file_positions_for_segments (abfd)
       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)
@@ -1863,52 +1936,77 @@ assign_file_positions_for_segments (abfd)
       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;
-             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;
-                     p->p_paddr -= off;
-                   }
-                 if (mi->p_type == PT_PHDR)
-                   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;
-                 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;
@@ -1924,15 +2022,18 @@ assign_file_positions_for_segments (abfd)
 
              /* 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;
@@ -1952,6 +2053,7 @@ assign_file_positions_for_segments (abfd)
 
          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)
@@ -1967,20 +2069,27 @@ assign_file_positions_for_segments (abfd)
        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++)
     {
@@ -2023,6 +2132,17 @@ get_program_header_size (abfd)
   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;
@@ -2044,9 +2164,15 @@ get_program_header_size (abfd)
     }
 
   /* 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;
@@ -2184,7 +2310,7 @@ prep_headers (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++)
@@ -2451,6 +2577,111 @@ _bfd_elf_symbol_from_bfd_symbol (abfd, asym_ptr_ptr)
   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.  */
 
@@ -2467,6 +2698,28 @@ _bfd_elf_copy_private_section_data (ibfd, isec, obfd, osec)
       || 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;
 
@@ -2562,10 +2815,7 @@ swap_out_syms (abfd, sttp)
     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") */
@@ -2587,6 +2837,7 @@ swap_out_syms (abfd, sttp)
        bfd_vma value = syms[idx]->value;
        elf_symbol_type *type_ptr;
        flagword flags = syms[idx]->flags;
+       int type;
 
        if (flags & BSF_SECTION_SYM)
          /* Section symbols have no names.  */
@@ -2681,15 +2932,20 @@ swap_out_syms (abfd, sttp)
            sym.st_shndx = shndx;
          }
 
+       if ((flags & BSF_FUNCTION) != 0)
+         type = STT_FUNC;
+       else if ((flags & BSF_OBJECT) != 0)
+         type = STT_OBJECT;
+       else
+         type = STT_NOTYPE;
+
        if (bfd_is_com_section (syms[idx]->section))
-         sym.st_info = ELF_ST_INFO (STB_GLOBAL, STT_OBJECT);
+         sym.st_info = ELF_ST_INFO (STB_GLOBAL, type);
        else if (bfd_is_und_section (syms[idx]->section))
          sym.st_info = ELF_ST_INFO (((flags & BSF_WEAK)
                                      ? STB_WEAK
                                      : STB_GLOBAL),
-                                    ((flags & BSF_FUNCTION)
-                                     ? STT_FUNC
-                                     : STT_NOTYPE));
+                                    type);
        else if (flags & BSF_SECTION_SYM)
          sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
        else if (flags & BSF_FILE)
@@ -2697,7 +2953,6 @@ swap_out_syms (abfd, sttp)
        else
          {
            int bind = STB_LOCAL;
-           int type = STT_OBJECT;
 
            if (flags & BSF_LOCAL)
              bind = STB_LOCAL;
@@ -2706,9 +2961,6 @@ swap_out_syms (abfd, sttp)
            else if (flags & BSF_GLOBAL)
              bind = STB_GLOBAL;
 
-           if (flags & BSF_FUNCTION)
-             type = STT_FUNC;
-
            sym.st_info = ELF_ST_INFO (bind, type);
          }
 
@@ -2832,10 +3084,7 @@ _bfd_elf_make_empty_symbol (abfd)
 
   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;
@@ -2896,15 +3145,26 @@ _bfd_elf_find_nearest_line (abfd,
      CONST char **functionname_ptr;
      unsigned int *line_ptr;
 {
+  boolean found;
   const char *filename;
   asymbol *func;
+  bfd_vma low_func;
   asymbol **p;
 
+  if (! _bfd_stab_section_find_nearest_line (abfd, symbols, section, offset,
+                                            &found, filename_ptr,
+                                            functionname_ptr, line_ptr,
+                                            &elf_tdata (abfd)->line_info))
+    return false;
+  if (found)
+    return true;
+
   if (symbols == NULL)
     return false;
 
   filename = NULL;
   func = NULL;
+  low_func = 0;
 
   for (p = symbols; *p != NULL; p++)
     {
@@ -2923,9 +3183,13 @@ _bfd_elf_find_nearest_line (abfd,
          filename = bfd_asymbol_name (&q->symbol);
          break;
        case STT_FUNC:
-         if (func == NULL
-             || q->symbol.value <= offset)
-           func = (asymbol *) q;
+         if (q->symbol.section == section
+             && q->symbol.value >= low_func
+             && q->symbol.value <= offset)
+           {
+             func = (asymbol *) q;
+             low_func = q->symbol.value;
+           }
          break;
        }
     }
This page took 0.038505 seconds and 4 git commands to generate.