This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[PATCH] SHF_MERGE string suffix merging


Hi!

The following patch implements suffix merging in SHF_MERGE|SHF_STRINGS
sections, so if there is a "foobar" string and "bar" string, "bar" will be
actually "foobar" + 3.
Also, it turned out that current SHF_MERGE support does not cope well with
e.g. GC sections, so I've changed the merging a little bit.
During add_object_symbols, SEC_MERGE sections are basically just registered
for merging (they are assigned a corresponding hash table (unique for each
name/SEC_STRINGS/entsize couple)).
Then, during linking after GC is done but before sections are assigned
output sections bfd_merge_sections is called, which does the actual merging,
finding identical strings or strings where one is a suffix of another one.
Initially, I've tried to do this from size_dynamic_sections, unfortunately
it turned out that it is too late in the game, because section removal is
hard at that point (and setting _cooked_size to 0 does not work either :( ).
So I've added a new bfd hook (which is unfortunate, but I saw no other
solution).
The suffix merging is done with two hashtables which are freed right after
the suffix discovery. Basically, things are sorted by length, longest first,
then each string longer than 3 characters is entered into a "last 4
characters equal" hash table and looking for hits, plus the same for last
character only (but this time only look for hits if inserting 3 character
long or shorter string). If a suffix hit is found, then the string entry is
not deleted from the hash table, but is just adjusted so that it points to
the longer strings' section and offset (plus delta). Looking from largest to
shortest is one of the advantages of doing the merging once all strings are
collected - otherwise we'd have to search all strings with identical
suffixes on each string addition.

The patch has been tested on i386-*-linux, using gcc with -fmerge-constants
patch.

2001-05-04  Jakub Jelinek  <jakub@redhat.com>

	* merge.c (struct sec_merge_hash_entry): Add u.entsize and u.suffix
	fields, change sec into secinfo.
	(struct sec_merge_info): Add chain, remove last fields.
	(struct sec_merge_sec_info): Add next, sec, psecinfo fields.
	(sec_merge_hash_lookup): If lookup could not use a string only
	because it has bad alignment, mark the old string for deletion.
	(sec_merge_add): Add secinfo argument. Don't compute entry's
	position, instead record the section.
	(sec_merge_emit): Update for the sec into secinfo change in
	struct sec_merge_hash_entry.
	(_bfd_merge_section): Only record the section for merging, defer
	putting strings into the hash table.
	(cmplengthentry, last4_eq, last_eq, record_section, merge_strings,
	_bfd_merge_sections): New functions.
	(_bfd_merged_section_offset): Update for the sec_merge_hash_entry
	changes.
	* libbfd-in.h (_bfd_merge_sections): Add prototype.
	(_bfd_nolink_bfd_merge_sections): Define.
	* libbfd.h: Likewise.
	(bfd_generic_merge_sections): Add prototype.
	* targets.c (BFD_JUMP_TABLE_LINK): Add _bfd_merge_sections.
	(struct bfd_target): Likewise.
	* bfd.c (bfd_merge_sections): Define.
	* bfd-in2.h: Rebuilt.
	* elf.c (_bfd_elf_merge_sections): New function.
	* elf-bfd.h (_bfd_elf_merge_sections): Add prototype.
	* elfxx-target.h (bfd_elfNN_bfd_merge_sections): Define.
	* reloc.c (bfd_generic_merge_sections): New function.
	* vms.c (vms_bfd_merge_sections): New function.
	* aout-adobe.c (aout_32_bfd_merge_sections): Define.
	* aout-target.h (MY_bfd_merge_sections): Define.
	* aout-tic30.c (MY_bfd_merge_sections): Define.
	* binary.c (binary_bfd_merge_sections): Define.
	* bout.c (b_out_bfd_merge_sections): Define.
	* coff-alpha.c (_bfd_ecoff_bfd_merge_sections): Define.
	* coffcode.c (coff_bfd_merge_sections): Define.
	* coff-mips.c (_bfd_ecoff_bfd_merge_sections): Define.
	* i386msdos.c (msdos_bfd_merge_sections): Define.
	* i386os9k.c (os9k_bfd_merge_sections): Define.
	* ieee.c (ieee_bfd_merge_sections): Define.
	* ihex.c (ihex_bfd_merge_sections): Define.
	* nlm-target.h (nlm_bfd_merge_sections): Define.
	* oasys.c (oasys_bfd_merge_sections): Define.
	* ppcboot.c (ppcboot_bfd_merge_sections): Define.
	* som.c (som_bfd_merge_sections): Define.
	* srec.c (srec_bfd_merge_sections): Define.
	* tekhex.c (tekhex_bfd_merge_sections): Define.
	* versados.c (versados_bfd_merge_sections): Define.
	* xcoff-target.h (_bfd_xcoff_bfd_merge_sections): Define.

	* ldlang.c (lang_process): Call bfd_merge_sections.

--- bfd/merge.c.jj	Fri Apr 20 14:49:03 2001
+++ bfd/merge.c	Thu May  3 18:56:21 2001
@@ -24,9 +24,12 @@ Foundation, Inc., 59 Temple Place - Suit
 #include "bfd.h"
 #include "sysdep.h"
 #include "libbfd.h"
+#include "hashtab.h"
 
 #include <ctype.h>
 
+struct sec_merge_sec_info;
+
 /* An entry in the section merge hash table.  */
 
 struct sec_merge_hash_entry
@@ -37,10 +40,16 @@ struct sec_merge_hash_entry
   /* Start of this string needs to be aligned to
      alignment octets (not 1 << align).  */
   unsigned int alignment;
-  /* Index within the merged section.  */
-  bfd_size_type index;
+  union {
+    /* Index within the merged section.  */
+    bfd_size_type index;
+    /* Entity size (if present in suffix hash tables).  */
+    unsigned int entsize;
+    /* Entry this is a suffix of (if alignment is 0).  */
+    struct sec_merge_hash_entry *suffix;
+  } u;
   /* Which section is it in.  */
-  asection *sec;
+  struct sec_merge_sec_info *secinfo;
   /* Next entity in the hash table.  */
   struct sec_merge_hash_entry *next;
 };
@@ -66,14 +75,20 @@ struct sec_merge_info
 {
   /* Chain of sec_merge_infos.  */
   struct sec_merge_info *next;
+  /* Chain of sec_merge_sec_infos.  */
+  struct sec_merge_sec_info *chain;
   /* A hash table used to hold section content.  */
   struct sec_merge_hash *htab;
-  /* The last section attempted for merge.  */
-  asection *last;
 };
 
 struct sec_merge_sec_info
 {
+  /* Chain of sec_merge_sec_infos.  */
+  struct sec_merge_sec_info *next;
+  /* The corresponding section.  */
+  asection *sec;
+  /* Pointer to merge_info pointing to us.  */
+  PTR *psecinfo;
   /* A hash table used to hold section content.  */
   struct sec_merge_hash *htab;
   /* First string in this section.  */
@@ -89,7 +104,8 @@ static struct sec_merge_hash_entry *sec_
 static struct sec_merge_hash *sec_merge_init
   PARAMS ((unsigned int, boolean));
 static struct sec_merge_hash_entry *sec_merge_add
-  PARAMS ((struct sec_merge_hash *, const char *, unsigned int));
+  PARAMS ((struct sec_merge_hash *, const char *, unsigned int,
+	   struct sec_merge_sec_info *));
 static boolean sec_merge_emit
   PARAMS ((bfd *, struct sec_merge_hash_entry *));
 
@@ -118,9 +134,9 @@ sec_merge_hash_newfunc (entry, table, st
   if (ret)
     {
       /* Initialize the local fields.  */
-      ret->index = (bfd_size_type) -1;
+      ret->u.suffix = NULL;
       ret->alignment = 0;
-      ret->sec = NULL;
+      ret->secinfo = NULL;
       ret->next = NULL;
     }
 
@@ -202,11 +218,14 @@ sec_merge_hash_lookup (table, string, al
 	  && memcmp (hashp->root.string, string, len) == 0)
 	{
 	  /* If the string we found does not have at least the required
-	     alignment, we need to insert another copy.
-	     FIXME: The old copy could be removed and the space allocated
-	     for it filled by some new string (similarly with padding).  */
+	     alignment, we need to insert another copy.  */
 	  if (hashp->alignment < alignment)
-	    break;
+	    {
+	      /*  Mark the less aligned copy as deleted.  */
+	      hashp->len = 0;
+	      hashp->alignment = 0;
+	      break;
+	    }
 	  return hashp;
 	}
     }
@@ -262,10 +281,11 @@ sec_merge_init (entsize, strings)
    already present.  */
 
 static struct sec_merge_hash_entry *
-sec_merge_add (tab, str, alignment)
+sec_merge_add (tab, str, alignment, secinfo)
      struct sec_merge_hash *tab;
      const char *str;
      unsigned int alignment;
+     struct sec_merge_sec_info *secinfo;
 {
   register struct sec_merge_hash_entry *entry;
 
@@ -273,11 +293,10 @@ sec_merge_add (tab, str, alignment)
   if (entry == NULL)
     return NULL;
 
-  if (entry->index == (bfd_size_type) -1)
+  if (entry->secinfo == NULL)
     {
-      tab->size = (tab->size + alignment - 1) & ~((bfd_vma) alignment - 1);
-      entry->index = tab->size;
-      tab->size += entry->len;
+      tab->size++;
+      entry->secinfo = secinfo;
       if (tab->first == NULL)
 	tab->first = entry;
       else
@@ -293,7 +312,8 @@ sec_merge_emit (abfd, entry)
      register bfd *abfd;
      struct sec_merge_hash_entry *entry;
 {
-  asection *sec = entry->sec;
+  struct sec_merge_sec_info *secinfo = entry->secinfo;
+  asection *sec = secinfo->sec;
   char *pad = "";
   bfd_size_type off = 0;
   int alignment_power = bfd_get_section_alignment (abfd, sec->output_section);
@@ -301,7 +321,7 @@ sec_merge_emit (abfd, entry)
   if (alignment_power)
     pad = bfd_zmalloc (1 << alignment_power);
 
-  for (; entry != NULL && entry->sec == sec; entry = entry->next)
+  for (; entry != NULL && entry->secinfo == secinfo; entry = entry->next)
     {
       register const char *str;
       register size_t len;
@@ -327,7 +347,7 @@ sec_merge_emit (abfd, entry)
   if (alignment_power)
     free (pad);
 
-  return entry == NULL || entry->sec != sec;
+  return entry == NULL || entry->secinfo != secinfo;
 }
 
 /* This function is called for each input file from the add_symbols
@@ -340,15 +360,12 @@ _bfd_merge_section (abfd, psinfo, sec, p
      asection *sec;
      PTR *psecinfo;
 {
-  boolean first, nul;
   struct sec_merge_info *sinfo;
   struct sec_merge_sec_info *secinfo;
-  unsigned char *p, *end;
-  bfd_vma mask, eltalign;
   unsigned int align;
-  unsigned int i;
 
   if (sec->_raw_size == 0
+      || (sec->flags & SEC_EXCLUDE)
       || (sec->flags & SEC_MERGE) == 0
       || sec->entsize == 0)
     return true;
@@ -367,7 +384,7 @@ _bfd_merge_section (abfd, psinfo, sec, p
       return true;
     }
 
-  align = bfd_get_section_alignment (abfd, sec);
+  align = bfd_get_section_alignment (sec->owner, sec);
   if ((sec->entsize < (unsigned int)(1 << align)
        && ((sec->entsize & (sec->entsize - 1))
 	   || !(sec->flags & SEC_STRINGS)))
@@ -383,23 +400,22 @@ _bfd_merge_section (abfd, psinfo, sec, p
       return true;
     }
 
-  first = false;
-
   for (sinfo = (struct sec_merge_info *) *psinfo; sinfo; sinfo = sinfo->next)
-    if (! ((sinfo->last->flags ^ sec->flags) & (SEC_MERGE | SEC_STRINGS))
-	&& sinfo->last->entsize == sec->entsize
-	&& ! strcmp (sinfo->last->name, sec->name))
+    if ((secinfo = sinfo->chain)
+	&& ! ((secinfo->sec->flags ^ sec->flags) & (SEC_MERGE | SEC_STRINGS))
+	&& secinfo->sec->entsize == sec->entsize
+	&& ! strcmp (secinfo->sec->name, sec->name))
       break;
 
   if (sinfo == NULL)
     {
       /* Initialize the information we need to keep track of.  */
-      first = true;
       sinfo = (struct sec_merge_info *)
 	      bfd_alloc (abfd, sizeof (struct sec_merge_info));
       if (sinfo == NULL)
 	goto error_return;
       sinfo->next = (struct sec_merge_info *) *psinfo;
+      sinfo->chain = NULL;
       *psinfo = (PTR) sinfo;
       sinfo->htab =
 	sec_merge_init (sec->entsize, (sec->flags & SEC_STRINGS));
@@ -415,14 +431,121 @@ _bfd_merge_section (abfd, psinfo, sec, p
     goto error_return;
 
   secinfo = (struct sec_merge_sec_info *)*psecinfo;
+  if (sinfo->chain)
+    {
+      secinfo->next = sinfo->chain->next;
+      sinfo->chain->next = secinfo;
+    }
+  else
+    secinfo->next = secinfo;
+  sinfo->chain = secinfo;
+  secinfo->sec = sec;
+  secinfo->psecinfo = psecinfo;
   secinfo->htab = sinfo->htab;
-  sinfo->htab->size = 0;
   secinfo->first = NULL;
 
-  if (! bfd_get_section_contents (abfd, sec, secinfo->contents, 0,
+  if (! bfd_get_section_contents (sec->owner, sec, secinfo->contents, 0,
 				  sec->_raw_size))
     goto error_return;
 
+  return true;
+
+ error_return:
+  *psecinfo = NULL;
+  return false;
+}
+
+/* Compare two sec_merge_hash_entry structures.  This is called via qsort.  */
+
+static int
+cmplengthentry (a, b)
+     const PTR a;
+     const PTR b;
+{
+  struct sec_merge_hash_entry * A = *(struct sec_merge_hash_entry **) a;
+  struct sec_merge_hash_entry * B = *(struct sec_merge_hash_entry **) b;
+              
+  if (A->len < B->len)
+    return 1;
+  else if (A->len > B->len)
+    return -1;
+
+  return memcmp (A->root.string, B->root.string, A->len);
+}
+
+static int
+last4_eq (a, b)
+     const void *a, *b;
+{
+  struct sec_merge_hash_entry * A = (struct sec_merge_hash_entry *) a;
+  struct sec_merge_hash_entry * B = (struct sec_merge_hash_entry *) b;
+
+  if (memcmp (A->root.string + A->len - 5 * A->u.entsize,
+	      B->root.string + B->len - 5 * A->u.entsize,
+	      4 * A->u.entsize) != 0)
+    /* This was a hashtable collision.  */
+    return 0;
+
+  if (A->len <= B->len)
+    /* B cannot be a suffix of A unless A is equal to B, which is quaranteed
+       not to be equal by the hash table.  */
+    return 0;
+
+  if (A->alignment < B->alignment
+      || ((A->len - B->len) & (B->alignment - 1)))
+    /* The suffix is not sufficiently aligned.  */
+    return 0;
+
+  return memcmp (A->root.string + (A->len - B->len),
+		 B->root.string, B->len - 5 * A->u.entsize) == 0;
+}
+
+static int
+last_eq (a, b)
+     const void *a, *b;
+{
+  struct sec_merge_hash_entry * A = (struct sec_merge_hash_entry *) a;
+  struct sec_merge_hash_entry * B = (struct sec_merge_hash_entry *) b;
+
+  if (B->len >= 5 * A->u.entsize)
+    /* Longer strings are just pushed into the hash table,
+       they'll be used when looking up for very short strings.  */
+    return 0;
+
+  if (memcmp (A->root.string + A->len - 2 * A->u.entsize,
+	      B->root.string + B->len - 2 * A->u.entsize,
+	      A->u.entsize) != 0)
+    /* This was a hashtable collision.  */
+    return 0;
+
+  if (A->len <= B->len)
+    /* B cannot be a suffix of A unless A is equal to B, which is quaranteed
+       not to be equal by the hash table.  */
+    return 0;
+
+  if (A->alignment < B->alignment
+      || ((A->len - B->len) & (B->alignment - 1)))
+    /* The suffix is not sufficiently aligned.  */
+    return 0;
+
+  return memcmp (A->root.string + (A->len - B->len),
+		 B->root.string, B->len - 2 * A->u.entsize) == 0;
+}
+
+/* Record one section into the hash table.  */
+static boolean
+record_section (sinfo, secinfo)
+     struct sec_merge_info *sinfo;
+     struct sec_merge_sec_info *secinfo;
+{
+  asection *sec = secinfo->sec;
+  struct sec_merge_hash_entry *entry;
+  boolean nul;
+  unsigned char *p, *end;
+  bfd_vma mask, eltalign;
+  unsigned int align, i;
+
+  align = bfd_get_section_alignment (sec->owner, sec);
   end = secinfo->contents + sec->_raw_size;
   nul = false;
   mask = ((bfd_vma)1 << align) - 1;
@@ -430,19 +553,13 @@ _bfd_merge_section (abfd, psinfo, sec, p
     {
       for (p = secinfo->contents; p < end;)
 	{
-	  struct sec_merge_hash_entry *entry;
-
 	  eltalign = p - secinfo->contents;
 	  eltalign = ((eltalign ^ (eltalign - 1)) + 1) >> 1;
 	  if (!eltalign || eltalign > mask)
 	    eltalign = mask + 1;
-	  entry = sec_merge_add (sinfo->htab, p, eltalign);
-	  if (entry->sec == NULL)
-	    {
-	      if (secinfo->first == NULL)
-		secinfo->first = entry;
-	      entry->sec = sec;
-	    }
+	  entry = sec_merge_add (sinfo->htab, p, eltalign, secinfo);
+	  if (! entry)
+	    goto error_return;
 	  p += entry->len;
 	  if (sec->entsize == 1)
 	    {
@@ -451,13 +568,10 @@ _bfd_merge_section (abfd, psinfo, sec, p
 		  if (!nul && !((p - secinfo->contents) & mask))
 		    {
 		      nul = true;
-		      entry = sec_merge_add (sinfo->htab, "", mask + 1);
-		      if (entry->sec == NULL)
-		        {
-			  if (secinfo->first == NULL)
-			    secinfo->first = entry;
-			  entry->sec = sec;
-		        }
+		      entry = sec_merge_add (sinfo->htab, "", mask + 1,
+					     secinfo);
+		      if (! entry)
+			goto error_return;
 		    }
 		  p++;
 	        }
@@ -474,13 +588,10 @@ _bfd_merge_section (abfd, psinfo, sec, p
 		  if (!nul && !((p - secinfo->contents) & mask))
 		    {
 		      nul = true;
-		      entry = sec_merge_add (sinfo->htab, p, mask + 1);
-		      if (entry->sec == NULL)
-			{
-			  if (secinfo->first == NULL)
-			    secinfo->first = entry;
-			  entry->sec = sec;
-			}
+		      entry = sec_merge_add (sinfo->htab, p, mask + 1,
+					     secinfo);
+		      if (! entry)
+			goto error_return;
 		    }
 		  p += sec->entsize;
 		}
@@ -491,29 +602,235 @@ _bfd_merge_section (abfd, psinfo, sec, p
     {
       for (p = secinfo->contents; p < end; p += sec->entsize)
 	{
-	  struct sec_merge_hash_entry *entry;
+	  entry = sec_merge_add (sinfo->htab, p, 1, secinfo);
+	  if (! entry)
+	    goto error_return;
+	}
+    }
+
+  return true;
 
-	  entry = sec_merge_add (sinfo->htab, p, 1);
-	  if (entry->sec == NULL)
+error_return:
+  for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next)
+    *secinfo->psecinfo = NULL;
+  return false;
+}
+
+/* This is a helper function for _bfd_merge_sections.  It attempts to
+   merge strings matching suffixes of longer strings.  */
+static void
+merge_strings (sinfo)
+     struct sec_merge_info *sinfo;
+{
+  struct sec_merge_hash_entry **array, **a, **end, *e;
+  struct sec_merge_sec_info *secinfo;
+  htab_t lasttab = NULL, last4tab = NULL;
+  bfd_size_type size;
+
+  /* Now sort the strings by length, longest first.  */
+  array = (struct sec_merge_hash_entry **)
+	  malloc (sinfo->htab->size
+		  * sizeof (struct sec_merge_hash_entry *));
+  if (array == NULL)
+    goto alloc_failure;
+
+  for (e = sinfo->htab->first, a = array; e; e = e->next)
+    if (e->alignment)
+      *a++ = e;
+
+  sinfo->htab->size = a - array;
+
+  qsort (array, sinfo->htab->size, sizeof (struct sec_merge_hash_entry *),
+	 cmplengthentry);
+
+  last4tab = htab_create (sinfo->htab->size * 4, NULL, last4_eq, NULL);
+  lasttab = htab_create (sinfo->htab->size * 4, NULL, last_eq, NULL);
+  if (lasttab == NULL || last4tab == NULL)
+    goto alloc_failure;
+
+  /* Now insert the strings into hash tables (strings with last 4 characters
+     and strings with last character equal), look for longer strings which
+     we're suffix of.  */
+  for (a = array, end = array + sinfo->htab->size; a < end; a++)
+    {
+      register hashval_t hash;
+      unsigned int c;
+      unsigned int i;
+      const unsigned char *s;
+      PTR *p;
+
+      e = *a;
+      e->u.entsize = sinfo->htab->entsize;
+      if (e->len <= e->u.entsize)
+	break;
+      if (e->len > 4 * e->u.entsize)
+	{
+	  s = e->root.string + e->len - e->u.entsize;
+	  hash = 0;
+	  for (i = 0; i < 4 * e->u.entsize; i++)
 	    {
-	      if (secinfo->first == NULL)
-		secinfo->first = entry;
-	      entry->sec = sec;
+	      c = *--s;
+	      hash += c + (c << 17);
+	      hash ^= hash >> 2;
+	    }
+	  p = htab_find_slot_with_hash (last4tab, e, hash, INSERT);
+	  if (p == NULL)
+	    goto alloc_failure;
+	  if (*p)
+	    {
+	      struct sec_merge_hash_entry *ent;
+
+	      ent = (struct sec_merge_hash_entry *) *p;
+	      e->u.suffix = ent;
+	      e->alignment = 0;
+	      continue;
 	    }
+	  else
+	    *p = (PTR) e;
+	}
+      s = e->root.string + e->len - e->u.entsize;
+      hash = 0;
+      for (i = 0; i < e->u.entsize; i++)
+	{
+	  c = *--s;
+	  hash += c + (c << 17);
+	  hash ^= hash >> 2;
+	}
+      p = htab_find_slot_with_hash (lasttab, e, hash, INSERT);
+      if (p == NULL)
+	goto alloc_failure;
+      if (*p)
+	{
+	  struct sec_merge_hash_entry *ent;
+
+	  ent = (struct sec_merge_hash_entry *) *p;
+	  e->u.suffix = ent;
+	  e->alignment = 0;
 	}
+      else
+	*p = (PTR) e;
     }
 
-  sec->_cooked_size = sinfo->htab->size;
-  if (!sec->_cooked_size)
-    sec->flags |= SEC_EXCLUDE;
-  sinfo->last = sec;
-  return true;
+alloc_failure:
+  if (array)
+    free (array);
+  if (lasttab)
+    htab_delete (lasttab);
+  if (last4tab)
+    htab_delete (last4tab);
+
+  /* Now assign positions to the strings we want to keep.  */
+  size = 0;
+  secinfo = sinfo->htab->first->secinfo;
+  for (e = sinfo->htab->first; e; e = e->next)
+    {
+      if (e->secinfo != secinfo)
+	{
+	  secinfo->sec->_cooked_size = size;
+	  secinfo = e->secinfo;
+	}
+      if (e->alignment)
+	{
+	  if (e->secinfo->first == NULL)
+	    {
+	      e->secinfo->first = e;
+	      size = 0;
+	    }
+	  size = (size + e->alignment - 1) & ~((bfd_vma) e->alignment - 1);
+	  e->u.index = size;
+	  size += e->len;
+	}
+    }
+  secinfo->sec->_cooked_size = size;
 
- error_return:
-  if (*psecinfo != NULL)
-    free (*psecinfo);
-  *psecinfo = NULL;
-  return false;
+  /* And now adjust the rest, removing them from the chain (but not hashtable)
+     at the same time.  */
+  for (a = &sinfo->htab->first, e = *a; e; e = e->next)
+    if (e->alignment)
+      a = &e->next;
+    else
+      {
+	*a = e->next;
+	if (e->len)
+	  {
+	    e->secinfo = e->u.suffix->secinfo;
+	    e->alignment = e->u.suffix->alignment;
+	    e->u.index = e->u.suffix->u.index + (e->u.suffix->len - e->len);
+	  }
+      }
+}
+
+/* This function is called once after all SEC_MERGE sections are registered
+   with _bfd_merge_section.  */
+
+boolean
+_bfd_merge_sections (abfd, xsinfo)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     PTR xsinfo;
+{
+  struct sec_merge_info *sinfo;
+
+  for (sinfo = (struct sec_merge_info *) xsinfo; sinfo; sinfo = sinfo->next)
+    {
+      struct sec_merge_sec_info * secinfo;
+
+      if (! sinfo->chain)
+	continue;
+
+      /* Move sinfo->chain to head of the chain, terminate it.  */
+      secinfo = sinfo->chain;
+      sinfo->chain = secinfo->next;
+      secinfo->next = NULL;
+
+      /* Record the sections into the hash table.  */
+      for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next)
+	if (secinfo->sec->flags & SEC_EXCLUDE)
+	  *secinfo->psecinfo = NULL;
+	else if (! record_section (sinfo, secinfo))
+	  break;
+
+      if (secinfo)
+	continue;
+
+      if (sinfo->htab->strings)
+	merge_strings (sinfo);
+      else
+	{
+	  struct sec_merge_hash_entry *e;
+	  bfd_size_type size = 0;
+
+	  /* Things are much simpler for non-strings.
+	     Just assign them slots in the section.  */
+	  secinfo = NULL;
+	  for (e = sinfo->htab->first; e; e = e->next)
+	    {
+	      if (e->secinfo->first == NULL)
+		{
+		  if (secinfo)
+		    secinfo->sec->_cooked_size = size;
+		  e->secinfo->first = e;
+		  size = 0;
+		}
+	      size = (size + e->alignment - 1)
+		     & ~((bfd_vma) e->alignment - 1);
+	      e->u.index = size;
+	      size += e->len;
+	      secinfo = e->secinfo;
+	    }
+	  secinfo->sec->_cooked_size = size;
+	}
+
+	/* Finally shrink 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 == NULL)
+	    {
+	      secinfo->sec->_cooked_size = 0;
+	      secinfo->sec->flags |= SEC_EXCLUDE;
+	    }
+    }
+
+  return true;
 }
 
 /* Write out the merged section.  */
@@ -619,6 +936,6 @@ _bfd_merged_section_offset (output_bfd, 
 	  - entry->len;
     }
 
-  *psec = entry->sec;
-  return entry->index + (secinfo->contents + offset - p);
+  *psec = entry->secinfo->sec;
+  return entry->u.index + (secinfo->contents + offset - p);
 }
--- bfd/libbfd-in.h.jj	Sat Apr 14 16:51:36 2001
+++ bfd/libbfd-in.h	Thu May  3 17:28:34 2001
@@ -323,6 +323,10 @@ extern boolean _bfd_generic_set_section_
   ((boolean (*) \
     PARAMS ((bfd *, struct bfd_link_info *))) \
    bfd_false)
+#define _bfd_nolink_bfd_merge_sections \
+  ((boolean (*) \
+    PARAMS ((bfd *, struct bfd_link_info *))) \
+   bfd_false)
 #define _bfd_nolink_bfd_link_hash_table_create \
   ((struct bfd_link_hash_table *(*) PARAMS ((bfd *))) bfd_nullvoidptr)
 #define _bfd_nolink_bfd_link_add_symbols \
@@ -466,6 +470,11 @@ extern bfd_vma _bfd_stab_section_offset
 
 extern boolean _bfd_merge_section
   PARAMS ((bfd *, PTR *, asection *, PTR *));
+
+/* Attempt to merge SEC_MERGE sections.  */
+
+extern boolean _bfd_merge_sections
+  PARAMS ((bfd *, PTR));
 
 /* Write out a merged section.  */
 
--- bfd/libbfd.h.jj	Tue Apr 24 20:27:52 2001
+++ bfd/libbfd.h	Thu May  3 17:29:01 2001
@@ -323,6 +323,10 @@ extern boolean _bfd_generic_set_section_
   ((boolean (*) \
     PARAMS ((bfd *, struct bfd_link_info *))) \
    bfd_false)
+#define _bfd_nolink_bfd_merge_sections \
+  ((boolean (*) \
+    PARAMS ((bfd *, struct bfd_link_info *))) \
+   bfd_false)
 #define _bfd_nolink_bfd_link_hash_table_create \
   ((struct bfd_link_hash_table *(*) PARAMS ((bfd *))) bfd_nullvoidptr)
 #define _bfd_nolink_bfd_link_add_symbols \
@@ -467,6 +471,11 @@ extern bfd_vma _bfd_stab_section_offset
 extern boolean _bfd_merge_section
   PARAMS ((bfd *, PTR *, asection *, PTR *));
 
+/* Attempt to merge SEC_MERGE sections.  */
+
+extern boolean _bfd_merge_sections
+  PARAMS ((bfd *, PTR));
+
 /* Write out a merged section.  */
 
 extern boolean _bfd_write_merged_section
@@ -1079,6 +1088,9 @@ bfd_generic_relax_section PARAMS ((bfd *
 
 boolean
 bfd_generic_gc_sections PARAMS ((bfd *, struct bfd_link_info *));
+
+boolean
+bfd_generic_merge_sections PARAMS ((bfd *, struct bfd_link_info *));
 
 bfd_byte *
 bfd_generic_get_relocated_section_contents PARAMS ((bfd *abfd,
--- bfd/bfd-in2.h.jj	Tue Apr 24 20:27:43 2001
+++ bfd/bfd-in2.h	Thu May  3 17:00:15 2001
@@ -3226,6 +3226,9 @@ bfd_set_private_flags PARAMS ((bfd *abfd
 #define bfd_gc_sections(abfd, link_info) \
        BFD_SEND (abfd, _bfd_gc_sections, (abfd, link_info))
 
+#define bfd_merge_sections(abfd, link_info) \
+       BFD_SEND (abfd, _bfd_merge_sections, (abfd, link_info))
+
 #define bfd_link_hash_table_create(abfd) \
        BFD_SEND (abfd, _bfd_link_hash_table_create, (abfd))
 
@@ -3522,7 +3525,8 @@ CAT(NAME,_bfd_link_hash_table_create),\
 CAT(NAME,_bfd_link_add_symbols),\
 CAT(NAME,_bfd_final_link),\
 CAT(NAME,_bfd_link_split_section),\
-CAT(NAME,_bfd_gc_sections)
+CAT(NAME,_bfd_gc_sections),\
+CAT(NAME,_bfd_merge_sections)
   int        (*_bfd_sizeof_headers) PARAMS ((bfd *, boolean));
   bfd_byte * (*_bfd_get_relocated_section_contents) PARAMS ((bfd *,
                     struct bfd_link_info *, struct bfd_link_order *,
@@ -3548,6 +3552,9 @@ CAT(NAME,_bfd_gc_sections)
 
   /* Remove sections that are not referenced from the output.  */
   boolean (*_bfd_gc_sections) PARAMS ((bfd *, struct bfd_link_info *));
+
+  /* Attempt to merge SEC_MERGE sections.  */
+  boolean (*_bfd_merge_sections) PARAMS ((bfd *, struct bfd_link_info *));
 
   /* Routines to handle dynamic symbols and relocs.  */
 #define BFD_JUMP_TABLE_DYNAMIC(NAME)\
--- bfd/aout-adobe.c.jj	Thu Mar  8 22:03:56 2001
+++ bfd/aout-adobe.c	Thu May  3 17:02:46 2001
@@ -513,6 +513,7 @@ aout_adobe_sizeof_headers (ignore_abfd, 
 #define aout_32_get_section_contents_in_window _bfd_generic_get_section_contents_in_window
 #define aout_32_bfd_relax_section       bfd_generic_relax_section
 #define aout_32_bfd_gc_sections         bfd_generic_gc_sections
+#define aout_32_bfd_merge_sections	bfd_generic_merge_sections
 #define aout_32_bfd_link_hash_table_create \
   _bfd_generic_link_hash_table_create
 #define aout_32_bfd_link_add_symbols	_bfd_generic_link_add_symbols
--- bfd/aout-target.h.jj	Thu Mar  8 22:03:56 2001
+++ bfd/aout-target.h	Thu May  3 17:03:13 2001
@@ -507,6 +507,9 @@ MY_bfd_final_link (abfd, info)
 #ifndef MY_bfd_gc_sections
 #define MY_bfd_gc_sections bfd_generic_gc_sections
 #endif
+#ifndef MY_bfd_merge_sections
+#define MY_bfd_merge_sections bfd_generic_merge_sections
+#endif
 #ifndef MY_bfd_reloc_type_lookup
 #define MY_bfd_reloc_type_lookup NAME(aout,reloc_type_lookup)
 #endif
--- bfd/aout-tic30.c.jj	Thu Mar  8 22:03:56 2001
+++ bfd/aout-tic30.c	Thu May  3 17:03:53 2001
@@ -940,6 +940,9 @@ tic30_aout_set_arch_mach (abfd, arch, ma
 #ifndef MY_bfd_gc_sections
 #define MY_bfd_gc_sections bfd_generic_gc_sections
 #endif
+#ifndef MY_bfd_merge_sections
+#define MY_bfd_merge_sections bfd_generic_merge_sections
+#endif
 #ifndef MY_bfd_reloc_type_lookup
 #define MY_bfd_reloc_type_lookup tic30_aout_reloc_type_lookup
 #endif
--- bfd/bfd.c.jj	Thu Mar  8 22:03:57 2001
+++ bfd/bfd.c	Thu May  3 17:04:51 2001
@@ -1126,6 +1126,9 @@ DESCRIPTION
 .#define bfd_gc_sections(abfd, link_info) \
 .	BFD_SEND (abfd, _bfd_gc_sections, (abfd, link_info))
 .
+.#define bfd_merge_sections(abfd, link_info) \
+.	BFD_SEND (abfd, _bfd_merge_sections, (abfd, link_info))
+.
 .#define bfd_link_hash_table_create(abfd) \
 .	BFD_SEND (abfd, _bfd_link_hash_table_create, (abfd))
 .
--- bfd/binary.c.jj	Tue Mar 13 01:08:34 2001
+++ bfd/binary.c	Thu May  3 17:05:17 2001
@@ -345,6 +345,7 @@ binary_sizeof_headers (abfd, exec)
   bfd_generic_get_relocated_section_contents
 #define binary_bfd_relax_section bfd_generic_relax_section
 #define binary_bfd_gc_sections bfd_generic_gc_sections
+#define binary_bfd_merge_sections bfd_generic_merge_sections
 #define binary_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
 #define binary_bfd_link_add_symbols _bfd_generic_link_add_symbols
 #define binary_bfd_final_link _bfd_generic_final_link
--- bfd/bout.c.jj	Thu Mar  8 22:03:57 2001
+++ bfd/bout.c	Thu May  3 17:05:35 2001
@@ -1436,6 +1436,7 @@ b_out_bfd_get_relocated_section_contents
 #define b_out_bfd_final_link _bfd_generic_final_link
 #define b_out_bfd_link_split_section  _bfd_generic_link_split_section
 #define b_out_bfd_gc_sections  bfd_generic_gc_sections
+#define b_out_bfd_merge_sections  bfd_generic_merge_sections
 
 #define aout_32_get_section_contents_in_window \
   _bfd_generic_get_section_contents_in_window
--- bfd/coff-alpha.c.jj	Thu Mar  8 22:03:57 2001
+++ bfd/coff-alpha.c	Thu May  3 17:06:40 2001
@@ -2359,6 +2359,7 @@ static const struct ecoff_backend_data a
 /* Relaxing sections is generic.  */
 #define _bfd_ecoff_bfd_relax_section bfd_generic_relax_section
 #define _bfd_ecoff_bfd_gc_sections bfd_generic_gc_sections
+#define _bfd_ecoff_bfd_merge_sections bfd_generic_merge_sections
 
 const bfd_target ecoffalpha_little_vec =
 {
--- bfd/coffcode.h.jj	Tue Apr 24 20:27:43 2001
+++ bfd/coffcode.h	Thu May  3 17:07:04 2001
@@ -5258,6 +5258,10 @@ static const bfd_coff_backend_data bfd_c
 #define coff_bfd_gc_sections		    bfd_generic_gc_sections
 #endif
 
+#ifndef coff_bfd_merge_sections
+#define coff_bfd_merge_sections		    bfd_generic_merge_sections
+#endif
+
 #define CREATE_BIG_COFF_TARGET_VEC(VAR, NAME, EXTRA_O_FLAGS, EXTRA_S_FLAGS, UNDER, ALTERNATIVE)	\
 const bfd_target VAR =							\
 {									\
--- bfd/coff-mips.c.jj	Thu Mar  8 22:03:57 2001
+++ bfd/coff-mips.c	Thu May  3 17:24:28 2001
@@ -2600,6 +2600,9 @@ static const struct ecoff_backend_data m
 /* GC of sections is not done.  */
 #define _bfd_ecoff_bfd_gc_sections bfd_generic_gc_sections
 
+/* Merging of sections is not done.  */
+#define _bfd_ecoff_bfd_merge_sections bfd_generic_merge_sections
+
 extern const bfd_target ecoff_big_vec;
 
 const bfd_target ecoff_little_vec =
--- bfd/i386msdos.c.jj	Thu Mar  8 22:04:01 2001
+++ bfd/i386msdos.c	Thu May  3 17:25:56 2001
@@ -170,6 +170,7 @@ msdos_set_section_contents (abfd, sectio
   bfd_generic_get_relocated_section_contents
 #define msdos_bfd_relax_section bfd_generic_relax_section
 #define msdos_bfd_gc_sections bfd_generic_gc_sections
+#define msdos_bfd_merge_sections bfd_generic_merge_sections
 #define msdos_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
 #define msdos_bfd_link_add_symbols _bfd_generic_link_add_symbols
 #define msdos_bfd_final_link _bfd_generic_final_link
--- bfd/i386os9k.c.jj	Thu Mar  8 22:04:01 2001
+++ bfd/i386os9k.c	Thu May  3 17:26:14 2001
@@ -328,6 +328,7 @@ os9k_sizeof_headers (ignore_abfd, ignore
   bfd_generic_get_relocated_section_contents
 #define os9k_bfd_relax_section bfd_generic_relax_section
 #define os9k_bfd_gc_sections bfd_generic_gc_sections
+#define os9k_bfd_merge_sections bfd_generic_merge_sections
 #define os9k_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
 #define os9k_bfd_link_add_symbols _bfd_generic_link_add_symbols
 #define os9k_bfd_final_link _bfd_generic_final_link
--- bfd/ieee.c.jj	Thu Mar  8 22:04:01 2001
+++ bfd/ieee.c	Thu May  3 17:26:33 2001
@@ -3926,6 +3926,7 @@ ieee_bfd_debug_info_accumulate (abfd, se
   bfd_generic_get_relocated_section_contents
 #define ieee_bfd_relax_section bfd_generic_relax_section
 #define ieee_bfd_gc_sections bfd_generic_gc_sections
+#define ieee_bfd_merge_sections bfd_generic_merge_sections
 #define ieee_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
 #define ieee_bfd_link_add_symbols _bfd_generic_link_add_symbols
 #define ieee_bfd_final_link _bfd_generic_final_link
--- bfd/ihex.c.jj	Thu Mar  8 22:04:01 2001
+++ bfd/ihex.c	Thu May  3 17:27:11 2001
@@ -983,6 +983,7 @@ ihex_sizeof_headers (abfd, exec)
   bfd_generic_get_relocated_section_contents
 #define ihex_bfd_relax_section bfd_generic_relax_section
 #define ihex_bfd_gc_sections bfd_generic_gc_sections
+#define ihex_bfd_merge_sections bfd_generic_merge_sections
 #define ihex_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
 #define ihex_bfd_link_add_symbols _bfd_generic_link_add_symbols
 #define ihex_bfd_final_link _bfd_generic_final_link
--- bfd/nlm-target.h.jj	Thu Mar  8 22:04:01 2001
+++ bfd/nlm-target.h	Thu May  3 17:30:03 2001
@@ -1,5 +1,5 @@
 /* Target definitions for 32/64-bit NLM (NetWare Loadable Module)
-   Copyright 1993, 1994, 1998, 1999, 2000 Free Software Foundation, Inc.
+   Copyright 1993, 1994, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
 
 This file is part of BFD, the Binary File Descriptor library.
 
@@ -42,6 +42,7 @@ Foundation, Inc., 59 Temple Place - Suit
   bfd_generic_get_relocated_section_contents
 #define nlm_bfd_relax_section bfd_generic_relax_section
 #define nlm_bfd_gc_sections bfd_generic_gc_sections
+#define nlm_bfd_merge_sections bfd_generic_merge_sections
 #define nlm_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
 #define nlm_bfd_link_add_symbols _bfd_generic_link_add_symbols
 #define nlm_bfd_final_link _bfd_generic_final_link
--- bfd/oasys.c.jj	Thu Mar  8 22:04:01 2001
+++ bfd/oasys.c	Thu May  3 17:30:23 2001
@@ -1476,6 +1476,7 @@ oasys_sizeof_headers (abfd, exec)
   bfd_generic_get_relocated_section_contents
 #define oasys_bfd_relax_section bfd_generic_relax_section
 #define oasys_bfd_gc_sections bfd_generic_gc_sections
+#define oasys_bfd_merge_sections bfd_generic_merge_sections
 #define oasys_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
 #define oasys_bfd_link_add_symbols _bfd_generic_link_add_symbols
 #define oasys_bfd_final_link _bfd_generic_final_link
--- bfd/ppcboot.c.jj	Thu Mar  8 22:04:01 2001
+++ bfd/ppcboot.c	Thu May  3 17:30:52 2001
@@ -475,6 +475,7 @@ ppcboot_bfd_print_private_bfd_data (abfd
   bfd_generic_get_relocated_section_contents
 #define ppcboot_bfd_relax_section bfd_generic_relax_section
 #define ppcboot_bfd_gc_sections bfd_generic_gc_sections
+#define ppcboot_bfd_merge_sections bfd_generic_merge_sections
 #define ppcboot_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
 #define ppcboot_bfd_link_add_symbols _bfd_generic_link_add_symbols
 #define ppcboot_bfd_final_link _bfd_generic_final_link
--- bfd/som.c.jj	Thu Mar  8 22:04:02 2001
+++ bfd/som.c	Thu May  3 17:31:15 2001
@@ -6286,6 +6286,7 @@ som_bfd_link_split_section (abfd, sec)
 #define som_bfd_final_link _bfd_generic_final_link
 
 #define som_bfd_gc_sections		bfd_generic_gc_sections
+#define som_bfd_merge_sections		bfd_generic_merge_sections
 
 const bfd_target som_vec = {
   "som",			/* name */
--- bfd/srec.c.jj	Thu Mar  8 22:04:02 2001
+++ bfd/srec.c	Thu May  3 17:31:51 2001
@@ -1262,6 +1262,7 @@ srec_print_symbol (ignore_abfd, afile, s
   bfd_generic_get_relocated_section_contents
 #define srec_bfd_relax_section bfd_generic_relax_section
 #define srec_bfd_gc_sections bfd_generic_gc_sections
+#define srec_bfd_merge_sections bfd_generic_merge_sections
 #define srec_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
 #define srec_bfd_link_add_symbols _bfd_generic_link_add_symbols
 #define srec_bfd_final_link _bfd_generic_final_link
--- bfd/targets.c.jj	Tue Apr 24 20:27:52 2001
+++ bfd/targets.c	Thu May  3 17:33:10 2001
@@ -416,7 +416,8 @@ BFD_JUMP_TABLE macros.
 .CAT(NAME,_bfd_link_add_symbols),\
 .CAT(NAME,_bfd_final_link),\
 .CAT(NAME,_bfd_link_split_section),\
-.CAT(NAME,_bfd_gc_sections)
+.CAT(NAME,_bfd_gc_sections),\
+.CAT(NAME,_bfd_merge_sections)
 .  int        (*_bfd_sizeof_headers) PARAMS ((bfd *, boolean));
 .  bfd_byte * (*_bfd_get_relocated_section_contents) PARAMS ((bfd *,
 .                    struct bfd_link_info *, struct bfd_link_order *,
@@ -442,6 +443,9 @@ BFD_JUMP_TABLE macros.
 .
 .  {* Remove sections that are not referenced from the output.  *}
 .  boolean (*_bfd_gc_sections) PARAMS ((bfd *, struct bfd_link_info *));
+.
+.  {* Attempt to merge SEC_MERGE sections.  *}
+.  boolean (*_bfd_merge_sections) PARAMS ((bfd *, struct bfd_link_info *));
 .
 .  {* Routines to handle dynamic symbols and relocs.  *}
 .#define BFD_JUMP_TABLE_DYNAMIC(NAME)\
--- bfd/tekhex.c.jj	Thu Mar  8 22:04:02 2001
+++ bfd/tekhex.c	Thu May  3 17:33:42 2001
@@ -1001,6 +1001,7 @@ tekhex_print_symbol (ignore_abfd, filep,
   bfd_generic_get_relocated_section_contents
 #define tekhex_bfd_relax_section bfd_generic_relax_section
 #define tekhex_bfd_gc_sections bfd_generic_gc_sections
+#define tekhex_bfd_merge_sections bfd_generic_merge_sections
 #define tekhex_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
 #define tekhex_bfd_link_add_symbols _bfd_generic_link_add_symbols
 #define tekhex_bfd_final_link _bfd_generic_final_link
--- bfd/versados.c.jj	Thu Mar  8 22:04:02 2001
+++ bfd/versados.c	Thu May  3 17:34:04 2001
@@ -840,6 +840,7 @@ versados_canonicalize_reloc (abfd, secti
   bfd_generic_get_relocated_section_contents
 #define versados_bfd_relax_section bfd_generic_relax_section
 #define versados_bfd_gc_sections bfd_generic_gc_sections
+#define versados_bfd_merge_sections bfd_generic_merge_sections
 #define versados_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
 #define versados_bfd_link_add_symbols _bfd_generic_link_add_symbols
 #define versados_bfd_final_link _bfd_generic_final_link
--- bfd/xcoff-target.h.jj	Thu Mar  8 22:04:02 2001
+++ bfd/xcoff-target.h	Thu May  3 17:39:58 2001
@@ -97,6 +97,7 @@ extern int lynx_core_file_failing_signal
   coff_bfd_get_relocated_section_contents
 #define _bfd_xcoff_bfd_relax_section coff_bfd_relax_section
 #define _bfd_xcoff_bfd_gc_sections coff_bfd_gc_sections
+#define _bfd_xcoff_bfd_merge_sections coff_bfd_merge_sections
 #define _bfd_xcoff_bfd_link_split_section coff_bfd_link_split_section
 
 /* XCOFF archives do not have anything which corresponds to an
--- bfd/vms.c.jj	Thu Mar  8 22:04:02 2001
+++ bfd/vms.c	Thu May  3 17:42:25 2001
@@ -110,6 +110,8 @@ static boolean vms_bfd_relax_section
 	   boolean *again));
 static boolean vms_bfd_gc_sections
   PARAMS ((bfd *abfd, struct bfd_link_info *link_info));
+static boolean vms_bfd_merge_sections
+  PARAMS ((bfd *abfd, struct bfd_link_info *link_info));
 static struct bfd_link_hash_table *vms_bfd_link_hash_table_create
   PARAMS ((bfd *abfd));
 static boolean vms_bfd_link_add_symbols
@@ -1780,6 +1782,17 @@ vms_bfd_gc_sections (abfd, link_info)
 {
 #if VMS_DEBUG
   vms_debug (1, "vms_bfd_gc_sections(%p, %p)\n", abfd, link_info);
+#endif
+  return true;
+}
+
+static boolean
+vms_bfd_merge_sections (abfd, link_info)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     struct bfd_link_info *link_info ATTRIBUTE_UNUSED;
+{
+#if VMS_DEBUG
+  vms_debug (1, "vms_bfd_merge_sections(%p, %p)\n", abfd, link_info);
 #endif
   return true;
 }
--- bfd/reloc.c.jj	Tue Apr 24 20:27:52 2001
+++ bfd/reloc.c	Thu May  3 17:44:27 2001
@@ -3254,6 +3254,28 @@ bfd_generic_gc_sections (abfd, link_info
 
 /*
 INTERNAL_FUNCTION
+	bfd_generic_merge_sections
+
+SYNOPSIS
+	boolean bfd_generic_merge_sections
+	 (bfd *, struct bfd_link_info *);
+
+DESCRIPTION
+	Provides default handling for SEC_MERGE section merging for back ends
+	which don't have SEC_MERGE support -- i.e., does nothing.
+*/
+
+/*ARGSUSED*/
+boolean
+bfd_generic_merge_sections (abfd, link_info)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     struct bfd_link_info *link_info ATTRIBUTE_UNUSED;
+{
+  return true;
+}
+
+/*
+INTERNAL_FUNCTION
 	bfd_generic_get_relocated_section_contents
 
 SYNOPSIS
--- bfd/elfxx-target.h.jj	Thu Mar  8 22:04:01 2001
+++ bfd/elfxx-target.h	Thu May  3 17:48:57 2001
@@ -111,6 +111,11 @@ Foundation, Inc., 59 Temple Place - Suit
 #define bfd_elfNN_bfd_gc_sections _bfd_elfNN_gc_sections
 #endif
 
+#ifndef bfd_elfNN_bfd_merge_sections
+#define bfd_elfNN_bfd_merge_sections \
+  _bfd_elf_merge_sections
+#endif
+
 #define bfd_elfNN_bfd_make_debug_symbol \
   ((asymbol *(*) PARAMS ((bfd *, void *, unsigned long))) bfd_nullvoidptr)
 
--- bfd/elf-bfd.h.jj	Sat Apr 14 16:51:36 2001
+++ bfd/elf-bfd.h	Thu May  3 17:50:14 2001
@@ -1006,6 +1006,9 @@ extern boolean _bfd_elf_link_hash_table_
 				       const char *)));
 extern boolean _bfd_elf_slurp_version_tables PARAMS ((bfd *));
 
+extern boolean _bfd_elf_merge_sections
+  PARAMS ((bfd *, struct bfd_link_info *));
+
 extern boolean _bfd_elf_copy_private_symbol_data
   PARAMS ((bfd *, asymbol *, bfd *, asymbol *));
 extern boolean _bfd_elf_copy_private_section_data
--- bfd/elf.c.jj	Tue Apr 24 20:27:52 2001
+++ bfd/elf.c	Thu May  3 17:51:56 2001
@@ -558,6 +558,18 @@ bfd_elf_generic_reloc (abfd,
   return bfd_reloc_continue;
 }
 
+/* Finish SHF_MERGE section merging.  */
+
+boolean
+_bfd_elf_merge_sections (abfd, info)
+     bfd *abfd;
+     struct bfd_link_info *info;
+{
+  if (elf_hash_table (info)->merge_info)
+    _bfd_merge_sections (abfd, elf_hash_table (info)->merge_info);
+  return true;
+}
+
 /* Print out the program headers.  */
 
 boolean
--- ld/ldlang.c.jj	Sat Apr 14 16:51:37 2001
+++ ld/ldlang.c	Thu May  3 17:56:42 2001
@@ -4131,6 +4131,12 @@ lang_process ()
   if (command_line.gc_sections)
     lang_gc_sections ();
 
+  /* If there were any SEC_MERGE sections, finish their merging, so that
+     section sizes can be computed.  This has to be done after GC of sections,
+     so that GCed sections are not merged, but before assigning output
+     sections, since removing whole input sections is hard then.  */
+  bfd_merge_sections (output_bfd, &link_info);
+
   /* Size up the common data.  */
   lang_common ();
 

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]