bfd/
authorAlan Modra <amodra@gmail.com>
Fri, 19 Feb 2010 01:47:16 +0000 (01:47 +0000)
committerAlan Modra <amodra@gmail.com>
Fri, 19 Feb 2010 01:47:16 +0000 (01:47 +0000)
* elf.c (_bfd_elf_fixup_group_sections): New function, split out from..
(_bfd_elf_copy_private_header_data): ..here.
* elflink.c (_bfd_elf_size_group_sections): New function.
(bfd_elf_size_dynamic_sections): Call it.
* elf-bfd.h (_bfd_elf_size_group_sections): Declare.
(_bfd_elf_fixup_group_sections): Declare.
ld/
* ldlang.c (unique_section_p): Add os param.  Allow group
sections to match /DISCARD/.  Update all callers.
* emultempl/genelf.em (gld${EMULATION_NAME}_before_allocation): New.
(LDEMUL_BEFORE_ALLOCATION): Define.
ld/testsuite/
* ld-elf/group.ld: Discard .dropme sections.
* ld-elf/group10.d, * ld-elf/group10.s: New test.

bfd/ChangeLog
bfd/elf-bfd.h
bfd/elf.c
bfd/elflink.c
ld/ChangeLog
ld/emultempl/genelf.em
ld/ldlang.c
ld/testsuite/ChangeLog
ld/testsuite/ld-elf/group.ld
ld/testsuite/ld-elf/group10.d [new file with mode: 0644]
ld/testsuite/ld-elf/group10.s [new file with mode: 0644]

index 8e0e2dd..a09058a 100644 (file)
@@ -1,3 +1,12 @@
+2010-02-19  Alan Modra  <amodra@gmail.com>
+
+       * elf.c (_bfd_elf_fixup_group_sections): New function, split out from..
+       (_bfd_elf_copy_private_header_data): ..here.
+       * elflink.c (_bfd_elf_size_group_sections): New function.
+       (bfd_elf_size_dynamic_sections): Call it.
+       * elf-bfd.h (_bfd_elf_size_group_sections): Declare.
+       (_bfd_elf_fixup_group_sections): Declare.
+
 2010-02-18  Matthew Gretton-Dann  <matthew.gretton-dann@arm.com>
 
        * elf32-arm.c (elf32_arm_merge_eabi_attributes): Add support for
index 6d4b8dd..74348d3 100644 (file)
@@ -1773,6 +1773,10 @@ extern void _bfd_elf_link_just_syms
   (asection *, struct bfd_link_info *);
 extern void _bfd_elf_copy_link_hash_symbol_type
   (bfd *, struct bfd_link_hash_entry *, struct bfd_link_hash_entry *);
+extern bfd_boolean _bfd_elf_size_group_sections
+  (struct bfd_link_info *);
+extern bfd_boolean _bfd_elf_fixup_group_sections
+(bfd *, asection *);
 extern bfd_boolean _bfd_elf_copy_private_header_data
   (bfd *, bfd *);
 extern bfd_boolean _bfd_elf_copy_private_symbol_data
index 85ece8b..20b82a7 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -6137,58 +6137,92 @@ _bfd_elf_copy_private_section_data (bfd *ibfd,
                                             NULL);
 }
 
-/* Copy private header information.  */
+/* Look at all the SHT_GROUP sections in IBFD, making any adjustments
+   necessary if we are removing either the SHT_GROUP section or any of
+   the group member sections.  DISCARDED is the value that a section's
+   output_section has if the section will be discarded, NULL when this
+   function is called from objcopy, bfd_abs_section_ptr when called
+   from the linker.  */
 
 bfd_boolean
-_bfd_elf_copy_private_header_data (bfd *ibfd, bfd *obfd)
+_bfd_elf_fixup_group_sections (bfd *ibfd, asection *discarded)
 {
   asection *isec;
 
-  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
-      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
-    return TRUE;
-
-  /* Copy over private BFD data if it has not already been copied.
-     This must be done here, rather than in the copy_private_bfd_data
-     entry point, because the latter is called after the section
-     contents have been set, which means that the program headers have
-     already been worked out.  */
-  if (elf_tdata (obfd)->segment_map == NULL && elf_tdata (ibfd)->phdr != NULL)
-    {
-      if (! copy_private_bfd_data (ibfd, obfd))
-       return FALSE;
-    }
-
   for (isec = ibfd->sections; isec != NULL; isec = isec->next)
     if (elf_section_type (isec) == SHT_GROUP)
       {
        asection *first = elf_next_in_group (isec);
        asection *s = first;
+       bfd_size_type removed = 0;
+
        while (s != NULL)
          {
            /* If this member section is being output but the
               SHT_GROUP section is not, then clear the group info
               set up by _bfd_elf_copy_private_section_data.  */
-           if (s->output_section != NULL
-               && isec->output_section == NULL)
+           if (s->output_section != discarded
+               && isec->output_section == discarded)
              {
                elf_section_flags (s->output_section) &= ~SHF_GROUP;
                elf_group_name (s->output_section) = NULL;
              }
            /* Conversely, if the member section is not being output
               but the SHT_GROUP section is, then adjust its size.  */
-           else if (s->output_section == NULL
-                    && isec->output_section != NULL)
-             isec->output_section->size -= 4;
+           else if (s->output_section == discarded
+                    && isec->output_section != discarded)
+             removed += 4;
            s = elf_next_in_group (s);
            if (s == first)
              break;
          }
+       if (removed != 0)
+         {
+           if (discarded != NULL)
+             {
+               /* If we've been called for ld -r, then we need to
+                  adjust the input section size.  This function may
+                  be called multiple times, so save the original
+                  size.  */
+               if (isec->rawsize == 0)
+                 isec->rawsize = isec->size;
+               isec->size = isec->rawsize - removed;
+             }
+           else
+             {
+               /* Adjust the output section size when called from
+                  objcopy. */
+               isec->output_section->size -= removed;
+             }
+         }
       }
 
   return TRUE;
 }
 
+/* Copy private header information.  */
+
+bfd_boolean
+_bfd_elf_copy_private_header_data (bfd *ibfd, bfd *obfd)
+{
+  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+    return TRUE;
+
+  /* Copy over private BFD data if it has not already been copied.
+     This must be done here, rather than in the copy_private_bfd_data
+     entry point, because the latter is called after the section
+     contents have been set, which means that the program headers have
+     already been worked out.  */
+  if (elf_tdata (obfd)->segment_map == NULL && elf_tdata (ibfd)->phdr != NULL)
+    {
+      if (! copy_private_bfd_data (ibfd, obfd))
+       return FALSE;
+    }
+
+  return _bfd_elf_fixup_group_sections (ibfd, NULL);
+}
+
 /* Copy private symbol information.  If this symbol is in a section
    which we did not map into a BFD section, try to map the section
    index correctly.  We use special macro definitions for the mapped
index a325c00..9fb347b 100644 (file)
@@ -5481,6 +5481,20 @@ compute_bucket_count (struct bfd_link_info *info,
   return best_size;
 }
 
+/* Size any SHT_GROUP section for ld -r.  */
+
+bfd_boolean
+_bfd_elf_size_group_sections (struct bfd_link_info *info)
+{
+  bfd *ibfd;
+
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+    if (bfd_get_flavour (ibfd) == bfd_target_elf_flavour
+       && !_bfd_elf_fixup_group_sections (ibfd, bfd_abs_section_ptr))
+      return FALSE;
+  return TRUE;
+}
+
 /* Set up the sizes and contents of the ELF dynamic sections.  This is
    called by the ELF linker emulation before_allocation routine.  We
    must set the sizes of the sections before the linker sets the
@@ -5555,6 +5569,10 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
   elf_hash_table (info)->init_plt_refcount
     = elf_hash_table (info)->init_plt_offset;
 
+  if (info->relocatable
+      && !_bfd_elf_size_group_sections (info))
+    return FALSE;
+
   /* The backend may have to create some sections regardless of whether
      we're dynamic or not.  */
   if (bed->elf_backend_always_size_sections
index cc2b5e6..ce42f17 100644 (file)
@@ -1,3 +1,10 @@
+2010-02-19  Alan Modra  <amodra@gmail.com>
+
+       * ldlang.c (unique_section_p): Add os param.  Allow group
+       sections to match /DISCARD/.  Update all callers.
+       * emultempl/genelf.em (gld${EMULATION_NAME}_before_allocation): New.
+       (LDEMUL_BEFORE_ALLOCATION): Define.
+
 2010-02-15  Nick Clifton  <nickc@redhat.com>
 
        * po/vi.po: Updated Vietnamese translation.
index 1a6c539..62af4de 100644 (file)
@@ -48,6 +48,15 @@ gld${EMULATION_NAME}_after_open (void)
 }
 
 static void
+gld${EMULATION_NAME}_before_allocation (void)
+{
+  if (link_info.relocatable
+      && !_bfd_elf_size_group_sections (&link_info))
+    einfo ("%X%P: can not size group sections: %E\n");
+  before_allocation_default ();
+}
+
+static void
 gld${EMULATION_NAME}_after_allocation (void)
 {
   gld${EMULATION_NAME}_map_segments (FALSE);
@@ -56,4 +65,5 @@ EOF
 # Put these extra routines in ld_${EMULATION_NAME}_emulation
 #
 LDEMUL_AFTER_OPEN=gld${EMULATION_NAME}_after_open
+LDEMUL_BEFORE_ALLOCATION=gld${EMULATION_NAME}_before_allocation
 LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation
index fd75a5b..ce5a11c 100644 (file)
@@ -195,7 +195,8 @@ input_statement_is_archive_path (const char *file_spec, char *sep,
 }
 
 static bfd_boolean
-unique_section_p (const asection *sec)
+unique_section_p (const asection *sec,
+                 const lang_output_section_statement_type *os)
 {
   struct unique_sections *unam;
   const char *secnam;
@@ -203,7 +204,8 @@ unique_section_p (const asection *sec)
   if (link_info.relocatable
       && sec->owner != NULL
       && bfd_is_group_section (sec->owner, sec))
-    return TRUE;
+    return !(os != NULL
+            && strcmp (os->name, DISCARD_SECTION_NAME) == 0);
 
   secnam = sec->name;
   for (unam = unique_section_list; unam; unam = unam->next)
@@ -445,12 +447,15 @@ output_section_callback_fast (lang_wild_statement_type *ptr,
                              struct wildcard_list *sec,
                              asection *section,
                              lang_input_statement_type *file,
-                             void *output ATTRIBUTE_UNUSED)
+                             void *output)
 {
   lang_section_bst_type *node;
   lang_section_bst_type **tree;
+  lang_output_section_statement_type *os;
 
-  if (unique_section_p (section))
+  os = (lang_output_section_statement_type *) output;
+
+  if (unique_section_p (section, os))
     return;
 
   node = (lang_section_bst_type *) xmalloc (sizeof (lang_section_bst_type));
@@ -2415,9 +2420,12 @@ output_section_callback (lang_wild_statement_type *ptr,
                         void *output)
 {
   lang_statement_union_type *before;
+  lang_output_section_statement_type *os;
+
+  os = (lang_output_section_statement_type *) output;
 
   /* Exclude sections that match UNIQUE_SECTION_LIST.  */
-  if (unique_section_p (section))
+  if (unique_section_p (section, os))
     return;
 
   before = wild_sort (ptr, sec, file, section);
@@ -2428,16 +2436,14 @@ output_section_callback (lang_wild_statement_type *ptr,
      of the current list.  */
 
   if (before == NULL)
-    lang_add_section (&ptr->children, section,
-                     (lang_output_section_statement_type *) output);
+    lang_add_section (&ptr->children, section, os);
   else
     {
       lang_statement_list_type list;
       lang_statement_union_type **pp;
 
       lang_list_init (&list);
-      lang_add_section (&list, section,
-                       (lang_output_section_statement_type *) output);
+      lang_add_section (&list, section, os);
 
       /* If we are discarding the section, LIST.HEAD will
         be NULL.  */
@@ -2464,14 +2470,18 @@ check_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED,
                        struct wildcard_list *sec ATTRIBUTE_UNUSED,
                        asection *section,
                        lang_input_statement_type *file ATTRIBUTE_UNUSED,
-                       void *data)
+                       void *output)
 {
+  lang_output_section_statement_type *os;
+
+  os = (lang_output_section_statement_type *) output;
+
   /* Exclude sections that match UNIQUE_SECTION_LIST.  */
-  if (unique_section_p (section))
+  if (unique_section_p (section, os))
     return;
 
   if (section->output_section == NULL && (section->flags & SEC_READONLY) == 0)
-    ((lang_output_section_statement_type *) data)->all_input_readonly = FALSE;
+    os->all_input_readonly = FALSE;
 }
 
 /* This is passed a file name which must have been seen already and
@@ -5848,7 +5858,8 @@ lang_place_orphans (void)
                  const char *name = s->name;
                  int constraint = 0;
 
-                 if (config.unique_orphan_sections || unique_section_p (s))
+                 if (config.unique_orphan_sections
+                     || unique_section_p (s, NULL))
                    constraint = SPECIAL;
 
                  if (!ldemul_place_orphan (s, name, constraint))
index 8e075ed..e170dfc 100644 (file)
@@ -1,3 +1,8 @@
+2010-02-19  Alan Modra  <amodra@gmail.com>
+
+       * ld-elf/group.ld: Discard .dropme sections.
+       * ld-elf/group10.d, * ld-elf/group10.s: New test.
+
 2010-02-18  Matthew Gretton-Dann  <matthew.gretton-dann@arm.com>
 
        * ld-arm/attr-merge-6.attr: Add new test.  Missed off last commit.
index 58d78da..123ab26 100644 (file)
@@ -2,5 +2,5 @@ SECTIONS
 {
   . = 0x1000;
   .text : { *(.text) *(.rodata.brlt) }
-  /DISCARD/ : { *(.reginfo) }
+  /DISCARD/ : { *(.dropme) *(.reginfo) }
 }
diff --git a/ld/testsuite/ld-elf/group10.d b/ld/testsuite/ld-elf/group10.d
new file mode 100644 (file)
index 0000000..d22a70a
--- /dev/null
@@ -0,0 +1,11 @@
+#source: group10.s
+#ld: -r -T group.ld
+#readelf: -Sg --wide
+
+#...
+group section \[[ 0-9]+\] `foo_group' \[foo_group\] contains 4 sections:
+   \[Index\]    Name
+   \[[ 0-9]+\]   \.text.*
+   \[[ 0-9]+\]   \.rodata\.str.*
+   \[[ 0-9]+\]   \.data.*
+   \[[ 0-9]+\]   \.keepme.*
diff --git a/ld/testsuite/ld-elf/group10.s b/ld/testsuite/ld-elf/group10.s
new file mode 100644 (file)
index 0000000..57704b4
--- /dev/null
@@ -0,0 +1,14 @@
+       .section .text.foo,"axG",%progbits,foo_group
+       .word 0
+
+       .section .rodata.str.1,"aMSG",%progbits,1,foo_group
+       .asciz "abc"
+
+       .section .data.foo,"waG",%progbits,foo_group
+       .word 1
+
+       .section .dropme,"G",%progbits,foo_group
+       .word 2
+
+       .section .keepme,"G",%progbits,foo_group
+       .word 3