PR ld/2513
[deliverable/binutils-gdb.git] / bfd / merge.c
index 6b367b5734a1bc85563bc0ef37ab27f7b9a50209..c1795d29112f71c5c8748636919cd71cc9ea33c0 100644 (file)
@@ -1,5 +1,6 @@
 /* SEC_MERGE support.
-   Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+   Copyright 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
    Written by Jakub Jelinek <jakub@redhat.com>.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -16,7 +17,7 @@
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
 
 /* This file contains support for merging duplicate entities within sections,
    as used in ELF SHF_MERGE.  */
@@ -241,7 +242,8 @@ sec_merge_init (unsigned int entsize, bfd_boolean strings)
   if (table == NULL)
     return NULL;
 
-  if (! bfd_hash_table_init (&table->table, sec_merge_hash_newfunc))
+  if (! bfd_hash_table_init_n (&table->table, sec_merge_hash_newfunc,
+                              sizeof (struct sec_merge_hash_entry), 16699))
     {
       free (table);
       return NULL;
@@ -288,24 +290,27 @@ sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry)
 {
   struct sec_merge_sec_info *secinfo = entry->secinfo;
   asection *sec = secinfo->sec;
-  char *pad = "";
+  char *pad = NULL;
   bfd_size_type off = 0;
   int alignment_power = sec->output_section->alignment_power;
 
   if (alignment_power)
-    pad = bfd_zmalloc ((bfd_size_type) 1 << alignment_power);
+    {
+      pad = bfd_zmalloc ((bfd_size_type) 1 << alignment_power);
+      if (pad == NULL)
+       return FALSE;
+    }
 
   for (; entry != NULL && entry->secinfo == secinfo; entry = entry->next)
     {
-      register const char *str;
-      register size_t len;
+      const char *str;
+      bfd_size_type len;
 
-      len = off & (entry->alignment - 1);
-      if (len)
+      len = -off & (entry->alignment - 1);
+      if (len != 0)
        {
-         len = entry->alignment - len;
          if (bfd_bwrite (pad, len, abfd) != len)
-           break;
+           goto err;
          off += len;
        }
 
@@ -313,15 +318,25 @@ sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry)
       len = entry->len;
 
       if (bfd_bwrite (str, len, abfd) != len)
-       break;
+       goto err;
 
       off += len;
     }
 
-  if (alignment_power)
+  /* Trailing alignment needed?  */
+  off = sec->size - off;
+  if (off != 0
+      && bfd_bwrite (pad, off, abfd) != off)
+    goto err;
+
+  if (pad != NULL)
     free (pad);
+  return TRUE;
 
-  return entry == NULL || entry->secinfo != secinfo;
+ err:
+  if (pad != NULL)
+    free (pad);
+  return FALSE;
 }
 
 /* Register a SEC_MERGE section as a candidate for merging.
@@ -340,7 +355,7 @@ _bfd_add_merge_section (bfd *abfd, void **psinfo, asection *sec,
       || (sec->flags & SEC_MERGE) == 0)
     abort ();
 
-  if (sec->_raw_size == 0
+  if (sec->size == 0
       || (sec->flags & SEC_EXCLUDE) != 0
       || sec->entsize == 0)
     return TRUE;
@@ -391,7 +406,7 @@ _bfd_add_merge_section (bfd *abfd, void **psinfo, asection *sec,
 
   /* Read the section from abfd.  */
 
-  amt = sizeof (struct sec_merge_sec_info) + sec->_raw_size - 1;
+  amt = sizeof (struct sec_merge_sec_info) + sec->size - 1;
   *psecinfo = bfd_alloc (abfd, amt);
   if (*psecinfo == NULL)
     goto error_return;
@@ -410,8 +425,9 @@ _bfd_add_merge_section (bfd *abfd, void **psinfo, asection *sec,
   secinfo->htab = sinfo->htab;
   secinfo->first_str = NULL;
 
+  sec->rawsize = sec->size;
   if (! bfd_get_section_contents (sec->owner, sec, secinfo->contents,
-                                 0, sec->_raw_size))
+                                 0, sec->size))
     goto error_return;
 
   return TRUE;
@@ -434,7 +450,7 @@ record_section (struct sec_merge_info *sinfo,
   unsigned int align, i;
 
   align = sec->alignment_power;
-  end = secinfo->contents + sec->_raw_size;
+  end = secinfo->contents + sec->size;
   nul = FALSE;
   mask = ((bfd_vma) 1 << align) - 1;
   if (sec->flags & SEC_STRINGS)
@@ -445,7 +461,8 @@ record_section (struct sec_merge_info *sinfo,
          eltalign = ((eltalign ^ (eltalign - 1)) + 1) >> 1;
          if (!eltalign || eltalign > mask)
            eltalign = mask + 1;
-         entry = sec_merge_add (sinfo->htab, p, (unsigned) eltalign, secinfo);
+         entry = sec_merge_add (sinfo->htab, (char *) p, (unsigned) eltalign,
+                                secinfo);
          if (! entry)
            goto error_return;
          p += entry->len;
@@ -476,7 +493,7 @@ record_section (struct sec_merge_info *sinfo,
                  if (!nul && !((p - secinfo->contents) & mask))
                    {
                      nul = TRUE;
-                     entry = sec_merge_add (sinfo->htab, p,
+                     entry = sec_merge_add (sinfo->htab, (char *) p,
                                             (unsigned) mask + 1, secinfo);
                      if (! entry)
                        goto error_return;
@@ -490,7 +507,7 @@ record_section (struct sec_merge_info *sinfo,
     {
       for (p = secinfo->contents; p < end; p += sec->entsize)
        {
-         entry = sec_merge_add (sinfo->htab, p, 1, secinfo);
+         entry = sec_merge_add (sinfo->htab, (char *) p, 1, secinfo);
          if (! entry)
            goto error_return;
        }
@@ -511,8 +528,8 @@ strrevcmp (const void *a, const void *b)
   struct sec_merge_hash_entry *B = *(struct sec_merge_hash_entry **) b;
   unsigned int lenA = A->len;
   unsigned int lenB = B->len;
-  const unsigned char *s = A->root.string + lenA - 1;
-  const unsigned char *t = B->root.string + lenB - 1;
+  const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1;
+  const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1;
   int l = lenA < lenB ? lenA : lenB;
 
   while (l)
@@ -536,8 +553,8 @@ strrevcmp_align (const void *a, const void *b)
   struct sec_merge_hash_entry *B = *(struct sec_merge_hash_entry **) b;
   unsigned int lenA = A->len;
   unsigned int lenB = B->len;
-  const unsigned char *s = A->root.string + lenA - 1;
-  const unsigned char *t = B->root.string + lenB - 1;
+  const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1;
+  const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1;
   int l = lenA < lenB ? lenA : lenB;
   int tail_align = (lenA & (A->alignment - 1)) - (lenB & (A->alignment - 1));
 
@@ -638,7 +655,7 @@ alloc_failure:
     {
       if (e->secinfo != secinfo)
        {
-         secinfo->sec->_cooked_size = size;
+         secinfo->sec->size = size;
          secinfo = e->secinfo;
        }
       if (e->alignment)
@@ -653,7 +670,12 @@ alloc_failure:
          size += e->len;
        }
     }
-  secinfo->sec->_cooked_size = size;
+  secinfo->sec->size = size;
+  if (secinfo->sec->alignment_power != 0)
+    {
+      bfd_size_type align = (bfd_size_type) 1 << secinfo->sec->alignment_power;
+      secinfo->sec->size = (secinfo->sec->size + align - 1) & -align;
+    }
 
   /* And now adjust the rest, removing them from the chain (but not hashtable)
      at the same time.  */
@@ -676,8 +698,10 @@ alloc_failure:
    with _bfd_merge_section.  */
 
 bfd_boolean
-_bfd_merge_sections (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info,
-                    void *xsinfo, void (*remove_hook) (bfd *, asection *))
+_bfd_merge_sections (bfd *abfd ATTRIBUTE_UNUSED,
+                    struct bfd_link_info *info ATTRIBUTE_UNUSED,
+                    void *xsinfo,
+                    void (*remove_hook) (bfd *, asection *))
 {
   struct sec_merge_info *sinfo;
 
@@ -725,7 +749,7 @@ _bfd_merge_sections (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info,
              if (e->secinfo->first_str == NULL)
                {
                  if (secinfo)
-                   secinfo->sec->_cooked_size = size;
+                   secinfo->sec->size = size;
                  e->secinfo->first_str = e;
                  size = 0;
                }
@@ -735,14 +759,14 @@ _bfd_merge_sections (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info,
              size += e->len;
              secinfo = e->secinfo;
            }
-         secinfo->sec->_cooked_size = size;
+         secinfo->sec->size = size;
        }
 
        /* Finally remove all input sections which have not made it into
           the hash table at all.  */
        for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next)
          if (secinfo->first_str == NULL)
-           _bfd_strip_section_from_output (info, secinfo->sec);
+           secinfo->sec->flags |= SEC_EXCLUDE;
     }
 
   return TRUE;
@@ -786,15 +810,15 @@ _bfd_merged_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, asection **psec,
 
   secinfo = (struct sec_merge_sec_info *) psecinfo;
 
-  if (offset >= sec->_raw_size)
+  if (offset >= sec->rawsize)
     {
-      if (offset > sec->_raw_size)
+      if (offset > sec->rawsize)
        {
          (*_bfd_error_handler)
            (_("%s: access beyond end of merged section (%ld)"),
             bfd_get_filename (sec->owner), (long) offset);
        }
-      return (secinfo->first_str ? sec->_cooked_size : 0);
+      return secinfo->first_str ? sec->size : 0;
     }
 
   if (secinfo->htab->strings)
@@ -828,7 +852,7 @@ _bfd_merged_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, asection **psec,
     {
       p = secinfo->contents + (offset / sec->entsize) * sec->entsize;
     }
-  entry = sec_merge_hash_lookup (secinfo->htab, p, 0, FALSE);
+  entry = sec_merge_hash_lookup (secinfo->htab, (char *) p, 0, FALSE);
   if (!entry)
     {
       if (! secinfo->htab->strings)
This page took 0.028074 seconds and 4 git commands to generate.