* ld.h (lang_phase_type): Move to..
authorAlan Modra <amodra@gmail.com>
Thu, 9 Jun 2005 02:05:47 +0000 (02:05 +0000)
committerAlan Modra <amodra@gmail.com>
Thu, 9 Jun 2005 02:05:47 +0000 (02:05 +0000)
* ldexp.h: ..here.  Add lang_mark_phase_enum.
(node_type): Remove etree_undef and etree_unspec.
(exp_data_seg): Delete.
(struct ldexp_control, expld): New.
(invalid, exp_mark_used_section): Delete.
(exp_fold_tree, exp_get_vma, exp_get_value_int, exp_get_fill,
exp_get_abs_int): Update prototypes.
* ldexp.c (assigning_to_dot): Delete.
(expld): Define.
(make_abs): Operate directly on expld.result.  Update all callers.
(new_abs): Likewise.  Return void.
(new_rel_from_abs): Rename from new_rel_from_section.
(new_rel, new_rel_from_abs): Operate on expld.result and return void.
Update all callers.
(fold_unary): Operate on expld.result and return void.  Remove
"current_section", "allocation_done", "dot", "dotp" and "mark_used"
params.  Update all callers.
(fold_binary, fold_trinary, fold_name, exp_fold_tree_1): Likewise.
(fold_unary <ALIGN_K>): Ensure alignment is absolute.
(fold_unary <ABSOLUTE>): Use make_abs.
(fold_unary <DATA_SEGMENT_END>): Evaluate mark_phase as for
allocating_phase.
(fold_binary <DATA_SEGMENT_ALIGN, DATA_SEGMENT_RELRO_END, >): Ditto.
(fold_binary <'%','/'>): Don't error if marking.
(fold_name <SIZEOF_HEADERS>): Don't call bfd_sizeof_headers when
marking.
(fold_name <NAME>): Remove FIXME; -R is handled correctly.  Don't
error when marking.
(fold_name <ADDR, LOADADDR, SIZEOF>): Don't set SEC_KEEP.
(exp_fold_tree_1): Don't error when marking.
(exp_fold_tree_1 <etree_rel>): Evaluate in all phases except first.
(exp_fold_tree_1 <etree_assign to dot>): Don't check for NULL
current section, instead check for NULL dotp.
(exp_fold_tree_1 <etree_provide>): Don't evaluate the assignment
source unless the symbol is referenced and undefined.
(exp_fold_tree): Remove "allocation_done" and "dot" params.  Save
params to expld.
(exp_fold_tree_no_dot): Remove "current_section", "allocation_done
and "mark_used" params.  Save params to expld.  Update all callers.
(exp_assop): Do without temp var.
(exp_print_tree <etree_undef>): Delete code.
(exp_get_vma): Remove "allocation_done" param.  Correct error return.
(exp_get_fill, exp_get_abs_int): Likewise.
(exp_get_value_int): Remove "allocation_done" param.
(exp_mark_used_section): Delete.
* ldgram.y (fill_exp): Update exp_get_fill call.
(origin_spec, length_spec): Update exp_get_vma call.
* ldlang.c (lang_init): Don't bother clearing lang_statement_iteration.
(lang_mark_used_section_1, lang_mark_used_section): Delete.
(strip_excluded_output_sections): Call one_lang_size_sections_pass in
marking mode.  Merge old lang_mark_used_section code.  Correct handling
of output sections with excluded input sections and data statements.
Don't drop non-zero sized sections.  Don't zap os->bfd_section.
Do set SEC_EXCLUDE when appropriate.
(print_output_section_statement): Update for changed ldexp.c
interface.
(print_assignment, lang_size_sections_1): Likewise.
(lang_do_assignments_1, lang_enter_output_section_statement): Likewise.
(lang_new_phdr, lang_record_phdrs): Likewise.
(lang_size_sections): Likewise.
(insert_pad): Use following statement if it is a pad, rather than
creating a new one.
(lang_size_sections_1 <lang_output_section_statement_enum>): Do
process ignored output section to set vma and lma, but don't
update dot for these sections.  Don't error if marking.
(lang_size_sections_1 <lang_assignment_statement_enum>): Don't
update dot for ignored sections.
(lang_size_sections_1 <lang_data_statement_enum>): Don't mark absolute
section with SEC_ALLOC.
(one_lang_size_sections_pass): New function.
(lang_size_sections): Remove first five params.  Set expld.phase on
entry and exit.   Use one_lang_size_sections_pass.
(lang_do_assignments): Remove all params.  Update all callers.
(lang_reset_memory_regions): Clear os->processed for all output
section statements.
* ldlang.h (lang_do_assignments): Update prototype.
(lang_size_sections): Likewise.
(one_lang_size_sections_pass): Declare.
* pe-dll.c (pe_dll_fill_sections, pe_exe_fill_sections): Update
lang_size_sections and lang_do_assignments calls.
* emultempl/elf32.em (layout_sections_again): Likewise.
* emultempl/ppc64elf.em (ppc_before_allocation): Use
one_lang_size_sections_pass.

ld/ChangeLog
ld/emultempl/elf32.em
ld/emultempl/ppc64elf.em
ld/ld.h
ld/ldexp.c
ld/ldexp.h
ld/ldgram.y
ld/ldlang.c
ld/ldlang.h
ld/pe-dll.c

index d8e93145f26fe08818c07a0128e801e090129751..ed249f0d3881977f37ff2f03cdc0947c64306de5 100644 (file)
@@ -1,3 +1,90 @@
+2005-06-09  Alan Modra  <amodra@bigpond.net.au>
+
+       * ld.h (lang_phase_type): Move to..
+       * ldexp.h: ..here.  Add lang_mark_phase_enum.
+       (node_type): Remove etree_undef and etree_unspec.
+       (exp_data_seg): Delete.
+       (struct ldexp_control, expld): New.
+       (invalid, exp_mark_used_section): Delete.
+       (exp_fold_tree, exp_get_vma, exp_get_value_int, exp_get_fill,
+       exp_get_abs_int): Update prototypes.
+       * ldexp.c (assigning_to_dot): Delete.
+       (expld): Define.
+       (make_abs): Operate directly on expld.result.  Update all callers.
+       (new_abs): Likewise.  Return void.
+       (new_rel_from_abs): Rename from new_rel_from_section.
+       (new_rel, new_rel_from_abs): Operate on expld.result and return void.
+       Update all callers.
+       (fold_unary): Operate on expld.result and return void.  Remove
+       "current_section", "allocation_done", "dot", "dotp" and "mark_used"
+       params.  Update all callers.
+       (fold_binary, fold_trinary, fold_name, exp_fold_tree_1): Likewise.
+       (fold_unary <ALIGN_K>): Ensure alignment is absolute.
+       (fold_unary <ABSOLUTE>): Use make_abs.
+       (fold_unary <DATA_SEGMENT_END>): Evaluate mark_phase as for
+       allocating_phase.
+       (fold_binary <DATA_SEGMENT_ALIGN, DATA_SEGMENT_RELRO_END, >): Ditto.
+       (fold_binary <'%','/'>): Don't error if marking.
+       (fold_name <SIZEOF_HEADERS>): Don't call bfd_sizeof_headers when
+       marking.
+       (fold_name <NAME>): Remove FIXME; -R is handled correctly.  Don't
+       error when marking.
+       (fold_name <ADDR, LOADADDR, SIZEOF>): Don't set SEC_KEEP.
+       (exp_fold_tree_1): Don't error when marking.
+       (exp_fold_tree_1 <etree_rel>): Evaluate in all phases except first.
+       (exp_fold_tree_1 <etree_assign to dot>): Don't check for NULL
+       current section, instead check for NULL dotp.
+       (exp_fold_tree_1 <etree_provide>): Don't evaluate the assignment
+       source unless the symbol is referenced and undefined.
+       (exp_fold_tree): Remove "allocation_done" and "dot" params.  Save
+       params to expld.
+       (exp_fold_tree_no_dot): Remove "current_section", "allocation_done
+       and "mark_used" params.  Save params to expld.  Update all callers.
+       (exp_assop): Do without temp var.
+       (exp_print_tree <etree_undef>): Delete code.
+       (exp_get_vma): Remove "allocation_done" param.  Correct error return.
+       (exp_get_fill, exp_get_abs_int): Likewise.
+       (exp_get_value_int): Remove "allocation_done" param.
+       (exp_mark_used_section): Delete.
+       * ldgram.y (fill_exp): Update exp_get_fill call.
+       (origin_spec, length_spec): Update exp_get_vma call.
+       * ldlang.c (lang_init): Don't bother clearing lang_statement_iteration.
+       (lang_mark_used_section_1, lang_mark_used_section): Delete.
+       (strip_excluded_output_sections): Call one_lang_size_sections_pass in
+       marking mode.  Merge old lang_mark_used_section code.  Correct handling
+       of output sections with excluded input sections and data statements.
+       Don't drop non-zero sized sections.  Don't zap os->bfd_section.
+       Do set SEC_EXCLUDE when appropriate.
+       (print_output_section_statement): Update for changed ldexp.c
+       interface.
+       (print_assignment, lang_size_sections_1): Likewise.
+       (lang_do_assignments_1, lang_enter_output_section_statement): Likewise.
+       (lang_new_phdr, lang_record_phdrs): Likewise.
+       (lang_size_sections): Likewise.
+       (insert_pad): Use following statement if it is a pad, rather than
+       creating a new one.
+       (lang_size_sections_1 <lang_output_section_statement_enum>): Do
+       process ignored output section to set vma and lma, but don't
+       update dot for these sections.  Don't error if marking.
+       (lang_size_sections_1 <lang_assignment_statement_enum>): Don't
+       update dot for ignored sections.
+       (lang_size_sections_1 <lang_data_statement_enum>): Don't mark absolute
+       section with SEC_ALLOC.
+       (one_lang_size_sections_pass): New function.
+       (lang_size_sections): Remove first five params.  Set expld.phase on
+       entry and exit.   Use one_lang_size_sections_pass.
+       (lang_do_assignments): Remove all params.  Update all callers.
+       (lang_reset_memory_regions): Clear os->processed for all output
+       section statements.
+       * ldlang.h (lang_do_assignments): Update prototype.
+       (lang_size_sections): Likewise.
+       (one_lang_size_sections_pass): Declare.
+       * pe-dll.c (pe_dll_fill_sections, pe_exe_fill_sections): Update
+       lang_size_sections and lang_do_assignments calls.
+       * emultempl/elf32.em (layout_sections_again): Likewise.
+       * emultempl/ppc64elf.em (ppc_before_allocation): Use
+       one_lang_size_sections_pass.
+
 2005-06-08  Aldy Hernandez  <aldyh@redhat.com>
 
        * emulparams/elf32ms1.sh: New.
index ee8a172762a663f7d5f2b4b46a1f4772842e2e17..e20bd738bdce971e45cef7f6cde95731b43ea9ed 100644 (file)
@@ -1497,15 +1497,13 @@ gld${EMULATION_NAME}_layout_sections_again (void)
   lang_reset_memory_regions ();
 
   /* Resize the sections.  */
-  lang_size_sections (stat_ptr->head, abs_output_section,
-                     &stat_ptr->head, 0, (bfd_vma) 0, NULL, TRUE);
+  lang_size_sections (NULL, TRUE);
 
   /* Redo special stuff.  */
   ldemul_after_allocation ();
 
   /* Do the assignments again.  */
-  lang_do_assignments (stat_ptr->head, abs_output_section,
-                      (fill_type *) 0, (bfd_vma) 0);
+  lang_do_assignments ();
 }
 
 static void
index c1343b67022df2d0d2711c48f6d3db28d6020dff..6eea93dd66960011318d9bb7fb9b9c0ecc268aa6 100644 (file)
@@ -110,14 +110,14 @@ ppc_before_allocation (void)
        {
          /* Size the sections.  This is premature, but we want to know the
             TLS segment layout so that certain optimizations can be done.  */
-         lang_size_sections (stat_ptr->head, abs_output_section,
-                             &stat_ptr->head, 0, 0, NULL, TRUE);
+         expld.phase = lang_mark_phase_enum;
+         expld.dataseg.phase = exp_dataseg_none;
+         one_lang_size_sections_pass (NULL, TRUE);
 
          if (!ppc64_elf_tls_optimize (output_bfd, &link_info))
            einfo ("%X%P: TLS problem %E\n");
 
          /* We must not cache anything from the preliminary sizing.  */
-         elf_tdata (output_bfd)->program_header_size = 0;
          lang_reset_memory_regions ();
        }
 
diff --git a/ld/ld.h b/ld/ld.h
index 16ee7a2b3a4bedf3d4ccb5c2f0bef86bb2df8233..9ada8bef95ab5908fe5d75bd1c9e4e6ecce4dd81 100644 (file)
--- a/ld/ld.h
+++ b/ld/ld.h
@@ -238,12 +238,6 @@ typedef struct {
 
 extern ld_config_type config;
 
-typedef enum {
-  lang_first_phase_enum,
-  lang_allocating_phase_enum,
-  lang_final_phase_enum
-} lang_phase_type;
-
 extern FILE * saved_script_handle;
 extern bfd_boolean force_make_executable;
 
index 3927f85f0b5c18c2edc7cca0820315dec6d91d32..9b899f0951aeeba31364e09bf0fb9210cbdb29c7 100644 (file)
 #include "libiberty.h"
 #include "safe-ctype.h"
 
-static etree_value_type exp_fold_tree_1
-  (etree_type *, asection *, lang_phase_type, bfd_vma, bfd_vma *, bfd_boolean);
-static etree_value_type exp_fold_tree_no_dot
-  (etree_type *, asection *, lang_phase_type, bfd_boolean);
-static bfd_vma align_n
-  (bfd_vma, bfd_vma);
-
-struct exp_data_seg exp_data_seg;
+static void exp_fold_tree_1 (etree_type *);
+static void exp_fold_tree_no_dot (etree_type *);
+static bfd_vma align_n (bfd_vma, bfd_vma);
 
 segment_type *segments;
 
-/* Principally used for diagnostics.  */
-static bfd_boolean assigning_to_dot = FALSE;
+struct ldexp_control expld;
 
 /* Print the string representation of the given token.  Surround it
    with spaces if INFIX_P is TRUE.  */
@@ -135,21 +129,19 @@ exp_print_token (token_code_type code, int infix_p)
 }
 
 static void
-make_abs (etree_value_type *ptr)
+make_abs (void)
 {
-  ptr->value += ptr->section->vma;
-  ptr->section = bfd_abs_section_ptr;
+  expld.result.value += expld.result.section->vma;
+  expld.result.section = bfd_abs_section_ptr;
 }
 
-static etree_value_type
+static void
 new_abs (bfd_vma value)
 {
-  etree_value_type new;
-  new.valid_p = TRUE;
-  new.section = bfd_abs_section_ptr;
-  new.value = value;
-  new.str = NULL;
-  return new;
+  expld.result.valid_p = TRUE;
+  expld.result.section = bfd_abs_section_ptr;
+  expld.result.value = value;
+  expld.result.str = NULL;
 }
 
 etree_type *
@@ -187,112 +179,90 @@ exp_relop (asection *section, bfd_vma value)
   return new;
 }
 
-static etree_value_type
-new_rel (bfd_vma value,
-        char *str,
-        asection *section)
+static void
+new_rel (bfd_vma value, char *str, asection *section)
 {
-  etree_value_type new;
-  new.valid_p = TRUE;
-  new.value = value;
-  new.str = str;
-  new.section = section;
-  return new;
+  expld.result.valid_p = TRUE;
+  expld.result.value = value;
+  expld.result.str = str;
+  expld.result.section = section;
 }
 
-static etree_value_type
-new_rel_from_section (bfd_vma value, asection *section)
+static void
+new_rel_from_abs (bfd_vma value)
 {
-  etree_value_type new;
-  new.valid_p = TRUE;
-  new.value = value;
-  new.str = NULL;
-  new.section = section;
-
-  new.value -= section->vma;
-
-  return new;
+  expld.result.valid_p = TRUE;
+  expld.result.value = value - expld.section->vma;
+  expld.result.str = NULL;
+  expld.result.section = expld.section;
 }
 
-static etree_value_type
-fold_unary (etree_type *tree,
-           asection *current_section,
-           lang_phase_type allocation_done,
-           bfd_vma dot,
-           bfd_vma *dotp,
-           bfd_boolean mark_used)
+static void
+fold_unary (etree_type *tree)
 {
-  etree_value_type result;
-
-  result = exp_fold_tree_1 (tree->unary.child,
-                           current_section,
-                           allocation_done, dot, dotp, mark_used);
-  if (result.valid_p)
+  exp_fold_tree_1 (tree->unary.child);
+  if (expld.result.valid_p)
     {
       switch (tree->type.node_code)
        {
        case ALIGN_K:
-         if (allocation_done != lang_first_phase_enum)
-           result = new_rel_from_section (align_n (dot, result.value),
-                                          current_section);
+         if (expld.phase != lang_first_phase_enum)
+           {
+             make_abs ();
+             new_rel_from_abs (align_n (expld.dot, expld.result.value));
+           }
          else
-           result.valid_p = FALSE;
+           expld.result.valid_p = FALSE;
          break;
 
        case ABSOLUTE:
-         if (allocation_done != lang_first_phase_enum)
-           {
-             result.value += result.section->vma;
-             result.section = bfd_abs_section_ptr;
-           }
-         else
-           result.valid_p = FALSE;
+         make_abs ();
          break;
 
        case '~':
-         make_abs (&result);
-         result.value = ~result.value;
+         make_abs ();
+         expld.result.value = ~expld.result.value;
          break;
 
        case '!':
-         make_abs (&result);
-         result.value = !result.value;
+         make_abs ();
+         expld.result.value = !expld.result.value;
          break;
 
        case '-':
-         make_abs (&result);
-         result.value = -result.value;
+         make_abs ();
+         expld.result.value = -expld.result.value;
          break;
 
        case NEXT:
          /* Return next place aligned to value.  */
-         if (allocation_done == lang_allocating_phase_enum)
+         if (expld.phase != lang_first_phase_enum)
            {
-             make_abs (&result);
-             result.value = align_n (dot, result.value);
+             make_abs ();
+             expld.result.value = align_n (expld.dot, expld.result.value);
            }
          else
-           result.valid_p = FALSE;
+           expld.result.valid_p = FALSE;
          break;
 
        case DATA_SEGMENT_END:
-         if (allocation_done != lang_first_phase_enum
-             && current_section == bfd_abs_section_ptr
-             && (exp_data_seg.phase == exp_dataseg_align_seen
-                 || exp_data_seg.phase == exp_dataseg_relro_seen
-                 || exp_data_seg.phase == exp_dataseg_adjust
-                 || exp_data_seg.phase == exp_dataseg_relro_adjust
-                 || allocation_done != lang_allocating_phase_enum))
+         if (expld.phase != lang_first_phase_enum
+             && expld.section == bfd_abs_section_ptr
+             && (expld.dataseg.phase == exp_dataseg_align_seen
+                 || expld.dataseg.phase == exp_dataseg_relro_seen
+                 || expld.dataseg.phase == exp_dataseg_adjust
+                 || expld.dataseg.phase == exp_dataseg_relro_adjust
+                 || expld.phase == lang_final_phase_enum))
            {
-             if (exp_data_seg.phase == exp_dataseg_align_seen
-                 || exp_data_seg.phase == exp_dataseg_relro_seen)
+             if (expld.dataseg.phase == exp_dataseg_align_seen
+                 || expld.dataseg.phase == exp_dataseg_relro_seen)
                {
-                 exp_data_seg.phase = exp_dataseg_end_seen;
-                 exp_data_seg.end = result.value;
+                 expld.dataseg.phase = exp_dataseg_end_seen;
+                 expld.dataseg.end = expld.result.value;
                }
            }
          else
-           result.valid_p = FALSE;
+           expld.result.valid_p = FALSE;
          break;
 
        default:
@@ -300,26 +270,16 @@ fold_unary (etree_type *tree,
          break;
        }
     }
-
-  return result;
 }
 
-static etree_value_type
-fold_binary (etree_type *tree,
-            asection *current_section,
-            lang_phase_type allocation_done,
-            bfd_vma dot,
-            bfd_vma *dotp,
-            bfd_boolean mark_used)
+static void
+fold_binary (etree_type *tree)
 {
-  etree_value_type result;
-
-  result = exp_fold_tree_1 (tree->binary.lhs, current_section,
-                           allocation_done, dot, dotp, mark_used);
+  exp_fold_tree_1 (tree->binary.lhs);
 
   /* The SEGMENT_START operator is special because its first
      operand is a string, not the name of a symbol.  */
-  if (result.valid_p && tree->type.node_code == SEGMENT_START)
+  if (expld.result.valid_p && tree->type.node_code == SEGMENT_START)
     {
       const char *segment_name;
       segment_type *seg;
@@ -330,68 +290,70 @@ fold_binary (etree_type *tree,
        if (strcmp (seg->name, segment_name) == 0)
          {
            seg->used = TRUE;
-           result.value = seg->value;
-           result.str = NULL;
-           result.section = NULL;
+           expld.result.value = seg->value;
+           expld.result.str = NULL;
+           expld.result.section = NULL;
            break;
          }
     }
-  else if (result.valid_p)
+  else if (expld.result.valid_p)
     {
-      etree_value_type other;
+      etree_value_type lhs = expld.result;
 
-      other = exp_fold_tree_1 (tree->binary.rhs,
-                              current_section,
-                              allocation_done,
-                              dot, dotp, mark_used);
-      if (other.valid_p)
+      exp_fold_tree_1 (tree->binary.rhs);
+      if (expld.result.valid_p)
        {
          /* If the values are from different sections, or this is an
             absolute expression, make both the source arguments
             absolute.  However, adding or subtracting an absolute
             value from a relative value is meaningful, and is an
             exception.  */
-         if (current_section != bfd_abs_section_ptr
-             && (other.section == bfd_abs_section_ptr
-                 || (result.section == bfd_abs_section_ptr
-                     && tree->type.node_code == '+'))
+         if (expld.section != bfd_abs_section_ptr
+             && lhs.section == bfd_abs_section_ptr
+             && tree->type.node_code == '+')
+           {
+             /* Keep the section of the rhs term.  */
+             expld.result.value = lhs.value + expld.result.value;
+             return;
+           }
+         else if (expld.section != bfd_abs_section_ptr
+             && expld.result.section == bfd_abs_section_ptr
              && (tree->type.node_code == '+'
                  || tree->type.node_code == '-'))
            {
-             if (other.section != bfd_abs_section_ptr)
-               {
-                 /* Keep the section of the other term.  */
-                 if (tree->type.node_code == '+')
-                   other.value = result.value + other.value;
-                 else
-                   other.value = result.value - other.value;
-                 return other;
-               }
+             /* Keep the section of the lhs term.  */
+             expld.result.section = lhs.section;
            }
-         else if (result.section != other.section
-                  || current_section == bfd_abs_section_ptr)
+         else if (expld.result.section != lhs.section
+                  || expld.section == bfd_abs_section_ptr)
            {
-             make_abs (&result);
-             make_abs (&other);
+             make_abs ();
+             lhs.value += lhs.section->vma;
            }
 
          switch (tree->type.node_code)
            {
            case '%':
-             if (other.value == 0)
+             if (expld.result.value != 0)
+               expld.result.value = ((bfd_signed_vma) lhs.value
+                                     % (bfd_signed_vma) expld.result.value);
+             else if (expld.phase != lang_mark_phase_enum)
                einfo (_("%F%S %% by zero\n"));
-             result.value = ((bfd_signed_vma) result.value
-                             % (bfd_signed_vma) other.value);
              break;
 
            case '/':
-             if (other.value == 0)
+             if (expld.result.value != 0)
+               expld.result.value = ((bfd_signed_vma) lhs.value
+                                     / (bfd_signed_vma) expld.result.value);
+             else if (expld.phase != lang_mark_phase_enum)
                einfo (_("%F%S / by zero\n"));
-             result.value = ((bfd_signed_vma) result.value
-                             / (bfd_signed_vma) other.value);
              break;
 
-#define BOP(x,y) case x : result.value = result.value y other.value; break;
+#define BOP(x, y) \
+           case x:                                                     \
+             expld.result.value = lhs.value y expld.result.value;      \
+             break;
+
              BOP ('+', +);
              BOP ('*', *);
              BOP ('-', -);
@@ -410,77 +372,82 @@ fold_binary (etree_type *tree,
              BOP (OROR, ||);
 
            case MAX_K:
-             if (result.value < other.value)
-               result = other;
+             if (lhs.value > expld.result.value)
+               expld.result.value = lhs.value;
              break;
 
            case MIN_K:
-             if (result.value > other.value)
-               result = other;
+             if (lhs.value < expld.result.value)
+               expld.result.value = lhs.value;
              break;
 
            case ALIGN_K:
-             result.value = align_n (result.value, other.value);
+             expld.result.value = align_n (lhs.value, expld.result.value);
              break;
 
            case DATA_SEGMENT_ALIGN:
-             if (allocation_done != lang_first_phase_enum
-                 && current_section == bfd_abs_section_ptr
-                 && (exp_data_seg.phase == exp_dataseg_none
-                     || exp_data_seg.phase == exp_dataseg_adjust
-                     || exp_data_seg.phase == exp_dataseg_relro_adjust
-                     || allocation_done != lang_allocating_phase_enum))
+             if (expld.phase != lang_first_phase_enum
+                 && expld.section == bfd_abs_section_ptr
+                 && (expld.dataseg.phase == exp_dataseg_none
+                     || expld.dataseg.phase == exp_dataseg_adjust
+                     || expld.dataseg.phase == exp_dataseg_relro_adjust
+                     || expld.phase == lang_final_phase_enum))
                {
-                 bfd_vma maxpage = result.value;
+                 bfd_vma maxpage = lhs.value;
+                 bfd_vma commonpage = expld.result.value;
 
-                 result.value = align_n (dot, maxpage);
-                 if (exp_data_seg.phase == exp_dataseg_relro_adjust)
-                   result.value = exp_data_seg.base;
-                 else if (exp_data_seg.phase != exp_dataseg_adjust)
+                 expld.result.value = align_n (expld.dot, maxpage);
+                 if (expld.dataseg.phase == exp_dataseg_relro_adjust)
+                   expld.result.value = expld.dataseg.base;
+                 else if (expld.dataseg.phase != exp_dataseg_adjust)
                    {
-                     result.value += dot & (maxpage - 1);
-                     if (allocation_done == lang_allocating_phase_enum)
+                     expld.result.value += expld.dot & (maxpage - 1);
+                     if (expld.phase == lang_allocating_phase_enum)
                        {
-                         exp_data_seg.phase = exp_dataseg_align_seen;
-                         exp_data_seg.min_base = align_n (dot, maxpage);
-                         exp_data_seg.base = result.value;
-                         exp_data_seg.pagesize = other.value;
-                         exp_data_seg.maxpagesize = maxpage;
-                         exp_data_seg.relro_end = 0;
+                         expld.dataseg.phase = exp_dataseg_align_seen;
+                         expld.dataseg.min_base = align_n (expld.dot, maxpage);
+                         expld.dataseg.base = expld.result.value;
+                         expld.dataseg.pagesize = commonpage;
+                         expld.dataseg.maxpagesize = maxpage;
+                         expld.dataseg.relro_end = 0;
                        }
                    }
-                 else if (other.value < maxpage)
-                   result.value += (dot + other.value - 1)
-                                   & (maxpage - other.value);
+                 else if (commonpage < maxpage)
+                   expld.result.value += ((expld.dot + commonpage - 1)
+                                          & (maxpage - commonpage));
                }
              else
-               result.valid_p = FALSE;
+               expld.result.valid_p = FALSE;
              break;
 
            case DATA_SEGMENT_RELRO_END:
-             if (allocation_done != lang_first_phase_enum
-                 && (exp_data_seg.phase == exp_dataseg_align_seen
-                     || exp_data_seg.phase == exp_dataseg_adjust
-                     || exp_data_seg.phase == exp_dataseg_relro_adjust
-                     || allocation_done != lang_allocating_phase_enum))
+             if (expld.phase != lang_first_phase_enum
+                 && (expld.dataseg.phase == exp_dataseg_align_seen
+                     || expld.dataseg.phase == exp_dataseg_adjust
+                     || expld.dataseg.phase == exp_dataseg_relro_adjust
+                     || expld.phase == lang_final_phase_enum))
                {
-                 if (exp_data_seg.phase == exp_dataseg_align_seen
-                     || exp_data_seg.phase == exp_dataseg_relro_adjust)
-                   exp_data_seg.relro_end
-                     = result.value + other.value;
-                 if (exp_data_seg.phase == exp_dataseg_relro_adjust
-                     && (exp_data_seg.relro_end
-                         & (exp_data_seg.pagesize - 1)))
+                 if (expld.dataseg.phase == exp_dataseg_align_seen
+                     || expld.dataseg.phase == exp_dataseg_relro_adjust)
+                   expld.dataseg.relro_end = lhs.value + expld.result.value;
+
+                 if (expld.dataseg.phase == exp_dataseg_relro_adjust
+                     && (expld.dataseg.relro_end
+                         & (expld.dataseg.pagesize - 1)))
                    {
-                     exp_data_seg.relro_end += exp_data_seg.pagesize - 1;
-                     exp_data_seg.relro_end &= ~(exp_data_seg.pagesize - 1);
-                     result.value = exp_data_seg.relro_end - other.value;
+                     expld.dataseg.relro_end += expld.dataseg.pagesize - 1;
+                     expld.dataseg.relro_end &= ~(expld.dataseg.pagesize - 1);
+                     expld.result.value = (expld.dataseg.relro_end
+                                           - expld.result.value);
                    }
-                 if (exp_data_seg.phase == exp_dataseg_align_seen)
-                   exp_data_seg.phase = exp_dataseg_relro_seen;
+                 else
+                   expld.result.value = lhs.value;
+
+                 if (expld.dataseg.phase == exp_dataseg_align_seen)
+                   expld.dataseg.phase = exp_dataseg_relro_seen;
                }
              else
-               result.valid_p = FALSE;
+               expld.result.valid_p = FALSE;
              break;
 
            default:
@@ -488,57 +455,40 @@ fold_binary (etree_type *tree,
            }
        }
       else
-       {
-         result.valid_p = FALSE;
-       }
+       expld.result.valid_p = FALSE;
     }
-
-  return result;
 }
 
-static etree_value_type
-fold_trinary (etree_type *tree,
-             asection *current_section,
-             lang_phase_type allocation_done,
-             bfd_vma dot,
-             bfd_vma *dotp,
-             bfd_boolean mark_used)
+static void
+fold_trinary (etree_type *tree)
 {
-  etree_value_type result;
-
-  result = exp_fold_tree_1 (tree->trinary.cond, current_section,
-                           allocation_done, dot, dotp, mark_used);
-  if (result.valid_p)
-    result = exp_fold_tree_1 ((result.value
-                              ? tree->trinary.lhs
-                              : tree->trinary.rhs),
-                             current_section,
-                             allocation_done,
-                             dot, dotp, mark_used);
-
-  return result;
+  exp_fold_tree_1 (tree->trinary.cond);
+  if (expld.result.valid_p)
+    exp_fold_tree_1 (expld.result.value
+                    ? tree->trinary.lhs
+                    : tree->trinary.rhs);
 }
 
-static etree_value_type
-fold_name (etree_type *tree,
-          asection *current_section,
-          lang_phase_type allocation_done,
-          bfd_vma dot,
-          bfd_boolean mark_used)
+static void
+fold_name (etree_type *tree)
 {
-  etree_value_type result;
-
-  memset (&result, 0, sizeof (result));
+  memset (&expld.result, 0, sizeof (expld.result));
 
   switch (tree->type.node_code)
     {
     case SIZEOF_HEADERS:
-      if (allocation_done != lang_first_phase_enum)
-       result = new_abs (bfd_sizeof_headers (output_bfd,
-                                             link_info.relocatable));
+      if (expld.phase != lang_first_phase_enum)
+       {
+         bfd_vma hdr_size = 0;
+         /* Don't find the real header size if only marking sections;
+            The bfd function may cache incorrect data.  */
+         if (expld.phase != lang_mark_phase_enum)
+           hdr_size = bfd_sizeof_headers (output_bfd, link_info.relocatable);
+         new_abs (hdr_size);
+       }
       break;
     case DEFINED:
-      if (allocation_done == lang_first_phase_enum)
+      if (expld.phase == lang_first_phase_enum)
        lang_track_definedness (tree->name.name);
       else
        {
@@ -549,23 +499,22 @@ fold_name (etree_type *tree,
          h = bfd_wrapped_link_hash_lookup (output_bfd, &link_info,
                                            tree->name.name,
                                            FALSE, FALSE, TRUE);
-         result.value = (h != NULL
-                         && (h->type == bfd_link_hash_defined
-                             || h->type == bfd_link_hash_defweak
-                             || h->type == bfd_link_hash_common)
-                         && (def_iteration == lang_statement_iteration
-                             || def_iteration == -1));
-         result.section = bfd_abs_section_ptr;
-         result.valid_p = TRUE;
+         expld.result.value = (h != NULL
+                               && (h->type == bfd_link_hash_defined
+                                   || h->type == bfd_link_hash_defweak
+                                   || h->type == bfd_link_hash_common)
+                               && (def_iteration == lang_statement_iteration
+                                   || def_iteration == -1));
+         expld.result.section = bfd_abs_section_ptr;
+         expld.result.valid_p = TRUE;
        }
       break;
     case NAME:
-      if (tree->name.name[0] == '.' && tree->name.name[1] == 0)
-       {
-         if (allocation_done != lang_first_phase_enum)
-           result = new_rel_from_section (dot, current_section);
-       }
-      else if (allocation_done != lang_first_phase_enum)
+      if (expld.phase == lang_first_phase_enum)
+       ;
+      else if (tree->name.name[0] == '.' && tree->name.name[1] == 0)
+       new_rel_from_abs (expld.dot);
+      else
        {
          struct bfd_link_hash_entry *h;
 
@@ -578,30 +527,26 @@ fold_name (etree_type *tree,
                   || h->type == bfd_link_hash_defweak)
            {
              if (bfd_is_abs_section (h->u.def.section))
-               result = new_abs (h->u.def.value);
-             else if (allocation_done == lang_final_phase_enum
-                      || allocation_done == lang_allocating_phase_enum)
+               new_abs (h->u.def.value);
+             else
                {
                  asection *output_section;
 
                  output_section = h->u.def.section->output_section;
                  if (output_section == NULL)
-                   einfo (_("%X%S: unresolvable symbol `%s' referenced in expression\n"),
-                          tree->name.name);
-                 else
                    {
-                     /* FIXME: Is this correct if this section is
-                        being linked with -R?  */
-                     result = new_rel ((h->u.def.value
-                                        + h->u.def.section->output_offset),
-                                       NULL,
-                                       output_section);
-                     output_section->flags |= SEC_KEEP;
+                     if (expld.phase != lang_mark_phase_enum)
+                       einfo (_("%X%S: unresolvable symbol `%s'"
+                                " referenced in expression\n"),
+                              tree->name.name);
                    }
+                 else
+                   new_rel (h->u.def.value + h->u.def.section->output_offset,
+                            NULL, output_section);
                }
            }
-         else if (allocation_done == lang_final_phase_enum
-                  || assigning_to_dot)
+         else if (expld.phase == lang_final_phase_enum
+                  || expld.assigning_to_dot)
            einfo (_("%F%S: undefined symbol `%s' referenced in expression\n"),
                   tree->name.name);
          else if (h->type == bfd_link_hash_new)
@@ -615,56 +560,41 @@ fold_name (etree_type *tree,
       break;
 
     case ADDR:
-      if (allocation_done != lang_first_phase_enum)
+      if (expld.phase != lang_first_phase_enum)
        {
          lang_output_section_statement_type *os;
 
          os = lang_output_section_find (tree->name.name);
-         if (os)
-           {
-             os->bfd_section->flags |= SEC_KEEP;
-             if (os->processed > 0)
-               result = new_rel (0, NULL, os->bfd_section);
-           }
+         if (os != NULL && os->processed > 0)
+           new_rel (0, NULL, os->bfd_section);
        }
       break;
 
     case LOADADDR:
-      if (allocation_done != lang_first_phase_enum)
+      if (expld.phase != lang_first_phase_enum)
        {
          lang_output_section_statement_type *os;
 
          os = lang_output_section_find (tree->name.name);
-         if (os)
+         if (os != NULL && os->processed > 0)
            {
-             os->bfd_section->flags |= SEC_KEEP;
-             if (os->processed != 0)
-               {
-                 if (os->load_base == NULL)
-                   result = new_rel (0, NULL, os->bfd_section);
-                 else
-                   result = exp_fold_tree_no_dot (os->load_base,
-                                                  bfd_abs_section_ptr,
-                                                  allocation_done,
-                                                  mark_used);
-               }
+             if (os->load_base == NULL)
+               new_rel (0, NULL, os->bfd_section);
+             else
+               exp_fold_tree_1 (os->load_base);
            }
        }
       break;
 
     case SIZEOF:
-      if (allocation_done != lang_first_phase_enum)
+      if (expld.phase != lang_first_phase_enum)
        {
          int opb = bfd_octets_per_byte (output_bfd);
          lang_output_section_statement_type *os;
 
          os = lang_output_section_find (tree->name.name);
-         if (os)
-           {
-             os->bfd_section->flags |= SEC_KEEP;
-             if (os->processed > 0)
-               result = new_abs (os->bfd_section->size / opb);
-           }
+         if (os != NULL && os->processed > 0)
+           new_abs (os->bfd_section->size / opb);
        }
       break;
 
@@ -674,10 +604,10 @@ fold_name (etree_type *tree,
         
         mem = lang_memory_region_lookup (tree->name.name, FALSE);  
         if (mem != NULL) 
-          result = new_abs (mem->length);
+          new_abs (mem->length);
         else          
-          einfo (_("%F%S: undefined MEMORY region `%s' referenced in expression\n"),
-                  tree->name.name);
+          einfo (_("%F%S: undefined MEMORY region `%s'"
+                  " referenced in expression\n"), tree->name.name);
       }
       break;
 
@@ -687,10 +617,10 @@ fold_name (etree_type *tree,
         
         mem = lang_memory_region_lookup (tree->name.name, FALSE);  
         if (mem != NULL) 
-          result = new_abs (mem->origin);
+          new_abs (mem->origin);
         else          
-          einfo (_("%F%S: undefined MEMORY region `%s' referenced in expression\n"),
-                  tree->name.name);
+          einfo (_("%F%S: undefined MEMORY region `%s'"
+                  " referenced in expression\n"), tree->name.name);
       }
       break;
 
@@ -698,72 +628,57 @@ fold_name (etree_type *tree,
       FAIL ();
       break;
     }
-
-  return result;
 }
 
-static etree_value_type
-exp_fold_tree_1 (etree_type *tree,
-                asection *current_section,
-                lang_phase_type allocation_done,
-                bfd_vma dot,
-                bfd_vma *dotp,
-                bfd_boolean mark_used)
+static void
+exp_fold_tree_1 (etree_type *tree)
 {
-  etree_value_type result;
-
   if (tree == NULL)
     {
-      memset (&result, 0, sizeof (result));
-      return result;
+      memset (&expld.result, 0, sizeof (expld.result));
+      return;
     }
 
   switch (tree->type.node_class)
     {
     case etree_value:
-      result = new_rel (tree->value.value, tree->value.str, current_section);
+      new_rel (tree->value.value, tree->value.str, expld.section);
       break;
 
     case etree_rel:
-      if (allocation_done != lang_final_phase_enum)
-       memset (&result, 0, sizeof (result));
+      if (expld.phase != lang_first_phase_enum)
+       {
+         asection *output_section = tree->rel.section->output_section;
+         new_rel (tree->rel.value + tree->rel.section->output_offset,
+                  NULL, output_section);
+       }
       else
-       result = new_rel ((tree->rel.value
-                          + tree->rel.section->output_section->vma
-                          + tree->rel.section->output_offset),
-                         NULL,
-                         current_section);
+       memset (&expld.result, 0, sizeof (expld.result));
       break;
 
     case etree_assert:
-      result = exp_fold_tree_1 (tree->assert_s.child,
-                               current_section,
-                               allocation_done, dot, dotp,
-                               mark_used);
-      if (result.valid_p)
+      exp_fold_tree_1 (tree->assert_s.child);
+      if (expld.result.valid_p)
        {
-         if (mark_used)
+         if (expld.phase == lang_mark_phase_enum)
            /* 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)
+           expld.result.value = 1;
+         else if (!expld.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, mark_used);
+      fold_unary (tree);
       break;
 
     case etree_binary:
-      result = fold_binary (tree, current_section, allocation_done,
-                           dot, dotp, mark_used);
+      fold_binary (tree);
       break;
 
     case etree_trinary:
-      result = fold_trinary (tree, current_section, allocation_done,
-                            dot, dotp, mark_used);
+      fold_trinary (tree);
       break;
 
     case etree_assign:
@@ -774,138 +689,128 @@ exp_fold_tree_1 (etree_type *tree,
          /* Assignment to dot can only be done during allocation.  */
          if (tree->type.node_class != etree_assign)
            einfo (_("%F%S can not PROVIDE assignment to location counter\n"));
-         if (allocation_done == lang_allocating_phase_enum
-             || (allocation_done == lang_final_phase_enum
-                 && current_section == bfd_abs_section_ptr))
+         if (expld.phase == lang_mark_phase_enum
+             || expld.phase == lang_allocating_phase_enum
+             || (expld.phase == lang_final_phase_enum
+                 && expld.section == bfd_abs_section_ptr))
            {
              /* Notify the folder that this is an assignment to dot.  */
-             assigning_to_dot = TRUE;
-             result = exp_fold_tree_1 (tree->assign.src,
-                                       current_section,
-                                       allocation_done,
-                                       dot, dotp, mark_used);
-             assigning_to_dot = FALSE;
-
-             if (! result.valid_p)
-               einfo (_("%F%S invalid assignment to location counter\n"));
+             expld.assigning_to_dot = TRUE;
+             exp_fold_tree_1 (tree->assign.src);
+             expld.assigning_to_dot = FALSE;
+
+             if (!expld.result.valid_p)
+               {
+                 if (expld.phase != lang_mark_phase_enum)
+                   einfo (_("%F%S invalid assignment to location counter\n"));
+               }
+             else if (expld.dotp == NULL)
+               einfo (_("%F%S assignment to location counter"
+                        " invalid outside of SECTION\n"));
              else
                {
-                 if (current_section == NULL)
-                   einfo (_("%F%S assignment to location counter invalid outside of SECTION\n"));
+                 bfd_vma nextdot;
+
+                 nextdot = expld.result.value + expld.section->vma;
+                 if (nextdot < expld.dot
+                     && expld.section != bfd_abs_section_ptr)
+                   einfo (_("%F%S cannot move location counter backwards"
+                            " (from %V to %V)\n"), expld.dot, nextdot);
                  else
                    {
-                     bfd_vma nextdot;
-
-                     nextdot = result.value + current_section->vma;
-                     if (nextdot < dot
-                         && current_section != bfd_abs_section_ptr)
-                       einfo (_("%F%S cannot move location counter backwards (from %V to %V)\n"),
-                              dot, nextdot);
-                     else
-                       *dotp = nextdot;
+                     expld.dot = nextdot;
+                     *expld.dotp = nextdot;
                    }
                }
            }
          else
-           memset (&result, 0, sizeof (result));
+           memset (&expld.result, 0, sizeof (expld.result));
        }
       else
        {
-         result = exp_fold_tree_1 (tree->assign.src,
-                                   current_section, allocation_done,
-                                   dot, dotp, mark_used);
-         if (result.valid_p)
-           {
-             bfd_boolean create;
-             struct bfd_link_hash_entry *h;
+         struct bfd_link_hash_entry *h = NULL;
 
-             if (tree->type.node_class == etree_assign)
-               create = TRUE;
-             else
-               create = FALSE;
+         if (tree->type.node_class == etree_provide)
+           {
              h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst,
-                                       create, FALSE, TRUE);
+                                       FALSE, FALSE, TRUE);
+             if (h == NULL
+                 || (h->type != bfd_link_hash_new
+                     && h->type != bfd_link_hash_undefined
+                     && h->type != bfd_link_hash_common))
+               {
+                 /* Do nothing.  The symbol was never referenced, or was
+                    defined by some object.  */
+                 break;
+               }
+           }
+
+         exp_fold_tree_1 (tree->assign.src);
+         if (expld.result.valid_p)
+           {
              if (h == NULL)
                {
-                 if (create)
+                 h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst,
+                                           TRUE, FALSE, TRUE);
+                 if (h == NULL)
                    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;
-                 if (tree->type.node_class == etree_provide)
-                   tree->type.node_class = etree_provided;
-               }
+
+             /* 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 = expld.result.value;
+             h->u.def.section = expld.result.section;
+             if (tree->type.node_class == etree_provide)
+               tree->type.node_class = etree_provided;
            }
        }
       break;
 
     case etree_name:
-      result = fold_name (tree, current_section, allocation_done, dot,
-                         mark_used);
+      fold_name (tree);
       break;
 
     default:
       FAIL ();
-      memset (&result, 0, sizeof (result));
+      memset (&expld.result, 0, sizeof (expld.result));
       break;
     }
-
-  return result;
 }
 
-etree_value_type
-exp_fold_tree (etree_type *tree,
-              asection *current_section,
-              lang_phase_type allocation_done,
-              bfd_vma dot,
-              bfd_vma *dotp)
+void
+exp_fold_tree (etree_type *tree, asection *current_section, bfd_vma *dotp)
 {
-  return exp_fold_tree_1 (tree, current_section, allocation_done,
-                         dot, dotp, FALSE);
+  expld.dot = *dotp;
+  expld.dotp = dotp;
+  expld.section = current_section;
+  exp_fold_tree_1 (tree);
 }
 
-static etree_value_type
-exp_fold_tree_no_dot (etree_type *tree,
-                     asection *current_section,
-                     lang_phase_type allocation_done,
-                     bfd_boolean mark_used)
+static void
+exp_fold_tree_no_dot (etree_type *tree)
 {
-  return exp_fold_tree_1 (tree, current_section, allocation_done, 0,
-                         NULL, mark_used);
+  expld.dot = 0;
+  expld.dotp = NULL;
+  expld.section = bfd_abs_section_ptr;
+  exp_fold_tree_1 (tree);
 }
 
 etree_type *
 exp_binop (int code, etree_type *lhs, etree_type *rhs)
 {
   etree_type value, *new;
-  etree_value_type r;
 
   value.type.node_code = code;
   value.binary.lhs = lhs;
   value.binary.rhs = rhs;
   value.type.node_class = etree_binary;
-  r = exp_fold_tree_no_dot (&value,
-                           bfd_abs_section_ptr,
-                           lang_first_phase_enum, FALSE);
-  if (r.valid_p)
-    {
-      return exp_intop (r.value);
-    }
+  exp_fold_tree_no_dot (&value);
+  if (expld.result.valid_p)
+    return exp_intop (expld.result.value);
+
   new = stat_alloc (sizeof (new->binary));
   memcpy (new, &value, sizeof (new->binary));
   return new;
@@ -915,15 +820,15 @@ etree_type *
 exp_trinop (int code, etree_type *cond, etree_type *lhs, etree_type *rhs)
 {
   etree_type value, *new;
-  etree_value_type r;
+
   value.type.node_code = code;
   value.trinary.lhs = lhs;
   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, FALSE);
-  if (r.valid_p)
-    return exp_intop (r.value);
+  exp_fold_tree_no_dot (&value);
+  if (expld.result.valid_p)
+    return exp_intop (expld.result.value);
 
   new = stat_alloc (sizeof (new->trinary));
   memcpy (new, &value, sizeof (new->trinary));
@@ -935,14 +840,12 @@ exp_unop (int code, etree_type *child)
 {
   etree_type value, *new;
 
-  etree_value_type r;
   value.unary.type.node_code = code;
   value.unary.child = child;
   value.unary.type.node_class = etree_unary;
-  r = exp_fold_tree_no_dot (&value, bfd_abs_section_ptr,
-                           lang_first_phase_enum, FALSE);
-  if (r.valid_p)
-    return exp_intop (r.value);
+  exp_fold_tree_no_dot (&value);
+  if (expld.result.valid_p)
+    return exp_intop (expld.result.value);
 
   new = stat_alloc (sizeof (new->unary));
   memcpy (new, &value, sizeof (new->unary));
@@ -953,14 +856,14 @@ etree_type *
 exp_nameop (int code, const char *name)
 {
   etree_type value, *new;
-  etree_value_type r;
+
   value.name.type.node_code = code;
   value.name.name = name;
   value.name.type.node_class = etree_name;
 
-  r = exp_fold_tree_no_dot (&value, NULL, lang_first_phase_enum, FALSE);
-  if (r.valid_p)
-    return exp_intop (r.value);
+  exp_fold_tree_no_dot (&value);
+  if (expld.result.valid_p)
+    return exp_intop (expld.result.value);
 
   new = stat_alloc (sizeof (new->name));
   memcpy (new, &value, sizeof (new->name));
@@ -971,16 +874,13 @@ exp_nameop (int code, const char *name)
 etree_type *
 exp_assop (int code, const char *dst, etree_type *src)
 {
-  etree_type value, *new;
-
-  value.assign.type.node_code = code;
-
-  value.assign.src = src;
-  value.assign.dst = dst;
-  value.assign.type.node_class = etree_assign;
+  etree_type *new;
 
   new = stat_alloc (sizeof (new->assign));
-  memcpy (new, &value, sizeof (new->assign));
+  new->type.node_code = code;
+  new->type.node_class = etree_assign;
+  new->assign.src = src;
+  new->assign.dst = dst;
   return new;
 }
 
@@ -1077,9 +977,6 @@ exp_print_tree (etree_type *tree)
       fprintf (config.map_file, ", %s)", tree->assert_s.message);
       break;
 
-    case etree_undef:
-      fprintf (config.map_file, "????????");
-      break;
     case etree_name:
       if (tree->type.node_code == NAME)
        {
@@ -1099,61 +996,51 @@ exp_print_tree (etree_type *tree)
 }
 
 bfd_vma
-exp_get_vma (etree_type *tree,
-            bfd_vma def,
-            char *name,
-            lang_phase_type allocation_done)
+exp_get_vma (etree_type *tree, bfd_vma def, char *name)
 {
-  etree_value_type r;
-
   if (tree != NULL)
     {
-      r = exp_fold_tree_no_dot (tree, bfd_abs_section_ptr,
-                               allocation_done, FALSE);
-      if (! r.valid_p && name != NULL)
+      exp_fold_tree_no_dot (tree);
+      if (expld.result.valid_p)
+       return expld.result.value;
+      else if (name != NULL && expld.phase != lang_mark_phase_enum)
        einfo (_("%F%S nonconstant expression for %s\n"), name);
-      return r.value;
     }
-  else
-    return def;
+  return def;
 }
 
 int
-exp_get_value_int (etree_type *tree,
-                  int def,
-                  char *name,
-                  lang_phase_type allocation_done)
+exp_get_value_int (etree_type *tree, int def, char *name)
 {
-  return exp_get_vma (tree, def, name, allocation_done);
+  return exp_get_vma (tree, def, name);
 }
 
 fill_type *
-exp_get_fill (etree_type *tree,
-             fill_type *def,
-             char *name,
-             lang_phase_type allocation_done)
+exp_get_fill (etree_type *tree, fill_type *def, char *name)
 {
   fill_type *fill;
-  etree_value_type r;
   size_t len;
   unsigned int val;
 
   if (tree == NULL)
     return def;
 
-  r = exp_fold_tree_no_dot (tree, bfd_abs_section_ptr, allocation_done,
-                           FALSE);
-  if (! r.valid_p && name != NULL)
-    einfo (_("%F%S nonconstant expression for %s\n"), name);
+  exp_fold_tree_no_dot (tree);
+  if (!expld.result.valid_p)
+    {
+      if (name != NULL && expld.phase != lang_mark_phase_enum)
+       einfo (_("%F%S nonconstant expression for %s\n"), name);
+      return def;
+    }
 
-  if (r.str != NULL && (len = strlen (r.str)) != 0)
+  if (expld.result.str != NULL && (len = strlen (expld.result.str)) != 0)
     {
       unsigned char *dst;
       unsigned char *s;
       fill = xmalloc ((len + 1) / 2 + sizeof (*fill) - 1);
       fill->size = (len + 1) / 2;
       dst = fill->data;
-      s = (unsigned char *) r.str;
+      s = (unsigned char *) expld.result.str;
       val = 0;
       do
        {
@@ -1176,7 +1063,7 @@ exp_get_fill (etree_type *tree,
   else
     {
       fill = xmalloc (4 + sizeof (*fill) - 1);
-      val = r.value;
+      val = expld.result.value;
       fill->data[0] = (val >> 24) & 0xff;
       fill->data[1] = (val >> 16) & 0xff;
       fill->data[2] = (val >>  8) & 0xff;
@@ -1187,21 +1074,21 @@ exp_get_fill (etree_type *tree,
 }
 
 bfd_vma
-exp_get_abs_int (etree_type *tree,
-                int def ATTRIBUTE_UNUSED,
-                char *name,
-                lang_phase_type allocation_done)
+exp_get_abs_int (etree_type *tree, int def, char *name)
 {
-  etree_value_type res;
-  res = exp_fold_tree_no_dot (tree, bfd_abs_section_ptr, allocation_done,
-                             FALSE);
-
-  if (res.valid_p)
-    res.value += res.section->vma;
-  else
-    einfo (_("%F%S non constant expression for %s\n"), name);
+  if (tree != NULL)
+    {
+      exp_fold_tree_no_dot (tree);
 
-  return res.value;
+      if (expld.result.valid_p)
+       {
+         expld.result.value += expld.result.section->vma;
+         return expld.result.value;
+       }
+      else if (name != NULL && expld.phase != lang_mark_phase_enum)
+       einfo (_("%F%S non constant expression for %s\n"), name);
+    }
+  return def;
 }
 
 static bfd_vma
@@ -1213,103 +1100,3 @@ align_n (bfd_vma value, bfd_vma align)
   value = (value + align - 1) / align;
   return value * align;
 }
-
-void
-exp_mark_used_section (etree_type *tree, asection *current_section)
-{
-  bfd_vma dot = 0;
-
-  switch (tree->type.node_class)
-    {
-    case etree_value:
-      break;
-
-    case etree_rel:
-      break;
-
-    case etree_assert:
-      break;
-
-    case etree_unary:
-      break;
-
-    case etree_binary:
-      fold_binary (tree, current_section, lang_allocating_phase_enum,
-                  dot, &dot, TRUE);
-      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_boolean create = tree->type.node_class == etree_assign;
-         struct bfd_link_hash_entry *h;
-
-         result = exp_fold_tree_1 (tree->assign.src,
-                                   current_section,
-                                   lang_allocating_phase_enum,
-                                   dot, &dot, TRUE);
-
-         /* We mark the current section SEC_KEEP only if the symbol
-            will be defined.  */
-         if (!create)
-           h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst,
-                                     create, FALSE, TRUE);
-         else
-           h = NULL;
-
-         if ((create || h)
-             && current_section != bfd_abs_section_ptr)
-           current_section->flags |= SEC_KEEP;
-
-         if (result.valid_p)
-           {
-
-             if (create)
-               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;
-                 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;
-    }
-}
index ae6b87408ccaa5214d545a06266e454cfbeff19f..7cf8ea7374d7ffcbc223fe7f960d6a9fc43fb1f6 100644 (file)
@@ -40,8 +40,6 @@ typedef struct {
     etree_assign,
     etree_provide,
     etree_provided,
-    etree_undef,
-    etree_unspec,
     etree_value,
     etree_assert,
     etree_rel
@@ -91,17 +89,44 @@ typedef union etree_union {
   } assert_s;
 } etree_type;
 
-extern struct exp_data_seg {
-  enum {
-    exp_dataseg_none,
-    exp_dataseg_align_seen,
-    exp_dataseg_relro_seen,
-    exp_dataseg_end_seen,
-    exp_dataseg_relro_adjust,
-    exp_dataseg_adjust
-  } phase;
-  bfd_vma base, min_base, relro_end, end, pagesize, maxpagesize;
-} exp_data_seg;
+typedef enum {
+  lang_first_phase_enum,
+  lang_mark_phase_enum,
+  lang_allocating_phase_enum,
+  lang_final_phase_enum
+} lang_phase_type;
+
+struct ldexp_control {
+  /* Modify expression evaluation depending on this.  */
+  lang_phase_type phase;
+
+  /* Principally used for diagnostics.  */
+  bfd_boolean assigning_to_dot;
+
+  /* Working results.  */
+  etree_value_type result;
+  bfd_vma dot;
+
+  /* Current dot and section passed to ldexp folder.  */
+  bfd_vma *dotp;
+  asection *section;
+
+  /* State machine and results for DATASEG.  */
+  struct {
+    enum {
+      exp_dataseg_none,
+      exp_dataseg_align_seen,
+      exp_dataseg_relro_seen,
+      exp_dataseg_end_seen,
+      exp_dataseg_relro_adjust,
+      exp_dataseg_adjust
+    } phase;
+
+    bfd_vma base, min_base, relro_end, end, pagesize, maxpagesize;
+  } dataseg;
+};
+
+extern struct ldexp_control expld;
 
 /* A maps from a segment name to a base address.  */
 typedef struct segment_struct {
@@ -127,10 +152,8 @@ etree_type *exp_bigintop
   (bfd_vma, char *);
 etree_type *exp_relop
   (asection *, bfd_vma);
-etree_value_type invalid
-  (void);
-etree_value_type exp_fold_tree
-  (etree_type *, asection *, lang_phase_type, bfd_vma, bfd_vma *);
+void exp_fold_tree
+  (etree_type *, asection *, bfd_vma *);
 etree_type *exp_binop
   (int, etree_type *, etree_type *);
 etree_type *exp_trinop
@@ -148,14 +171,12 @@ etree_type *exp_assert
 void exp_print_tree
   (etree_type *);
 bfd_vma exp_get_vma
-  (etree_type *, bfd_vma, char *, lang_phase_type);
+  (etree_type *, bfd_vma, char *);
 int exp_get_value_int
-  (etree_type *, int, char *, lang_phase_type);
+  (etree_type *, int, char *);
 fill_type *exp_get_fill
-  (etree_type *, fill_type *, char *, lang_phase_type);
+  (etree_type *, fill_type *, char *);
 bfd_vma exp_get_abs_int
-  (etree_type *, int, char *, lang_phase_type);
-void exp_mark_used_section
-  (etree_type *, asection *);
+  (etree_type *, int, char *);
 
 #endif
index e4da870f1a332e1934a1ff9a74c161a8d26bb484..cdb220919889a4b717b104ec2f7d8dbaee52ad9a 100644 (file)
@@ -600,10 +600,7 @@ length:
 fill_exp:
        mustbe_exp
                {
-                 $$ = exp_get_fill ($1,
-                                    0,
-                                    "fill value",
-                                    lang_first_phase_enum);
+                 $$ = exp_get_fill ($1, 0, "fill value");
                }
        ;
 
@@ -681,18 +678,16 @@ memory_spec:      NAME
 
 origin_spec:
        ORIGIN '=' mustbe_exp
-               { region->current =
-                region->origin =
-                exp_get_vma($3, 0L,"origin", lang_first_phase_enum);
-}
+               {
+                 region->origin = exp_get_vma ($3, 0, "origin");
+                 region->current = region->origin;
+               }
        ;
 
 length_spec:
              LENGTH '=' mustbe_exp
-               { region->length = exp_get_vma($3,
-                                              ~((bfd_vma)0),
-                                              "length",
-                                              lang_first_phase_enum);
+               {
+                 region->length = exp_get_vma ($3, -1, "length");
                }
        ;
 
index 973ed4105af2f81697bda1378521f1bb79f5e985..4f9569f42ac5cb06abbed656881a74368514320a 100644 (file)
@@ -101,6 +101,9 @@ bfd_boolean delete_output_file_on_failure = FALSE;
 struct lang_nocrossrefs *nocrossref_list;
 static struct unique_sections *unique_section_list;
 static bfd_boolean ldlang_sysrooted_script = FALSE;
+
+ /* Functions that traverse the linker script and might evaluate
+    DEFINED() need to increment this.  */
 int lang_statement_iteration = 0;
 
 etree_type *base; /* Relocation base - or null */
@@ -895,9 +898,6 @@ lang_init (void)
   if (!bfd_hash_table_init_n (&lang_definedness_table,
                              lang_definedness_newfunc, 3))
     einfo (_("%P%F: out of memory during initialization"));
-
-  /* Callers of exp_fold_tree need to increment this.  */
-  lang_statement_iteration = 0;
 }
 
 /*----------------------------------------------------------------------
@@ -3044,95 +3044,6 @@ 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);
-               if (os->load_base)
-                 exp_mark_used_section (os->load_base,
-                                        bfd_abs_section_ptr);
-             }
-         }
-         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,
-                                bfd_abs_section_ptr);
-         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->bfd_section);
-         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.  */
@@ -3141,8 +3052,25 @@ void
 strip_excluded_output_sections (void)
 {
   lang_output_section_statement_type *os;
+  unsigned int gc_sections;
 
-  lang_mark_used_section ();
+  /* Run lang_size_sections (if not already done) to ensure that all
+     symbols defined in the linker script are put in the bfd hash
+     table.  */
+  if (expld.phase != lang_mark_phase_enum)
+    {
+      expld.phase = lang_mark_phase_enum;
+      expld.dataseg.phase = exp_dataseg_none;
+      one_lang_size_sections_pass (NULL, FALSE);
+      lang_reset_memory_regions ();
+    }
+
+  /* Now call into bfd_gc_sections to mark all sections defining global
+     symbols with SEC_KEEP.  */
+  gc_sections = link_info.gc_sections;
+  link_info.gc_sections = 0;
+  bfd_gc_sections (output_bfd, &link_info);
+  link_info.gc_sections = gc_sections;
 
   for (os = &lang_output_section_statement.head->output_section_statement;
        os != NULL;
@@ -3158,7 +3086,7 @@ strip_excluded_output_sections (void)
       if (output_section == NULL)
        continue;
 
-      exclude = FALSE;
+      exclude = TRUE;
       if (output_section->map_head.s != NULL)
        {
          asection *s;
@@ -3166,26 +3094,25 @@ strip_excluded_output_sections (void)
          for (s = output_section->map_head.s; s != NULL;
               s = s->map_head.s)
            if ((s->flags & SEC_EXCLUDE) == 0)
-             break;
+             {
+               exclude = FALSE;
+               break;
+             }
 
          output_section->map_head.link_order = NULL;
          output_section->map_tail.link_order = NULL;
-
-         if (s == NULL)
-           exclude = TRUE;
        }
 
       if (exclude
-         || (output_section->linker_has_input == 0
-             && ((output_section->flags
-                  & (SEC_KEEP | SEC_HAS_CONTENTS)) == 0)))
+         && (output_section->flags & SEC_KEEP) == 0
+         && output_section->rawsize == 0
+         && !bfd_is_abs_section (output_section))
        {
-         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;
+         /* We don't set bfd_section to NULL since bfd_section of the
+            removed output section statement may still be used.  */
+         os->ignored = TRUE;
+         output_section->flags |= SEC_EXCLUDE;
+
          if (!bfd_section_removed_from_list (output_bfd,
                                              output_section))
            {
@@ -3234,7 +3161,7 @@ print_output_section_statement
              bfd_vma addr;
 
              addr = exp_get_abs_int (output_section_statement->load_base, 0,
-                                     "load base", lang_final_phase_enum);
+                                     "load base");
              minfo (_(" load address 0x%V"), addr);
            }
        }
@@ -3304,7 +3231,6 @@ print_assignment (lang_assignment_statement_type *assignment,
   bfd_boolean is_dot;
   bfd_boolean computation_is_valid = TRUE;
   etree_type *tree;
-  etree_value_type result;
 
   for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
     print_space ();
@@ -3324,18 +3250,17 @@ print_assignment (lang_assignment_statement_type *assignment,
       computation_is_valid = is_dot || (scan_for_self_assignment (dst, tree) == FALSE);
     }
 
-  result = exp_fold_tree (tree, output_section->bfd_section,
-                         lang_final_phase_enum, print_dot, &print_dot);
-  if (result.valid_p)
+  exp_fold_tree (tree, output_section->bfd_section, &print_dot);
+  if (expld.result.valid_p)
     {
       bfd_vma value;
 
       if (computation_is_valid)
        {
-         value = result.value;
+         value = expld.result.value;
 
-         if (result.section)
-           value += result.section->vma;
+         if (expld.result.section)
+           value += expld.result.section->vma;
 
          minfo ("0x%V", value);
          if (is_dot)
@@ -3351,8 +3276,8 @@ print_assignment (lang_assignment_statement_type *assignment,
            {
              value = h->u.def.value;
 
-             if (result.section)
-             value += result.section->vma;
+             if (expld.result.section)
+             value += expld.result.section->vma;
 
              minfo ("[0x%V]", value);
            }
@@ -3821,16 +3746,22 @@ insert_pad (lang_statement_union_type **ptr,
            bfd_vma dot)
 {
   static fill_type zero_fill = { 1, { 0 } };
-  lang_statement_union_type *pad;
+  lang_statement_union_type *pad = NULL;
 
-  pad = ((lang_statement_union_type *)
-        ((char *) ptr - offsetof (lang_statement_union_type, header.next)));
-  if (ptr != &statement_list.head
+  if (ptr != &statement_list.head)
+    pad = ((lang_statement_union_type *)
+          ((char *) ptr - offsetof (lang_statement_union_type, header.next)));
+  if (pad != NULL
+      && pad->header.type == lang_padding_statement_enum
+      && pad->padding_statement.output_section == output_section)
+    {
+      /* Use the existing pad statement.  */
+    }
+  else if ((pad = *ptr) != NULL
       && pad->header.type == lang_padding_statement_enum
       && pad->padding_statement.output_section == output_section)
     {
-      /* Use the existing pad statement.  The above test on output
-        section is probably redundant, but it doesn't hurt to check.  */
+      /* Use the existing pad statement.  */
     }
   else
     {
@@ -4045,11 +3976,11 @@ lang_size_sections_1
        {
        case lang_output_section_statement_enum:
          {
-           bfd_vma after;
+           bfd_vma newdot, after;
            lang_output_section_statement_type *os;
 
            os = &s->output_section_statement;
-           if (os->bfd_section == NULL || os->ignored)
+           if (os->bfd_section == NULL)
              /* This section was removed or never actually created.  */
              break;
 
@@ -4109,7 +4040,8 @@ lang_size_sections_1
                        && lang_memory_region_list != NULL
                        && (strcmp (lang_memory_region_list->name,
                                    DEFAULT_MEMORY_REGION) != 0
-                           || lang_memory_region_list->next != NULL))
+                           || lang_memory_region_list->next != NULL)
+                       && expld.phase != lang_mark_phase_enum)
                      {
                        /* By default this is an error rather than just a
                           warning because if we allocate the section to the
@@ -4132,80 +4064,80 @@ lang_size_sections_1
                                                       os->bfd_section));
                      }
 
-                   dot = os->region->current;
+                   newdot = os->region->current;
 
                    if (os->section_alignment == -1)
                      {
-                       bfd_vma olddot;
-
-                       olddot = dot;
-                       dot = align_power (dot,
-                                          os->bfd_section->alignment_power);
+                       bfd_vma savedot = newdot;
+                       newdot = align_power (newdot,
+                                             os->bfd_section->alignment_power);
 
-                       if (dot != olddot && config.warn_section_align)
+                       if (newdot != savedot
+                           && config.warn_section_align
+                           && expld.phase != lang_mark_phase_enum)
                          einfo (_("%P: warning: changing start of section"
-                                  " %s by %u bytes\n"),
-                                os->name, (unsigned int) (dot - olddot));
+                                  " %s by %lu bytes\n"),
+                                os->name, (unsigned long) (newdot - savedot));
                      }
                  }
                else
                  {
-                   etree_value_type r;
-
+                   newdot = dot;
                    os->processed = -1;
-                   r = exp_fold_tree (os->addr_tree,
-                                      bfd_abs_section_ptr,
-                                      lang_allocating_phase_enum,
-                                      dot, &dot);
+                   exp_fold_tree (os->addr_tree, bfd_abs_section_ptr,
+                                  &newdot);
                    os->processed = 0;
 
-                   if (!r.valid_p)
+                   if (!expld.result.valid_p
+                       && expld.phase != lang_mark_phase_enum)
                      einfo (_("%F%S: non constant or forward reference"
                               " address expression for section %s\n"),
                             os->name);
 
-                   dot = r.value + r.section->vma;
+                   newdot = expld.result.value + expld.result.section->vma;
                  }
 
                /* The section starts here.
                   First, align to what the section needs.  */
 
                if (os->section_alignment != -1)
-                 dot = align_power (dot, os->section_alignment);
+                 newdot = align_power (newdot, os->section_alignment);
 
-               bfd_set_section_vma (0, os->bfd_section, dot);
+               bfd_set_section_vma (0, os->bfd_section, newdot);
 
                os->bfd_section->output_offset = 0;
              }
 
            lang_size_sections_1 (os->children.head, os, &os->children.head,
-                                 os->fill, dot, relax, check_regions);
+                                 os->fill, newdot, relax, check_regions);
+
+           os->processed = 1;
+
+           if (bfd_is_abs_section (os->bfd_section) || os->ignored)
+             {
+               ASSERT (os->bfd_section->size == 0);
+               break;
+             }
+
+           dot = os->bfd_section->vma;
 
            /* Put the section within the requested block size, or
               align at the block boundary.  */
-           after = ((os->bfd_section->vma
+           after = ((dot
                      + TO_ADDR (os->bfd_section->size)
                      + os->block_value - 1)
                     & - (bfd_vma) os->block_value);
 
-           if (bfd_is_abs_section (os->bfd_section))
-             ASSERT (after == os->bfd_section->vma);
-           else
-             os->bfd_section->size
-               = TO_SIZE (after - os->bfd_section->vma);
+           os->bfd_section->size = TO_SIZE (after - os->bfd_section->vma);
 
-           dot = os->bfd_section->vma;
            /* .tbss sections effectively have zero size.  */
            if ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0
                || (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0
                || link_info.relocatable)
              dot += TO_ADDR (os->bfd_section->size);
 
-           os->processed = 1;
-
            if (os->update_dot_tree != 0)
-             exp_fold_tree (os->update_dot_tree, bfd_abs_section_ptr,
-                            lang_allocating_phase_enum, dot, &dot);
+             exp_fold_tree (os->update_dot_tree, bfd_abs_section_ptr, &dot);
 
            /* Update dot in the region ?
               We only do this if the section is going to be allocated,
@@ -4263,8 +4195,7 @@ lang_size_sections_1
 
            /* We might refer to provided symbols in the expression, and
               need to mark them as needed.  */
-           exp_fold_tree (s->data_statement.exp, bfd_abs_section_ptr,
-                          lang_allocating_phase_enum, dot, &dot);
+           exp_fold_tree (s->data_statement.exp, bfd_abs_section_ptr, &dot);
 
            switch (s->data_statement.type)
              {
@@ -4306,21 +4237,21 @@ lang_size_sections_1
          break;
 
        case lang_wild_statement_enum:
-
          dot = lang_size_sections_1 (s->wild_statement.children.head,
                                      output_section_statement,
                                      &s->wild_statement.children.head,
                                      fill, dot, relax, check_regions);
-
          break;
 
        case lang_object_symbols_statement_enum:
          link_info.create_object_symbols_section =
            output_section_statement->bfd_section;
          break;
+
        case lang_output_statement_enum:
        case lang_target_statement_enum:
          break;
+
        case lang_input_section_enum:
          {
            asection *i;
@@ -4339,25 +4270,26 @@ lang_size_sections_1
                                      output_section_statement->fill, dot);
          }
          break;
+
        case lang_input_statement_enum:
          break;
+
        case lang_fill_statement_enum:
          s->fill_statement.output_section =
            output_section_statement->bfd_section;
 
          fill = s->fill_statement.fill;
          break;
+
        case lang_assignment_statement_enum:
          {
            bfd_vma newdot = dot;
 
            exp_fold_tree (s->assignment_statement.exp,
                           output_section_statement->bfd_section,
-                          lang_allocating_phase_enum,
-                          dot,
                           &newdot);
 
-           if (newdot != dot)
+           if (newdot != dot && !output_section_statement->ignored)
              {
                if (output_section_statement == abs_output_section)
                  {
@@ -4376,15 +4308,15 @@ lang_size_sections_1
 
                    /* Don't neuter the pad below when relaxing.  */
                    s = s->header.next;
-                 }
-
-               /* If dot is advanced, this implies that the section should
-                  have space allocated to it, unless the user has explicitly
-                  stated that the section should never be loaded.  */
-               if (!(output_section_statement->flags
-                     & (SEC_NEVER_LOAD | SEC_ALLOC)))
-                 output_section_statement->bfd_section->flags |= SEC_ALLOC;
 
+                   /* If dot is advanced, this implies that the section
+                      should have space allocated to it, unless the
+                      user has explicitly stated that the section
+                      should never be loaded.  */
+                   if (!(output_section_statement->flags
+                         & (SEC_NEVER_LOAD | SEC_ALLOC)))
+                     output_section_statement->bfd_section->flags |= SEC_ALLOC;
+                 }
                dot = newdot;
              }
          }
@@ -4427,47 +4359,43 @@ lang_size_sections_1
   return dot;
 }
 
-bfd_vma
-lang_size_sections
-  (lang_statement_union_type *s,
-   lang_output_section_statement_type *output_section_statement,
-   lang_statement_union_type **prev,
-   fill_type *fill,
-   bfd_vma dot,
-   bfd_boolean *relax,
-   bfd_boolean check_regions)
+void
+one_lang_size_sections_pass (bfd_boolean *relax, bfd_boolean check_regions)
 {
-  bfd_vma result;
-
-  /* Callers of exp_fold_tree need to increment this.  */
   lang_statement_iteration++;
+  lang_size_sections_1 (statement_list.head, abs_output_section,
+                       &statement_list.head, 0, 0, relax, check_regions);
+}
 
-  exp_data_seg.phase = exp_dataseg_none;
-  result = lang_size_sections_1 (s, output_section_statement, prev, fill,
-                                dot, relax, check_regions);
-  if (exp_data_seg.phase == exp_dataseg_end_seen
-      && link_info.relro && exp_data_seg.relro_end)
+void
+lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions)
+{
+  expld.phase = lang_allocating_phase_enum;
+  expld.dataseg.phase = exp_dataseg_none;
+
+  one_lang_size_sections_pass (relax, check_regions);
+  if (expld.dataseg.phase == exp_dataseg_end_seen
+      && link_info.relro && expld.dataseg.relro_end)
     {
       /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END pair was seen, try
-        to put exp_data_seg.relro on a (common) page boundary.  */
+        to put expld.dataseg.relro on a (common) page boundary.  */
       bfd_vma old_min_base, relro_end, maxpage;
 
-      exp_data_seg.phase = exp_dataseg_relro_adjust;
-      old_min_base = exp_data_seg.min_base;
-      maxpage = exp_data_seg.maxpagesize;
-      exp_data_seg.base += (-exp_data_seg.relro_end
-                           & (exp_data_seg.pagesize - 1));
+      expld.dataseg.phase = exp_dataseg_relro_adjust;
+      old_min_base = expld.dataseg.min_base;
+      maxpage = expld.dataseg.maxpagesize;
+      expld.dataseg.base += (-expld.dataseg.relro_end
+                            & (expld.dataseg.pagesize - 1));
       /* Compute the expected PT_GNU_RELRO segment end.  */
-      relro_end = (exp_data_seg.relro_end + exp_data_seg.pagesize - 1)
-                 & ~(exp_data_seg.pagesize - 1);
-      if (old_min_base + maxpage < exp_data_seg.base)
+      relro_end = (expld.dataseg.relro_end + expld.dataseg.pagesize - 1)
+                 & ~(expld.dataseg.pagesize - 1);
+      if (old_min_base + maxpage < expld.dataseg.base)
        {
-         exp_data_seg.base -= maxpage;
+         expld.dataseg.base -= maxpage;
          relro_end -= maxpage;
        }
-      result = lang_size_sections_1 (s, output_section_statement, prev, fill,
-                                    dot, relax, check_regions);
-      if (exp_data_seg.relro_end > relro_end)
+      one_lang_size_sections_pass (relax, check_regions);
+      if (expld.dataseg.relro_end > relro_end)
        {
          /* The alignment of sections between DATA_SEGMENT_ALIGN
             and DATA_SEGMENT_RELRO_END caused huge padding to be
@@ -4478,46 +4406,42 @@ lang_size_sections
          /* Find maximum alignment power of sections between
             DATA_SEGMENT_ALIGN and DATA_SEGMENT_RELRO_END.  */
          for (sec = output_bfd->sections; sec; sec = sec->next)
-           if (sec->vma >= exp_data_seg.base
-               && sec->vma < exp_data_seg.relro_end
+           if (sec->vma >= expld.dataseg.base
+               && sec->vma < expld.dataseg.relro_end
                && sec->alignment_power > max_alignment_power)
              max_alignment_power = sec->alignment_power;
 
-         if (((bfd_vma) 1 << max_alignment_power) < exp_data_seg.pagesize)
+         if (((bfd_vma) 1 << max_alignment_power) < expld.dataseg.pagesize)
            {
-             if (exp_data_seg.base - (1 << max_alignment_power)
+             if (expld.dataseg.base - (1 << max_alignment_power)
                  < old_min_base)
-               exp_data_seg.base += exp_data_seg.pagesize;
-             exp_data_seg.base -= (1 << max_alignment_power);
-             result = lang_size_sections_1 (s, output_section_statement,
-                                            prev, fill, dot, relax,
-                                            check_regions);
+               expld.dataseg.base += expld.dataseg.pagesize;
+             expld.dataseg.base -= (1 << max_alignment_power);
+             one_lang_size_sections_pass (relax, check_regions);
            }
        }
-      link_info.relro_start = exp_data_seg.base;
-      link_info.relro_end = exp_data_seg.relro_end;
+      link_info.relro_start = expld.dataseg.base;
+      link_info.relro_end = expld.dataseg.relro_end;
     }
-  else if (exp_data_seg.phase == exp_dataseg_end_seen)
+  else if (expld.dataseg.phase == exp_dataseg_end_seen)
     {
       /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_END pair was seen, check whether
         a page could be saved in the data segment.  */
       bfd_vma first, last;
 
-      first = -exp_data_seg.base & (exp_data_seg.pagesize - 1);
-      last = exp_data_seg.end & (exp_data_seg.pagesize - 1);
+      first = -expld.dataseg.base & (expld.dataseg.pagesize - 1);
+      last = expld.dataseg.end & (expld.dataseg.pagesize - 1);
       if (first && last
-         && ((exp_data_seg.base & ~(exp_data_seg.pagesize - 1))
-             != (exp_data_seg.end & ~(exp_data_seg.pagesize - 1)))
-         && first + last <= exp_data_seg.pagesize)
+         && ((expld.dataseg.base & ~(expld.dataseg.pagesize - 1))
+             != (expld.dataseg.end & ~(expld.dataseg.pagesize - 1)))
+         && first + last <= expld.dataseg.pagesize)
        {
-         exp_data_seg.phase = exp_dataseg_adjust;
-         lang_statement_iteration++;
-         result = lang_size_sections_1 (s, output_section_statement, prev,
-                                        fill, dot, relax, check_regions);
+         expld.dataseg.phase = exp_dataseg_adjust;
+         one_lang_size_sections_pass (relax, check_regions);
        }
     }
 
-  return result;
+  expld.phase = lang_final_phase_enum;
 }
 
 /* Worker function for lang_do_assignments.  Recursiveness goes here.  */
@@ -4562,36 +4486,31 @@ lang_do_assignments_1
                if (os->bfd_section && !os->ignored)
                  {
                    os->bfd_section->lma
-                     = exp_get_abs_int (os->load_base, 0, "load base",
-                                        lang_final_phase_enum);
+                     = exp_get_abs_int (os->load_base, 0, "load base");
                  }
              }
          }
          break;
+
        case lang_wild_statement_enum:
 
          dot = lang_do_assignments_1 (s->wild_statement.children.head,
                                       output_section_statement,
                                       fill, dot);
-
          break;
 
        case lang_object_symbols_statement_enum:
        case lang_output_statement_enum:
        case lang_target_statement_enum:
          break;
+
        case lang_data_statement_enum:
-         {
-           etree_value_type value;
-
-           value = exp_fold_tree (s->data_statement.exp,
-                                  bfd_abs_section_ptr,
-                                  lang_final_phase_enum, dot, &dot);
-           if (!value.valid_p)
-             einfo (_("%F%P: invalid data statement\n"));
-           s->data_statement.value
-             = value.value + value.section->vma;
-         }
+         exp_fold_tree (s->data_statement.exp, bfd_abs_section_ptr, &dot);
+         if (expld.result.valid_p)
+           s->data_statement.value = (expld.result.value
+                                      + expld.result.section->vma);
+         else
+           einfo (_("%F%P: invalid data statement\n"));
          {
            unsigned int size;
            switch (s->data_statement.type)
@@ -4619,16 +4538,12 @@ lang_do_assignments_1
          break;
 
        case lang_reloc_statement_enum:
-         {
-           etree_value_type value;
-
-           value = exp_fold_tree (s->reloc_statement.addend_exp,
-                                  bfd_abs_section_ptr,
-                                  lang_final_phase_enum, dot, &dot);
-           s->reloc_statement.addend_value = value.value;
-           if (!value.valid_p)
-             einfo (_("%F%P: invalid reloc statement\n"));
-         }
+         exp_fold_tree (s->reloc_statement.addend_exp,
+                        bfd_abs_section_ptr, &dot);
+         if (expld.result.valid_p)
+           s->reloc_statement.addend_value = expld.result.value;
+         else
+           einfo (_("%F%P: invalid reloc statement\n"));
          dot += TO_ADDR (bfd_get_reloc_size (s->reloc_statement.howto));
          break;
 
@@ -4643,19 +4558,17 @@ lang_do_assignments_1
 
        case lang_input_statement_enum:
          break;
+
        case lang_fill_statement_enum:
          fill = s->fill_statement.fill;
          break;
-       case lang_assignment_statement_enum:
-         {
-           exp_fold_tree (s->assignment_statement.exp,
-                          output_section_statement->bfd_section,
-                          lang_final_phase_enum,
-                          dot,
-                          &dot);
-         }
 
+       case lang_assignment_statement_enum:
+         exp_fold_tree (s->assignment_statement.exp,
+                        output_section_statement->bfd_section,
+                        &dot);
          break;
+
        case lang_padding_statement_enum:
          dot += TO_ADDR (s->padding_statement.size);
          break;
@@ -4664,30 +4577,24 @@ lang_do_assignments_1
          dot = lang_do_assignments_1 (s->group_statement.children.head,
                                       output_section_statement,
                                       fill, dot);
-
          break;
 
        default:
          FAIL ();
          break;
+
        case lang_address_statement_enum:
          break;
        }
-
     }
   return dot;
 }
 
 void
-lang_do_assignments
-  (lang_statement_union_type *s,
-   lang_output_section_statement_type *output_section_statement,
-   fill_type *fill,
-   bfd_vma dot)
+lang_do_assignments (void)
 {
-  /* Callers of exp_fold_tree need to increment this.  */
   lang_statement_iteration++;
-  lang_do_assignments_1 (s, output_section_statement, fill, dot);
+  lang_do_assignments_1 (statement_list.head, abs_output_section, NULL, 0);
 }
 
 /* Fix any .startof. or .sizeof. symbols.  When the assemblers see the
@@ -5227,9 +5134,9 @@ lang_enter_output_section_statement (const char *output_section_statement_name,
   stat_ptr = &os->children;
 
   os->subsection_alignment =
-    topower (exp_get_value_int (subalign, -1, "subsection alignment", 0));
+    topower (exp_get_value_int (subalign, -1, "subsection alignment"));
   os->section_alignment =
-    topower (exp_get_value_int (align, -1, "section alignment", 0));
+    topower (exp_get_value_int (align, -1, "section alignment"));
 
   os->load_base = ebase;
   return os;
@@ -5251,6 +5158,7 @@ lang_reset_memory_regions (void)
 {
   lang_memory_region_type *p = lang_memory_region_list;
   asection *o;
+  lang_output_section_statement_type *os;
 
   for (p = lang_memory_region_list; p != NULL; p = p->next)
     {
@@ -5258,6 +5166,11 @@ lang_reset_memory_regions (void)
       p->current = p->origin;
     }
 
+  for (os = &lang_output_section_statement.head->output_section_statement;
+       os != NULL;
+       os = os->next)
+    os->processed = 0;
+
   for (o = output_bfd->sections; o != NULL; o = o->next)
     {
       /* Save the last size for possible use by bfd_relax_section.  */
@@ -5444,9 +5357,7 @@ lang_process (void)
   lang_record_phdrs ();
 
   /* Size up the sections.  */
-  lang_size_sections (statement_list.head, abs_output_section,
-                     &statement_list.head, 0, 0, NULL,
-                     command_line.relax ? FALSE : TRUE);
+  lang_size_sections (NULL, !command_line.relax);
 
   /* Now run around and relax if we can.  */
   if (command_line.relax)
@@ -5464,8 +5375,7 @@ lang_process (void)
 
          /* Do all the assignments with our current guesses as to
             section sizes.  */
-         lang_do_assignments (statement_list.head, abs_output_section,
-                              NULL, 0);
+         lang_do_assignments ();
 
          /* We must do this after lang_do_assignments, because it uses
             size.  */
@@ -5473,8 +5383,7 @@ lang_process (void)
 
          /* Perform another relax pass - this time we know where the
             globals are, so can make a better guess.  */
-         lang_size_sections (statement_list.head, abs_output_section,
-                             &statement_list.head, 0, 0, &relax_again, FALSE);
+         lang_size_sections (&relax_again, FALSE);
 
          /* If the normal relax is done and the relax finalize pass
             is not performed yet, we perform another relax pass.  */
@@ -5487,10 +5396,9 @@ lang_process (void)
       while (relax_again);
 
       /* Final extra sizing to report errors.  */
-      lang_do_assignments (statement_list.head, abs_output_section, NULL, 0);
+      lang_do_assignments ();
       lang_reset_memory_regions ();
-      lang_size_sections (statement_list.head, abs_output_section,
-                         &statement_list.head, 0, 0, NULL, TRUE);
+      lang_size_sections (NULL, TRUE);
     }
 
   /* See if anything special should be done now we know how big
@@ -5503,7 +5411,7 @@ lang_process (void)
   /* Do all the assignments, now that we know the final resting places
      of all the symbols.  */
 
-  lang_do_assignments (statement_list.head, abs_output_section, NULL, 0);
+  lang_do_assignments ();
 
   /* Make sure that the section addresses make sense.  */
   if (! link_info.relocatable
@@ -5891,8 +5799,7 @@ lang_new_phdr (const char *name,
   n = stat_alloc (sizeof (struct lang_phdr));
   n->next = NULL;
   n->name = name;
-  n->type = exp_get_value_int (type, 0, "program header type",
-                              lang_final_phase_enum);
+  n->type = exp_get_value_int (type, 0, "program header type");
   n->filehdr = filehdr;
   n->phdrs = phdrs;
   n->at = at;
@@ -5968,14 +5875,12 @@ lang_record_phdrs (void)
       if (l->flags == NULL)
        flags = 0;
       else
-       flags = exp_get_vma (l->flags, 0, "phdr flags",
-                            lang_final_phase_enum);
+       flags = exp_get_vma (l->flags, 0, "phdr flags");
 
       if (l->at == NULL)
        at = 0;
       else
-       at = exp_get_vma (l->at, 0, "phdr load address",
-                         lang_final_phase_enum);
+       at = exp_get_vma (l->at, 0, "phdr load address");
 
       if (! bfd_record_phdr (output_bfd, l->type,
                             l->flags != NULL, flags, l->at != NULL,
index 7b88647865512ac7e835b4068d1fd817f248cc1d..a23a04dbb07f7f83c921c6e3796928b2f6d84da6 100644 (file)
@@ -509,8 +509,7 @@ extern void lang_for_each_file
 extern void lang_reset_memory_regions
   (void);
 extern void lang_do_assignments
-  (lang_statement_union_type *, lang_output_section_statement_type *,
-   fill_type *, bfd_vma);
+  (void);
 
 #define LANG_FOR_EACH_INPUT_STATEMENT(statement)                       \
   lang_input_statement_type *statement;                                        \
@@ -556,10 +555,10 @@ extern void strip_excluded_output_sections
   (void);
 extern void dprint_statement
   (lang_statement_union_type *, int);
-extern bfd_vma lang_size_sections
-  (lang_statement_union_type *, lang_output_section_statement_type *,
-   lang_statement_union_type **, fill_type *, bfd_vma, bfd_boolean *,
-   bfd_boolean);
+extern void lang_size_sections
+  (bfd_boolean *, bfd_boolean);
+extern void one_lang_size_sections_pass
+  (bfd_boolean *, bfd_boolean);
 extern void lang_enter_group
   (void);
 extern void lang_leave_group
index d08f1abbdf32da4f70b31d3e44eed6d66fdf46a7..e89c8b911acd3302c27ccffb6a76e4d18b7147c7 100644 (file)
@@ -2636,14 +2636,13 @@ pe_dll_fill_sections (bfd *abfd, struct bfd_link_info *info)
       bfd_set_section_size (filler_bfd, reloc_s, reloc_sz);
 
       /* Resize the sections.  */
-      lang_size_sections (stat_ptr->head, abs_output_section,
-                         &stat_ptr->head, 0, 0, NULL, TRUE);
+      lang_size_sections (NULL, TRUE);
 
       /* Redo special stuff.  */
       ldemul_after_allocation ();
 
       /* Do the assignments again.  */
-      lang_do_assignments (stat_ptr->head, abs_output_section, NULL, 0);
+      lang_do_assignments ();
     }
 
   fill_edata (abfd, info);
@@ -2667,14 +2666,13 @@ pe_exe_fill_sections (bfd *abfd, struct bfd_link_info *info)
       bfd_set_section_size (filler_bfd, reloc_s, reloc_sz);
 
       /* Resize the sections.  */
-      lang_size_sections (stat_ptr->head, abs_output_section,
-                         &stat_ptr->head, 0, 0, NULL, TRUE);
+      lang_size_sections (NULL, TRUE);
 
       /* Redo special stuff.  */
       ldemul_after_allocation ();
 
       /* Do the assignments again.  */
-      lang_do_assignments (stat_ptr->head, abs_output_section, NULL, 0);
+      lang_do_assignments ();
     }
   reloc_s->contents = reloc_d;
 }