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)
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: Richard Sandiford <rsandifo at redhat dot com>
- Cc: "Leonard N. Zubkoff" <lnz at dandelion dot com>, hjl at lucon dot org, binutils at sources dot redhat dot com
- Date: Thu, 4 Jul 2002 12:28:48 +0930
- Subject: Re: PATCH: Fix removed sections (Re: 2.12.90.0.12 Kernel Miscompile)
- References: <200207031629.g63GTqoH026003@dandelion.com> <wvnfzz0lm2u.fsf@talisman.cambridge.redhat.com>
On Wed, Jul 03, 2002 at 07:10:01PM +0100, Richard Sandiford wrote:
> Leonard, thanks for reducing the test case.
>
> The problem was that we didn't set os->region->current for the removed
> sections, but left os->bfd_section non-null. So this code in
> lang_do_assignments() still triggered:
>
> if (os->bfd_section != NULL)
> {
> dot = os->bfd_section->vma;
> (void) lang_do_assignments (os->children.head, os,
> os->fill, dot);
> dot = os->bfd_section->vma + os->bfd_section->_raw_size / opb;
>
> }
>
> effectively setting "." to 0. The patch below fixes the test case,
> and shows no regressions on i686-pc-linux-gnu. FWIW, I don't mind
> whether we go with this patch or HJ's.
Ah ha! I'm glad I insisted on understanding the problem before
applying HJ's patch. I think it may be better to clean up these
dangling os->bfd_section entries a little earlier, since
lang_record_phdrs may have similar problems. Testing the following,
which cleans up _bfd_strip_section_from_output too, making it safe
(though pointless) to call _bfd_strip_section_from_output later in
the link. I've been bitten by _bfd_strip_section_from_output a
number of times, and now add comments like this one from elf64-ppc.c:
/* 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.
ld/ChangeLog
* ldlang.c (strip_excluded_output_sections): New function.
(lang_process): Call it.
(lang_size_sections_1): Revert 2002-06-10 change.
--
Alan Modra
IBM OzLabs - Linux Technology Centre
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 02:46:42 -0000
*************** DESCRIPTION
*** 1304,1380 ****
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;
}
/*
--- 1304,1346 ----
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.
+
+ 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;
! 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 the output section. */
! if (info != NULL)
{
bfd *abfd;
! asection *is;
! 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. */