aboutsummaryrefslogtreecommitdiff
path: root/ld/ldlang.c
diff options
context:
space:
mode:
Diffstat (limited to 'ld/ldlang.c')
-rw-r--r--ld/ldlang.c150
1 files changed, 123 insertions, 27 deletions
diff --git a/ld/ldlang.c b/ld/ldlang.c
index ee85422..835c93a 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -1024,6 +1024,7 @@ lang_output_section_statement_lookup_1 (const char *const name, int constraint)
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);
@@ -3042,6 +3043,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. */
@@ -3051,32 +3136,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--;
}
}
@@ -3936,8 +4043,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
@@ -4432,7 +4539,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);
@@ -4446,7 +4553,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_finish ();
}