* elf.c (setup_group): Set SEC_LINK_ONCE on GRP_COMDAT groups.
authorAlan Modra <amodra@gmail.com>
Tue, 4 Jun 2002 01:05:21 +0000 (01:05 +0000)
committerAlan Modra <amodra@gmail.com>
Tue, 4 Jun 2002 01:05:21 +0000 (01:05 +0000)
(bfd_section_from_shdr): Likewise.  Set section name of group
sections from signature.
(group_signature): Split out from setup_group.  Ensure symbol table
is available.
(bfd_elf_discard_group): New function.
(_bfd_elf_make_section_from_shdr): Don't set SEC_LINK_ONCE on
.gnu.linkonce* sections if they are members of a group.
(set_group_contents): Set GRP_COMDAT flag.
* section.c (bfd_discard_group): New function.
* bfd-in.h (bfd_elf_discard_group): Declare.
* bfd-in2.h: Regenerate.
* elf-bfd.h (struct bfd_elf_section_data): Add linkonce_p field.
(elf_linkonce_p): Define.

bfd/ChangeLog
bfd/bfd-in.h
bfd/bfd-in2.h
bfd/elf-bfd.h
bfd/elf.c
bfd/section.c

index bd2d5ee566b5a203dd6317b8c3f91f65ba07b0ef..6e10fadf09ba8fced71523fd498f199642d0f3d3 100644 (file)
@@ -1,3 +1,20 @@
+2002-06-04  Alan Modra  <amodra@bigpond.net.au>
+
+       * elf.c (setup_group): Set SEC_LINK_ONCE on GRP_COMDAT groups.
+       (bfd_section_from_shdr): Likewise.  Set section name of group
+       sections from signature.
+       (group_signature): Split out from setup_group.  Ensure symbol table
+       is available.
+       (bfd_elf_discard_group): New function.
+       (_bfd_elf_make_section_from_shdr): Don't set SEC_LINK_ONCE on
+       .gnu.linkonce* sections if they are members of a group.
+       (set_group_contents): Set GRP_COMDAT flag.
+       * section.c (bfd_discard_group): New function.
+       * bfd-in.h (bfd_elf_discard_group): Declare.
+       * bfd-in2.h: Regenerate.
+       * elf-bfd.h (struct bfd_elf_section_data): Add linkonce_p field.
+       (elf_linkonce_p): Define.
+
 2002-06-04  Alan Modra  <amodra@bigpond.net.au>
 
        * elf.c (bfd_section_from_shdr): Make "name" const.
index eecd798dcc28c15f65b2a5f949330428354f4c05..0ba88985292bd00d04dbc2979ec0bb52a22478ab 100644 (file)
@@ -657,6 +657,8 @@ extern boolean bfd_elf32_discard_info
   PARAMS ((bfd *, struct bfd_link_info *));
 extern boolean bfd_elf64_discard_info
   PARAMS ((bfd *, struct bfd_link_info *));
+extern void bfd_elf_discard_group
+  PARAMS ((bfd *, struct sec *));
 
 /* Return an upper bound on the number of bytes required to store a
    copy of ABFD's program header table entries.  Return -1 if an error
index f11ba2a39bb870b11b9fdfbe75ef18cc35559907..afaefef40d481f72e25c9fe43746c2c2c4e14b2f 100644 (file)
@@ -663,6 +663,8 @@ extern boolean bfd_elf32_discard_info
   PARAMS ((bfd *, struct bfd_link_info *));
 extern boolean bfd_elf64_discard_info
   PARAMS ((bfd *, struct bfd_link_info *));
+extern void bfd_elf_discard_group
+  PARAMS ((bfd *, struct sec *));
 
 /* Return an upper bound on the number of bytes required to store a
    copy of ABFD's program header table entries.  Return -1 if an error
@@ -1450,6 +1452,9 @@ bfd_copy_private_section_data PARAMS ((bfd *ibfd, asection *isec,
 void
 _bfd_strip_section_from_output PARAMS ((struct bfd_link_info *info, asection *section));
 
+void
+bfd_discard_group PARAMS ((bfd *abfd, asection *group));
+
 enum bfd_architecture
 {
   bfd_arch_unknown,   /* File arch not known.  */
index d771840722a3edfb00a1743ce43719a5568c5afa..47bb6891b5d1b11918fe8fb39f7c624639d5abfc 100644 (file)
@@ -926,11 +926,15 @@ struct bfd_elf_section_data
 
   /* Nonzero if this section uses RELA relocations, rather than REL.  */
   unsigned int use_rela_p:1;
+
+  /* Nonzero when a group is COMDAT.  */
+  unsigned int linkonce_p:1;
 };
 
 #define elf_section_data(sec)  ((struct bfd_elf_section_data*)sec->used_by_bfd)
 #define elf_group_name(sec)    (elf_section_data(sec)->group_name)
 #define elf_next_in_group(sec) (elf_section_data(sec)->next_in_group)
+#define elf_linkonce_p(sec)    (elf_section_data(sec)->linkonce_p)
 
 /* Return true if section has been discarded.  */
 #define elf_discarded_section(sec)                                     \
index a92827ff03b83ee28731b952ad5b34334a136ea5..e1e929f275079204f49b91ac4cb2d13289556209 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -50,6 +50,7 @@ static boolean prep_headers PARAMS ((bfd *));
 static boolean swap_out_syms PARAMS ((bfd *, struct bfd_strtab_hash **, int));
 static boolean copy_private_bfd_data PARAMS ((bfd *, bfd *));
 static char *elf_read PARAMS ((bfd *, file_ptr, bfd_size_type));
+static const char *group_signature PARAMS ((bfd *, Elf_Internal_Shdr *));
 static boolean setup_group PARAMS ((bfd *, Elf_Internal_Shdr *, asection *));
 static void merge_sections_remove_hook PARAMS ((bfd *, asection *));
 static void elf_fake_sections PARAMS ((bfd *, asection *, PTR));
@@ -361,6 +362,35 @@ typedef union elf_internal_group {
   unsigned int flags;
 } Elf_Internal_Group;
 
+/* Return the name of the group signature symbol.  Why isn't the
+   signature just a string?  */
+
+static const char *
+group_signature (abfd, ghdr)
+     bfd *abfd;
+     Elf_Internal_Shdr *ghdr;
+{
+  struct elf_backend_data *bed;
+  file_ptr pos;
+  unsigned char ename[4];
+  unsigned long iname;
+
+  /* First we need to ensure the symbol table is available.  */
+  if (! bfd_section_from_shdr (abfd, ghdr->sh_link))
+    return NULL;
+
+  /* Fortunately, the name index is at the same place in the external
+     symbol for both 32 and 64 bit ELF.  */
+  bed = get_elf_backend_data (abfd);
+  pos = elf_tdata (abfd)->symtab_hdr.sh_offset;
+  pos += ghdr->sh_info * bed->s->sizeof_sym;
+  if (bfd_seek (abfd, pos, SEEK_SET) != 0
+      || bfd_bread (ename, (bfd_size_type) 4, abfd) != 4)
+    return NULL;
+  iname = H_GET_32 (abfd, ename);
+  return elf_string_from_elf_strtab (abfd, iname);
+}
+
 /* Set next_in_group list pointer, and group name for NEWSECT.  */
 
 static boolean
@@ -440,6 +470,9 @@ setup_group (abfd, hdr, newsect)
                      if (src == shdr->contents)
                        {
                          dest->flags = idx;
+                         if (shdr->bfd_section != NULL && (idx & GRP_COMDAT))
+                           shdr->bfd_section->flags
+                             |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
                          break;
                        }
                      if (idx >= shnum)
@@ -492,32 +525,20 @@ setup_group (abfd, hdr, newsect)
                  }
                else
                  {
-                   struct elf_backend_data *bed;
-                   file_ptr pos;
-                   unsigned char ename[4];
-                   unsigned long iname;
                    const char *gname;
 
-                   /* Humbug.  Get the name from the group signature
-                      symbol.  Why isn't the signature just a string?
-                      Fortunately, the name index is at the same
-                      place in the external symbol for both 32 and 64
-                      bit ELF.  */
-                   bed = get_elf_backend_data (abfd);
-                   pos = elf_tdata (abfd)->symtab_hdr.sh_offset;
-                   pos += shdr->sh_info * bed->s->sizeof_sym;
-                   if (bfd_seek (abfd, pos, SEEK_SET) != 0
-                       || bfd_bread (ename, (bfd_size_type) 4, abfd) != 4)
+                   gname = group_signature (abfd, shdr);
+                   if (gname == NULL)
                      return false;
-                   iname = H_GET_32 (abfd, ename);
-                   gname = elf_string_from_elf_strtab (abfd, iname);
                    elf_group_name (newsect) = gname;
 
                    /* Start a circular list with one element.  */
                    elf_next_in_group (newsect) = newsect;
                  }
+
                if (shdr->bfd_section != NULL)
                  elf_next_in_group (shdr->bfd_section) = newsect;
+
                i = num_group - 1;
                break;
              }
@@ -532,6 +553,24 @@ setup_group (abfd, hdr, newsect)
   return true;
 }
 
+void
+bfd_elf_discard_group (abfd, group)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     asection *group;
+{
+  asection *first = elf_next_in_group (group);
+  asection *s = first;
+
+  while (s != NULL)
+    {
+      s->output_section = bfd_abs_section_ptr;
+      s = elf_next_in_group (s);
+      /* These lists are circular.  */
+      if (s == first)
+       break;
+    }
+}
+
 /* Make a BFD section from an ELF section.  We store a pointer to the
    BFD section in the bfd_section field of the header.  */
 
@@ -620,7 +659,8 @@ _bfd_elf_make_section_from_shdr (abfd, hdr, name)
      The symbols will be defined as weak, so that multiple definitions
      are permitted.  The GNU linker extension is to actually discard
      all but one of the sections.  */
-  if (strncmp (name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1) == 0)
+  if (strncmp (name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1) == 0
+      && elf_next_in_group (newsect) == NULL)
     flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
 
   bed = get_elf_backend_data (abfd);
@@ -1820,7 +1860,12 @@ bfd_section_from_shdr (abfd, shindex)
       return true;
 
     case SHT_GROUP:
-      /* Make a section for objcopy and relocatable links.  */
+      /* We need a BFD section for objcopy and relocatable linking,
+        and it's handy to have the signature available as the section
+        name.  */
+      name = group_signature (abfd, hdr);
+      if (name == NULL)
+       return false;
       if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name))
        return false;
       if (hdr->contents != NULL)
@@ -1829,6 +1874,10 @@ bfd_section_from_shdr (abfd, shindex)
          unsigned int n_elt = hdr->sh_size / 4;
          asection *s;
 
+         if (idx->flags & GRP_COMDAT)
+           hdr->bfd_section->flags
+             |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
+
          while (--n_elt != 0)
            if ((s = (++idx)->shdr->bfd_section) != NULL
                && elf_next_in_group (s) != NULL)
@@ -2369,7 +2418,7 @@ set_group_contents (abfd, sec, failedptrarg)
       while (elt != elf_next_in_group (l->u.indirect.section));
 
   loc -= 4;
-  H_PUT_32 (abfd, 0, loc);
+  H_PUT_32 (abfd, sec->flags & SEC_LINK_ONCE ? GRP_COMDAT : 0, loc);
 
   BFD_ASSERT (loc == sec->contents);
 }
index 358f5c4f0bef092759885d609276fee75ccbf804..70c7f27d029c5e6f38027da3d705026b9871b1a4 100644 (file)
@@ -1375,3 +1375,24 @@ _bfd_strip_section_from_output (info, s)
 
   s->flags |= SEC_EXCLUDE;
 }
+
+/*
+FUNCTION
+       bfd_discard_group
+
+SYNOPSIS
+       void bfd_discard_group (bfd *abfd, asection *group);
+
+DESCRIPTION
+       Remove all members of @var{group} from the output.
+*/
+
+void
+bfd_discard_group (abfd, group)
+     bfd *abfd;
+     asection *group;
+{
+  if ((group->flags & SEC_GROUP) != 0
+      && abfd->xvec->flavour == bfd_target_elf_flavour)
+    bfd_elf_discard_group (abfd, group);
+}