2006-12-13 Paul Brook <paul@codesourcery.com>
[binutils-gdb.git] / bfd / elf.c
index 73a8713e218334000c7e4bc2c1b74c068a2c902f..943db786bbc73bbdc7a5bb5418d5dba8f6626ea3 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1668,7 +1668,7 @@ bfd_elf_get_dyn_lib_class (bfd *abfd)
 }
 
 void
-bfd_elf_set_dyn_lib_class (bfd *abfd, int lib_class)
+bfd_elf_set_dyn_lib_class (bfd *abfd, enum dynamic_lib_link_class lib_class)
 {
   if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
       && bfd_get_format (abfd) == bfd_object)
@@ -2126,13 +2126,11 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
        abfd->flags |= HAS_RELOC;
        return TRUE;
       }
-      break;
 
     case SHT_GNU_verdef:
       elf_dynverdef (abfd) = shindex;
       elf_tdata (abfd)->dynverdef_hdr = *hdr;
       return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
-      break;
 
     case SHT_GNU_versym:
       if (hdr->sh_entsize != sizeof (Elf_External_Versym))
@@ -3175,7 +3173,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
                         s, s->owner);
                      /* Point to the kept section if it has the same
                         size as the discarded one.  */
-                     kept = _bfd_elf_check_kept_section (s);
+                     kept = _bfd_elf_check_kept_section (s, link_info);
                      if (kept == NULL)
                        {
                          bfd_set_error (bfd_error_bad_value);
@@ -4662,13 +4660,15 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
        hdr->sh_offset = hdr->bfd_section->filepos;
       else if ((hdr->sh_flags & SHF_ALLOC) != 0)
        {
-         ((*_bfd_error_handler)
-          (_("%B: warning: allocated section `%s' not in segment"),
-           abfd,
-           (hdr->bfd_section == NULL
-            ? "*unknown*"
-            : hdr->bfd_section->name)));
-         if ((abfd->flags & D_PAGED) != 0)
+         if (hdr->sh_size != 0)
+           ((*_bfd_error_handler)
+            (_("%B: warning: allocated section `%s' not in segment"),
+             abfd,
+             (hdr->bfd_section == NULL
+              ? "*unknown*"
+              : hdr->bfd_section->name)));
+         /* We don't need to page align empty sections.  */
+         if ((abfd->flags & D_PAGED) != 0 && hdr->sh_size != 0)
            off += vma_page_aligned_bias (hdr->sh_addr, off,
                                          bed->maxpagesize);
          else
@@ -5257,13 +5257,12 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
        7. SHF_TLS sections are only in PT_TLS or PT_LOAD segments.
        8. PT_DYNAMIC should not contain empty sections at the beginning
           (with the possible exception of .dynamic).  */
-#define INCLUDE_SECTION_IN_SEGMENT(section, segment, bed)              \
+#define IS_SECTION_IN_INPUT_SEGMENT(section, segment, bed)             \
   ((((segment->p_paddr                                                 \
       ? IS_CONTAINED_BY_LMA (section, segment, segment->p_paddr)       \
       : IS_CONTAINED_BY_VMA (section, segment))                                \
      && (section->flags & SEC_ALLOC) != 0)                             \
     || IS_COREFILE_NOTE (segment, section))                            \
-   && section->output_section != NULL                                  \
    && segment->p_type != PT_GNU_STACK                                  \
    && (segment->p_type != PT_TLS                                       \
        || (section->flags & SEC_THREAD_LOCAL))                         \
@@ -5279,6 +5278,12 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
            == 0))                                                      \
    && ! section->segment_mark)
 
+/* If the output section of a section in the input segment is NULL,
+   it is removed from the corresponding output segment.   */
+#define INCLUDE_SECTION_IN_SEGMENT(section, segment, bed)              \
+  (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed)         \
+   && section->output_section != NULL)
+
   /* Returns TRUE iff seg1 starts after the end of seg2.  */
 #define SEGMENT_AFTER_SEGMENT(seg1, seg2, field)                       \
   (seg1->field >= SEGMENT_END (seg2, seg2->field))
@@ -5386,22 +5391,33 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
       bfd_vma       suggested_lma;
       unsigned int  j;
       bfd_size_type amt;
+      asection *    first_section;
 
       if (segment->p_type == PT_NULL)
        continue;
 
+      first_section = NULL;
       /* Compute how many sections might be placed into this segment.  */
       for (section = ibfd->sections, section_count = 0;
           section != NULL;
           section = section->next)
-       if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed))
-         ++section_count;
+       {
+         /* Find the first section in the input segment, which may be
+            removed from the corresponding output segment.   */
+         if (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed))
+           {
+             if (first_section == NULL)
+               first_section = section;
+             if (section->output_section != NULL)
+               ++section_count;
+           }
+       }
 
       /* Allocate a segment map big enough to contain
         all of the sections we have selected.  */
       amt = sizeof (struct elf_segment_map);
       amt += ((bfd_size_type) section_count - 1) * sizeof (asection *);
-      map = bfd_alloc (obfd, amt);
+      map = bfd_zalloc (obfd, amt);
       if (map == NULL)
        return FALSE;
 
@@ -5411,8 +5427,15 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
       map->p_type        = segment->p_type;
       map->p_flags       = segment->p_flags;
       map->p_flags_valid = 1;
-      map->p_paddr       = segment->p_paddr;
-      map->p_paddr_valid = 1;
+
+      /* If the first section in the input segment is removed, there is
+        no need to preserve segment physical address in the corresponding
+        output segment.  */
+      if (!first_section || first_section->output_section != NULL)
+       {
+         map->p_paddr = segment->p_paddr;
+         map->p_paddr_valid = 1;
+       }
 
       /* Determine if this segment contains the ELF file header
         and if it contains the program headers themselves.  */
@@ -5742,6 +5765,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
 #undef IS_CONTAINED_BY_LMA
 #undef IS_COREFILE_NOTE
 #undef IS_SOLARIS_PT_INTERP
+#undef IS_SECTION_IN_INPUT_SEGMENT
 #undef INCLUDE_SECTION_IN_SEGMENT
 #undef SEGMENT_AFTER_SEGMENT
 #undef SEGMENT_OVERLAPS
@@ -5796,7 +5820,7 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)
       amt = sizeof (struct elf_segment_map);
       if (section_count != 0)
        amt += ((bfd_size_type) section_count - 1) * sizeof (asection *);
-      map = bfd_alloc (obfd, amt);
+      map = bfd_zalloc (obfd, amt);
       if (map == NULL)
        return FALSE;
 
@@ -5950,9 +5974,17 @@ _bfd_elf_init_private_section_data (bfd *ibfd,
      output BFD section flags have been set to something different.
      elf_fake_sections will set ELF section type based on BFD
      section flags.  */
-  if (osec->flags == isec->flags
-      || (osec->flags == 0 && elf_section_type (osec) == SHT_NULL))
-    elf_section_type (osec) = elf_section_type (isec);
+  if (osec->flags == isec->flags || !osec->flags)
+    {
+      BFD_ASSERT (osec->flags == isec->flags 
+                 || (!osec->flags
+                     && elf_section_type (osec) == SHT_NULL));
+      elf_section_type (osec) = elf_section_type (isec);
+    }
+
+  /* FIXME: Is this correct for all OS/PROC specific flags?  */
+  elf_section_flags (osec) |= (elf_section_flags (isec)
+                              & (SHF_MASKOS | SHF_MASKPROC));
 
   /* Set things up for objcopy and relocatable link.  The output
      SHT_GROUP section will have its elf_next_in_group pointing back
@@ -8080,45 +8112,42 @@ elfcore_grok_nto_note (bfd *abfd, Elf_Internal_Note *note)
 /* Function: elfcore_write_note
 
    Inputs:
-     buffer to hold note
+     buffer to hold note, and current size of buffer
      name of note
      type of note
      data for note
      size of data for note
 
+   Writes note to end of buffer.  ELF64 notes are written exactly as
+   for ELF32, despite the current (as of 2006) ELF gabi specifying
+   that they ought to have 8-byte namesz and descsz field, and have
+   8-byte alignment.  Other writers, eg. Linux kernel, do the same.
+
    Return:
-   End of buffer containing note.  */
+   Pointer to realloc'd buffer, *BUFSIZ updated.  */
 
 char *
-elfcore_write_note (bfd  *abfd,
+elfcore_write_note (bfd *abfd,
                    char *buf,
-                   int  *bufsiz,
+                   int *bufsiz,
                    const char *name,
-                   int  type,
+                   int type,
                    const void *input,
-                   int  size)
+                   int size)
 {
   Elf_External_Note *xnp;
   size_t namesz;
-  size_t pad;
   size_t newspace;
-  char *p, *dest;
+  char *dest;
 
   namesz = 0;
-  pad = 0;
   if (name != NULL)
-    {
-      const struct elf_backend_data *bed;
-
-      namesz = strlen (name) + 1;
-      bed = get_elf_backend_data (abfd);
-      pad = -namesz & ((1 << bed->s->log_file_align) - 1);
-    }
+    namesz = strlen (name) + 1;
 
-  newspace = 12 + namesz + pad + size;
+  newspace = 12 + ((namesz + 3) & -4) + ((size + 3) & -4);
 
-  p = realloc (buf, *bufsiz + newspace);
-  dest = p + *bufsiz;
+  buf = realloc (buf, *bufsiz + newspace);
+  dest = buf + *bufsiz;
   *bufsiz += newspace;
   xnp = (Elf_External_Note *) dest;
   H_PUT_32 (abfd, namesz, xnp->namesz);
@@ -8129,14 +8158,20 @@ elfcore_write_note (bfd  *abfd,
     {
       memcpy (dest, name, namesz);
       dest += namesz;
-      while (pad != 0)
+      while (namesz & 3)
        {
          *dest++ = '\0';
-         --pad;
+         ++namesz;
        }
     }
   memcpy (dest, input, size);
-  return p;
+  dest += size;
+  while (size & 3)
+    {
+      *dest++ = '\0';
+      ++size;
+    }
+  return buf;
 }
 
 #if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T)
@@ -8666,7 +8701,8 @@ elf_sym_name_compare (const void *arg1, const void *arg2)
    symbols.  */
 
 bfd_boolean
-bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2)
+bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2,
+                                  struct bfd_link_info *info)
 {
   bfd *bfd1, *bfd2;
   const struct elf_backend_data *bed1, *bed2;
@@ -8722,21 +8758,37 @@ bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2)
   if (symcount1 == 0 || symcount2 == 0)
     return FALSE;
 
-  isymbuf1 = bfd_elf_get_elf_syms (bfd1, hdr1, symcount1, 0,
-                                  NULL, NULL, NULL);
-  isymbuf2 = bfd_elf_get_elf_syms (bfd2, hdr2, symcount2, 0,
-                                  NULL, NULL, NULL);
-
   result = FALSE;
-  if (isymbuf1 == NULL || isymbuf2 == NULL)
-    goto done;
+  isymbuf1 = elf_tdata (bfd1)->symbuf;
+  isymbuf2 = elf_tdata (bfd2)->symbuf;
+
+  if (isymbuf1 == NULL)
+    {
+      isymbuf1 = bfd_elf_get_elf_syms (bfd1, hdr1, symcount1, 0,
+                                      NULL, NULL, NULL);
+      if (isymbuf1 == NULL)
+       goto done;
+      /* Sort symbols by binding and section. Global definitions are at
+        the beginning.  */
+      qsort (isymbuf1, symcount1, sizeof (Elf_Internal_Sym),
+            elf_sort_elf_symbol);
+      if (!info->reduce_memory_overheads)
+       elf_tdata (bfd1)->symbuf = isymbuf1;
+    }
 
-  /* Sort symbols by binding and section. Global definitions are at
-     the beginning.  */
-  qsort (isymbuf1, symcount1, sizeof (Elf_Internal_Sym),
-        elf_sort_elf_symbol);
-  qsort (isymbuf2, symcount2, sizeof (Elf_Internal_Sym),
-        elf_sort_elf_symbol);
+  if (isymbuf2 == NULL)
+    {
+      isymbuf2 = bfd_elf_get_elf_syms (bfd2, hdr2, symcount2, 0,
+                                      NULL, NULL, NULL);
+      if (isymbuf2 == NULL)
+       goto done;
+      /* Sort symbols by binding and section. Global definitions are at
+        the beginning.  */
+      qsort (isymbuf2, symcount2, sizeof (Elf_Internal_Sym),
+            elf_sort_elf_symbol);
+      if (!info->reduce_memory_overheads)
+       elf_tdata (bfd2)->symbuf = isymbuf2;
+    }
 
   /* Count definitions in the section.  */
   count1 = 0;
@@ -8820,10 +8872,13 @@ done:
     free (symtable1);
   if (symtable2)
     free (symtable2);
-  if (isymbuf1)
-    free (isymbuf1);
-  if (isymbuf2)
-    free (isymbuf2);
+  if (info->reduce_memory_overheads)
+    {
+      if (isymbuf1)
+       free (isymbuf1);
+      if (isymbuf2)
+       free (isymbuf2);
+    }
 
   return result;
 }