2006-09-10 H.J. Lu <hongjiu.lu@intel.com>
[deliverable/binutils-gdb.git] / bfd / elf.c
index 8a725c39edf36e61a8c08842877e9ff6a10f9b97..e47f2667ffcf9e57df25011a9d2748bf410eaf87 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -206,16 +206,32 @@ bfd_elf_hash (const char *namearg)
   return h & 0xffffffff;
 }
 
+/* DT_GNU_HASH hash function.  Do not change this function; you will
+   cause invalid hash tables to be generated.  */
+
+unsigned long
+bfd_elf_gnu_hash (const char *namearg)
+{
+  const unsigned char *name = (const unsigned char *) namearg;
+  unsigned long h = 5381;
+  unsigned char ch;
+
+  while ((ch = *name++) != '\0')
+    h = (h << 5) + h + ch;
+  return h & 0xffffffff;
+}
+
 bfd_boolean
 bfd_elf_mkobject (bfd *abfd)
 {
-  /* This just does initialization.  */
-  /* coff_mkobject zalloc's space for tdata.coff_obj_data ...  */
-  elf_tdata (abfd) = bfd_zalloc (abfd, sizeof (struct elf_obj_tdata));
-  if (elf_tdata (abfd) == 0)
-    return FALSE;
-  /* Since everything is done at close time, do we need any
-     initialization?  */
+  if (abfd->tdata.any == NULL)
+    {
+      abfd->tdata.any = bfd_zalloc (abfd, sizeof (struct elf_obj_tdata));
+      if (abfd->tdata.any == NULL)
+       return FALSE;
+    }
+
+  elf_tdata (abfd)->program_header_size = (bfd_size_type) -1;
 
   return TRUE;
 }
@@ -803,7 +819,7 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
          { "debug",             5  },  /* 'd' */
          { NULL,                0  },  /* 'e' */
          { NULL,                0  },  /* 'f' */
-         { "gnu.linkonce.wi.", 17 },   /* 'g' */
+         { "gnu.linkonce.wi.", 16 },   /* 'g' */
          { NULL,                0  },  /* 'h' */
          { NULL,                0  },  /* 'i' */
          { NULL,                0  },  /* 'j' */
@@ -1239,6 +1255,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
            case DT_AUXILIARY: name = "AUXILIARY"; stringp = TRUE; break;
            case DT_USED: name = "USED"; break;
            case DT_FILTER: name = "FILTER"; stringp = TRUE; break;
+           case DT_GNU_HASH: name = "GNU_HASH"; break;
            }
 
          fprintf (f, "  %-11s ", name);
@@ -1823,6 +1840,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
     case SHT_FINI_ARRAY:       /* .fini_array section.  */
     case SHT_PREINIT_ARRAY:    /* .preinit_array section.  */
     case SHT_GNU_LIBLIST:      /* .gnu.liblist section.  */
+    case SHT_GNU_HASH:         /* .gnu.hash section.  */
       return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
 
     case SHT_DYNAMIC:  /* Dynamic linking information.  */
@@ -2183,11 +2201,20 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
             "`%s' [0x%8x]"),
           abfd, name, hdr->sh_type);
       else if (hdr->sh_type >= SHT_LOOS && hdr->sh_type <= SHT_HIOS)
-       /* FIXME: We should handle this section.  */
-       (*_bfd_error_handler)
-         (_("%B: don't know how to handle OS specific section "
-            "`%s' [0x%8x]"),
-          abfd, name, hdr->sh_type);
+       {
+         /* Unrecognised OS-specific sections.  */
+         if ((hdr->sh_flags & SHF_OS_NONCONFORMING) != 0)
+           /* SHF_OS_NONCONFORMING indicates that special knowledge is
+              required to correctly process the section and the file should 
+              be rejected with an error message.  */
+           (*_bfd_error_handler)
+             (_("%B: don't know how to handle OS specific section "
+                "`%s' [0x%8x]"),
+              abfd, name, hdr->sh_type);
+         else
+           /* Otherwise it should be processed.  */
+           return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
+       }
       else
        /* FIXME: We should handle this section.  */
        (*_bfd_error_handler)
@@ -2295,6 +2322,7 @@ static const struct bfd_elf_special_section special_sections_g[] =
   { ".gnu.version_r", 14,  0, SHT_GNU_verneed, 0 },
   { ".gnu.liblist",   12,  0, SHT_GNU_LIBLIST, SHF_ALLOC },
   { ".gnu.conflict",  13,  0, SHT_RELA,     SHF_ALLOC },
+  { ".gnu.hash",       9,  0, SHT_GNU_HASH, SHF_ALLOC },
   { NULL,              0,  0, 0,            0 }
 };
 
@@ -2811,6 +2839,10 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
     case SHT_GROUP:
       this_hdr->sh_entsize = 4;
       break;
+
+    case SHT_GNU_HASH:
+      this_hdr->sh_entsize = bed->s->arch_size == 64 ? 0 : 4;
+      break;
     }
 
   if ((asect->flags & SEC_ALLOC) != 0)
@@ -3256,6 +3288,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
          break;
 
        case SHT_HASH:
+       case SHT_GNU_HASH:
        case SHT_GNU_versym:
          /* sh_link is the section header index of the symbol table
             this hash table or version table is for.  */
@@ -3589,6 +3622,13 @@ get_program_header_size (bfd *abfd, struct bfd_link_info *info)
     {
       /* We need a PT_DYNAMIC segment.  */
       ++segs;
+      
+      if (elf_tdata (abfd)->relro)
+       {
+         /* We need a PT_GNU_RELRO segment only when there is a
+            PT_DYNAMIC segment.  */
+         ++segs;
+       }
     }
 
   if (elf_tdata (abfd)->eh_frame_hdr)
@@ -3603,12 +3643,6 @@ get_program_header_size (bfd *abfd, struct bfd_link_info *info)
       ++segs;
     }
 
-  if (elf_tdata (abfd)->relro)
-    {
-      /* We need a PT_GNU_RELRO segment.  */
-      ++segs;
-    }
-
   for (s = abfd->sections; s != NULL; s = s->next)
     {
       if ((s->flags & SEC_LOAD) != 0
@@ -3703,41 +3737,41 @@ _bfd_elf_make_dynamic_segment (bfd *abfd, asection *dynsec)
 static bfd_boolean
 elf_modify_segment_map (bfd *abfd, struct bfd_link_info *info)
 {
-  struct elf_segment_map *m;
+  struct elf_segment_map **m;
   const struct elf_backend_data *bed;
 
   /* The placement algorithm assumes that non allocated sections are
      not in PT_LOAD segments.  We ensure this here by removing such
      sections from the segment map.  We also remove excluded
-     sections.  */
-  for (m = elf_tdata (abfd)->segment_map;
-       m != NULL;
-       m = m->next)
+     sections.  Finally, any PT_LOAD segment without sections is
+     removed.  */
+  m = &elf_tdata (abfd)->segment_map;
+  while (*m)
     {
       unsigned int i, new_count;
 
-      new_count = 0;
-      for (i = 0; i < m->count; i ++)
+      for (new_count = 0, i = 0; i < (*m)->count; i++)
        {
-         if ((m->sections[i]->flags & SEC_EXCLUDE) == 0
-             && ((m->sections[i]->flags & SEC_ALLOC) != 0
-                 || m->p_type != PT_LOAD))
+         if (((*m)->sections[i]->flags & SEC_EXCLUDE) == 0
+             && (((*m)->sections[i]->flags & SEC_ALLOC) != 0
+                 || (*m)->p_type != PT_LOAD))
            {
-             if (i != new_count)
-               m->sections[new_count] = m->sections[i];
-
-             new_count ++;
+             (*m)->sections[new_count] = (*m)->sections[i];
+             new_count++;
            }
        }
+      (*m)->count = new_count;
 
-      if (new_count != m->count)
-       m->count = new_count;
+      if ((*m)->p_type == PT_LOAD && (*m)->count == 0)
+       *m = (*m)->next;
+      else
+       m = &(*m)->next;
     }
 
   bed = get_elf_backend_data (abfd);
   if (bed->elf_backend_modify_segment_map != NULL)
     {
-      if (! (*bed->elf_backend_modify_segment_map) (abfd, info))
+      if (!(*bed->elf_backend_modify_segment_map) (abfd, info))
        return FALSE;
     }
 
@@ -3852,7 +3886,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
        {
          bfd_size_type phdr_size = elf_tdata (abfd)->program_header_size;
 
-         if (phdr_size == 0)
+         if (phdr_size == (bfd_size_type) -1)
            phdr_size = get_program_header_size (abfd, info);
          if ((abfd->flags & D_PAGED) == 0
              || sections[0]->lma < phdr_size
@@ -4077,8 +4111,10 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
          pm = &m->next;
        }
 
-      if (elf_tdata (abfd)->relro)
+      if (dynsec != NULL && elf_tdata (abfd)->relro)
        {
+         /* We make a PT_GNU_RELRO segment only when there is a
+            PT_DYNAMIC segment.  */
          amt = sizeof (struct elf_segment_map);
          m = bfd_zalloc (abfd, amt);
          if (m == NULL)
@@ -4227,7 +4263,7 @@ assign_file_positions_for_load_sections (bfd *abfd,
   elf_elfheader (abfd)->e_phentsize = bed->s->sizeof_phdr;
   elf_elfheader (abfd)->e_phnum = alloc;
 
-  if (elf_tdata (abfd)->program_header_size == 0)
+  if (elf_tdata (abfd)->program_header_size == (bfd_size_type) -1)
     elf_tdata (abfd)->program_header_size = alloc * bed->s->sizeof_phdr;
   else
     BFD_ASSERT (elf_tdata (abfd)->program_header_size
@@ -4346,7 +4382,8 @@ assign_file_positions_for_load_sections (bfd *abfd,
                 .tbss, we need to look at the next section to decide
                 whether the segment has any loadable sections.  */
              i = 0;
-             while ((m->sections[i]->flags & SEC_LOAD) == 0)
+             while ((m->sections[i]->flags & SEC_LOAD) == 0
+                    && (m->sections[i]->flags & SEC_HAS_CONTENTS) == 0)
                {
                  if ((m->sections[i]->flags & SEC_THREAD_LOCAL) == 0
                      || ++i >= m->count)
@@ -4515,7 +4552,7 @@ assign_file_positions_for_load_sections (bfd *abfd,
            {
              if (p->p_type == PT_LOAD)
                {
-                 sec->filepos = off;
+                 sec->filepos = off + voff;
                  /* FIXME: The SEC_HAS_CONTENTS test here dates back to
                     1997, and the exact reason for it isn't clear.  One
                     plausible explanation is that it is to work around
@@ -4557,9 +4594,11 @@ assign_file_positions_for_load_sections (bfd *abfd,
                    p->p_memsz += o->offset + o->size;
                }
 
-             if (align > p->p_align
-                 && (p->p_type != PT_LOAD
-                     || (abfd->flags & D_PAGED) == 0))
+             if (p->p_type == PT_GNU_RELRO)
+               p->p_align = 1;
+             else if (align > p->p_align
+                      && (p->p_type != PT_LOAD
+                          || (abfd->flags & D_PAGED) == 0))
                p->p_align = align;
            }
 
@@ -4607,7 +4646,9 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
 
       hdr = *hdrpp;
       if (hdr->bfd_section != NULL
-         && hdr->bfd_section->filepos != 0)
+         && (hdr->bfd_section->filepos != 0
+             || (hdr->sh_type == SHT_NOBITS
+                 && hdr->contents == NULL)))
        hdr->sh_offset = hdr->bfd_section->filepos;
       else if ((hdr->sh_flags & SHF_ALLOC) != 0)
        {
@@ -7063,14 +7104,19 @@ _bfd_elf_sizeof_headers (bfd *abfd, struct bfd_link_info *info)
 
   if (!info->relocatable)
     {
-      struct elf_segment_map *m;
-      bfd_size_type phdr_size = 0;
+      bfd_size_type phdr_size = elf_tdata (abfd)->program_header_size;
 
-      for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
-       phdr_size += bed->s->sizeof_phdr;
+      if (phdr_size == (bfd_size_type) -1)
+       {
+         struct elf_segment_map *m;
+
+         phdr_size = 0;
+         for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
+           phdr_size += bed->s->sizeof_phdr;
 
-      if (phdr_size == 0)
-       phdr_size = get_program_header_size (abfd, info);
+         if (phdr_size == 0)
+           phdr_size = get_program_header_size (abfd, info);
+       }
 
       elf_tdata (abfd)->program_header_size = phdr_size;
       ret += phdr_size;
This page took 0.030348 seconds and 4 git commands to generate.