+ entry = sec_merge_add (sinfo->htab, (char *) p, 1, secinfo);
+ if (! entry)
+ goto error_return;
+ }
+ }
+
+ return TRUE;
+
+error_return:
+ for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next)
+ *secinfo->psecinfo = NULL;
+ return FALSE;
+}
+
+static int
+strrevcmp (const void *a, const void *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;
+ unsigned int lenA = A->len;
+ unsigned int lenB = B->len;
+ 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)
+ {
+ if (*s != *t)
+ return (int) *s - (int) *t;
+ s--;
+ t--;
+ l--;
+ }
+ return lenA - lenB;
+}
+
+/* Like strrevcmp, but for the case where all strings have the same
+ alignment > entsize. */
+
+static int
+strrevcmp_align (const void *a, const void *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;
+ unsigned int lenA = A->len;
+ unsigned int lenB = B->len;
+ 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));
+
+ if (tail_align != 0)
+ return tail_align;
+
+ while (l)
+ {
+ if (*s != *t)
+ return (int) *s - (int) *t;
+ s--;
+ t--;
+ l--;
+ }
+ return lenA - lenB;
+}
+
+static inline int
+is_suffix (const struct sec_merge_hash_entry *A,
+ const struct sec_merge_hash_entry *B)
+{
+ if (A->len <= B->len)
+ /* B cannot be a suffix of A unless A is equal to B, which is guaranteed
+ not to be equal by the hash table. */
+ return 0;
+
+ return memcmp (A->root.string + (A->len - B->len),
+ B->root.string, B->len) == 0;
+}
+
+/* This is a helper function for _bfd_merge_sections. It attempts to
+ merge strings matching suffixes of longer strings. */
+static void
+merge_strings (struct sec_merge_info *sinfo)
+{
+ struct sec_merge_hash_entry **array, **a, *e;
+ struct sec_merge_sec_info *secinfo;
+ bfd_size_type size, amt;
+ unsigned int alignment = 0;
+
+ /* Now sort the strings */
+ amt = sinfo->htab->size * sizeof (struct sec_merge_hash_entry *);
+ array = (struct sec_merge_hash_entry **) bfd_malloc (amt);
+ if (array == NULL)
+ goto alloc_failure;
+
+ for (e = sinfo->htab->first, a = array; e; e = e->next)
+ if (e->alignment)
+ {
+ *a++ = e;
+ /* Adjust the length to not include the zero terminator. */
+ e->len -= sinfo->htab->entsize;
+ if (alignment != e->alignment)
+ {
+ if (alignment == 0)
+ alignment = e->alignment;
+ else
+ alignment = (unsigned) -1;
+ }
+ }
+
+ sinfo->htab->size = a - array;
+ if (sinfo->htab->size != 0)
+ {
+ qsort (array, (size_t) sinfo->htab->size,
+ sizeof (struct sec_merge_hash_entry *),
+ (alignment != (unsigned) -1 && alignment > sinfo->htab->entsize
+ ? strrevcmp_align : strrevcmp));
+
+ /* Loop over the sorted array and merge suffixes */
+ e = *--a;
+ e->len += sinfo->htab->entsize;
+ while (--a >= array)
+ {
+ struct sec_merge_hash_entry *cmp = *a;