+ asection *output_section = tree->rel.section->output_section;
+ new_rel (tree->rel.value + tree->rel.section->output_offset,
+ output_section);
+ }
+ else
+ memset (&expld.result, 0, sizeof (expld.result));
+ break;
+
+ case etree_assert:
+ exp_fold_tree_1 (tree->assert_s.child);
+ if (expld.phase == lang_final_phase_enum && !expld.result.value)
+ einfo ("%X%P: %s\n", tree->assert_s.message);
+ break;
+
+ case etree_unary:
+ fold_unary (tree);
+ break;
+
+ case etree_binary:
+ fold_binary (tree);
+ break;
+
+ case etree_trinary:
+ fold_trinary (tree);
+ break;
+
+ case etree_assign:
+ case etree_provide:
+ case etree_provided:
+ if (tree->assign.dst[0] == '.' && tree->assign.dst[1] == 0)
+ {
+ if (tree->type.node_class != etree_assign)
+ einfo (_("%F%P:%pS can not PROVIDE assignment to"
+ " location counter\n"), tree);
+ if (expld.phase != lang_first_phase_enum)
+ {
+ /* Notify the folder that this is an assignment to dot. */
+ expld.assigning_to_dot = TRUE;
+ exp_fold_tree_1 (tree->assign.src);
+ expld.assigning_to_dot = FALSE;
+
+ /* If we are assigning to dot inside an output section
+ arrange to keep the section, except for certain
+ expressions that evaluate to zero. We ignore . = 0,
+ . = . + 0, and . = ALIGN (. != 0 ? expr : 1).
+ We can't ignore all expressions that evaluate to zero
+ because an otherwise empty section might have padding
+ added by an alignment expression that changes with
+ relaxation. Such a section might have zero size
+ before relaxation and so be stripped incorrectly. */
+ if (expld.phase == lang_mark_phase_enum
+ && expld.section != bfd_abs_section_ptr
+ && expld.section != bfd_und_section_ptr
+ && !(expld.result.valid_p
+ && expld.result.value == 0
+ && (is_value (tree->assign.src, 0)
+ || is_sym_value (tree->assign.src, 0)
+ || is_dot_plus_0 (tree->assign.src)
+ || is_align_conditional (tree->assign.src))))
+ expld.section->flags |= SEC_KEEP;
+
+ if (!expld.result.valid_p
+ || expld.section == bfd_und_section_ptr)
+ {
+ if (expld.phase != lang_mark_phase_enum)
+ einfo (_("%F%P:%pS invalid assignment to"
+ " location counter\n"), tree);
+ }
+ else if (expld.dotp == NULL)
+ einfo (_("%F%P:%pS assignment to location counter"
+ " invalid outside of SECTIONS\n"), tree);
+
+ /* After allocation, assignment to dot should not be
+ done inside an output section since allocation adds a
+ padding statement that effectively duplicates the
+ assignment. */
+ else if (expld.phase <= lang_allocating_phase_enum
+ || expld.section == bfd_abs_section_ptr)
+ {
+ bfd_vma nextdot;
+
+ nextdot = expld.result.value;
+ if (expld.result.section != NULL)
+ nextdot += expld.result.section->vma;
+ else
+ nextdot += expld.section->vma;
+ if (nextdot < expld.dot
+ && expld.section != bfd_abs_section_ptr)
+ einfo (_("%F%P:%pS cannot move location counter backwards"
+ " (from %V to %V)\n"),
+ tree, expld.dot, nextdot);
+ else