Discussion:
PATCH: PR 797: Alignment in empty section changes the output layout
(too old to reply)
H. J. Lu
2005-05-04 18:09:41 UTC
Permalink
The recent linker change makes this bug easier to fix. Here is an
updated patch.


H.J.
---
bfd/

2005-05-04 H.J. Lu <***@intel.com>

PR 797
* elf32-i386.c (elf_i386_size_dynamic_sections): Also remove
empty sdynbss section.
* elf64-x86-64.c (elf64_x86_64_size_dynamic_sections): Likewise.

ld/

2005-05-04 H.J. Lu <***@intel.com>

PR 797
* ldlang.c (lang_output_section_statement_lookup_1): Set the
ignored field to FALSE.
(strip_unused_output_sections): New.
(strip_excluded_or_unused_output_sections): This. Accept an
argument to check for unused sections.
(lang_size_sections_1): Skip an output section if it should
be ignored.
(lang_do_assignments_1): Likewise.
(lang_process): Call strip_unused_output_sections to remove
unused output sections after lang_mark_used_section.

* ldlang.h (lang_output_section_statement_type): Change
all_input_readonly to bitfield. Add ignored.

--- binutils/bfd/elf32-i386.c.empty 2005-05-04 08:52:10.000000000 -0700
+++ binutils/bfd/elf32-i386.c 2005-05-04 10:08:02.000000000 -0700
@@ -1830,7 +1830,8 @@ elf_i386_size_dynamic_sections (bfd *out

if (s == htab->splt
|| s == htab->sgot
- || s == htab->sgotplt)
+ || s == htab->sgotplt
+ || s == htab->sdynbss)
{
/* Strip this section if we don't need it; see the
comment below. */
--- binutils/bfd/elf64-x86-64.c.empty 2005-05-04 08:52:16.000000000 -0700
+++ binutils/bfd/elf64-x86-64.c 2005-05-04 10:08:02.000000000 -0700
@@ -1622,7 +1622,8 @@ elf64_x86_64_size_dynamic_sections (bfd

if (s == htab->splt
|| s == htab->sgot
- || s == htab->sgotplt)
+ || s == htab->sgotplt
+ || s == htab->sdynbss)
{
/* Strip this section if we don't need it; see the
comment below. */
--- binutils/ld/ldlang.c.empty 2005-05-04 08:52:34.000000000 -0700
+++ binutils/ld/ldlang.c 2005-05-04 11:03:09.000000000 -0700
@@ -1022,6 +1022,7 @@ lang_output_section_statement_lookup_1 (
lookup->bfd_section = NULL;
lookup->processed = 0;
lookup->constraint = constraint;
+ lookup->ignored = FALSE;
lookup->sectype = normal_section;
lookup->addr_tree = NULL;
lang_list_init (&lookup->children);
@@ -3084,6 +3085,41 @@ strip_excluded_output_sections (void)
stripped_excluded_sections = TRUE;
}

+/* An output section might have been removed after its statement was
+ added if it isn't used at all. Clean them up here. */
+
+static void
+strip_unused_output_sections (void)
+{
+ lang_output_section_statement_type *os;
+
+ for (os = &lang_output_section_statement.head->output_section_statement;
+ os != NULL;
+ os = os->next)
+ {
+ asection *s;
+
+ if (os->constraint == -1)
+ continue;
+
+ s = os->bfd_section;
+
+ if (s != NULL
+ && s->linker_has_input == 0
+ && (s->flags & (SEC_KEEP | SEC_HAS_CONTENTS)) == 0)
+ {
+ /* We don't set bfd_section to NULL since bfd_section of the
+ removed output section statement may still be used. */
+ os->ignored = TRUE;
+ if (!bfd_section_removed_from_list (output_bfd, s))
+ {
+ bfd_section_list_remove (output_bfd, s);
+ output_bfd->section_count--;
+ }
+ }
+ }
+}
+
static void
print_output_section_statement
(lang_output_section_statement_type *output_section_statement)
@@ -3855,8 +3891,8 @@ lang_size_sections_1
lang_output_section_statement_type *os;

os = &s->output_section_statement;
- if (os->bfd_section == NULL)
- /* This section was never actually created. */
+ if (os->bfd_section == NULL || os->ignored)
+ /* This section was removed or never actually created. */
break;

/* If this is a COFF shared library section, use the size and
@@ -4351,7 +4387,7 @@ lang_do_assignments_1
lang_output_section_statement_type *os;

os = &(s->output_section_statement);
- if (os->bfd_section != NULL)
+ if (os->bfd_section != NULL && !os->ignored)
{
dot = os->bfd_section->vma;
lang_do_assignments_1 (os->children.head, os, os->fill, dot);
@@ -4365,7 +4401,7 @@ lang_do_assignments_1
{
/* If nothing has been placed into the output section then
it won't have a bfd_section. */
- if (os->bfd_section)
+ if (os->bfd_section && !os->ignored)
{
os->bfd_section->lma
= exp_get_abs_int (os->load_base, 0, "load base",
@@ -5301,9 +5337,19 @@ lang_process (void)
}
}
while (relax_again);
+ }

+ if (command_line.relax || !link_info.relocatable)
+ {
/* Final extra sizing to report errors. */
lang_do_assignments (statement_list.head, abs_output_section, NULL, 0);
+ if (!link_info.relocatable)
+ {
+ lang_mark_used_section ();
+ /* Do it here so that the unused output_sections won't affect
+ memory layout. */
+ strip_unused_output_sections ();
+ }
lang_reset_memory_regions ();
lang_size_sections (statement_list.head, abs_output_section,
&statement_list.head, 0, 0, NULL, TRUE);
@@ -5327,7 +5373,7 @@ lang_process (void)
lang_check_section_addresses ();

/* Final stuffs. */
- lang_mark_used_section ();
+
ldemul_finish ();
lang_finish ();
}
--- binutils/ld/ldlang.h.empty 2005-05-04 08:52:34.000000000 -0700
+++ binutils/ld/ldlang.h 2005-05-04 10:36:53.000000000 -0700
@@ -147,7 +147,8 @@ typedef struct lang_output_section_state
int subsection_alignment; /* Alignment of components. */
int section_alignment; /* Alignment of start of section. */
int constraint;
- bfd_boolean all_input_readonly;
+ unsigned int all_input_readonly : 1;
+ unsigned int ignored : 1;

union etree_union *load_base;
Alan Modra
2005-05-05 02:37:17 UTC
Permalink
Post by H. J. Lu
+ if (command_line.relax || !link_info.relocatable)
+ {
/* Final extra sizing to report errors. */
lang_do_assignments (statement_list.head, abs_output_section, NULL, 0);
+ if (!link_info.relocatable)
+ {
+ lang_mark_used_section ();
+ /* Do it here so that the unused output_sections won't affect
+ memory layout. */
+ strip_unused_output_sections ();
+ }
Can you please look at merging lang_mark_used_section and
strip_unused_output_sections into strip_excluded_output_sections?

I think it should be possible if you call lang_do_assignments before
bfd_gc_sections to ensure that linker script symbols defined inside
output sections are in the hash table.
--
Alan Modra
IBM OzLabs - Linux Technology Centre
H. J. Lu
2005-05-05 04:48:17 UTC
Permalink
Post by Alan Modra
Post by H. J. Lu
+ if (command_line.relax || !link_info.relocatable)
+ {
/* Final extra sizing to report errors. */
lang_do_assignments (statement_list.head, abs_output_section, NULL, 0);
+ if (!link_info.relocatable)
+ {
+ lang_mark_used_section ();
+ /* Do it here so that the unused output_sections won't affect
+ memory layout. */
+ strip_unused_output_sections ();
+ }
Can you please look at merging lang_mark_used_section and
strip_unused_output_sections into strip_excluded_output_sections?
I think it should be possible if you call lang_do_assignments before
bfd_gc_sections to ensure that linker script symbols defined inside
output sections are in the hash table.
I am not sure it will work since the order is quite important. I
got many

/export/build/gnu/binutils-debug/build-i686-linux/ld/ld-new:
tmpdir/ld1: Not enough room for program headers (allocated 2, need 4)
/export/build/gnu/binutils-debug/build-i686-linux/ld/ld-new: final link
failed: Bad value


H.J.
H.J.
Alan Modra
2005-05-05 05:14:56 UTC
Permalink
Post by H. J. Lu
Post by Alan Modra
Can you please look at merging lang_mark_used_section and
strip_unused_output_sections into strip_excluded_output_sections?
I think it should be possible if you call lang_do_assignments before
bfd_gc_sections to ensure that linker script symbols defined inside
output sections are in the hash table.
I am not sure it will work since the order is quite important. I
got many
tmpdir/ld1: Not enough room for program headers (allocated 2, need 4)
/export/build/gnu/binutils-debug/build-i686-linux/ld/ld-new: final link
failed: Bad value
Did you find that you needed to run lang_size_sections early as well?
If so, see emultempl/ppc64elf.em:ppc_before_allocation for what needs to
be undone.
--
Alan Modra
IBM OzLabs - Linux Technology Centre
H. J. Lu
2005-05-05 05:35:44 UTC
Permalink
Post by Alan Modra
Post by H. J. Lu
Post by Alan Modra
Can you please look at merging lang_mark_used_section and
strip_unused_output_sections into strip_excluded_output_sections?
I think it should be possible if you call lang_do_assignments before
bfd_gc_sections to ensure that linker script symbols defined inside
output sections are in the hash table.
I am not sure it will work since the order is quite important. I
got many
tmpdir/ld1: Not enough room for program headers (allocated 2, need 4)
/export/build/gnu/binutils-debug/build-i686-linux/ld/ld-new: final link
failed: Bad value
Did you find that you needed to run lang_size_sections early as well?
If so, see emultempl/ppc64elf.em:ppc_before_allocation for what needs to
be undone.
Same problem. ldemul_before_allocation is called after
map_input_to_output_sections. I guess it is hard to call
lang_do_assignments before it. Besides, it makes lang_process even
more complicated.


H.J.
Alan Modra
2005-05-05 05:56:16 UTC
Permalink
Post by H. J. Lu
Post by Alan Modra
Post by H. J. Lu
Post by Alan Modra
Can you please look at merging lang_mark_used_section and
strip_unused_output_sections into strip_excluded_output_sections?
I think it should be possible if you call lang_do_assignments before
bfd_gc_sections to ensure that linker script symbols defined inside
output sections are in the hash table.
I am not sure it will work since the order is quite important. I
got many
tmpdir/ld1: Not enough room for program headers (allocated 2, need 4)
/export/build/gnu/binutils-debug/build-i686-linux/ld/ld-new: final link
failed: Bad value
Did you find that you needed to run lang_size_sections early as well?
If so, see emultempl/ppc64elf.em:ppc_before_allocation for what needs to
be undone.
Same problem. ldemul_before_allocation is called after
map_input_to_output_sections. I guess it is hard to call
lang_do_assignments before it. Besides, it makes lang_process even
more complicated.
I meant for you to call lang_do_assignments, bfd_gc_sections and
strip_unused_output_sections from strip_excluded_output_sections. Is
that what you're doing?
--
Alan Modra
IBM OzLabs - Linux Technology Centre
H. J. Lu
2005-05-05 16:02:23 UTC
Permalink
Post by Alan Modra
Post by H. J. Lu
Post by Alan Modra
Post by H. J. Lu
Post by Alan Modra
Can you please look at merging lang_mark_used_section and
strip_unused_output_sections into strip_excluded_output_sections?
I think it should be possible if you call lang_do_assignments before
bfd_gc_sections to ensure that linker script symbols defined inside
output sections are in the hash table.
I am not sure it will work since the order is quite important. I
got many
tmpdir/ld1: Not enough room for program headers (allocated 2, need 4)
/export/build/gnu/binutils-debug/build-i686-linux/ld/ld-new: final link
failed: Bad value
Did you find that you needed to run lang_size_sections early as well?
If so, see emultempl/ppc64elf.em:ppc_before_allocation for what needs to
be undone.
Same problem. ldemul_before_allocation is called after
map_input_to_output_sections. I guess it is hard to call
lang_do_assignments before it. Besides, it makes lang_process even
more complicated.
I meant for you to call lang_do_assignments, bfd_gc_sections and
strip_unused_output_sections from strip_excluded_output_sections. Is
that what you're doing?
With

lang_size_sections (statement_list.head, abs_output_section,
&statement_list.head, 0, 0, NULL,
command_line.relax ? FALSE : TRUE);
lang_do_assignments (statement_list.head, abs_output_section, NULL,
0);
lang_reset_memory_regions ();
lang_mark_used_section ();
strip_unused_output_sections ();

at the end of strip_excluded_output_sections, I got

Running
/export/gnu/src/binutils/binutils/ld/testsuite/ld-scripts/phdrs.exp ...
/export/build/gnu/binutils-debug/build-i686-linux/ld/../gas/as-new -o
tmpdir/phdrs.o
/export/gnu/src/binutils/binutils/ld/testsuite/ld-scripts/phdrs.s
/export/build/gnu/binutils-debug/build-i686-linux/ld/ld-new -o
tmpdir/phdrs -T
/export/gnu/src/binutils/binutils/ld/testsuite/ld-scripts/phdrs.t
tmpdir/phdrs.o/export/build/gnu/binutils-debug/build-i686-linux/ld/ld-new:
tmpdir/phdrs: Not enough room for program headers (allocated 2, need 3)
/export/build/gnu/binutils-debug/build-i686-linux/ld/ld-new: final link
failed: Bad value FAIL: PHDRS

and

Running
/export/gnu/src/binutils/binutils/ld/testsuite/ld-scripts/phdrs2.exp
.../export/build/gnu/binutils-debug/build-i686-linux/ld/../gas/as-new
-o tmpdir/phdrs2.o
/export/gnu/src/binutils/binutils/ld/testsuite/ld-scripts/phdrs2.s
/export/build/gnu/binutils-debug/build-i686-linux/ld/ld-new -o
tmpdir/phdrs2 -T
/export/gnu/src/binutils/binutils/ld/testsuite/ld-scripts/phdrs2.t
tmpdir/phdrs2.o
/export/build/gnu/binutils-debug/build-i686-linux/ld/../binutils/objdump
--private tmpdir/phdrs2

tmpdir/phdrs2: file format elf32-i386

Program Header:
LOAD off 0x00001000 vaddr 0x00800000 paddr 0x00800000 align
2**12
filesz 0x00000004 memsz 0x00000004 flags r-x
LOAD off 0x00001000 vaddr 0x00000000 paddr 0x00000000 align
2**12
filesz 0x0080000c memsz 0x0080000c flags rw-

FAIL: PHDRS2


H.J.
Alan Modra
2005-05-06 06:17:17 UTC
Permalink
Post by H. J. Lu
With
lang_size_sections (statement_list.head, abs_output_section,
&statement_list.head, 0, 0, NULL,
command_line.relax ? FALSE : TRUE);
lang_do_assignments (statement_list.head, abs_output_section, NULL, 0);
lang_reset_memory_regions ();
lang_mark_used_section ();
strip_unused_output_sections ();
at the end of strip_excluded_output_sections, I got
failed: Bad value FAIL: PHDRS
FAIL: PHDRS2
You need this from ppc64elf.em.

/* We must not cache anything from the preliminary sizing. */
elf_tdata (output_bfd)->program_header_size = 0;

Perhaps a better approach would be to run a cut-down lang_do_assignments
that just keeps track of output section and symbol assignments other
than "." within output sections. If it finds such an assignment, mark
the section as needed.
--
Alan Modra
IBM OzLabs - Linux Technology Centre
H. J. Lu
2005-05-07 17:34:32 UTC
Permalink
Post by Alan Modra
Post by H. J. Lu
With
lang_size_sections (statement_list.head, abs_output_section,
&statement_list.head, 0, 0, NULL,
command_line.relax ? FALSE : TRUE);
lang_do_assignments (statement_list.head, abs_output_section, NULL, 0);
lang_reset_memory_regions ();
lang_mark_used_section ();
strip_unused_output_sections ();
at the end of strip_excluded_output_sections, I got
failed: Bad value FAIL: PHDRS
FAIL: PHDRS2
You need this from ppc64elf.em.
/* We must not cache anything from the preliminary sizing. */
elf_tdata (output_bfd)->program_header_size = 0;
Perhaps a better approach would be to run a cut-down lang_do_assignments
that just keeps track of output section and symbol assignments other
than "." within output sections. If it finds such an assignment, mark
the section as needed.
This patch implements it.


H.J.
-----
bfd/

2005-05-07 H.J. Lu <***@intel.com>

PR 797
* elf32-i386.c (elf_i386_size_dynamic_sections): Also remove
empty sdynbss section.
* elf64-x86-64.c (elf64_x86_64_size_dynamic_sections): Likewise.

ld/

2005-05-07 H.J. Lu <***@intel.com>

PR 797
* ldexp.c (exp_fold_tree_1): Renamed from exp_fold_tree and
take take a bfd_boolean, mark_used. Skip etree_assert if
mark_used is TRUE.
(exp_fold_tree) Call exp_fold_tree_1 with mark_used == FALSE.
(exp_fold_tree_no_dot): Updated to take a bfd_boolean,
mark_used and pass down.
(fold_unary): Likewise.
(fold_binary): Likewise.
(fold_trinary): Likewise.
(exp_binop): Add FALSE to call to exp_fold_tree_no_dot.
(exp_trinop): Likewise.
(exp_unop): Likewise.
(exp_nameop): Likewise.
(exp_get_vma): Likewise.
(exp_get_fill): Likewise.
(exp_get_abs_int): Likewise.
(fold_name): Likewise. Set SEC_KEEP in output section flags.
(exp_mark_used_section): New.

* ldexp.h (exp_mark_used_section): New.

* ldlang.c (lang_output_section_statement_lookup_1): Set the
ignored field to FALSE.
(lang_mark_used_section_1): New.
(lang_mark_used_section): Call lang_mark_used_section_1.
(strip_excluded_output_sections): Call lang_mark_used_section
and check for unused sections.
(lang_size_sections_1): Skip an output section if it should
be ignored.
(lang_do_assignments_1): Likewise.
(lang_process): Don't call lang_mark_used_section here.

* ldlang.h (lang_output_section_statement_type): Change
all_input_readonly to bitfield. Add ignored.

--- binutils/bfd/elf32-i386.c.empty 2005-05-05 07:44:37.000000000 -0700
+++ binutils/bfd/elf32-i386.c 2005-05-07 06:58:49.000000000 -0700
@@ -1914,7 +1914,8 @@ elf_i386_size_dynamic_sections (bfd *out

if (s == htab->splt
|| s == htab->sgot
- || s == htab->sgotplt)
+ || s == htab->sgotplt
+ || s == htab->sdynbss)
{
/* Strip this section if we don't need it; see the
comment below. */
--- binutils/bfd/elf64-x86-64.c.empty 2005-05-05 07:44:41.000000000 -0700
+++ binutils/bfd/elf64-x86-64.c 2005-05-07 06:58:49.000000000 -0700
@@ -1624,7 +1624,8 @@ elf64_x86_64_size_dynamic_sections (bfd

if (s == htab->splt
|| s == htab->sgot
- || s == htab->sgotplt)
+ || s == htab->sgotplt
+ || s == htab->sdynbss)
{
/* Strip this section if we don't need it; see the
comment below. */
--- binutils/ld/ldexp.c.empty 2005-03-15 09:35:19.000000000 -0800
+++ binutils/ld/ldexp.c 2005-05-07 09:54:41.000000000 -0700
@@ -41,8 +41,12 @@
#include "libiberty.h"
#include "safe-ctype.h"

+static etree_value_type exp_fold_tree_1
+ (etree_type *, lang_output_section_statement_type *,
+ lang_phase_type, bfd_vma, bfd_vma *, bfd_boolean);
static etree_value_type exp_fold_tree_no_dot
- (etree_type *, lang_output_section_statement_type *, lang_phase_type);
+ (etree_type *, lang_output_section_statement_type *, lang_phase_type,
+ bfd_boolean);
static bfd_vma align_n
(bfd_vma, bfd_vma);

@@ -219,13 +223,14 @@ fold_unary (etree_type *tree,
lang_output_section_statement_type *current_section,
lang_phase_type allocation_done,
bfd_vma dot,
- bfd_vma *dotp)
+ bfd_vma *dotp,
+ bfd_boolean mark_used)
{
etree_value_type result;

- result = exp_fold_tree (tree->unary.child,
- current_section,
- allocation_done, dot, dotp);
+ result = exp_fold_tree_1 (tree->unary.child,
+ current_section,
+ allocation_done, dot, dotp, mark_used);
if (result.valid_p)
{
switch (tree->type.node_code)
@@ -308,12 +313,13 @@ fold_binary (etree_type *tree,
lang_output_section_statement_type *current_section,
lang_phase_type allocation_done,
bfd_vma dot,
- bfd_vma *dotp)
+ bfd_vma *dotp,
+ bfd_boolean mark_used)
{
etree_value_type result;

- result = exp_fold_tree (tree->binary.lhs, current_section,
- allocation_done, dot, dotp);
+ result = exp_fold_tree_1 (tree->binary.lhs, current_section,
+ allocation_done, dot, dotp, mark_used);

/* The SEGMENT_START operator is special because its first
operand is a string, not the name of a symbol. */
@@ -338,9 +344,10 @@ fold_binary (etree_type *tree,
{
etree_value_type other;

- other = exp_fold_tree (tree->binary.rhs,
- current_section,
- allocation_done, dot, dotp);
+ other = exp_fold_tree_1 (tree->binary.rhs,
+ current_section,
+ allocation_done,
+ dot, dotp, mark_used);
if (other.valid_p)
{
/* If the values are from different sections, or this is an
@@ -498,18 +505,20 @@ fold_trinary (etree_type *tree,
lang_output_section_statement_type *current_section,
lang_phase_type allocation_done,
bfd_vma dot,
- bfd_vma *dotp)
+ bfd_vma *dotp,
+ bfd_boolean mark_used)
{
etree_value_type result;

- result = exp_fold_tree (tree->trinary.cond, current_section,
- allocation_done, dot, dotp);
+ result = exp_fold_tree_1 (tree->trinary.cond, current_section,
+ allocation_done, dot, dotp, mark_used);
if (result.valid_p)
- result = exp_fold_tree ((result.value
- ? tree->trinary.lhs
- : tree->trinary.rhs),
- current_section,
- allocation_done, dot, dotp);
+ result = exp_fold_tree_1 ((result.value
+ ? tree->trinary.lhs
+ : tree->trinary.rhs),
+ current_section,
+ allocation_done,
+ dot, dotp, mark_used);

return result;
}
@@ -518,7 +527,8 @@ static etree_value_type
fold_name (etree_type *tree,
lang_output_section_statement_type *current_section,
lang_phase_type allocation_done,
- bfd_vma dot)
+ bfd_vma dot,
+ bfd_boolean mark_used)
{
etree_value_type result;

@@ -596,6 +606,7 @@ fold_name (etree_type *tree,
+ h->u.def.section->output_offset),
NULL,
os);
+ os->bfd_section->flags |= SEC_KEEP;
}
}
}
@@ -619,8 +630,12 @@ fold_name (etree_type *tree,
lang_output_section_statement_type *os;

os = lang_output_section_find (tree->name.name);
- if (os && os->processed > 0)
- result = new_rel (0, NULL, os);
+ if (os)
+ {
+ os->bfd_section->flags |= SEC_KEEP;
+ if (os->processed > 0)
+ result = new_rel (0, NULL, os);
+ }
}
break;

@@ -630,14 +645,19 @@ fold_name (etree_type *tree,
lang_output_section_statement_type *os;

os = lang_output_section_find (tree->name.name);
- if (os && os->processed != 0)
+ if (os)
{
- if (os->load_base == NULL)
- result = new_rel (0, NULL, os);
- else
- result = exp_fold_tree_no_dot (os->load_base,
- abs_output_section,
- allocation_done);
+ os->bfd_section->flags |= SEC_KEEP;
+ if (os->processed != 0)
+ {
+ if (os->load_base == NULL)
+ result = new_rel (0, NULL, os);
+ else
+ result = exp_fold_tree_no_dot (os->load_base,
+ abs_output_section,
+ allocation_done,
+ mark_used);
+ }
}
}
break;
@@ -649,8 +669,12 @@ fold_name (etree_type *tree,
lang_output_section_statement_type *os;

os = lang_output_section_find (tree->name.name);
- if (os && os->processed > 0)
- result = new_abs (os->bfd_section->size / opb);
+ if (os)
+ {
+ os->bfd_section->flags |= SEC_KEEP;
+ if (os->processed > 0)
+ result = new_abs (os->bfd_section->size / opb);
+ }
}
break;

@@ -688,12 +712,13 @@ fold_name (etree_type *tree,
return result;
}

-etree_value_type
-exp_fold_tree (etree_type *tree,
- lang_output_section_statement_type *current_section,
- lang_phase_type allocation_done,
- bfd_vma dot,
- bfd_vma *dotp)
+static etree_value_type
+exp_fold_tree_1 (etree_type *tree,
+ lang_output_section_statement_type *current_section,
+ lang_phase_type allocation_done,
+ bfd_vma dot,
+ bfd_vma *dotp,
+ bfd_boolean mark_used)
{
etree_value_type result;

@@ -721,26 +746,32 @@ exp_fold_tree (etree_type *tree,
break;

case etree_assert:
- result = exp_fold_tree (tree->assert_s.child,
- current_section,
- allocation_done, dot, dotp);
- if (result.valid_p && !result.value)
- einfo ("%X%P: %s\n", tree->assert_s.message);
+ if (!mark_used)
+ {
+ result = exp_fold_tree_1 (tree->assert_s.child,
+ current_section,
+ allocation_done, dot, dotp,
+ mark_used);
+ if (result.valid_p && !result.value)
+ einfo ("%X%P: %s\n", tree->assert_s.message);
+ }
+ else
+ memset (&result, 0, sizeof (result));
break;

case etree_unary:
result = fold_unary (tree, current_section, allocation_done,
- dot, dotp);
+ dot, dotp, mark_used);
break;

case etree_binary:
result = fold_binary (tree, current_section, allocation_done,
- dot, dotp);
+ dot, dotp, mark_used);
break;

case etree_trinary:
result = fold_trinary (tree, current_section, allocation_done,
- dot, dotp);
+ dot, dotp, mark_used);
break;

case etree_assign:
@@ -757,9 +788,10 @@ exp_fold_tree (etree_type *tree,
{
/* Notify the folder that this is an assignment to dot. */
assigning_to_dot = TRUE;
- result = exp_fold_tree (tree->assign.src,
- current_section,
- allocation_done, dot, dotp);
+ result = exp_fold_tree_1 (tree->assign.src,
+ current_section,
+ allocation_done,
+ dot, dotp, mark_used);
assigning_to_dot = FALSE;

if (! result.valid_p)
@@ -788,9 +820,9 @@ exp_fold_tree (etree_type *tree,
}
else
{
- result = exp_fold_tree (tree->assign.src,
- current_section, allocation_done,
- dot, dotp);
+ result = exp_fold_tree_1 (tree->assign.src,
+ current_section, allocation_done,
+ dot, dotp, mark_used);
if (result.valid_p)
{
bfd_boolean create;
@@ -832,7 +864,8 @@ exp_fold_tree (etree_type *tree,
break;

case etree_name:
- result = fold_name (tree, current_section, allocation_done, dot);
+ result = fold_name (tree, current_section, allocation_done, dot,
+ mark_used);
break;

default:
@@ -844,12 +877,25 @@ exp_fold_tree (etree_type *tree,
return result;
}

+etree_value_type
+exp_fold_tree (etree_type *tree,
+ lang_output_section_statement_type *current_section,
+ lang_phase_type allocation_done,
+ bfd_vma dot,
+ bfd_vma *dotp)
+{
+ return exp_fold_tree_1 (tree, current_section, allocation_done,
+ dot, dotp, FALSE);
+}
+
static etree_value_type
exp_fold_tree_no_dot (etree_type *tree,
lang_output_section_statement_type *current_section,
- lang_phase_type allocation_done)
+ lang_phase_type allocation_done,
+ bfd_boolean mark_used)
{
- return exp_fold_tree (tree, current_section, allocation_done, 0, NULL);
+ return exp_fold_tree_1 (tree, current_section, allocation_done, 0,
+ NULL, mark_used);
}

etree_type *
@@ -864,7 +910,7 @@ exp_binop (int code, etree_type *lhs, et
value.type.node_class = etree_binary;
r = exp_fold_tree_no_dot (&value,
abs_output_section,
- lang_first_phase_enum);
+ lang_first_phase_enum, FALSE);
if (r.valid_p)
{
return exp_intop (r.value);
@@ -884,7 +930,7 @@ exp_trinop (int code, etree_type *cond,
value.trinary.cond = cond;
value.trinary.rhs = rhs;
value.type.node_class = etree_trinary;
- r = exp_fold_tree_no_dot (&value, NULL, lang_first_phase_enum);
+ r = exp_fold_tree_no_dot (&value, NULL, lang_first_phase_enum, FALSE);
if (r.valid_p)
return exp_intop (r.value);

@@ -903,7 +949,7 @@ exp_unop (int code, etree_type *child)
value.unary.child = child;
value.unary.type.node_class = etree_unary;
r = exp_fold_tree_no_dot (&value, abs_output_section,
- lang_first_phase_enum);
+ lang_first_phase_enum, FALSE);
if (r.valid_p)
return exp_intop (r.value);

@@ -921,7 +967,7 @@ exp_nameop (int code, const char *name)
value.name.name = name;
value.name.type.node_class = etree_name;

- r = exp_fold_tree_no_dot (&value, NULL, lang_first_phase_enum);
+ r = exp_fold_tree_no_dot (&value, NULL, lang_first_phase_enum, FALSE);
if (r.valid_p)
return exp_intop (r.value);

@@ -1071,7 +1117,8 @@ exp_get_vma (etree_type *tree,

if (tree != NULL)
{
- r = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done);
+ r = exp_fold_tree_no_dot (tree, abs_output_section,
+ allocation_done, FALSE);
if (! r.valid_p && name != NULL)
einfo (_("%F%S nonconstant expression for %s\n"), name);
return r.value;
@@ -1103,7 +1150,8 @@ exp_get_fill (etree_type *tree,
if (tree == NULL)
return def;

- r = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done);
+ r = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done,
+ FALSE);
if (! r.valid_p && name != NULL)
einfo (_("%F%S nonconstant expression for %s\n"), name);

@@ -1154,7 +1202,8 @@ exp_get_abs_int (etree_type *tree,
lang_phase_type allocation_done)
{
etree_value_type res;
- res = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done);
+ res = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done,
+ FALSE);

if (res.valid_p)
res.value += res.section->bfd_section->vma;
@@ -1173,3 +1222,91 @@ align_n (bfd_vma value, bfd_vma align)
value = (value + align - 1) / align;
return value * align;
}
+
+void
+exp_mark_used_section
+ (etree_type *tree,
+ lang_output_section_statement_type *current_section)
+{
+ switch (tree->type.node_class)
+ {
+ case etree_value:
+ break;
+
+ case etree_rel:
+ break;
+
+ case etree_assert:
+ break;
+
+ case etree_unary:
+ break;
+
+ case etree_binary:
+ break;
+
+ case etree_trinary:
+ break;
+
+ case etree_assign:
+ case etree_provide:
+ case etree_provided:
+ if (tree->assign.dst[0] != '.' || tree->assign.dst[1] != 0)
+ {
+ etree_value_type result;
+ bfd_vma dot = 0;
+
+ result = exp_fold_tree_1 (tree->assign.src,
+ current_section,
+ lang_allocating_phase_enum,
+ dot, &dot, TRUE);
+ if (result.valid_p)
+ {
+ bfd_boolean create;
+ struct bfd_link_hash_entry *h;
+
+ if (tree->type.node_class == etree_assign)
+ create = TRUE;
+ else
+ create = FALSE;
+ h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst,
+ create, FALSE, TRUE);
+ if (h == NULL)
+ {
+ if (create)
+ einfo (_("%P%F:%s: hash creation failed\n"),
+ tree->assign.dst);
+ }
+ else if (tree->type.node_class == etree_provide
+ && h->type != bfd_link_hash_new
+ && h->type != bfd_link_hash_undefined
+ && h->type != bfd_link_hash_common)
+ {
+ /* Do nothing. The symbol was defined by some
+ object. */
+ }
+ else
+ {
+ /* FIXME: Should we worry if the symbol is already
+ defined? */
+ lang_update_definedness (tree->assign.dst, h);
+ h->type = bfd_link_hash_defined;
+ h->u.def.value = result.value;
+ h->u.def.section = result.section->bfd_section;
+ if (tree->type.node_class == etree_provide)
+ tree->type.node_class = etree_provided;
+ }
+ }
+ }
+ break;
+
+ case etree_name:
+ fold_name (tree, current_section, lang_allocating_phase_enum, 0,
+ TRUE);
+ break;
+
+ default:
+ abort ();
+ break;
+ }
+}
--- binutils/ld/ldexp.h.empty 2004-12-22 09:30:57.000000000 -0800
+++ binutils/ld/ldexp.h 2005-05-07 09:34:05.000000000 -0700
@@ -156,5 +156,7 @@ fill_type *exp_get_fill
(etree_type *, fill_type *, char *, lang_phase_type);
bfd_vma exp_get_abs_int
(etree_type *, int, char *, lang_phase_type);
+void exp_mark_used_section
+ (etree_type *, struct lang_output_section_statement_struct *);

#endif
--- binutils/ld/ldlang.c.empty 2005-05-07 06:58:49.000000000 -0700
+++ binutils/ld/ldlang.c 2005-05-07 10:13:04.000000000 -0700
@@ -1083,6 +1083,7 @@ lang_output_section_statement_lookup_1 (
lookup->bfd_section = NULL;
lookup->processed = 0;
lookup->constraint = constraint;
+ lookup->ignored = FALSE;
lookup->sectype = normal_section;
lookup->addr_tree = NULL;
lang_list_init (&lookup->children);
@@ -3109,6 +3110,90 @@ map_input_to_output_sections
}
}

+/* Worker function for lang_mark_used_section. Recursiveness goes
+ here. */
+
+static void
+lang_mark_used_section_1
+ (lang_statement_union_type *s,
+ lang_output_section_statement_type *output_section_statement)
+{
+ for (; s != NULL; s = s->header.next)
+ {
+ switch (s->header.type)
+ {
+ case lang_constructors_statement_enum:
+ break;
+
+ case lang_output_section_statement_enum:
+ {
+ lang_output_section_statement_type *os;
+
+ os = &(s->output_section_statement);
+ if (os->bfd_section != NULL)
+ lang_mark_used_section_1 (os->children.head, os);
+ }
+ break;
+ case lang_wild_statement_enum:
+ lang_mark_used_section_1 (s->wild_statement.children.head,
+ output_section_statement);
+
+ break;
+
+ case lang_object_symbols_statement_enum:
+ case lang_output_statement_enum:
+ case lang_target_statement_enum:
+ break;
+ case lang_data_statement_enum:
+ exp_mark_used_section (s->data_statement.exp,
+ abs_output_section);
+ break;
+
+ case lang_reloc_statement_enum:
+ break;
+
+ case lang_input_section_enum:
+ break;
+
+ case lang_input_statement_enum:
+ break;
+ case lang_fill_statement_enum:
+ break;
+ case lang_assignment_statement_enum:
+ exp_mark_used_section (s->assignment_statement.exp,
+ output_section_statement);
+ break;
+ case lang_padding_statement_enum:
+ break;
+
+ case lang_group_statement_enum:
+ lang_mark_used_section_1 (s->group_statement.children.head,
+ output_section_statement);
+ break;
+
+ default:
+ FAIL ();
+ break;
+ case lang_address_statement_enum:
+ break;
+ }
+ }
+}
+
+static void
+lang_mark_used_section (void)
+{
+ unsigned int gc_sections = link_info.gc_sections;
+
+ /* Callers of exp_fold_tree need to increment this. */
+ lang_statement_iteration++;
+ lang_mark_used_section_1 (statement_list.head, abs_output_section);
+
+ link_info.gc_sections = 0;
+ bfd_gc_sections (output_bfd, &link_info);
+ link_info.gc_sections = gc_sections;
+}
+
/* 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. */
@@ -3118,32 +3203,54 @@ strip_excluded_output_sections (void)
{
lang_output_section_statement_type *os;

+ lang_mark_used_section ();
+
for (os = &lang_output_section_statement.head->output_section_statement;
os != NULL;
os = os->next)
{
- asection *s;
+ asection *output_section;
+ bfd_boolean exclude;

if (os->constraint == -1)
continue;

- if (os->bfd_section == NULL || os->bfd_section->map_head.s == NULL)
+ output_section = os->bfd_section;
+ if (output_section == NULL)
continue;

- for (s = os->bfd_section->map_head.s; s != NULL; s = s->map_head.s)
- if ((s->flags & SEC_EXCLUDE) == 0)
- break;
+ exclude = FALSE;
+ if (output_section->map_head.s != NULL)
+ {
+ asection *s;

- os->bfd_section->map_head.link_order = NULL;
- os->bfd_section->map_tail.link_order = NULL;
+ for (s = output_section->map_head.s; s != NULL;
+ s = s->map_head.s)
+ if ((s->flags & SEC_EXCLUDE) == 0)
+ break;
+
+ output_section->map_head.link_order = NULL;
+ output_section->map_tail.link_order = NULL;
+
+ if (s == NULL)
+ exclude = TRUE;
+ }

- if (s == NULL)
+ if (exclude
+ || (output_section->linker_has_input == 0
+ && ((output_section->flags
+ & (SEC_KEEP | SEC_HAS_CONTENTS)) == 0)))
{
- s = os->bfd_section;
- os->bfd_section = NULL;
- if (!bfd_section_removed_from_list (output_bfd, s))
+ if (exclude)
+ os->bfd_section = NULL;
+ else
+ /* We don't set bfd_section to NULL since bfd_section of the
+ * removed output section statement may still be used. */
+ os->ignored = TRUE;
+ if (!bfd_section_removed_from_list (output_bfd,
+ output_section))
{
- bfd_section_list_remove (output_bfd, s);
+ bfd_section_list_remove (output_bfd, output_section);
output_bfd->section_count--;
}
}
@@ -3925,8 +4032,8 @@ lang_size_sections_1
lang_output_section_statement_type *os;

os = &s->output_section_statement;
- if (os->bfd_section == NULL)
- /* This section was never actually created. */
+ if (os->bfd_section == NULL || os->ignored)
+ /* This section was removed or never actually created. */
break;

/* If this is a COFF shared library section, use the size and
@@ -4421,7 +4528,7 @@ lang_do_assignments_1
lang_output_section_statement_type *os;

os = &(s->output_section_statement);
- if (os->bfd_section != NULL)
+ if (os->bfd_section != NULL && !os->ignored)
{
dot = os->bfd_section->vma;
lang_do_assignments_1 (os->children.head, os, os->fill, dot);
@@ -4435,7 +4542,7 @@ lang_do_assignments_1
{
/* If nothing has been placed into the output section then
it won't have a bfd_section. */
- if (os->bfd_section)
+ if (os->bfd_section && !os->ignored)
{
os->bfd_section->lma
= exp_get_abs_int (os->load_base, 0, "load base",
@@ -5240,16 +5347,6 @@ lang_gc_sections (void)
bfd_gc_sections (output_bfd, &link_info);
}

-static void
-lang_mark_used_section (void)
-{
- unsigned int gc_sections = link_info.gc_sections;
-
- link_info.gc_sections = 0;
- bfd_gc_sections (output_bfd, &link_info);
- link_info.gc_sections = gc_sections;
-}
-
void
lang_process (void)
{
@@ -5408,7 +5505,6 @@ lang_process (void)
lang_check_section_addresses ();

/* Final stuffs. */
- lang_mark_used_section ();
ldemul_finish ();
lang_end ();
}
--- binutils/ld/ldlang.h.empty 2005-05-07 06:58:49.000000000 -0700
+++ binutils/ld/ldlang.h 2005-05-07 08:59:05.000000000 -0700
@@ -147,7 +147,8 @@ typedef struct lang_output_section_state
int subsection_alignment; /* Alignment of components. */
int section_alignment; /* Alignment of start of section. */
int constraint;
- bfd_boolean all_input_readonly;
+ unsigned int all_input_readonly : 1;
+ unsigned int ignored : 1;

union etree_union *load_base;
H. J. Lu
2005-05-07 19:16:07 UTC
Permalink
Post by H. J. Lu
Post by Alan Modra
Post by H. J. Lu
With
lang_size_sections (statement_list.head, abs_output_section,
&statement_list.head, 0, 0, NULL,
command_line.relax ? FALSE : TRUE);
lang_do_assignments (statement_list.head, abs_output_section, NULL, 0);
lang_reset_memory_regions ();
lang_mark_used_section ();
strip_unused_output_sections ();
at the end of strip_excluded_output_sections, I got
failed: Bad value FAIL: PHDRS
FAIL: PHDRS2
You need this from ppc64elf.em.
/* We must not cache anything from the preliminary sizing. */
elf_tdata (output_bfd)->program_header_size = 0;
Perhaps a better approach would be to run a cut-down lang_do_assignments
that just keeps track of output section and symbol assignments other
than "." within output sections. If it finds such an assignment, mark
the section as needed.
This patch implements it.
We should ignore assert failure if mark_used is TRUE, not skip it.


H.J.
---
bfd/

2005-05-07 H.J. Lu <***@intel.com>

PR 797
* elf32-i386.c (elf_i386_size_dynamic_sections): Also remove
empty sdynbss section.
* elf64-x86-64.c (elf64_x86_64_size_dynamic_sections): Likewise.

ld/

2005-05-07 H.J. Lu <***@intel.com>

PR 797
* ldexp.c (exp_fold_tree_1): Renamed from exp_fold_tree and
take take a bfd_boolean, mark_used. Ignore assert failure if
mark_used is TRUE.
(exp_fold_tree) Call exp_fold_tree_1 with mark_used == FALSE.
(exp_fold_tree_no_dot): Updated to take a bfd_boolean,
mark_used and pass down.
(fold_unary): Likewise.
(fold_binary): Likewise.
(fold_trinary): Likewise.
(exp_binop): Add FALSE to call to exp_fold_tree_no_dot.
(exp_trinop): Likewise.
(exp_unop): Likewise.
(exp_nameop): Likewise.
(exp_get_vma): Likewise.
(exp_get_fill): Likewise.
(exp_get_abs_int): Likewise.
(fold_name): Likewise. Set SEC_KEEP in output section flags.
(exp_mark_used_section): New.

* ldexp.h (exp_mark_used_section): New.

* ldlang.c (lang_output_section_statement_lookup_1): Set the
ignored field to FALSE.
(lang_mark_used_section_1): New.
(lang_mark_used_section): Call lang_mark_used_section_1.
(strip_excluded_output_sections): Call lang_mark_used_section
and check for unused sections.
(lang_size_sections_1): Skip an output section if it should
be ignored.
(lang_do_assignments_1): Likewise.
(lang_process): Don't call lang_mark_used_section here.

* ldlang.h (lang_output_section_statement_type): Change
all_input_readonly to bitfield. Add ignored.

--- binutils/bfd/elf32-i386.c.empty 2005-05-05 07:44:37.000000000 -0700
+++ binutils/bfd/elf32-i386.c 2005-05-07 06:58:49.000000000 -0700
@@ -1914,7 +1914,8 @@ elf_i386_size_dynamic_sections (bfd *out

if (s == htab->splt
|| s == htab->sgot
- || s == htab->sgotplt)
+ || s == htab->sgotplt
+ || s == htab->sdynbss)
{
/* Strip this section if we don't need it; see the
comment below. */
--- binutils/bfd/elf64-x86-64.c.empty 2005-05-05 07:44:41.000000000 -0700
+++ binutils/bfd/elf64-x86-64.c 2005-05-07 06:58:49.000000000 -0700
@@ -1624,7 +1624,8 @@ elf64_x86_64_size_dynamic_sections (bfd

if (s == htab->splt
|| s == htab->sgot
- || s == htab->sgotplt)
+ || s == htab->sgotplt
+ || s == htab->sdynbss)
{
/* Strip this section if we don't need it; see the
comment below. */
--- binutils/ld/ldexp.c.empty 2005-03-15 09:35:19.000000000 -0800
+++ binutils/ld/ldexp.c 2005-05-07 12:11:09.000000000 -0700
@@ -41,8 +41,12 @@
#include "libiberty.h"
#include "safe-ctype.h"

+static etree_value_type exp_fold_tree_1
+ (etree_type *, lang_output_section_statement_type *,
+ lang_phase_type, bfd_vma, bfd_vma *, bfd_boolean);
static etree_value_type exp_fold_tree_no_dot
- (etree_type *, lang_output_section_statement_type *, lang_phase_type);
+ (etree_type *, lang_output_section_statement_type *, lang_phase_type,
+ bfd_boolean);
static bfd_vma align_n
(bfd_vma, bfd_vma);

@@ -219,13 +223,14 @@ fold_unary (etree_type *tree,
lang_output_section_statement_type *current_section,
lang_phase_type allocation_done,
bfd_vma dot,
- bfd_vma *dotp)
+ bfd_vma *dotp,
+ bfd_boolean mark_used)
{
etree_value_type result;

- result = exp_fold_tree (tree->unary.child,
- current_section,
- allocation_done, dot, dotp);
+ result = exp_fold_tree_1 (tree->unary.child,
+ current_section,
+ allocation_done, dot, dotp, mark_used);
if (result.valid_p)
{
switch (tree->type.node_code)
@@ -308,12 +313,13 @@ fold_binary (etree_type *tree,
lang_output_section_statement_type *current_section,
lang_phase_type allocation_done,
bfd_vma dot,
- bfd_vma *dotp)
+ bfd_vma *dotp,
+ bfd_boolean mark_used)
{
etree_value_type result;

- result = exp_fold_tree (tree->binary.lhs, current_section,
- allocation_done, dot, dotp);
+ result = exp_fold_tree_1 (tree->binary.lhs, current_section,
+ allocation_done, dot, dotp, mark_used);

/* The SEGMENT_START operator is special because its first
operand is a string, not the name of a symbol. */
@@ -338,9 +344,10 @@ fold_binary (etree_type *tree,
{
etree_value_type other;

- other = exp_fold_tree (tree->binary.rhs,
- current_section,
- allocation_done, dot, dotp);
+ other = exp_fold_tree_1 (tree->binary.rhs,
+ current_section,
+ allocation_done,
+ dot, dotp, mark_used);
if (other.valid_p)
{
/* If the values are from different sections, or this is an
@@ -498,18 +505,20 @@ fold_trinary (etree_type *tree,
lang_output_section_statement_type *current_section,
lang_phase_type allocation_done,
bfd_vma dot,
- bfd_vma *dotp)
+ bfd_vma *dotp,
+ bfd_boolean mark_used)
{
etree_value_type result;

- result = exp_fold_tree (tree->trinary.cond, current_section,
- allocation_done, dot, dotp);
+ result = exp_fold_tree_1 (tree->trinary.cond, current_section,
+ allocation_done, dot, dotp, mark_used);
if (result.valid_p)
- result = exp_fold_tree ((result.value
- ? tree->trinary.lhs
- : tree->trinary.rhs),
- current_section,
- allocation_done, dot, dotp);
+ result = exp_fold_tree_1 ((result.value
+ ? tree->trinary.lhs
+ : tree->trinary.rhs),
+ current_section,
+ allocation_done,
+ dot, dotp, mark_used);

return result;
}
@@ -518,7 +527,8 @@ static etree_value_type
fold_name (etree_type *tree,
lang_output_section_statement_type *current_section,
lang_phase_type allocation_done,
- bfd_vma dot)
+ bfd_vma dot,
+ bfd_boolean mark_used)
{
etree_value_type result;

@@ -596,6 +606,7 @@ fold_name (etree_type *tree,
+ h->u.def.section->output_offset),
NULL,
os);
+ os->bfd_section->flags |= SEC_KEEP;
}
}
}
@@ -619,8 +630,12 @@ fold_name (etree_type *tree,
lang_output_section_statement_type *os;

os = lang_output_section_find (tree->name.name);
- if (os && os->processed > 0)
- result = new_rel (0, NULL, os);
+ if (os)
+ {
+ os->bfd_section->flags |= SEC_KEEP;
+ if (os->processed > 0)
+ result = new_rel (0, NULL, os);
+ }
}
break;

@@ -630,14 +645,19 @@ fold_name (etree_type *tree,
lang_output_section_statement_type *os;

os = lang_output_section_find (tree->name.name);
- if (os && os->processed != 0)
+ if (os)
{
- if (os->load_base == NULL)
- result = new_rel (0, NULL, os);
- else
- result = exp_fold_tree_no_dot (os->load_base,
- abs_output_section,
- allocation_done);
+ os->bfd_section->flags |= SEC_KEEP;
+ if (os->processed != 0)
+ {
+ if (os->load_base == NULL)
+ result = new_rel (0, NULL, os);
+ else
+ result = exp_fold_tree_no_dot (os->load_base,
+ abs_output_section,
+ allocation_done,
+ mark_used);
+ }
}
}
break;
@@ -649,8 +669,12 @@ fold_name (etree_type *tree,
lang_output_section_statement_type *os;

os = lang_output_section_find (tree->name.name);
- if (os && os->processed > 0)
- result = new_abs (os->bfd_section->size / opb);
+ if (os)
+ {
+ os->bfd_section->flags |= SEC_KEEP;
+ if (os->processed > 0)
+ result = new_abs (os->bfd_section->size / opb);
+ }
}
break;

@@ -688,12 +712,13 @@ fold_name (etree_type *tree,
return result;
}

-etree_value_type
-exp_fold_tree (etree_type *tree,
- lang_output_section_statement_type *current_section,
- lang_phase_type allocation_done,
- bfd_vma dot,
- bfd_vma *dotp)
+static etree_value_type
+exp_fold_tree_1 (etree_type *tree,
+ lang_output_section_statement_type *current_section,
+ lang_phase_type allocation_done,
+ bfd_vma dot,
+ bfd_vma *dotp,
+ bfd_boolean mark_used)
{
etree_value_type result;

@@ -721,26 +746,34 @@ exp_fold_tree (etree_type *tree,
break;

case etree_assert:
- result = exp_fold_tree (tree->assert_s.child,
- current_section,
- allocation_done, dot, dotp);
- if (result.valid_p && !result.value)
- einfo ("%X%P: %s\n", tree->assert_s.message);
+ result = exp_fold_tree_1 (tree->assert_s.child,
+ current_section,
+ allocation_done, dot, dotp,
+ mark_used);
+ if (result.valid_p)
+ {
+ if (mark_used)
+ /* We don't care if assert fails or not when we are just
+ marking if a section is used or not. */
+ result.value = 1;
+ else if (!result.value)
+ einfo ("%X%P: %s\n", tree->assert_s.message);
+ }
break;

case etree_unary:
result = fold_unary (tree, current_section, allocation_done,
- dot, dotp);
+ dot, dotp, mark_used);
break;

case etree_binary:
result = fold_binary (tree, current_section, allocation_done,
- dot, dotp);
+ dot, dotp, mark_used);
break;

case etree_trinary:
result = fold_trinary (tree, current_section, allocation_done,
- dot, dotp);
+ dot, dotp, mark_used);
break;

case etree_assign:
@@ -757,9 +790,10 @@ exp_fold_tree (etree_type *tree,
{
/* Notify the folder that this is an assignment to dot. */
assigning_to_dot = TRUE;
- result = exp_fold_tree (tree->assign.src,
- current_section,
- allocation_done, dot, dotp);
+ result = exp_fold_tree_1 (tree->assign.src,
+ current_section,
+ allocation_done,
+ dot, dotp, mark_used);
assigning_to_dot = FALSE;

if (! result.valid_p)
@@ -788,9 +822,9 @@ exp_fold_tree (etree_type *tree,
}
else
{
- result = exp_fold_tree (tree->assign.src,
- current_section, allocation_done,
- dot, dotp);
+ result = exp_fold_tree_1 (tree->assign.src,
+ current_section, allocation_done,
+ dot, dotp, mark_used);
if (result.valid_p)
{
bfd_boolean create;
@@ -832,7 +866,8 @@ exp_fold_tree (etree_type *tree,
break;

case etree_name:
- result = fold_name (tree, current_section, allocation_done, dot);
+ result = fold_name (tree, current_section, allocation_done, dot,
+ mark_used);
break;

default:
@@ -844,12 +879,25 @@ exp_fold_tree (etree_type *tree,
return result;
}

+etree_value_type
+exp_fold_tree (etree_type *tree,
+ lang_output_section_statement_type *current_section,
+ lang_phase_type allocation_done,
+ bfd_vma dot,
+ bfd_vma *dotp)
+{
+ return exp_fold_tree_1 (tree, current_section, allocation_done,
+ dot, dotp, FALSE);
+}
+
static etree_value_type
exp_fold_tree_no_dot (etree_type *tree,
lang_output_section_statement_type *current_section,
- lang_phase_type allocation_done)
+ lang_phase_type allocation_done,
+ bfd_boolean mark_used)
{
- return exp_fold_tree (tree, current_section, allocation_done, 0, NULL);
+ return exp_fold_tree_1 (tree, current_section, allocation_done, 0,
+ NULL, mark_used);
}

etree_type *
@@ -864,7 +912,7 @@ exp_binop (int code, etree_type *lhs, et
value.type.node_class = etree_binary;
r = exp_fold_tree_no_dot (&value,
abs_output_section,
- lang_first_phase_enum);
+ lang_first_phase_enum, FALSE);
if (r.valid_p)
{
return exp_intop (r.value);
@@ -884,7 +932,7 @@ exp_trinop (int code, etree_type *cond,
value.trinary.cond = cond;
value.trinary.rhs = rhs;
value.type.node_class = etree_trinary;
- r = exp_fold_tree_no_dot (&value, NULL, lang_first_phase_enum);
+ r = exp_fold_tree_no_dot (&value, NULL, lang_first_phase_enum, FALSE);
if (r.valid_p)
return exp_intop (r.value);

@@ -903,7 +951,7 @@ exp_unop (int code, etree_type *child)
value.unary.child = child;
value.unary.type.node_class = etree_unary;
r = exp_fold_tree_no_dot (&value, abs_output_section,
- lang_first_phase_enum);
+ lang_first_phase_enum, FALSE);
if (r.valid_p)
return exp_intop (r.value);

@@ -921,7 +969,7 @@ exp_nameop (int code, const char *name)
value.name.name = name;
value.name.type.node_class = etree_name;

- r = exp_fold_tree_no_dot (&value, NULL, lang_first_phase_enum);
+ r = exp_fold_tree_no_dot (&value, NULL, lang_first_phase_enum, FALSE);
if (r.valid_p)
return exp_intop (r.value);

@@ -1071,7 +1119,8 @@ exp_get_vma (etree_type *tree,

if (tree != NULL)
{
- r = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done);
+ r = exp_fold_tree_no_dot (tree, abs_output_section,
+ allocation_done, FALSE);
if (! r.valid_p && name != NULL)
einfo (_("%F%S nonconstant expression for %s\n"), name);
return r.value;
@@ -1103,7 +1152,8 @@ exp_get_fill (etree_type *tree,
if (tree == NULL)
return def;

- r = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done);
+ r = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done,
+ FALSE);
if (! r.valid_p && name != NULL)
einfo (_("%F%S nonconstant expression for %s\n"), name);

@@ -1154,7 +1204,8 @@ exp_get_abs_int (etree_type *tree,
lang_phase_type allocation_done)
{
etree_value_type res;
- res = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done);
+ res = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done,
+ FALSE);

if (res.valid_p)
res.value += res.section->bfd_section->vma;
@@ -1173,3 +1224,91 @@ align_n (bfd_vma value, bfd_vma align)
value = (value + align - 1) / align;
return value * align;
}
+
+void
+exp_mark_used_section
+ (etree_type *tree,
+ lang_output_section_statement_type *current_section)
+{
+ switch (tree->type.node_class)
+ {
+ case etree_value:
+ break;
+
+ case etree_rel:
+ break;
+
+ case etree_assert:
+ break;
+
+ case etree_unary:
+ break;
+
+ case etree_binary:
+ break;
+
+ case etree_trinary:
+ break;
+
+ case etree_assign:
+ case etree_provide:
+ case etree_provided:
+ if (tree->assign.dst[0] != '.' || tree->assign.dst[1] != 0)
+ {
+ etree_value_type result;
+ bfd_vma dot = 0;
+
+ result = exp_fold_tree_1 (tree->assign.src,
+ current_section,
+ lang_allocating_phase_enum,
+ dot, &dot, TRUE);
+ if (result.valid_p)
+ {
+ bfd_boolean create;
+ struct bfd_link_hash_entry *h;
+
+ if (tree->type.node_class == etree_assign)
+ create = TRUE;
+ else
+ create = FALSE;
+ h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst,
+ create, FALSE, TRUE);
+ if (h == NULL)
+ {
+ if (create)
+ einfo (_("%P%F:%s: hash creation failed\n"),
+ tree->assign.dst);
+ }
+ else if (tree->type.node_class == etree_provide
+ && h->type != bfd_link_hash_new
+ && h->type != bfd_link_hash_undefined
+ && h->type != bfd_link_hash_common)
+ {
+ /* Do nothing. The symbol was defined by some
+ object. */
+ }
+ else
+ {
+ /* FIXME: Should we worry if the symbol is already
+ defined? */
+ lang_update_definedness (tree->assign.dst, h);
+ h->type = bfd_link_hash_defined;
+ h->u.def.value = result.value;
+ h->u.def.section = result.section->bfd_section;
+ if (tree->type.node_class == etree_provide)
+ tree->type.node_class = etree_provided;
+ }
+ }
+ }
+ break;
+
+ case etree_name:
+ fold_name (tree, current_section, lang_allocating_phase_enum, 0,
+ TRUE);
+ break;
+
+ default:
+ abort ();
+ break;
+ }
+}
--- binutils/ld/ldexp.h.empty 2004-12-22 09:30:57.000000000 -0800
+++ binutils/ld/ldexp.h 2005-05-07 09:34:05.000000000 -0700
@@ -156,5 +156,7 @@ fill_type *exp_get_fill
(etree_type *, fill_type *, char *, lang_phase_type);
bfd_vma exp_get_abs_int
(etree_type *, int, char *, lang_phase_type);
+void exp_mark_used_section
+ (etree_type *, struct lang_output_section_statement_struct *);

#endif
--- binutils/ld/ldlang.c.empty 2005-05-07 06:58:49.000000000 -0700
+++ binutils/ld/ldlang.c 2005-05-07 10:13:04.000000000 -0700
@@ -1083,6 +1083,7 @@ lang_output_section_statement_lookup_1 (
lookup->bfd_section = NULL;
lookup->processed = 0;
lookup->constraint = constraint;
+ lookup->ignored = FALSE;
lookup->sectype = normal_section;
lookup->addr_tree = NULL;
lang_list_init (&lookup->children);
@@ -3109,6 +3110,90 @@ map_input_to_output_sections
}
}

+/* Worker function for lang_mark_used_section. Recursiveness goes
+ here. */
+
+static void
+lang_mark_used_section_1
+ (lang_statement_union_type *s,
+ lang_output_section_statement_type *output_section_statement)
+{
+ for (; s != NULL; s = s->header.next)
+ {
+ switch (s->header.type)
+ {
+ case lang_constructors_statement_enum:
+ break;
+
+ case lang_output_section_statement_enum:
+ {
+ lang_output_section_statement_type *os;
+
+ os = &(s->output_section_statement);
+ if (os->bfd_section != NULL)
+ lang_mark_used_section_1 (os->children.head, os);
+ }
+ break;
+ case lang_wild_statement_enum:
+ lang_mark_used_section_1 (s->wild_statement.children.head,
+ output_section_statement);
+
+ break;
+
+ case lang_object_symbols_statement_enum:
+ case lang_output_statement_enum:
+ case lang_target_statement_enum:
+ break;
+ case lang_data_statement_enum:
+ exp_mark_used_section (s->data_statement.exp,
+ abs_output_section);
+ break;
+
+ case lang_reloc_statement_enum:
+ break;
+
+ case lang_input_section_enum:
+ break;
+
+ case lang_input_statement_enum:
+ break;
+ case lang_fill_statement_enum:
+ break;
+ case lang_assignment_statement_enum:
+ exp_mark_used_section (s->assignment_statement.exp,
+ output_section_statement);
+ break;
+ case lang_padding_statement_enum:
+ break;
+
+ case lang_group_statement_enum:
+ lang_mark_used_section_1 (s->group_statement.children.head,
+ output_section_statement);
+ break;
+
+ default:
+ FAIL ();
+ break;
+ case lang_address_statement_enum:
+ break;
+ }
+ }
+}
+
+static void
+lang_mark_used_section (void)
+{
+ unsigned int gc_sections = link_info.gc_sections;
+
+ /* Callers of exp_fold_tree need to increment this. */
+ lang_statement_iteration++;
+ lang_mark_used_section_1 (statement_list.head, abs_output_section);
+
+ link_info.gc_sections = 0;
+ bfd_gc_sections (output_bfd, &link_info);
+ link_info.gc_sections = gc_sections;
+}
+
/* 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. */
@@ -3118,32 +3203,54 @@ strip_excluded_output_sections (void)
{
lang_output_section_statement_type *os;

+ lang_mark_used_section ();
+
for (os = &lang_output_section_statement.head->output_section_statement;
os != NULL;
os = os->next)
{
- asection *s;
+ asection *output_section;
+ bfd_boolean exclude;

if (os->constraint == -1)
continue;

- if (os->bfd_section == NULL || os->bfd_section->map_head.s == NULL)
+ output_section = os->bfd_section;
+ if (output_section == NULL)
continue;

- for (s = os->bfd_section->map_head.s; s != NULL; s = s->map_head.s)
- if ((s->flags & SEC_EXCLUDE) == 0)
- break;
+ exclude = FALSE;
+ if (output_section->map_head.s != NULL)
+ {
+ asection *s;

- os->bfd_section->map_head.link_order = NULL;
- os->bfd_section->map_tail.link_order = NULL;
+ for (s = output_section->map_head.s; s != NULL;
+ s = s->map_head.s)
+ if ((s->flags & SEC_EXCLUDE) == 0)
+ break;
+
+ output_section->map_head.link_order = NULL;
+ output_section->map_tail.link_order = NULL;
+
+ if (s == NULL)
+ exclude = TRUE;
+ }

- if (s == NULL)
+ if (exclude
+ || (output_section->linker_has_input == 0
+ && ((output_section->flags
+ & (SEC_KEEP | SEC_HAS_CONTENTS)) == 0)))
{
- s = os->bfd_section;
- os->bfd_section = NULL;
- if (!bfd_section_removed_from_list (output_bfd, s))
+ if (exclude)
+ os->bfd_section = NULL;
+ else
+ /* We don't set bfd_section to NULL since bfd_section of the
+ * removed output section statement may still be used. */
+ os->ignored = TRUE;
+ if (!bfd_section_removed_from_list (output_bfd,
+ output_section))
{
- bfd_section_list_remove (output_bfd, s);
+ bfd_section_list_remove (output_bfd, output_section);
output_bfd->section_count--;
}
}
@@ -3925,8 +4032,8 @@ lang_size_sections_1
lang_output_section_statement_type *os;

os = &s->output_section_statement;
- if (os->bfd_section == NULL)
- /* This section was never actually created. */
+ if (os->bfd_section == NULL || os->ignored)
+ /* This section was removed or never actually created. */
break;

/* If this is a COFF shared library section, use the size and
@@ -4421,7 +4528,7 @@ lang_do_assignments_1
lang_output_section_statement_type *os;

os = &(s->output_section_statement);
- if (os->bfd_section != NULL)
+ if (os->bfd_section != NULL && !os->ignored)
{
dot = os->bfd_section->vma;
lang_do_assignments_1 (os->children.head, os, os->fill, dot);
@@ -4435,7 +4542,7 @@ lang_do_assignments_1
{
/* If nothing has been placed into the output section then
it won't have a bfd_section. */
- if (os->bfd_section)
+ if (os->bfd_section && !os->ignored)
{
os->bfd_section->lma
= exp_get_abs_int (os->load_base, 0, "load base",
@@ -5240,16 +5347,6 @@ lang_gc_sections (void)
bfd_gc_sections (output_bfd, &link_info);
}

-static void
-lang_mark_used_section (void)
-{
- unsigned int gc_sections = link_info.gc_sections;
-
- link_info.gc_sections = 0;
- bfd_gc_sections (output_bfd, &link_info);
- link_info.gc_sections = gc_sections;
-}
-
void
lang_process (void)
{
@@ -5408,7 +5505,6 @@ lang_process (void)
lang_check_section_addresses ();

/* Final stuffs. */
- lang_mark_used_section ();
ldemul_finish ();
lang_end ();
}
--- binutils/ld/ldlang.h.empty 2005-05-07 06:58:49.000000000 -0700
+++ binutils/ld/ldlang.h 2005-05-07 08:59:05.000000000 -0700
@@ -147,7 +147,8 @@ typedef struct lang_output_section_state
int subsection_alignment; /* Alignment of components. */
int section_alignment; /* Alignment of start of section. */
int constraint;
- bfd_boolean all_input_readonly;
+ unsigned int all_input_readonly : 1;
+ unsigned int ignored : 1;

union etree_union *load_base;
Nick Clifton
2005-05-17 15:09:26 UTC
Permalink
Hi H. J.
Post by H. J. Lu
bfd/
PR 797
* elf32-i386.c (elf_i386_size_dynamic_sections): Also remove
empty sdynbss section.
* elf64-x86-64.c (elf64_x86_64_size_dynamic_sections): Likewise.
ld/
PR 797
* ldexp.c (exp_fold_tree_1): Renamed from exp_fold_tree and
take take a bfd_boolean, mark_used. Ignore assert failure if
mark_used is TRUE.
(exp_fold_tree) Call exp_fold_tree_1 with mark_used == FALSE.
(exp_fold_tree_no_dot): Updated to take a bfd_boolean,
mark_used and pass down.
(fold_unary): Likewise.
(fold_binary): Likewise.
(fold_trinary): Likewise.
(exp_binop): Add FALSE to call to exp_fold_tree_no_dot.
(exp_trinop): Likewise.
(exp_unop): Likewise.
(exp_nameop): Likewise.
(exp_get_vma): Likewise.
(exp_get_fill): Likewise.
(exp_get_abs_int): Likewise.
(fold_name): Likewise. Set SEC_KEEP in output section flags.
(exp_mark_used_section): New.
* ldexp.h (exp_mark_used_section): New.
* ldlang.c (lang_output_section_statement_lookup_1): Set the
ignored field to FALSE.
(lang_mark_used_section_1): New.
(lang_mark_used_section): Call lang_mark_used_section_1.
(strip_excluded_output_sections): Call lang_mark_used_section
and check for unused sections.
(lang_size_sections_1): Skip an output section if it should
be ignored.
(lang_do_assignments_1): Likewise.
(lang_process): Don't call lang_mark_used_section here.
* ldlang.h (lang_output_section_statement_type): Change
all_input_readonly to bitfield. Add ignored.
Approved - please apply - but could also generate a test case to make
sure that this problem does not reoccur.

Cheers
Nick

Loading...