PATCH: Support mixing COMDAT and linkonce

H. J. Lu hjl@lucon.org
Tue May 18 03:41:00 GMT 2004


On Mon, May 17, 2004 at 06:06:05PM -0700, H. J. Lu wrote:
> On Mon, May 17, 2004 at 02:24:23PM -0700, H. J. Lu wrote:
> > On Sat, May 15, 2004 at 11:09:47AM +0930, Alan Modra wrote:
> > > On Fri, May 14, 2004 at 02:07:37PM -0700, H. J. Lu wrote:
> > > > When there are mixed COMDAT and linkonce inputs, linker doesn't handle
> > > > them gracefully:
> > > 
> > > Ewww.  Should we even try?  I understand that such a patch might be
> > > useful while gcc is emitting both comdat and linkonce, but once you've
> > > completed the change to comdat it shouldn't be necessary.  Also, I'm not
> > > really happy with where you have added this code.  At least, it is the
> > > wrong place to be discarding duplicate sections.  That ought to happen
> > > in ldlang.c:section_already_linked.
> > > 
> > 
> > This patch implements it.
> > 
> > 
> 
> Here is an update. I should skip checking members of section groups
> for already linked section.
> 

Another update. Should I skip COMDAT group members on the already
linked list? It may happen if a COMDAT group member has the same
section name as a linkonce section.


H.J.
-------------- next part --------------
bfd/

2004-05-17  H.J. Lu  <hongjiu.lu@intel.com>

	* aout-adobe.c (aout_32_bfd_match_symbols_in_sections): Defined.
	* aout-target.h (MY_bfd_match_symbols_in_sections): Likewise.
	* aout-tic30.c (MY_bfd_match_symbols_in_sections): Likewise.
	* binary.c (binary_bfd_match_symbols_in_sections): Likewise.
	* bout.c (b_out_bfd_match_symbols_in_sections): Likewise.
	* coff-alpha.c (_bfd_ecoff_bfd_match_symbols_in_sections): Likewise.
	* coff-mips.c (_bfd_ecoff_bfd_match_symbols_in_sections): Likewise.
	* coffcode.h (coff_bfd_match_symbols_in_sections): Likewise.
	* i386msdos.c (msdos_bfd_match_symbols_in_sections): Likewise.
	* i386os9k.c (os9k_bfd_match_symbols_in_sections): Likewise.
	* ieee.c (ieee_bfd_match_symbols_in_sections): Likewise.
	* ihex.c (ihex_bfd_match_symbols_in_sections): Likewise.
	* mach-o.c (bfd_mach_o_bfd_match_symbols_in_sections): Likewise.
	* mmo.c (mmo_bfd_discard_group): Likewise.
	* nlm-target.h (nlm_bfd_match_symbols_in_sections): Likewise.
	* oasys.c (oasys_bfd_match_symbols_in_sections): Likewise.
	* pef.c (bfd_pef_bfd_match_symbols_in_sections): Likewise.
	* ppcboot.c (ppcboot_bfd_match_symbols_in_sections): Likewise.
	* som.c (som_bfd_discard_group): Likewise.
	* srec.c (srec_bfd_match_symbols_in_sections): Likewise.
	* tekhex.c (tekhex_bfd_match_symbols_in_sections): Likewise.
	* versados.c (versados_bfd_match_symbols_in_sections): Likewise.
	* vms.c (vms_bfd_match_symbols_in_sections): Likewise.
	* coff-target.h (_bfd_xcoff_bfd_match_symbols_in_sections): Likewise.
	* xsym.c (bfd_sym_bfd_match_symbols_in_sections): Likewise.

	* bfd.c (bfd_match_symbols_in_sections): New.

	* coff-rs6000.c (rs6000coff_vec): Add
	_bfd_nolink_bfd_match_symbols_in_sections,
	(pmac_xcoff_vec): Likewise.
	* coff64-rs6000.c (rs6000coff64_vec): Likewise.
	(aix5coff64_vec): Likewise.

	* elf-bfd.h (bfd_elf_match_symbols_in_sections): New prototype.
	(_bfd_elf_setup_group_pointers): Likewise.

	* elf.c (_bfd_elf_setup_group_pointers): New function.
	(elf_sort_elf_symbol): Likewise.
	(elf_sym_name_compare): Likewise.
	(bfd_elf_match_symbols_in_sections): Likewise.

	* elfcode.h (elf_object_p): Call _bfd_elf_setup_group_pointers.

	* elfxx-target.h (bfd_elfNN_bfd_match_symbols_in_sections): Defined.

	* libbfd-in.h (_bfd_nolink_bfd_match_symbols_in_sections): Defined/

	* section.c (bfd_section): Add group, a pointer to section group.

	* section (STD_SECTION): Initialize group to NULL.
	* ecoff.c (bfd_debug_section): Likewise.

	* targets.c (bfd_target): Add _bfd_match_symbols_in_sections.
	(BFD_JUMP_TABLE_LINK): Updated.

	* bfd-in2.h: Regenerated.
	* libbfd.h: Regenerated.

ld/

2004-05-17  H.J. Lu  <hongjiu.lu@intel.com>

	* ldlang.c (already_linked_section): New structure.
	(try_match_symbols_in_sections): New function.
	(section_already_linked): Check if a member of a COMDAT group
	matches a .gnu.linkonce section.

--- binutils/bfd/aout-adobe.c.linkonce	2004-04-30 08:25:52.000000000 -0700
+++ binutils/bfd/aout-adobe.c	2004-05-17 13:27:55.000000000 -0700
@@ -519,6 +519,8 @@ aout_adobe_sizeof_headers (ignore_abfd, 
 #define aout_32_bfd_merge_sections	bfd_generic_merge_sections
 #define aout_32_bfd_is_group_section	bfd_generic_is_group_section
 #define aout_32_bfd_discard_group	bfd_generic_discard_group
+#define aout_32_bfd_match_symbols_in_sections \
+  _bfd_nolink_bfd_match_symbols_in_sections
 #define aout_32_bfd_link_hash_table_create \
   _bfd_generic_link_hash_table_create
 #define aout_32_bfd_link_hash_table_free \
--- binutils/bfd/aout-target.h.linkonce	2004-04-30 08:25:53.000000000 -0700
+++ binutils/bfd/aout-target.h	2004-05-17 09:41:08.000000000 -0700
@@ -519,6 +519,10 @@ MY_bfd_final_link (abfd, info)
 #ifndef MY_bfd_discard_group
 #define MY_bfd_discard_group bfd_generic_discard_group
 #endif
+#ifndef MY_bfd_match_symbols_in_sections
+#define MY_bfd_match_symbols_in_sections \
+  _bfd_nolink_bfd_match_symbols_in_sections
+#endif
 #ifndef MY_bfd_reloc_type_lookup
 #define MY_bfd_reloc_type_lookup NAME(aout,reloc_type_lookup)
 #endif
--- binutils/bfd/aout-tic30.c.linkonce	2004-04-30 08:25:54.000000000 -0700
+++ binutils/bfd/aout-tic30.c	2004-05-17 09:41:32.000000000 -0700
@@ -976,6 +976,10 @@ tic30_aout_set_arch_mach (abfd, arch, ma
 #ifndef MY_bfd_discard_group
 #define MY_bfd_discard_group bfd_generic_discard_group
 #endif
+#ifndef MY_bfd_match_symbols_in_sections
+#define MY_bfd_match_symbols_in_sections \
+  _bfd_nolink_bfd_match_symbols_in_sections
+#endif
 #ifndef MY_bfd_reloc_type_lookup
 #define MY_bfd_reloc_type_lookup tic30_aout_reloc_type_lookup
 #endif
--- binutils/bfd/bfd.c.linkonce	2004-05-14 09:00:52.000000000 -0700
+++ binutils/bfd/bfd.c	2004-05-17 09:40:43.000000000 -0700
@@ -1089,6 +1089,9 @@ DESCRIPTION
 .#define bfd_discard_group(abfd, sec) \
 .	BFD_SEND (abfd, _bfd_discard_group, (abfd, sec))
 .
+.#define bfd_match_symbols_in_sections(abfd, sec1, sec2) \
+.	BFD_SEND (abfd, _bfd_match_symbols_in_sections, (sec1, sec2))
+.
 .#define bfd_link_hash_table_create(abfd) \
 .	BFD_SEND (abfd, _bfd_link_hash_table_create, (abfd))
 .
--- binutils/bfd/binary.c.linkonce	2004-04-30 08:26:01.000000000 -0700
+++ binutils/bfd/binary.c	2004-05-17 09:41:47.000000000 -0700
@@ -341,6 +341,8 @@ binary_sizeof_headers (abfd, exec)
 #define binary_bfd_merge_sections bfd_generic_merge_sections
 #define binary_bfd_is_group_section bfd_generic_is_group_section
 #define binary_bfd_discard_group bfd_generic_discard_group
+#define binary_bfd_match_symbols_in_sections \
+  _bfd_nolink_bfd_match_symbols_in_sections
 #define binary_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
 #define binary_bfd_link_hash_table_free _bfd_generic_link_hash_table_free
 #define binary_bfd_link_just_syms _bfd_generic_link_just_syms
--- binutils/bfd/bout.c.linkonce	2004-04-30 08:26:02.000000000 -0700
+++ binutils/bfd/bout.c	2004-05-17 13:28:43.000000000 -0700
@@ -1489,6 +1489,8 @@ b_out_bfd_get_relocated_section_contents
 #define b_out_bfd_merge_sections  bfd_generic_merge_sections
 #define b_out_bfd_is_group_section bfd_generic_is_group_section
 #define b_out_bfd_discard_group bfd_generic_discard_group
+#define b_out_bfd_match_symbols_in_sections \
+  _bfd_nolink_bfd_match_symbols_in_sections
 
 #define aout_32_get_section_contents_in_window \
   _bfd_generic_get_section_contents_in_window
--- binutils/bfd/coff-alpha.c.linkonce	2004-04-30 08:26:04.000000000 -0700
+++ binutils/bfd/coff-alpha.c	2004-05-17 09:41:52.000000000 -0700
@@ -2361,6 +2361,8 @@ static const struct ecoff_backend_data a
 #define _bfd_ecoff_bfd_merge_sections bfd_generic_merge_sections
 #define _bfd_ecoff_bfd_is_group_section bfd_generic_is_group_section
 #define _bfd_ecoff_bfd_discard_group bfd_generic_discard_group
+#define _bfd_ecoff_bfd_match_symbols_in_sections \
+  _bfd_nolink_bfd_match_symbols_in_sections
 
 const bfd_target ecoffalpha_little_vec =
 {
--- binutils/bfd/coff-mips.c.linkonce	2004-04-30 08:26:06.000000000 -0700
+++ binutils/bfd/coff-mips.c	2004-05-17 09:42:02.000000000 -0700
@@ -1395,6 +1395,8 @@ static const struct ecoff_backend_data m
 
 #define _bfd_ecoff_bfd_is_group_section bfd_generic_is_group_section
 #define _bfd_ecoff_bfd_discard_group bfd_generic_discard_group
+#define _bfd_ecoff_bfd_match_symbols_in_sections \
+  _bfd_nolink_bfd_match_symbols_in_sections
 
 extern const bfd_target ecoff_big_vec;
 
--- binutils/bfd/coff-rs6000.c.linkonce	2004-04-30 08:26:10.000000000 -0700
+++ binutils/bfd/coff-rs6000.c	2004-05-17 09:42:06.000000000 -0700
@@ -4198,6 +4198,7 @@ const bfd_target rs6000coff_vec =
     bfd_generic_merge_sections,
     bfd_generic_is_group_section,
     bfd_generic_discard_group,
+    _bfd_nolink_bfd_match_symbols_in_sections,
 
     /* Dynamic */
     _bfd_xcoff_get_dynamic_symtab_upper_bound,
@@ -4442,6 +4443,7 @@ const bfd_target pmac_xcoff_vec =
     bfd_generic_merge_sections,
     bfd_generic_is_group_section,
     bfd_generic_discard_group,
+    _bfd_nolink_bfd_match_symbols_in_sections,
 
     /* Dynamic */
     _bfd_xcoff_get_dynamic_symtab_upper_bound,
--- binutils/bfd/coff64-rs6000.c.linkonce	2004-04-30 08:26:13.000000000 -0700
+++ binutils/bfd/coff64-rs6000.c	2004-05-17 09:42:18.000000000 -0700
@@ -2739,6 +2739,7 @@ const bfd_target rs6000coff64_vec =
     bfd_generic_merge_sections,
     bfd_generic_is_group_section,
     bfd_generic_discard_group,
+    _bfd_nolink_bfd_match_symbols_in_sections,
 
     /* Dynamic */
     _bfd_xcoff_get_dynamic_symtab_upper_bound,
@@ -2984,6 +2985,7 @@ const bfd_target aix5coff64_vec =
     bfd_generic_merge_sections,
     bfd_generic_is_group_section,
     bfd_generic_discard_group,
+    _bfd_nolink_bfd_match_symbols_in_sections,
 
     /* Dynamic */
     _bfd_xcoff_get_dynamic_symtab_upper_bound,
--- binutils/bfd/coffcode.h.linkonce	2004-05-07 13:21:00.000000000 -0700
+++ binutils/bfd/coffcode.h	2004-05-17 09:42:24.000000000 -0700
@@ -5574,6 +5574,11 @@ static const bfd_coff_backend_data ticof
 #define coff_bfd_discard_group		    bfd_generic_discard_group
 #endif
 
+#ifndef coff_bfd_match_symbols_in_sections
+#define coff_bfd_match_symbols_in_sections \
+  _bfd_nolink_bfd_match_symbols_in_sections
+#endif
+
 #define CREATE_BIG_COFF_TARGET_VEC(VAR, NAME, EXTRA_O_FLAGS, EXTRA_S_FLAGS, UNDER, ALTERNATIVE, SWAP_TABLE)	\
 const bfd_target VAR =							\
 {									\
--- binutils/bfd/ecoff.c.linkonce	2004-04-26 21:11:29.000000000 -0700
+++ binutils/bfd/ecoff.c	2004-05-17 13:30:52.000000000 -0700
@@ -95,8 +95,8 @@ static asection bfd_debug_section =
      NULL,       NULL,        0,           0,       0,
   /* line_filepos, userdata, contents, lineno, lineno_count,       */
      0,            NULL,     NULL,     NULL,   0,
-  /* entsize, comdat, kept_section, moving_line_filepos,           */
-     0,       NULL,   NULL,         0,
+  /* entsize, comdat, group, kept_section, moving_line_filepos,    */
+     0,       NULL,   NULL,  NULL,         0,
   /* target_index, used_by_bfd, constructor_chain, owner,          */
      0,            NULL,        NULL,              NULL,
   /* symbol,                                                       */
--- binutils/bfd/elf-bfd.h.linkonce	2004-05-11 13:33:49.000000000 -0700
+++ binutils/bfd/elf-bfd.h	2004-05-17 12:32:04.000000000 -0700
@@ -1375,6 +1375,8 @@ extern bfd_boolean bfd_elf_is_group_sect
   (bfd *, const struct bfd_section *);
 extern bfd_boolean bfd_elf_discard_group
   (bfd *, struct bfd_section *);
+extern bfd_boolean bfd_elf_match_symbols_in_sections
+  (struct bfd_section *, struct bfd_section *);
 extern void bfd_elf_set_group_contents
   (bfd *, asection *, void *);
 extern void _bfd_elf_link_just_syms
@@ -1554,6 +1556,9 @@ extern bfd_boolean _bfd_elf_dynamic_symb
 extern bfd_boolean _bfd_elf_symbol_refs_local_p
   (struct elf_link_hash_entry *, struct bfd_link_info *, bfd_boolean);
 
+extern void _bfd_elf_setup_group_pointers
+  (bfd *);
+
 extern const bfd_target *bfd_elf32_object_p
   (bfd *);
 extern const bfd_target *bfd_elf32_core_file_p
--- binutils/bfd/elf.c.linkonce	2004-05-11 13:33:56.000000000 -0700
+++ binutils/bfd/elf.c	2004-05-17 14:14:58.000000000 -0700
@@ -612,6 +612,26 @@ setup_group (bfd *abfd, Elf_Internal_Shd
   return TRUE;
 }
 
+void
+_bfd_elf_setup_group_pointers (bfd *abfd)
+{
+  unsigned int i;
+  unsigned int num_group = elf_tdata (abfd)->num_group;
+
+  if (num_group == (unsigned) -1)
+    return;
+
+  for (i = 0; i < num_group; i++)
+    {
+      Elf_Internal_Shdr *shdr = elf_tdata (abfd)->group_sect_ptr[i];
+      Elf_Internal_Group *idx = (Elf_Internal_Group *) shdr->contents;
+      unsigned int n_elt = shdr->sh_size / 4;
+
+      while (--n_elt != 0)
+	(++idx)->shdr->bfd_section->group = shdr->bfd_section;
+    }
+}
+
 bfd_boolean
 bfd_elf_is_group_section (bfd *abfd ATTRIBUTE_UNUSED, const asection *sec)
 {
@@ -7678,3 +7698,240 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd
 
   return n;
 }
+
+/* Sort symbol by binding and section. We want to put global
+   symbols sorted by section at the beginning.  */
+
+static int
+elf_sort_elf_symbol (const void *arg1, const void *arg2)
+{
+  const Elf_Internal_Sym *s1;
+  const Elf_Internal_Sym *s2;
+
+  /* Make sure local or undefined symbols are at the end.  */
+  s1 = (const Elf_Internal_Sym *) arg1;
+  if (s1->st_shndx == SHN_UNDEF
+      || ELF_ST_BIND (s1->st_info) == STB_LOCAL)
+    return 1;
+  s2 = (const Elf_Internal_Sym *) arg2;
+  if (s2->st_shndx == SHN_UNDEF
+      || ELF_ST_BIND (s2->st_info) == STB_LOCAL)
+    return -1;
+
+  /* Grouped by section index.  */
+  return s1->st_shndx - s2->st_shndx;
+}
+
+struct elf_symbol
+{
+  Elf_Internal_Sym *sym;
+  const char *name;
+};
+
+static int
+elf_sym_name_compare (const void *arg1, const void *arg2)
+{
+  const struct elf_symbol *s1 = (const struct elf_symbol *) arg1;
+  const struct elf_symbol *s2 = (const struct elf_symbol *) arg2;
+  return strcmp (s1->name, s2->name);
+}
+
+/* Check if 2 sections export the same set of symbols.  */
+
+bfd_boolean
+bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2)
+{
+  bfd *bfd1, *bfd2;
+  const struct elf_backend_data *bed1, *bed2;
+  Elf_Internal_Shdr *hdr1, *hdr2;
+  bfd_size_type symcount1, symcount2;
+  bfd_size_type extsymcount1, extsymcount2;
+  bfd_size_type extsymoff1, extsymoff2;
+  Elf_Internal_Sym *isymbuf1, *isymbuf2;
+  Elf_Internal_Sym *isymstart1 = NULL, *isymstart2 = NULL, *isym;
+  Elf_Internal_Sym *isymend;
+  struct elf_symbol *symp, *symtable1 = NULL, *symtable2 = NULL;
+  bfd_size_type count1, count2, i;
+  int shndx1, shndx2;
+  bfd_boolean result;
+
+  bfd1 = sec1->owner;
+  bfd2 = sec2->owner;
+
+  /* Both sections have to be in ELF.  */
+  if (bfd_get_flavour (bfd1) != bfd_target_elf_flavour
+      || bfd_get_flavour (bfd2) != bfd_target_elf_flavour)
+    return FALSE;
+
+  /* One section has to be in a COMDAT group with only one section and
+     the other one has to be a .gnu.linkonce section.  */
+  if (!(elf_section_type (sec1) == elf_section_type (sec2)
+	&& ((elf_section_flags (sec1) & ~SHF_GROUP)
+	    == (elf_section_flags (sec2) & ~SHF_GROUP))
+	&& ((sec1->group != NULL
+	     && ((sec1->group->flags & (SEC_LINK_ONCE
+					| SEC_LINK_DUPLICATES_DISCARD))
+		 == (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD))
+	     && elf_next_in_group (sec1) == sec1
+	     && sec2->group == NULL
+	     && ((sec2->flags & (SEC_LINK_ONCE
+				 | SEC_LINK_DUPLICATES_DISCARD))
+		 == (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD)))
+	    || (sec1->group == NULL
+		&& sec2->group != NULL
+		&& ((sec2->group->flags & (SEC_LINK_ONCE
+					   | SEC_LINK_DUPLICATES_DISCARD))
+		    == (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD))
+		&& elf_next_in_group (sec2) == sec2
+		&& ((sec1->flags & (SEC_LINK_ONCE
+				    | SEC_LINK_DUPLICATES_DISCARD))
+		    == (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD))))))
+    return FALSE;
+
+  shndx1 = _bfd_elf_section_from_bfd_section (bfd1, sec1);
+  shndx2 = _bfd_elf_section_from_bfd_section (bfd2, sec2);
+  if (shndx1 == -1 || shndx2 == -1)
+    return FALSE;
+
+  bed1 = get_elf_backend_data (bfd1);
+  bed2 = get_elf_backend_data (bfd2);
+  hdr1 = &elf_tdata (bfd1)->symtab_hdr;
+  symcount1 = hdr1->sh_size / bed1->s->sizeof_sym;
+  hdr2 = &elf_tdata (bfd2)->symtab_hdr;
+  symcount2 = hdr2->sh_size / bed2->s->sizeof_sym;
+
+  if (elf_bad_symtab (bfd1))
+    {
+      extsymcount1 = symcount1;
+      extsymoff1 = 0;
+    }
+  else
+    {
+      extsymcount1 = symcount1 - hdr1->sh_info;
+      extsymoff1 = hdr1->sh_info;
+    }
+
+  if (elf_bad_symtab (bfd2))
+    {
+      extsymcount2 = symcount2;
+      extsymoff2 = 0;
+    }
+  else
+    {
+      extsymcount2 = symcount2 - hdr2->sh_info;
+      extsymoff2 = hdr2->sh_info;
+    }
+
+  if (extsymcount1 == 0 || extsymcount2 == 0)
+    return FALSE;
+
+  isymbuf1 = bfd_elf_get_elf_syms (bfd1, hdr1, extsymcount1,
+				     extsymoff1, NULL, NULL, NULL);
+  isymbuf2 = bfd_elf_get_elf_syms (bfd2, hdr2, extsymcount2,
+				     extsymoff2, NULL, NULL, NULL);
+  if (isymbuf1 == NULL || isymbuf2 == NULL)
+    return FALSE;
+
+  /* Sort symbols by binding and section. Global definitions are at
+     the beginning.  */
+  qsort (isymbuf1, extsymcount1, sizeof (Elf_Internal_Sym),
+	 elf_sort_elf_symbol);
+  qsort (isymbuf2, extsymcount2, sizeof (Elf_Internal_Sym),
+	 elf_sort_elf_symbol);
+
+  /* Count global symbols defined in the section.  */
+  count1 = 0;
+  for (isym = isymbuf1, isymend = isym + extsymcount1;
+       isym < isymend; isym++)
+    {
+      if (isym->st_shndx == (unsigned int) shndx1)
+	{
+	  if (count1 == 0)
+	    isymstart1 = isym;
+	  count1++;
+	}
+
+      if (count1 && isym->st_shndx != (unsigned int) shndx1)
+	break;
+    }
+
+  count2 = 0;
+  for (isym = isymbuf2, isymend = isym + extsymcount2;
+       isym < isymend; isym++)
+    {
+      if (isym->st_shndx == (unsigned int) shndx2)
+	{
+	  if (count2 == 0)
+	    isymstart2 = isym;
+	  count2++;
+	}
+
+      if (count2 && isym->st_shndx != (unsigned int) shndx2)
+	break;
+    }
+
+  if (count1 == 0 && count2 == 0)
+    {
+      result = TRUE;
+      goto done;
+    }
+
+  result = FALSE;
+  if (count1 != count2)
+    goto done;
+
+  symtable1 = bfd_malloc (count1 * sizeof (struct elf_symbol));
+  symtable2 = bfd_malloc (count1 * sizeof (struct elf_symbol));
+
+  if (symtable1 == NULL || symtable2 == NULL)
+    goto done;
+
+  symp = symtable1;
+  for (isym = isymstart1, isymend = isym + count1;
+       isym < isymend; isym++)
+    {
+      symp->sym = isym;
+      symp->name = bfd_elf_string_from_elf_section (bfd1,
+						    hdr1->sh_link,
+						    isym->st_name);
+      symp++;
+    }
+ 
+  symp = symtable2;
+  for (isym = isymstart2, isymend = isym + count1;
+       isym < isymend; isym++)
+    {
+      symp->sym = isym;
+      symp->name = bfd_elf_string_from_elf_section (bfd2,
+						    hdr2->sh_link,
+						    isym->st_name);
+      symp++;
+    }
+  
+  /* Sort symbol by name.  */
+  qsort (symtable1, count1, sizeof (struct elf_symbol),
+	 elf_sym_name_compare);
+  qsort (symtable2, count1, sizeof (struct elf_symbol),
+	 elf_sym_name_compare);
+
+  for (i = 0; i < count1; i++)
+    /* Two symbols must have the same binding, type and name.  */
+    if (symtable1 [i].sym->st_info != symtable2 [i].sym->st_info
+	|| symtable1 [i].sym->st_other != symtable2 [i].sym->st_other
+	|| strcmp (symtable1 [i].name, symtable2 [i].name) != 0)
+      goto done;
+
+  result = TRUE;
+
+done:
+  if (symtable1)
+    free (symtable1);
+  if (symtable2)
+    free (symtable2);
+  if (isymbuf1)
+    free (isymbuf1);
+  if (isymbuf2)
+    free (isymbuf2);
+
+  return result;
+}
--- binutils/bfd/elfcode.h.linkonce	2004-04-22 08:20:00.000000000 -0700
+++ binutils/bfd/elfcode.h	2004-05-17 12:30:41.000000000 -0700
@@ -742,6 +742,9 @@ elf_object_p (bfd *abfd)
 	  if (shindex == SHN_LORESERVE - 1)
 	    shindex += SHN_HIRESERVE + 1 - SHN_LORESERVE;
 	}
+
+      /* Set up group pointers.  */
+      _bfd_elf_setup_group_pointers (abfd);
     }
 
   /* Let the backend double check the format and override global
--- binutils/bfd/elfxx-target.h.linkonce	2004-04-30 08:26:46.000000000 -0700
+++ binutils/bfd/elfxx-target.h	2004-05-17 09:42:45.000000000 -0700
@@ -144,6 +144,11 @@
 #define bfd_elfNN_bfd_discard_group bfd_elf_discard_group
 #endif
 
+#ifndef bfd_elfNN_bfd_match_symbols_in_sections
+#define bfd_elfNN_bfd_match_symbols_in_sections \
+  bfd_elf_match_symbols_in_sections
+#endif
+
 #ifndef bfd_elfNN_bfd_make_debug_symbol
 #define bfd_elfNN_bfd_make_debug_symbol \
   ((asymbol * (*) (bfd *, void *, unsigned long)) bfd_nullvoidptr)
--- binutils/bfd/i386msdos.c.linkonce	2004-04-30 08:26:47.000000000 -0700
+++ binutils/bfd/i386msdos.c	2004-05-17 09:42:50.000000000 -0700
@@ -178,6 +178,8 @@ msdos_set_section_contents (abfd, sectio
 #define msdos_bfd_merge_sections bfd_generic_merge_sections
 #define msdos_bfd_is_group_section bfd_generic_is_group_section
 #define msdos_bfd_discard_group bfd_generic_discard_group
+#define msdos_bfd_match_symbols_in_sections \
+  _bfd_nolink_bfd_match_symbols_in_sections
 #define msdos_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
 #define msdos_bfd_link_hash_table_free _bfd_generic_link_hash_table_free
 #define msdos_bfd_link_add_symbols _bfd_generic_link_add_symbols
--- binutils/bfd/i386os9k.c.linkonce	2004-04-30 08:26:47.000000000 -0700
+++ binutils/bfd/i386os9k.c	2004-05-17 13:33:11.000000000 -0700
@@ -335,6 +335,8 @@ os9k_sizeof_headers (ignore_abfd, ignore
 #define os9k_bfd_merge_sections bfd_generic_merge_sections
 #define os9k_bfd_is_group_section bfd_generic_is_group_section
 #define os9k_bfd_discard_group bfd_generic_discard_group
+#define os9k_bfd_match_symbols_in_sections \
+  _bfd_nolink_bfd_match_symbols_in_sections
 #define os9k_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
 #define os9k_bfd_link_hash_table_free _bfd_generic_link_hash_table_free
 #define os9k_bfd_link_add_symbols _bfd_generic_link_add_symbols
--- binutils/bfd/ieee.c.linkonce	2004-04-30 08:26:50.000000000 -0700
+++ binutils/bfd/ieee.c	2004-05-17 09:42:58.000000000 -0700
@@ -4039,6 +4039,8 @@ ieee_bfd_debug_info_accumulate (abfd, se
 #define ieee_bfd_merge_sections bfd_generic_merge_sections
 #define ieee_bfd_is_group_section bfd_generic_is_group_section
 #define ieee_bfd_discard_group bfd_generic_discard_group
+#define ieee_bfd_match_symbols_in_sections \
+  _bfd_nolink_bfd_match_symbols_in_sections
 #define ieee_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
 #define ieee_bfd_link_hash_table_free _bfd_generic_link_hash_table_free
 #define ieee_bfd_link_add_symbols _bfd_generic_link_add_symbols
--- binutils/bfd/ihex.c.linkonce	2004-04-30 08:26:51.000000000 -0700
+++ binutils/bfd/ihex.c	2004-05-17 09:43:03.000000000 -0700
@@ -990,6 +990,8 @@ ihex_sizeof_headers (abfd, exec)
 #define ihex_bfd_merge_sections bfd_generic_merge_sections
 #define ihex_bfd_is_group_section bfd_generic_is_group_section
 #define ihex_bfd_discard_group bfd_generic_discard_group
+#define ihex_bfd_match_symbols_in_sections \
+  _bfd_nolink_bfd_match_symbols_in_sections
 #define ihex_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
 #define ihex_bfd_link_hash_table_free _bfd_generic_link_hash_table_free
 #define ihex_bfd_link_add_symbols _bfd_generic_link_add_symbols
--- binutils/bfd/libbfd-in.h.linkonce	2004-04-30 08:26:52.000000000 -0700
+++ binutils/bfd/libbfd-in.h	2004-05-17 09:43:08.000000000 -0700
@@ -361,6 +361,9 @@ extern bfd_boolean _bfd_generic_set_sect
 #define _bfd_nolink_bfd_discard_group \
   ((bfd_boolean (*) (bfd *, struct bfd_section *)) \
    bfd_false)
+#define _bfd_nolink_bfd_match_symbols_in_sections \
+  ((bfd_boolean (*) (struct bfd_section *, struct bfd_section *)) \
+   bfd_false)
 #define _bfd_nolink_bfd_link_hash_table_create \
   ((struct bfd_link_hash_table *(*) (bfd *)) bfd_nullvoidptr)
 #define _bfd_nolink_bfd_link_hash_table_free \
--- binutils/bfd/mach-o.c.linkonce	2004-04-30 08:26:56.000000000 -0700
+++ binutils/bfd/mach-o.c	2004-05-17 09:43:35.000000000 -0700
@@ -70,6 +70,8 @@
 #define bfd_mach_o_bfd_merge_sections bfd_generic_merge_sections
 #define bfd_mach_o_bfd_is_group_section bfd_generic_is_group_section
 #define bfd_mach_o_bfd_discard_group bfd_generic_discard_group
+#define bfd_mach_o_bfd_match_symbols_in_sections \
+  _bfd_nolink_bfd_match_symbols_in_sections
 
 static bfd_boolean bfd_mach_o_bfd_copy_private_symbol_data
   PARAMS ((bfd *, asymbol *, bfd *, asymbol *));
--- binutils/bfd/mmo.c.linkonce	2004-04-30 08:26:59.000000000 -0700
+++ binutils/bfd/mmo.c	2004-05-17 09:43:40.000000000 -0700
@@ -3288,6 +3288,8 @@ mmo_canonicalize_reloc (abfd, section, r
 #define mmo_bfd_merge_sections bfd_generic_merge_sections
 #define mmo_bfd_is_group_section bfd_generic_is_group_section
 #define mmo_bfd_discard_group bfd_generic_discard_group
+#define mmo_bfd_match_symbols_in_sections \
+  _bfd_nolink_bfd_match_symbols_in_sections
 
 /* objcopy will be upset if we return -1 from bfd_get_reloc_upper_bound by
    using BFD_JUMP_TABLE_RELOCS (_bfd_norelocs) rather than 0.  FIXME: Most
--- binutils/bfd/nlm-target.h.linkonce	2004-04-30 08:26:59.000000000 -0700
+++ binutils/bfd/nlm-target.h	2004-05-17 09:43:45.000000000 -0700
@@ -46,6 +46,8 @@ Foundation, Inc., 59 Temple Place - Suit
 #define nlm_bfd_merge_sections bfd_generic_merge_sections
 #define nlm_bfd_is_group_section bfd_generic_is_group_section
 #define nlm_bfd_discard_group bfd_generic_discard_group
+#define nlm_bfd_match_symbols_in_sections \
+  _bfd_nolink_bfd_match_symbols_in_sections
 #define nlm_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
 #define nlm_bfd_link_hash_table_free _bfd_generic_link_hash_table_free
 #define nlm_bfd_link_add_symbols _bfd_generic_link_add_symbols
--- binutils/bfd/oasys.c.linkonce	2004-04-30 08:27:01.000000000 -0700
+++ binutils/bfd/oasys.c	2004-05-17 09:43:49.000000000 -0700
@@ -1508,6 +1508,8 @@ oasys_sizeof_headers (abfd, exec)
 #define oasys_bfd_merge_sections bfd_generic_merge_sections
 #define oasys_bfd_is_group_section bfd_generic_is_group_section
 #define oasys_bfd_discard_group bfd_generic_discard_group
+#define oasys_bfd_match_symbols_in_sections \
+  _bfd_nolink_bfd_match_symbols_in_sections
 #define oasys_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
 #define oasys_bfd_link_hash_table_free _bfd_generic_link_hash_table_free
 #define oasys_bfd_link_add_symbols _bfd_generic_link_add_symbols
--- binutils/bfd/pef.c.linkonce	2004-04-30 08:27:01.000000000 -0700
+++ binutils/bfd/pef.c	2004-05-17 13:33:50.000000000 -0700
@@ -54,6 +54,7 @@
 #define bfd_pef_bfd_merge_sections                  bfd_generic_merge_sections
 #define bfd_pef_bfd_is_group_section		    bfd_generic_is_group_section
 #define bfd_pef_bfd_discard_group                   bfd_generic_discard_group
+#define bfd_pef_bfd_match_symbols_in_sections	    _bfd_nolink_bfd_match_symbols_in_sections
 #define bfd_pef_bfd_link_hash_table_create          _bfd_generic_link_hash_table_create
 #define bfd_pef_bfd_link_hash_table_free            _bfd_generic_link_hash_table_free
 #define bfd_pef_bfd_link_add_symbols                _bfd_generic_link_add_symbols
--- binutils/bfd/ppcboot.c.linkonce	2004-04-30 08:27:02.000000000 -0700
+++ binutils/bfd/ppcboot.c	2004-05-17 09:44:21.000000000 -0700
@@ -471,6 +471,8 @@ ppcboot_bfd_print_private_bfd_data (abfd
 #define ppcboot_bfd_merge_sections bfd_generic_merge_sections
 #define ppcboot_bfd_is_group_section bfd_generic_is_group_section
 #define ppcboot_bfd_discard_group bfd_generic_discard_group
+#define ppcboot_bfd_match_symbols_in_sections \
+  _bfd_nolink_bfd_match_symbols_in_sections
 #define ppcboot_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
 #define ppcboot_bfd_link_hash_table_free _bfd_generic_link_hash_table_free
 #define ppcboot_bfd_link_add_symbols _bfd_generic_link_add_symbols
--- binutils/bfd/section.c.linkonce	2004-05-17 07:37:17.000000000 -0700
+++ binutils/bfd/section.c	2004-05-17 07:38:59.000000000 -0700
@@ -493,6 +493,10 @@ CODE_FRAGMENT
 .  {* Optional information about a COMDAT entry; NULL if not COMDAT.  *}
 .  struct bfd_comdat_info *comdat;
 .
+.  {* Optional information about section group; NULL if it doesn't
+.     belongs to any section group.  *}
+.  struct bfd_section *group;
+.
 .  {* Points to the kept section if this section is a link-once section,
 .     and is discarded.  *}
 .  struct bfd_section *kept_section;
@@ -643,8 +647,8 @@ static const asymbol global_syms[] =
     /* line_filepos, userdata, contents, lineno, lineno_count,       */	\
        0,            NULL,     NULL,     NULL,   0,			\
 									\
-    /* entsize, comdat, kept_section, moving_line_filepos,           */	\
-       0,       NULL,   NULL,	      0,				\
+    /* entsize, comdat, group, kept_section, moving_line_filepos,    */	\
+       0,       NULL,   NULL,  NULL,	      0,			\
 									\
     /* target_index, used_by_bfd, constructor_chain, owner,          */	\
        0,            NULL,        NULL,              NULL,		\
--- binutils/bfd/som.c.linkonce	2004-05-03 09:00:44.000000000 -0700
+++ binutils/bfd/som.c	2004-05-17 09:44:25.000000000 -0700
@@ -6412,6 +6412,8 @@ som_bfd_link_split_section (abfd, sec)
 #define som_bfd_merge_sections		bfd_generic_merge_sections
 #define som_bfd_is_group_section	bfd_generic_is_group_section
 #define som_bfd_discard_group		bfd_generic_discard_group
+#define som_bfd_match_symbols_in_sections \
+  _bfd_nolink_bfd_match_symbols_in_sections
 
 const bfd_target som_vec = {
   "som",			/* name */
--- binutils/bfd/srec.c.linkonce	2004-04-30 08:27:15.000000000 -0700
+++ binutils/bfd/srec.c	2004-05-17 09:44:33.000000000 -0700
@@ -1286,6 +1286,8 @@ srec_print_symbol (abfd, afile, symbol, 
 #define srec_bfd_merge_sections bfd_generic_merge_sections
 #define srec_bfd_is_group_section bfd_generic_is_group_section
 #define srec_bfd_discard_group bfd_generic_discard_group
+#define srec_bfd_match_symbols_in_sections \
+  _bfd_nolink_bfd_match_symbols_in_sections
 #define srec_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
 #define srec_bfd_link_hash_table_free _bfd_generic_link_hash_table_free
 #define srec_bfd_link_add_symbols _bfd_generic_link_add_symbols
--- binutils/bfd/targets.c.linkonce	2004-05-14 09:00:50.000000000 -0700
+++ binutils/bfd/targets.c	2004-05-17 09:44:55.000000000 -0700
@@ -407,7 +407,8 @@ BFD_JUMP_TABLE macros.
 .  NAME##_bfd_gc_sections, \
 .  NAME##_bfd_merge_sections, \
 .  NAME##_bfd_is_group_section, \
-.  NAME##_bfd_discard_group
+.  NAME##_bfd_discard_group, \
+.  NAME##_bfd_match_symbols_in_sections \
 .
 .  int         (*_bfd_sizeof_headers) (bfd *, bfd_boolean);
 .  bfd_byte *  (*_bfd_get_relocated_section_contents)
@@ -450,6 +451,11 @@ BFD_JUMP_TABLE macros.
 .  {* Discard members of a group.  *}
 .  bfd_boolean (*_bfd_discard_group) (bfd *, struct bfd_section *);
 .
+.  {* Return TRUE if need to try if 2 sections export the same set of
+.     symbols.  *}
+.  bfd_boolean (*_bfd_match_symbols_in_sections)
+.    (struct bfd_section *, struct bfd_section *);
+.
 .  {* Routines to handle dynamic symbols and relocs.  *}
 .#define BFD_JUMP_TABLE_DYNAMIC(NAME) \
 .  NAME##_get_dynamic_symtab_upper_bound, \
--- binutils/bfd/tekhex.c.linkonce	2004-04-30 08:27:18.000000000 -0700
+++ binutils/bfd/tekhex.c	2004-05-17 09:45:02.000000000 -0700
@@ -1003,6 +1003,8 @@ tekhex_print_symbol (abfd, filep, symbol
 #define tekhex_bfd_merge_sections bfd_generic_merge_sections
 #define tekhex_bfd_is_group_section bfd_generic_is_group_section
 #define tekhex_bfd_discard_group bfd_generic_discard_group
+#define tekhex_bfd_match_symbols_in_sections \
+  _bfd_nolink_bfd_match_symbols_in_sections
 #define tekhex_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
 #define tekhex_bfd_link_hash_table_free _bfd_generic_link_hash_table_free
 #define tekhex_bfd_link_add_symbols _bfd_generic_link_add_symbols
--- binutils/bfd/versados.c.linkonce	2004-04-30 08:27:18.000000000 -0700
+++ binutils/bfd/versados.c	2004-05-17 09:45:10.000000000 -0700
@@ -874,6 +874,8 @@ versados_canonicalize_reloc (abfd, secti
 #define versados_bfd_merge_sections bfd_generic_merge_sections
 #define versados_bfd_is_group_section bfd_generic_is_group_section
 #define versados_bfd_discard_group bfd_generic_discard_group
+#define versados_bfd_match_symbols_in_sections \
+  _bfd_nolink_bfd_match_symbols_in_sections
 #define versados_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
 #define versados_bfd_link_hash_table_free _bfd_generic_link_hash_table_free
 #define versados_bfd_link_add_symbols _bfd_generic_link_add_symbols
--- binutils/bfd/vms.c.linkonce	2004-04-30 08:27:20.000000000 -0700
+++ binutils/bfd/vms.c	2004-05-17 13:35:00.000000000 -0700
@@ -168,6 +168,8 @@ static bfd_boolean vms_bfd_set_private_f
 #define vms_bfd_link_just_syms _bfd_generic_link_just_syms
 #define vms_bfd_is_group_section bfd_generic_is_group_section
 #define vms_bfd_discard_group bfd_generic_discard_group
+#define vms_bfd_match_symbols_in_sections \
+  _bfd_nolink_bfd_match_symbols_in_sections
 
 /*===========================================================================*/
 
--- binutils/bfd/xcoff-target.h.linkonce	2002-12-04 09:03:10.000000000 -0800
+++ binutils/bfd/xcoff-target.h	2004-05-17 09:45:17.000000000 -0700
@@ -99,6 +99,8 @@ extern int lynx_core_file_failing_signal
 #define _bfd_xcoff_bfd_gc_sections coff_bfd_gc_sections
 #define _bfd_xcoff_bfd_merge_sections coff_bfd_merge_sections
 #define _bfd_xcoff_bfd_discard_group bfd_generic_discard_group
+#define _bfd_xcoff_bfd_match_symbols_in_sections \
+  _bfd_nolink_bfd_match_symbols_in_sections
 #define _bfd_xcoff_bfd_link_split_section coff_bfd_link_split_section
 
 /* XCOFF archives do not have anything which corresponds to an
--- binutils/bfd/xsym.c.linkonce	2004-04-30 08:27:22.000000000 -0700
+++ binutils/bfd/xsym.c	2004-05-17 09:45:22.000000000 -0700
@@ -44,6 +44,8 @@
 #define bfd_sym_bfd_merge_sections bfd_generic_merge_sections
 #define bfd_sym_bfd_is_group_section bfd_generic_is_group_section
 #define bfd_sym_bfd_discard_group bfd_generic_discard_group
+#define bfd_sym_bfd_match_symbols_in_sections \
+  _bfd_nolink_bfd_match_symbols_in_sections
 #define bfd_sym_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
 #define bfd_sym_bfd_link_hash_table_free _bfd_generic_link_hash_table_free
 #define bfd_sym_bfd_link_add_symbols _bfd_generic_link_add_symbols
--- binutils/ld/ldlang.c.linkonce	2004-05-14 09:00:52.000000000 -0700
+++ binutils/ld/ldlang.c	2004-05-17 20:17:52.000000000 -0700
@@ -853,6 +853,36 @@ struct already_linked
   asection *sec;
 };
 
+struct already_linked_section
+{
+  asection *sec;
+  asection *linked;
+};
+
+static bfd_boolean
+try_match_symbols_in_sections (struct already_linked_hash_entry *h,
+			       void *info)
+{
+  struct already_linked *l;
+  struct already_linked_section *s
+    = (struct already_linked_section *) info;
+
+  /* No need to check group section.  */
+  if ((s->sec->flags & SEC_GROUP) != 0)
+    return TRUE;
+
+  for (l = h->entry; l != NULL; l = l->next)
+    if ((l->sec->flags & SEC_GROUP) == 0
+	&& bfd_match_symbols_in_sections (l->sec->owner,
+					  l->sec, s->sec))
+      {
+	s->linked = l->sec;
+	return FALSE;
+      }
+
+  return TRUE;
+}
+
 /* The hash table.  */
 
 static struct bfd_hash_table already_linked_table;
@@ -865,6 +895,8 @@ section_already_linked (bfd *abfd, asect
   const char *name;
   struct already_linked *l;
   struct already_linked_hash_entry *already_linked_list;
+  struct already_linked_section result;
+  asection *group;
 
   /* If we are only reading symbols from this object, then we want to
      discard all sections.  */
@@ -876,7 +908,12 @@ section_already_linked (bfd *abfd, asect
 
   flags = bfd_get_section_flags (abfd, sec);
 
-  if ((flags & SEC_LINK_ONCE) == 0)
+  /* Check if it belongs to a section group.  */
+  group = sec->group;
+
+  /* Return if it isn't a .gnu.linkonce section nor a member of a
+     group.  */
+  if ((flags & SEC_LINK_ONCE) == 0 && group == NULL)
     return;
 
   /* FIXME: When doing a relocatable link, we may have trouble
@@ -902,8 +939,24 @@ section_already_linked (bfd *abfd, asect
     ((struct already_linked_hash_entry *)
      bfd_hash_lookup (&already_linked_table, name, TRUE, FALSE));
 
+  if ((flags & SEC_LINK_ONCE) == 0)
+    {
+      /* If this is a member of a COMDAT group, go to comdat and
+	 .gnu.linkonce check.  */
+      if ((group->flags
+	   & (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD))
+	  == (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD))
+	goto comdat;
+      else
+	return;
+    }
+
   for (l = already_linked_list->entry; l != NULL; l = l->next)
     {
+      /* Don't check members of COMDAT groups.  */
+      if (l->group != NULL)
+	continue;
+
       if (sec->comdat == NULL
 	  || l->sec->comdat == NULL
 	  || strcmp (sec->comdat->name, l->sec->comdat->name) == 0)
@@ -957,6 +1010,26 @@ section_already_linked (bfd *abfd, asect
 	}
     }
 
+comdat:
+  /* When we get here, it must be either a member of a COMDAT group or a
+     .gnu.linkonce section. Check if a member of a COMDAT group matches
+     a .gnu.linkonce section and vice versa.  */
+  result.sec = sec;
+  result.linked = NULL;
+  bfd_hash_traverse (&already_linked_table,
+		     (bfd_boolean (*) (struct bfd_hash_entry *, void *))
+		     try_match_symbols_in_sections,
+		     &result);
+  if (result.linked)
+    {
+      sec->output_section = bfd_abs_section_ptr;
+      sec->kept_section = result.linked;
+
+      /* Also discard the group section.  */
+      if (group != NULL)
+	group->output_section = bfd_abs_section_ptr;
+    }
+
   /* This is the first section with this name.  Record it.  Allocate
      the memory from the same obstack as the hash table is kept in.  */
 


More information about the Binutils mailing list