PR ld/11304
authorAlan Modra <amodra@gmail.com>
Mon, 22 Feb 2010 12:09:59 +0000 (12:09 +0000)
committerAlan Modra <amodra@gmail.com>
Mon, 22 Feb 2010 12:09:59 +0000 (12:09 +0000)
* ldlang.c (exp_init_os): Delete forward declaration.
(init_os): Don't check for bfd_section already created and don't
init addr_tree and load_base expressions here.
(map_input_to_output_sections): Only map input to output sections
and set constraints here, and as an exception, create output
sections which have their address set.  Move all the other code to..
(create_other_output_sections): ..here.  New function.  Handle init
of addr_tree and load_base here too.
(lang_process): Call create_other_output_sections.

ld/ChangeLog
ld/ldlang.c

index 466e0a6..4b31b49 100644 (file)
@@ -1,3 +1,16 @@
+2010-02-22  Alan Modra  <amodra@gmail.com>
+
+       PR ld/11304
+       * ldlang.c (exp_init_os): Delete forward declaration.
+       (init_os): Don't check for bfd_section already created and don't
+       init addr_tree and load_base expressions here.
+       (map_input_to_output_sections): Only map input to output sections
+       and set constraints here, and as an exception, create output
+       sections which have their address set.  Move all the other code to..
+       (create_other_output_sections): ..here.  New function.  Handle init
+       of addr_tree and load_base here too.
+       (lang_process): Call create_other_output_sections.
+
 2010-02-19  Alan Modra  <amodra@gmail.com>
 
        * Makefile.am (eelf32_i960.c): Depend on ELF_GEN_DEPS, not ELF_DEPS.
index ce5a11c..18ec6a4 100644 (file)
@@ -68,7 +68,6 @@ static struct unique_sections *unique_section_list;
 static bfd_boolean ldlang_sysrooted_script = FALSE;
 
 /* Forward declarations.  */
-static void exp_init_os (etree_type *);
 static void init_map_userdata (bfd *, asection *, void *);
 static lang_input_statement_type *lookup_name (const char *);
 static struct bfd_hash_entry *lang_definedness_newfunc
@@ -2048,12 +2047,8 @@ sort_def_symbol (struct bfd_link_hash_entry *hash_entry,
 /* Initialize an output section.  */
 
 static void
-init_os (lang_output_section_statement_type *s, asection *isec,
-        flagword flags)
+init_os (lang_output_section_statement_type *s, asection *isec, flagword flags)
 {
-  if (s->bfd_section != NULL)
-    return;
-
   if (strcmp (s->name, DISCARD_SECTION_NAME) == 0)
     einfo (_("%P%F: Illegal use of `%s' section\n"), DISCARD_SECTION_NAME);
 
@@ -2078,14 +2073,6 @@ init_os (lang_output_section_statement_type *s, asection *isec,
       get_userdata (s->bfd_section) = new_userdata;
     }
 
-  /* If there is a base address, make sure that any sections it might
-     mention are initialized.  */
-  if (s->addr_tree != NULL)
-    exp_init_os (s->addr_tree);
-
-  if (s->load_base != NULL)
-    exp_init_os (s->load_base);
-
   /* If supplied an alignment, set it.  */
   if (s->section_alignment != -1)
     s->bfd_section->alignment_power = s->section_alignment;
@@ -3430,10 +3417,10 @@ map_input_to_output_sections
   (lang_statement_union_type *s, const char *target,
    lang_output_section_statement_type *os)
 {
-  flagword flags;
-
   for (; s != NULL; s = s->header.next)
     {
+      lang_output_section_statement_type *tos;
+
       switch (s->header.type)
        {
        case lang_wild_statement_enum:
@@ -3445,29 +3432,23 @@ map_input_to_output_sections
                                        os);
          break;
        case lang_output_section_statement_enum:
-         if (s->output_section_statement.constraint)
+         tos = &s->output_section_statement;
+         if (tos->constraint != 0)
            {
-             if (s->output_section_statement.constraint != ONLY_IF_RW
-                 && s->output_section_statement.constraint != ONLY_IF_RO)
+             if (tos->constraint != ONLY_IF_RW
+                 && tos->constraint != ONLY_IF_RO)
                break;
-             s->output_section_statement.all_input_readonly = TRUE;
-             check_input_sections (s->output_section_statement.children.head,
-                                   &s->output_section_statement);
-             if ((s->output_section_statement.all_input_readonly
-                  && s->output_section_statement.constraint == ONLY_IF_RW)
-                 || (!s->output_section_statement.all_input_readonly
-                     && s->output_section_statement.constraint == ONLY_IF_RO))
+             tos->all_input_readonly = TRUE;
+             check_input_sections (tos->children.head, tos);
+             if (tos->all_input_readonly != (tos->constraint == ONLY_IF_RO))
                {
-                 s->output_section_statement.constraint = -1;
+                 tos->constraint = -1;
                  break;
                }
            }
-
-         map_input_to_output_sections (s->output_section_statement.children.head,
+         map_input_to_output_sections (tos->children.head,
                                        target,
-                                       &s->output_section_statement);
-         break;
-       case lang_output_statement_enum:
+                                       tos);
          break;
        case lang_target_statement_enum:
          target = s->target_statement.target;
@@ -3477,19 +3458,102 @@ map_input_to_output_sections
                                        target,
                                        os);
          break;
+       case lang_address_statement_enum:
+         /* Mark the specified section with the supplied address.
+            If this section was actually a segment marker, then the
+            directive is ignored if the linker script explicitly
+            processed the segment marker.  Originally, the linker
+            treated segment directives (like -Ttext on the
+            command-line) as section directives.  We honor the
+            section directive semantics for backwards compatibilty;
+            linker scripts that do not specifically check for
+            SEGMENT_START automatically get the old semantics.  */
+         if (!s->address_statement.segment
+             || !s->address_statement.segment->used)
+           {
+             const char *name = s->address_statement.section_name;
+
+             /* Create the output section statement here rather than
+                in create_other_output_sections so that orphans with
+                a set address will be placed after other script
+                sections.  If we let the orphan placement code place
+                them in amongst other sections then the address will
+                affect following script sections, which is likely to
+                surprise naive users.  */
+             tos = lang_output_section_statement_lookup (name, 0, TRUE);
+             tos->addr_tree = s->address_statement.address;
+           }
+         break;
+       case lang_output_statement_enum:
+       case lang_data_statement_enum:
+       case lang_input_section_enum:
+       case lang_fill_statement_enum:
+       case lang_object_symbols_statement_enum:
+       case lang_reloc_statement_enum:
+       case lang_padding_statement_enum:
+       case lang_input_statement_enum:
+       case lang_assignment_statement_enum:
+       case lang_insert_statement_enum:
+         break;
+       }
+    }
+}
+
+/* Create any other output sections, such as needed for data statements
+   or those referenced in expressions.  */
+
+static void
+create_other_output_sections
+  (lang_statement_union_type *s,
+   lang_output_section_statement_type *os)
+{
+  lang_output_section_statement_type *tos;
+  flagword flags;
+
+  for (; s != NULL; s = s->header.next)
+    {
+      switch (s->header.type)
+       {
+       case lang_wild_statement_enum:
+         break;
+       case lang_constructors_statement_enum:
+         create_other_output_sections (constructor_list.head, os);
+         break;
+       case lang_output_section_statement_enum:
+         tos = &s->output_section_statement;
+         if (tos->constraint != 0
+             && tos->constraint != ONLY_IF_RW
+             && tos->constraint != ONLY_IF_RO)
+           break;
+         create_other_output_sections (tos->children.head, tos);
+         if (tos->bfd_section != NULL)
+           {
+             /* If there is a base address, make sure that any sections
+                it might mention are initialized.  */
+             if (tos->addr_tree != NULL)
+               exp_init_os (tos->addr_tree);
+             if (tos->load_base != NULL)
+               exp_init_os (tos->load_base);
+           }
+         break;
+       case lang_output_statement_enum:
+       case lang_target_statement_enum:
+         break;
+       case lang_group_statement_enum:
+         create_other_output_sections (s->group_statement.children.head, os);
+         break;
        case lang_data_statement_enum:
          /* Make sure that any sections mentioned in the expression
             are initialized.  */
          exp_init_os (s->data_statement.exp);
+         if (os->bfd_section == NULL)
+           init_os (os, NULL, 0);
          flags = SEC_HAS_CONTENTS;
          /* The output section gets contents, and then we inspect for
             any flags set in the input script which override any ALLOC.  */
          if (!(os->flags & SEC_NEVER_LOAD))
            flags |= SEC_ALLOC | SEC_LOAD;
-         if (os->bfd_section == NULL)
-           init_os (os, NULL, flags);
-         else
-           os->bfd_section->flags |= flags;
+         os->bfd_section->flags |= flags;
          break;
        case lang_input_section_enum:
          break;
@@ -3510,25 +3574,14 @@ map_input_to_output_sections
          exp_init_os (s->assignment_statement.exp);
          break;
        case lang_address_statement_enum:
-         /* Mark the specified section with the supplied address.
-            If this section was actually a segment marker, then the
-            directive is ignored if the linker script explicitly
-            processed the segment marker.  Originally, the linker
-            treated segment directives (like -Ttext on the
-            command-line) as section directives.  We honor the
-            section directive semantics for backwards compatibilty;
-            linker scripts that do not specifically check for
-            SEGMENT_START automatically get the old semantics.  */
          if (!s->address_statement.segment
              || !s->address_statement.segment->used)
            {
-             lang_output_section_statement_type *aos
-               = (lang_output_section_statement_lookup
-                  (s->address_statement.section_name, 0, TRUE));
+             const char *name = s->address_statement.section_name;
 
-             if (aos->bfd_section == NULL)
-               init_os (aos, NULL, 0);
-             aos->addr_tree = s->address_statement.address;
+             tos = lang_output_section_find (name);
+             if (tos->bfd_section == NULL)
+               init_os (tos, NULL, 0);
            }
          break;
        case lang_insert_statement_enum:
@@ -6347,6 +6400,10 @@ lang_process (void)
   /* Find any sections not attached explicitly and handle them.  */
   lang_place_orphans ();
 
+  /* Create sections for data statements and those referenced in
+     expressions but otherwise empty.  */
+  create_other_output_sections (statement_list.head, NULL);
+
   if (! link_info.relocatable)
     {
       asection *found;