if (allocation_done == lang_allocating_phase_enum) {
if (allocation_done == lang_allocating_phase_enum || (allocation_done == lang_final_phase_enum && current_section == abs_output_section)) {
exp_fold_tree (tree, current_section, allocation_done, dot, dotp)     etree_type *tree;     lang_output_section_statement_type *current_section;     lang_phase_type  allocation_done;     bfd_vma dot;     bfd_vma *dotp;{  etree_value_type result;  if (tree == (etree_type *)NULL) {    result.valid = false;  }  else {    switch (tree->type.node_class)     {     case etree_value:      result = new_rel(tree->value.value, current_section);      break;    case etree_rel:      if (allocation_done != lang_final_phase_enum)	result.valid = false;      else	result = new_rel ((tree->rel.value			   + tree->rel.section->output_section->vma			   + tree->rel.section->output_offset),			  current_section);      break;     case etree_unary:      result = exp_fold_tree(tree->unary.child,			     current_section,			     allocation_done, dot, dotp);      if (result.valid == true)      {	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);	  }	  else {	    result.valid = false;	  }	  break;	 case ABSOLUTE:	  if (allocation_done != lang_first_phase_enum) 	  {	    if (current_section 		== (lang_output_section_statement_type*)NULL) 	    {	      /* Outside a section, so it's all ok */	    }	    else {	      /* Inside a section, subtract the base of the section,		 so when it's added again (in an assignment), everything comes out fine		 */	      result.section = abs_output_section;	      result.value -= current_section->bfd_section->vma;	      result.valid = true;	    }	  }	  else 	  {	    result.valid = false;	  }	  break;	 case '~':	  make_abs(&result);	  result.value = ~result.value;	  break;	 case '!':	  make_abs(&result);	  result.value = !result.value;	  break;	 case '-':	  make_abs(&result);	  result.value = -result.value;	  break;	 case NEXT:	  if (allocation_done ==lang_allocating_phase_enum) {	    make_abs(&result);	    result.value = ALIGN_N(dot, result.value);	  }	  else {	    /* Return next place aligned to value */	    result.valid = false;	  }	  break;	 default:	  FAIL();	}      }      break;     case etree_trinary:      result = exp_fold_tree(tree->trinary.cond,			     current_section,			     allocation_done, dot, dotp);      if (result.valid) {	result = exp_fold_tree(result.value ?			       tree->trinary.lhs:tree->trinary.rhs,			       current_section,			       allocation_done, dot, dotp);      }      break;     case etree_binary:      result = fold_binary(tree, current_section, allocation_done,			   dot, dotp);      break;     case etree_assign:     case etree_provide:      if (tree->assign.dst[0] == '.' && tree->assign.dst[1] == 0) {	/* Assignment to dot can only be done during allocation */	if (tree->type.node_class == etree_provide)	  einfo ("%F%S can not PROVIDE assignment to location counter\n");	if (allocation_done == lang_allocating_phase_enum) {	  result = exp_fold_tree(tree->assign.src,				 current_section,				 lang_allocating_phase_enum, dot, dotp);	  if (result.valid == false) {	    einfo("%F%S invalid assignment to location counter\n");	  }	  else {	    if (current_section ==		(lang_output_section_statement_type  *)NULL) {	      einfo("%F%S assignment to location counter invalid outside of SECTION\n");	    }	    else {	      bfd_vma nextdot =result.value +	       current_section->bfd_section->vma;	      if (nextdot < dot && current_section != abs_output_section) {		einfo("%F%S cannot move location counter backwards (from %V to %V)\n", dot, nextdot);	      }	      else {		*dotp = nextdot; 	      }	    }	  }	}      }      else	{	  result = exp_fold_tree (tree->assign.src,				  current_section, allocation_done,				  dot, dotp);	  if (result.valid)	    {	      struct bfd_link_hash_entry *h;	      h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst,					(tree->type.node_class == etree_assign					 ? true : false),					false, false);	      if (h == (struct bfd_link_hash_entry *) NULL)		{		  if (tree->type.node_class == etree_assign)		    einfo ("%P%F:%s: hash creation failed\n",			   tree->assign.dst);		}	      else if (tree->type.node_class == etree_provide		       && 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?  */		  h->type = bfd_link_hash_defined;		  h->u.def.value = result.value;		  h->u.def.section = result.section->bfd_section;		}	    }	}        break;     case etree_name:      result = fold_name(tree, current_section, allocation_done, dot);      break;     default:      einfo("%F%S need more of these %d\n",tree->type.node_class );    }  }  return result;}