This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Re: PATCH: Fix removed sections (Re: 2.12.90.0.12 Kernel Miscompile)
On Thu, Jul 04, 2002 at 12:28:48PM +0930, Alan Modra wrote:
> /* It would be nice to strip .branch_lt from the output if the
> section is empty, but it's too late. If we strip sections here,
> the dynamic symbol table is corrupted since the section symbol
> for the stripped section isn't written. */
>
> bfd/ChangeLog
> * section.c (_bfd_strip_section_from_output): Remove unnecessary
> link order code. Don't actually remove the output section here;
> Just set a flag for the linker to do so.
Ironic that I should have a comment about dynamic symbol table
corruption here, when that's exactly what the above patch does.
_bfd_elf_link_renumber_dynsyms trundles over the output bfd sections,
so not actually removing them until later means we calculate the wrong
number of dynsyms. I still like the idea of delaying the actual
stripping though, so..
bfd/ChangeLog
* section.c (_bfd_strip_section_from_output): Remove unnecessary
link order code. Don't actually remove the output section here;
Just set a flag for the linker to do so.
* elflink.c (_bfd_elf_link_renumber_dynsyms): Test for removed
sections when setting up output section dynsyms.
ld/ChangeLog
* ldlang.c (strip_excluded_output_sections): New function.
(lang_process): Call it.
(lang_size_sections_1): Revert 2002-06-10 change.
Oh, and the section.c patch is changed a little as I don't see the
point in allowing _bfd_strip_section_from_output to accept NULL info.
--
Alan Modra
IBM OzLabs - Linux Technology Centre
Index: bfd/elflink.c
===================================================================
RCS file: /cvs/src/src/bfd/elflink.c,v
retrieving revision 1.25
diff -u -p -r1.25 elflink.c
--- bfd/elflink.c 25 Jun 2002 09:40:43 -0000 1.25
+++ bfd/elflink.c 4 Jul 2002 14:21:54 -0000
@@ -357,7 +357,8 @@ _bfd_elf_link_renumber_dynsyms (output_b
{
asection *p;
for (p = output_bfd->sections; p ; p = p->next)
- elf_section_data (p)->dynindx = ++dynsymcount;
+ if ((p->flags & SEC_EXCLUDE) == 0)
+ elf_section_data (p)->dynindx = ++dynsymcount;
}
if (elf_hash_table (info)->dynlocal)
Index: bfd/section.c
===================================================================
RCS file: /cvs/src/src/bfd/section.c,v
retrieving revision 1.49
diff -c -p -r1.49 section.c
*** bfd/section.c 25 Jun 2002 09:40:44 -0000 1.49
--- bfd/section.c 4 Jul 2002 14:22:50 -0000
*************** SYNOPSIS
*** 1301,1380 ****
DESCRIPTION
Remove @var{section} from the output. If the output section
! becomes empty, remove it from the output bfd. @var{info} may
! be NULL; if it is not, it is used to decide whether the output
! section is empty.
*/
void
_bfd_strip_section_from_output (info, s)
struct bfd_link_info *info;
asection *s;
{
! asection **spp, *os;
! struct bfd_link_order *p, *pp;
! boolean keep_os;
! /* Excise the input section from the link order.
! FIXME: For all calls that I can see to this function, the link
! orders have not yet been set up. So why are we checking them? --
! Ian */
os = s->output_section;
!
! /* Handle a section that wasn't output. */
! if (os == NULL)
return;
! for (p = os->link_order_head, pp = NULL; p != NULL; pp = p, p = p->next)
! if (p->type == bfd_indirect_link_order
! && p->u.indirect.section == s)
! {
! if (pp)
! pp->next = p->next;
! else
! os->link_order_head = p->next;
! if (!p->next)
! os->link_order_tail = pp;
! break;
! }
!
! keep_os = os->link_order_head != NULL;
!
! if (! keep_os && info != NULL)
! {
! bfd *abfd;
! for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next)
! {
! asection *is;
! for (is = abfd->sections; is != NULL; is = is->next)
! {
! if (is != s && is->output_section == os
! && (is->flags & SEC_EXCLUDE) == 0)
! break;
! }
! if (is != NULL)
! break;
! }
! if (abfd != NULL)
! keep_os = true;
! }
!
! /* If the output section is empty, remove it too. Careful about sections
! that have been discarded in the link script -- they are mapped to
! bfd_abs_section, which has no owner. */
! if (!keep_os && os->owner != NULL)
! {
! for (spp = &os->owner->sections; *spp; spp = &(*spp)->next)
! if (*spp == os)
! {
! bfd_section_list_remove (os->owner, spp);
! os->flags |= SEC_EXCLUDE;
! os->owner->section_count--;
! break;
! }
! }
!
! s->flags |= SEC_EXCLUDE;
}
/*
--- 1301,1340 ----
DESCRIPTION
Remove @var{section} from the output. If the output section
! becomes empty, remove it from the output bfd.
!
! This function won't actually do anything except twiddle flags
! if called too late in the linking process, when it's not safe
! to remove sections.
*/
void
_bfd_strip_section_from_output (info, s)
struct bfd_link_info *info;
asection *s;
{
! asection *os;
! asection *is;
! bfd *abfd;
! s->flags |= SEC_EXCLUDE;
! /* If the section wasn't assigned to an output section, or the
! section has been discarded by the linker script, there's nothing
! more to do. */
os = s->output_section;
! if (os == NULL || os->owner == NULL)
return;
! /* If the output section has other (non-excluded) input sections, we
! can't remove it. */
! for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next)
! for (is = abfd->sections; is != NULL; is = is->next)
! if (is->output_section == os && (is->flags & SEC_EXCLUDE) == 0)
! return;
!
! /* If the output section is empty, flag it for removal too.
! See ldlang.c:strip_excluded_output_sections for the action. */
! os->flags |= SEC_EXCLUDE;
}
/*
Index: ld/ldlang.c
===================================================================
RCS file: /cvs/src/src/ld/ldlang.c,v
retrieving revision 1.91
diff -u -p -r1.91 ldlang.c
--- ld/ldlang.c 1 Jul 2002 08:07:29 -0000 1.91
+++ ld/ldlang.c 4 Jul 2002 02:44:23 -0000
@@ -97,6 +97,7 @@ static void lang_place_undefineds PARAMS
static void map_input_to_output_sections
PARAMS ((lang_statement_union_type *, const char *,
lang_output_section_statement_type *));
+static void strip_excluded_output_sections PARAMS ((void));
static void print_output_section_statement
PARAMS ((lang_output_section_statement_type *));
static void print_assignment
@@ -2161,6 +2162,41 @@ map_input_to_output_sections (s, target,
}
}
+/* An output section might have been removed after its statement was
+ added. For example, ldemul_before_allocation can remove dynamic
+ sections if they turn out to be not needed. Clean them up here. */
+
+static void
+strip_excluded_output_sections ()
+{
+ lang_statement_union_type *u;
+
+ for (u = lang_output_section_statement.head;
+ u != NULL;
+ u = u->output_section_statement.next)
+ {
+ lang_output_section_statement_type *os;
+ asection *s;
+
+ os = &u->output_section_statement;
+ s = os->bfd_section;
+ if (s != NULL && (s->flags & SEC_EXCLUDE) != 0)
+ {
+ asection **p;
+
+ os->bfd_section = NULL;
+
+ for (p = &output_bfd->sections; *p; p = &(*p)->next)
+ if (*p == s)
+ {
+ bfd_section_list_remove (output_bfd, p);
+ output_bfd->section_count--;
+ break;
+ }
+ }
+ }
+}
+
static void
print_output_section_statement (output_section_statement)
lang_output_section_statement_type *output_section_statement;
@@ -2903,14 +2939,6 @@ lang_size_sections_1 (s, output_section_
/* This section was never actually created. */
break;
- /* The section might have been removed after its statement was
- added. For example, ldemul_before_allocation can remove
- dynamic sections if they turn out not to be needed. */
- if (!link_info.relocateable
- && (bfd_get_section_flags (output_bfd, os->bfd_section)
- & SEC_EXCLUDE) != 0)
- break;
-
/* If this is a COFF shared library section, use the size and
address from the input section. FIXME: This is COFF
specific; it would be cleaner if there were some other way
@@ -4251,6 +4279,9 @@ lang_process ()
/* Do anything special before sizing sections. This is where ELF
and other back-ends size dynamic sections. */
ldemul_before_allocation ();
+
+ if (!link_info.relocateable)
+ strip_excluded_output_sections ();
/* We must record the program headers before we try to fix the
section positions, since they will affect SIZEOF_HEADERS. */