summaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorAlan Modra <amodra@bigpond.net.au>2010-02-19 01:47:13 +0000
committerAlan Modra <amodra@bigpond.net.au>2010-02-19 01:47:13 +0000
commita37671093643f1d923ab97ff25ef6c97fda41286 (patch)
treed1b5fcd1a58b54d24496bd2c7d122dd907e12738 /bfd
parenta4a91e4b48ed9055ca9f127893c6ac9b2c939e0a (diff)
downloadbinutils-redhat-a37671093643f1d923ab97ff25ef6c97fda41286.tar.gz
bfd/
* 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.
Diffstat (limited to 'bfd')
-rw-r--r--bfd/ChangeLog9
-rw-r--r--bfd/elf-bfd.h4
-rw-r--r--bfd/elf.c78
-rw-r--r--bfd/elflink.c18
4 files changed, 87 insertions, 22 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 8e0e2ddbb0..a09058aa57 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -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
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 6d4b8dd173..74348d3abb 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -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
diff --git a/bfd/elf.c b/bfd/elf.c
index 85ece8b063..20b82a7c42 100644
--- 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
diff --git a/bfd/elflink.c b/bfd/elflink.c
index a325c00ca5..9fb347b7c5 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -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