public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* PATCH: PR 992: regression: ld selective1 and selective2 fails, cris-elf
@ 2005-06-04  6:35 H. J. Lu
  2005-06-04 13:45 ` H. J. Lu
  0 siblings, 1 reply; 8+ messages in thread
From: H. J. Lu @ 2005-06-04  6:35 UTC (permalink / raw)
  To: binutils

The updated patch of

http://sourceware.org/ml/binutils/2005-06/msg00030.html

should also fix PR 992.


H.J.
---
2005-06-03  H.J. Lu  <hongjiu.lu@intel.com>

	PR 992
	* ldexp.c (exp_mark_used_section): Set SEC_KEEP on current
	section for etree_assign, etree_provide and etree_provided.
	Call fold_binary on etree_binary.

	* ldlang.c (lang_mark_used_section_1): Handle load base.

--- ld/ldexp.c.base	2005-06-02 16:02:26.000000000 -0700
+++ ld/ldexp.c	2005-06-03 23:16:33.000000000 -0700
@@ -1217,6 +1217,8 @@ align_n (bfd_vma value, bfd_vma align)
 void
 exp_mark_used_section (etree_type *tree, asection *current_section)
 {
+  bfd_vma dot = 0;
+
   switch (tree->type.node_class)
     {
     case etree_value:
@@ -1232,6 +1234,8 @@ exp_mark_used_section (etree_type *tree,
       break;
 
     case etree_binary:
+      fold_binary (tree, current_section, lang_allocating_phase_enum,
+		   dot, &dot, TRUE);
       break;
 
     case etree_trinary:
@@ -1243,12 +1247,12 @@ exp_mark_used_section (etree_type *tree,
       if (tree->assign.dst[0] != '.' || tree->assign.dst[1] != 0)
 	{
 	  etree_value_type result;
-	  bfd_vma dot = 0;
 
 	  result = exp_fold_tree_1 (tree->assign.src,
 				    current_section,
 				    lang_allocating_phase_enum,
 				    dot, &dot, TRUE);
+	  current_section->flags |= SEC_KEEP;
 	  if (result.valid_p)
 	    {
 	      bfd_boolean create;
--- ld/ldlang.c.base	2005-06-03 22:28:20.000000000 -0700
+++ ld/ldlang.c	2005-06-03 22:54:05.000000000 -0700
@@ -3065,7 +3065,12 @@ lang_mark_used_section_1
 
 	    os = &(s->output_section_statement);
 	    if (os->bfd_section != NULL)
-	      lang_mark_used_section_1 (os->children.head, os);
+	      {
+		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:

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: PATCH: PR 992: regression: ld selective1 and selective2 fails, cris-elf
  2005-06-04  6:35 PATCH: PR 992: regression: ld selective1 and selective2 fails, cris-elf H. J. Lu
@ 2005-06-04 13:45 ` H. J. Lu
  2005-06-04 15:08   ` Alan Modra
  2005-06-04 19:58   ` H. J. Lu
  0 siblings, 2 replies; 8+ messages in thread
From: H. J. Lu @ 2005-06-04 13:45 UTC (permalink / raw)
  To: binutils

On Fri, Jun 03, 2005 at 11:35:51PM -0700, H. J. Lu wrote:
> The updated patch of
> 
> http://sourceware.org/ml/binutils/2005-06/msg00030.html
> 
> should also fix PR 992.
> 
> 

We need to check if the current section isn't abs section before
settig SEC_KEEP.


H.J.
---
2005-06-04  H.J. Lu  <hongjiu.lu@intel.com>

	PR 992
	* ldexp.c (exp_mark_used_section): Set SEC_KEEP on current
	section for etree_assign, etree_provide and etree_provided.
	Call fold_binary on etree_binary.

	* ldlang.c (lang_mark_used_section_1): Handle load base.

--- ld/ldexp.c.base	2005-06-04 06:35:03.000000000 -0700
+++ ld/ldexp.c	2005-06-04 06:40:59.000000000 -0700
@@ -1237,6 +1237,8 @@ align_n (bfd_vma value, bfd_vma align)
 void
 exp_mark_used_section (etree_type *tree, asection *current_section)
 {
+  bfd_vma dot = 0;
+
   switch (tree->type.node_class)
     {
     case etree_value:
@@ -1252,6 +1254,8 @@ exp_mark_used_section (etree_type *tree,
       break;
 
     case etree_binary:
+      fold_binary (tree, current_section, lang_allocating_phase_enum,
+		   dot, &dot, TRUE);
       break;
 
     case etree_trinary:
@@ -1263,12 +1267,13 @@ exp_mark_used_section (etree_type *tree,
       if (tree->assign.dst[0] != '.' || tree->assign.dst[1] != 0)
 	{
 	  etree_value_type result;
-	  bfd_vma dot = 0;
 
 	  result = exp_fold_tree_1 (tree->assign.src,
 				    current_section,
 				    lang_allocating_phase_enum,
 				    dot, &dot, TRUE);
+	  if (current_section != bfd_abs_section_ptr)
+	    current_section->flags |= SEC_KEEP;
 	  if (result.valid_p)
 	    {
 	      bfd_boolean create;
--- ld/ldlang.c.base	2005-06-04 06:35:03.000000000 -0700
+++ ld/ldlang.c	2005-06-04 06:36:31.000000000 -0700
@@ -3065,7 +3065,12 @@ lang_mark_used_section_1
 
 	    os = &(s->output_section_statement);
 	    if (os->bfd_section != NULL)
-	      lang_mark_used_section_1 (os->children.head, os);
+	      {
+		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:

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: PATCH: PR 992: regression: ld selective1 and selective2 fails, cris-elf
  2005-06-04 13:45 ` H. J. Lu
@ 2005-06-04 15:08   ` Alan Modra
  2005-06-04 19:58   ` H. J. Lu
  1 sibling, 0 replies; 8+ messages in thread
From: Alan Modra @ 2005-06-04 15:08 UTC (permalink / raw)
  To: H. J. Lu; +Cc: binutils

On Sat, Jun 04, 2005 at 06:45:30AM -0700, H. J. Lu wrote:
> 	PR 992
> 	* ldexp.c (exp_mark_used_section): Set SEC_KEEP on current
> 	section for etree_assign, etree_provide and etree_provided.
> 	Call fold_binary on etree_binary.
> 
> 	* ldlang.c (lang_mark_used_section_1): Handle load base.

OK.

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: PATCH: PR 992: regression: ld selective1 and selective2 fails, cris-elf
  2005-06-04 13:45 ` H. J. Lu
  2005-06-04 15:08   ` Alan Modra
@ 2005-06-04 19:58   ` H. J. Lu
  2005-06-05  1:40     ` Hans-Peter Nilsson
                       ` (2 more replies)
  1 sibling, 3 replies; 8+ messages in thread
From: H. J. Lu @ 2005-06-04 19:58 UTC (permalink / raw)
  To: binutils

On Sat, Jun 04, 2005 at 06:45:30AM -0700, H. J. Lu wrote:
> On Fri, Jun 03, 2005 at 11:35:51PM -0700, H. J. Lu wrote:
> > The updated patch of
> > 
> > http://sourceware.org/ml/binutils/2005-06/msg00030.html
> > 
> > should also fix PR 992.
> > 
> > 
> 
> We need to check if the current section isn't abs section before
> settig SEC_KEEP.
> 
> 

We should set SEC_KEEP on current section only if the symbol will be
defined.


H.J.
----
ld/

2005-06-04  H.J. Lu  <hongjiu.lu@intel.com>

	* ldexp.c (exp_mark_used_section): Set SEC_KEEP on current
	section only if the symbol will be defined.

ld/testsuite/

2005-06-04  H.J. Lu  <hongjiu.lu@intel.com>

	* ld-cris/hiddef1.d: Undo the last change.
	* ld-cris/libdso-10.d: Likewise.
	* ld-cris/libdso-2.d: Likewise.

--- ld/ldexp.c.base	2005-06-04 10:53:29.000000000 -0700
+++ ld/ldexp.c	2005-06-04 12:48:58.000000000 -0700
@@ -1247,24 +1247,33 @@ exp_mark_used_section (etree_type *tree,
       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);
-	  if (current_section != bfd_abs_section_ptr)
+
+	  /* 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)
 	    {
-	      bfd_boolean create;
-	      struct bfd_link_hash_entry *h;
 
-	      if (tree->type.node_class == etree_assign)
-		create = TRUE;
-	      else
-		create = FALSE;
-	      h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst,
-					create, FALSE, TRUE);
+	      if (create)
+		h = bfd_link_hash_lookup (link_info.hash,
+					  tree->assign.dst, create,
+					  FALSE, TRUE);
 	      if (h == NULL)
 		{
 		  if (create)
--- ld/testsuite/ld-cris/hiddef1.d.base	2005-06-04 12:52:23.000000000 -0700
+++ ld/testsuite/ld-cris/hiddef1.d	2005-06-04 12:48:14.000000000 -0700
@@ -14,7 +14,7 @@
 # and sections change, make sure that there's no .plt and that
 # dsofn is hidden (not exported as a dynamic symbol).
 
-There are 12 section headers, starting at offset 0x[0-9a-f]+:
+There are 11 section headers, starting at offset 0x[0-9a-f]+:
 #...
   \[[ 0-9]+\] \.got              PROGBITS        [0-9a-f]+ [0-9a-f]+ 0+10 04  WA  0   0  4
 #...
@@ -24,5 +24,5 @@ Relocation section '\.rela\.dyn' at offs
 #...
 Symbol table '\.dynsym' contains 9 entries:
 #...
-Symbol table '\.symtab' contains 20 entries:
+Symbol table '\.symtab' contains 19 entries:
 #pass
--- ld/testsuite/ld-cris/libdso-10.d.base	2005-06-04 12:52:23.000000000 -0700
+++ ld/testsuite/ld-cris/libdso-10.d	2005-06-04 12:48:14.000000000 -0700
@@ -35,7 +35,5 @@ Idx Name          Size      VMA       LM
                   CONTENTS, ALLOC, LOAD, DATA
   5 \.got          0+c  0+21e0  0+21e0  0+1e0  2\*\*2
                   CONTENTS, ALLOC, LOAD, DATA
-  6 \.data         0+  0+21ec  0+21ec  0+1ec  2\*\*0
-                  CONTENTS, ALLOC, LOAD, DATA
-  7 \.bss          0+14  0+21ec  0+21ec  0+1ec  2\*\*0
+  6 \.bss          0+14  0+21ec  0+21ec  0+1ec  2\*\*0
                   ALLOC
--- ld/testsuite/ld-cris/libdso-2.d.base	2005-06-04 12:52:23.000000000 -0700
+++ ld/testsuite/ld-cris/libdso-2.d	2005-06-04 12:48:14.000000000 -0700
@@ -10,7 +10,7 @@
 # entries.  This formerly SEGV:ed because .rela.got was created
 # too late to have it mapped to an output section.
 
-There are 15 section headers.*
+There are 14 section headers.*
 #...
   \[ 1\] \.hash             HASH     .*
   \[ 2\] \.dynsym           DYNSYM   .*
@@ -21,11 +21,10 @@ There are 15 section headers.*
   \[ 7\] \.text             PROGBITS .*
   \[ 8\] \.dynamic          DYNAMIC  .*
   \[ 9\] \.got              PROGBITS .*
-  \[10\] \.data             PROGBITS .*
-  \[11\] \.bss              NOBITS   .*
-  \[12\] \.shstrtab         STRTAB   .*
-  \[13\] \.symtab           SYMTAB   .*
-  \[14\] \.strtab           STRTAB   .*
+  \[10\] \.bss              NOBITS   .*
+  \[11\] \.shstrtab         STRTAB   .*
+  \[12\] \.symtab           SYMTAB   .*
+  \[13\] \.strtab           STRTAB   .*
 #...
 Relocation section '\.rela\.dyn' at offset 0x[0-9a-f]+ contains 1 entries:
 #...
@@ -35,12 +34,12 @@ Symbol table '\.dynsym' contains 6 entri
    Num:    Value  Size Type    Bind   Vis      Ndx Name
      0: 0+     0 NOTYPE  LOCAL  DEFAULT  UND 
      1: [0-9a-f]+     0 SECTION LOCAL  DEFAULT    7 
-     2: [0-9a-f]+     0 SECTION LOCAL  DEFAULT   10 
-     3: [0-9a-f]+     0 SECTION LOCAL  DEFAULT   11 
+     2: [0-9a-f]+     0 NOTYPE  LOCAL  DEFAULT  UND 
+     3: [0-9a-f]+     0 SECTION LOCAL  DEFAULT   10 
      4: 0+     0 OBJECT  GLOBAL DEFAULT  ABS TST1
      5: 0+188     0 FUNC    GLOBAL DEFAULT    7 export_1@@TST1
 
-Symbol table '\.symtab' contains 23 entries:
+Symbol table '\.symtab' contains 22 entries:
    Num:    Value  Size Type    Bind   Vis      Ndx Name
      0: 0+     0 NOTYPE  LOCAL  DEFAULT  UND 
      1: [0-9a-f]+     0 SECTION LOCAL  DEFAULT    1 
@@ -56,12 +55,11 @@ Symbol table '\.symtab' contains 23 entr
     11: [0-9a-f]+     0 SECTION LOCAL  DEFAULT   11 
     12: [0-9a-f]+     0 SECTION LOCAL  DEFAULT   12 
     13: [0-9a-f]+     0 SECTION LOCAL  DEFAULT   13 
-    14: [0-9a-f]+     0 SECTION LOCAL  DEFAULT   14 
-    15: 0+2198     0 OBJECT  LOCAL  DEFAULT  ABS _DYNAMIC
-    16: 0+2230     0 NOTYPE  LOCAL  DEFAULT  ABS __bss_start
-    17: 0+2230     0 NOTYPE  LOCAL  DEFAULT  ABS _edata
-    18: 0+2220     0 OBJECT  LOCAL  HIDDEN  ABS _GLOBAL_OFFSET_TABLE_
-    19: 0+2240     0 NOTYPE  LOCAL  DEFAULT  ABS _end
-    20: 0+184     0 FUNC    LOCAL  DEFAULT    7 dsofn
-    21: 0+     0 OBJECT  GLOBAL DEFAULT  ABS TST1
-    22: 0+188     0 FUNC    GLOBAL DEFAULT    7 export_1
+    14: 0+2198     0 OBJECT  LOCAL  DEFAULT  ABS _DYNAMIC
+    15: 0+2230     0 NOTYPE  LOCAL  DEFAULT  ABS __bss_start
+    16: 0+2230     0 NOTYPE  LOCAL  DEFAULT  ABS _edata
+    17: 0+2220     0 OBJECT  LOCAL  HIDDEN  ABS _GLOBAL_OFFSET_TABLE_
+    18: 0+2240     0 NOTYPE  LOCAL  DEFAULT  ABS _end
+    19: 0+184     0 FUNC    LOCAL  DEFAULT    7 dsofn
+    20: 0+     0 OBJECT  GLOBAL DEFAULT  ABS TST1
+    21: 0+188     0 FUNC    GLOBAL DEFAULT    7 export_1

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: PATCH: PR 992: regression: ld selective1 and selective2 fails, cris-elf
  2005-06-04 19:58   ` H. J. Lu
@ 2005-06-05  1:40     ` Hans-Peter Nilsson
  2005-06-05  7:39     ` Nick Clifton
  2005-06-09  1:58     ` Alan Modra
  2 siblings, 0 replies; 8+ messages in thread
From: Hans-Peter Nilsson @ 2005-06-05  1:40 UTC (permalink / raw)
  To: H. J. Lu; +Cc: binutils

On Sat, 4 Jun 2005, H. J. Lu wrote:
> We should set SEC_KEEP on current section only if the symbol will be
> defined.
> [patches elided]

Just to say: thanks!

brgds, H-P

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: PATCH: PR 992: regression: ld selective1 and selective2 fails, cris-elf
  2005-06-04 19:58   ` H. J. Lu
  2005-06-05  1:40     ` Hans-Peter Nilsson
@ 2005-06-05  7:39     ` Nick Clifton
  2005-06-09  1:58     ` Alan Modra
  2 siblings, 0 replies; 8+ messages in thread
From: Nick Clifton @ 2005-06-05  7:39 UTC (permalink / raw)
  To: H. J. Lu; +Cc: binutils

Hi H. J.

> 2005-06-04  H.J. Lu  <hongjiu.lu@intel.com>
> 
> 	* ldexp.c (exp_mark_used_section): Set SEC_KEEP on current
> 	section only if the symbol will be defined.
> 
> ld/testsuite/
> 
> 2005-06-04  H.J. Lu  <hongjiu.lu@intel.com>
> 
> 	* ld-cris/hiddef1.d: Undo the last change.
> 	* ld-cris/libdso-10.d: Likewise.
> 	* ld-cris/libdso-2.d: Likewise.

Approved - please apply.

Cheers
   Nick

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: PATCH: PR 992: regression: ld selective1 and selective2 fails, cris-elf
  2005-06-04 19:58   ` H. J. Lu
  2005-06-05  1:40     ` Hans-Peter Nilsson
  2005-06-05  7:39     ` Nick Clifton
@ 2005-06-09  1:58     ` Alan Modra
  2005-06-09  2:58       ` Alan Modra
  2 siblings, 1 reply; 8+ messages in thread
From: Alan Modra @ 2005-06-09  1:58 UTC (permalink / raw)
  To: binutils

On Sat, Jun 04, 2005 at 12:58:30PM -0700, H. J. Lu wrote:
> We should set SEC_KEEP on current section only if the symbol will be
> defined.

I'm not really happy with the way HJ's lang_mark_used_section has panned
out.  It seems like we'll be forever chasing down corner cases.  When I
made the suggestion to write a special version of lang_do_assignments
that just marked sections, I was thinking that this might avoid lots of
special cases in lang_do_assignments and/or changes to expression
folding.  Of course, it turned out that a new ldexp.c function was
needed for expression folding.

Worse, I'm sure that many possible linker script constructs are not
handled currently by lang_mark_used_section, and others are handled
wrongly.  An obvious example of the latter is that SIZEOF marks the
referenced section as needed.  A little more complicated example is that
LOADADDR need not access the referenced section's lma if load_base for
the section is some expression that depends on other sections.  Even
if it does access the lma, then all that requires is that the lma be
set.  So I decided to rip out this code and rewrite, in the process
getting rid of all the needless passing of parameters and structure
copies in ldexp.c.  The majority of this patch is a result of
restructuring ldexp.c.  I suppose I should have separated that out into
a separate patch, and also the fixes for bugs I discovered along the
way..

As far as marking goes, there really is only one reason to keep an empty
output section, and that is if symbols are defined there.  Access to a
section vma, lma or size don't require that a section actually be
output, merely that those values be set.  A lang_size_sections_1 tweak
does this, and global symbols are marked in elf_mark_used_section.  Of
course, elf_mark_used_section only works for ELF and we need this for
other formats.  So move elf_mark_used_section into the generic linker
code.

That leaves no place in ldexp.c that needs to mark a section with
SEC_KEEP, and we just need to make sure that link script symbols are
put into the bfd hash table somehow.  I chose to use a
lang_size_sections run to do that rather than lang_do_assignments,
because sizing sections allowed me to easily handle data statements and
assignments to dot (*).  Also, we have the precedent of running
lang_size_sections multiple times.  Now, lang_size_sections is
unnecessarily heavyweight due to running through the sections multiple
times to support DATA_SEGMENT_ALIGN and DATA_SEGMENT_RELRO_END, so to
mitigate this I defined one_lang_size_sections_pass.

*) I believe any assignment to "dot" that allocates space in a section
should result in the section being kept.  ld-scripts/empty-aligned thus
ought to keep .text2.

bfd/
	* elflink.c (elf_mark_used_section): Delete.
	(bfd_elf_gc_sections): Call bfd_generic_gc_sections.
	* reloc.c (bfd_mark_used_section): New function.
	(bfd_generic_gc_sections): Call bfd_mark_used_section.

ld/
	* 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.

ld/testsuite/
	* ld-scripts/empty-aligned.d: Adjust.

Index: bfd/elflink.c
===================================================================
RCS file: /cvs/src/src/bfd/elflink.c,v
retrieving revision 1.166
diff -u -p -r1.166 elflink.c
--- bfd/elflink.c	3 Jun 2005 09:52:49 -0000	1.166
+++ bfd/elflink.c	8 Jun 2005 13:44:04 -0000
@@ -9067,27 +9067,6 @@ elf_gc_mark_dynamic_ref_symbol (struct e
   return TRUE;
 }
 
-/* Mark sections containing global symbols.  This is called through
-   elf_link_hash_traverse.  */
-
-static bfd_boolean
-elf_mark_used_section (struct elf_link_hash_entry *h,
-		       void *data ATTRIBUTE_UNUSED)
-{
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
-  if (h->root.type == bfd_link_hash_defined
-      || h->root.type == bfd_link_hash_defweak)
-    {
-      asection *s = h->root.u.def.section;
-      if (s != NULL && s->output_section != NULL)
-	s->output_section->flags |= SEC_KEEP;
-    }
-
-  return TRUE;
-}
-
 /* Do mark and sweep of unused sections.  */
 
 bfd_boolean
@@ -9100,15 +9079,7 @@ bfd_elf_gc_sections (bfd *abfd, struct b
      struct elf_link_hash_entry *h, Elf_Internal_Sym *);
 
   if (!info->gc_sections)
-    {
-      /* If we are called when info->gc_sections is 0, we will mark
-	 all sections containing global symbols for non-relocatable
-	 link.  */
-      if (!info->relocatable)
-	elf_link_hash_traverse (elf_hash_table (info),
-				elf_mark_used_section, NULL);
-      return TRUE;
-    }
+    return bfd_generic_gc_sections (abfd, info);
 
   if (!get_elf_backend_data (abfd)->can_gc_sections
       || info->relocatable
Index: bfd/reloc.c
===================================================================
RCS file: /cvs/src/src/bfd/reloc.c,v
retrieving revision 1.128
diff -u -p -r1.128 reloc.c
--- bfd/reloc.c	18 May 2005 05:40:06 -0000	1.128
+++ bfd/reloc.c	8 Jun 2005 13:44:08 -0000
@@ -4516,6 +4516,27 @@ bfd_generic_relax_section (bfd *abfd ATT
   return TRUE;
 }
 
+/* Mark sections containing global symbols.  This is called through
+   bfd_link_hash_traverse.  */
+
+static bfd_boolean
+bfd_mark_used_section (struct bfd_link_hash_entry *h,
+		       void *data ATTRIBUTE_UNUSED)
+{
+  if (h->type == bfd_link_hash_warning)
+    h = h->u.i.link;
+
+  if (h->type == bfd_link_hash_defined
+      || h->type == bfd_link_hash_defweak)
+    {
+      asection *s = h->u.def.section;
+      if (s != NULL && s->output_section != NULL)
+	s->output_section->flags |= SEC_KEEP;
+    }
+
+  return TRUE;
+}
+
 /*
 INTERNAL_FUNCTION
 	bfd_generic_gc_sections
@@ -4526,13 +4547,18 @@ SYNOPSIS
 
 DESCRIPTION
 	Provides default handling for relaxing for back ends which
-	don't do section gc -- i.e., does nothing.
+	don't do section gc -- i.e., does nothing besides the special
+	case for marking sections having global symbols.
 */
 
 bfd_boolean
 bfd_generic_gc_sections (bfd *abfd ATTRIBUTE_UNUSED,
-			 struct bfd_link_info *link_info ATTRIBUTE_UNUSED)
+			 struct bfd_link_info *info)
 {
+  /* If called when info->gc_sections is 0, then mark all sections
+     containing global symbols with SEC_KEEP.  */
+  if (!info->gc_sections && !info->relocatable)
+    bfd_link_hash_traverse (info->hash, bfd_mark_used_section, NULL);
   return TRUE;
 }
 
Index: ld/ld.h
===================================================================
RCS file: /cvs/src/src/ld/ld.h,v
retrieving revision 1.28
diff -u -p -r1.28 ld.h
--- ld/ld.h	12 May 2005 07:32:02 -0000	1.28
+++ ld/ld.h	8 Jun 2005 23:58:35 -0000
@@ -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: ld/ldexp.h
===================================================================
RCS file: /cvs/src/src/ld/ldexp.h,v
retrieving revision 1.17
diff -u -p -r1.17 ldexp.h
--- ld/ldexp.h	2 Jun 2005 03:08:41 -0000	1.17
+++ ld/ldexp.h	8 Jun 2005 23:58:35 -0000
@@ -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: ld/ldexp.c
===================================================================
RCS file: /cvs/src/src/ld/ldexp.c,v
retrieving revision 1.51
diff -u -p -r1.51 ldexp.c
--- ld/ldexp.c	5 Jun 2005 15:28:35 -0000	1.51
+++ ld/ldexp.c	8 Jun 2005 23:58:35 -0000
@@ -41,19 +41,13 @@
 #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, i
 }
 
 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 va
   return new;
 }
 
-static etree_value_type
-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;
+static void
+new_rel (bfd_vma value, char *str, asection *section)
+{
+  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)
-{
-  etree_value_type result;
-
-  result = exp_fold_tree_1 (tree->unary.child,
-			    current_section,
-			    allocation_done, dot, dotp, mark_used);
-  if (result.valid_p)
+static void
+fold_unary (etree_type *tree)
+{
+  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)
-{
-  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;
-}
-
-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_trinary (etree_type *tree)
 {
-  etree_value_type 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);
+}
 
-  memset (&result, 0, sizeof (result));
+static void
+fold_name (etree_type *tree)
+{
+  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;
+	      expld.assigning_to_dot = TRUE;
+	      exp_fold_tree_1 (tree->assign.src);
+	      expld.assigning_to_dot = FALSE;
 
-	      if (! result.valid_p)
-		einfo (_("%F%S invalid assignment to location counter\n"));
+	      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)
-{
-  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);
+exp_get_abs_int (etree_type *tree, int def, char *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: ld/ldgram.y
===================================================================
RCS file: /cvs/src/src/ld/ldgram.y,v
retrieving revision 1.42
diff -u -p -r1.42 ldgram.y
--- ld/ldgram.y	12 May 2005 07:32:02 -0000	1.42
+++ ld/ldgram.y	8 Jun 2005 23:58:35 -0000
@@ -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: ld/ldlang.c
===================================================================
RCS file: /cvs/src/src/ld/ldlang.c,v
retrieving revision 1.188
diff -u -p -r1.188 ldlang.c
--- ld/ldlang.c	4 Jun 2005 14:40:21 -0000	1.188
+++ ld/ldlang.c	8 Jun 2005 23:58:37 -0000
@@ -101,6 +101,9 @@ bfd_boolean delete_output_file_on_failur
 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)))
-	{
-	  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;
+	  && (output_section->flags & SEC_KEEP) == 0
+	  && output_section->rawsize == 0
+	  && !bfd_is_abs_section (output_section))
+	{
+	  /* 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_statem
   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_statem
       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_statem
 	    {
 	      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 **
 	    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.  The above test on output
-	 section is probably redundant, but it doesn't hurt to check.  */
+      /* 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.  */
     }
   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);
-
-			if (dot != olddot && config.warn_section_align)
+			bfd_vma savedot = newdot;
+			newdot = align_power (newdot,
+					      os->bfd_section->alignment_power);
+
+			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);
+}
+
+void
+lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions)
+{
+  expld.phase = lang_allocating_phase_enum;
+  expld.dataseg.phase = exp_dataseg_none;
 
-  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)
+  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)
-	{
-	  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.base & ~(expld.dataseg.pagesize - 1))
+	      != (expld.dataseg.end & ~(expld.dataseg.pagesize - 1)))
+	  && first + last <= expld.dataseg.pagesize)
+	{
+	  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;
-	  }
+	case lang_data_statement_enum:
+	  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 (con
   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: ld/ldlang.h
===================================================================
RCS file: /cvs/src/src/ld/ldlang.h,v
retrieving revision 1.50
diff -u -p -r1.50 ldlang.h
--- ld/ldlang.h	1 Jun 2005 04:04:18 -0000	1.50
+++ ld/ldlang.h	8 Jun 2005 23:58:37 -0000
@@ -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_sectio
   (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: ld/pe-dll.c
===================================================================
RCS file: /cvs/src/src/ld/pe-dll.c,v
retrieving revision 1.78
diff -u -p -r1.78 pe-dll.c
--- ld/pe-dll.c	12 May 2005 07:32:03 -0000	1.78
+++ ld/pe-dll.c	8 Jun 2005 23:58:38 -0000
@@ -2636,14 +2636,13 @@ pe_dll_fill_sections (bfd *abfd, struct 
       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_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;
 }
Index: ld/emultempl/elf32.em
===================================================================
RCS file: /cvs/src/src/ld/emultempl/elf32.em,v
retrieving revision 1.147
diff -u -p -r1.147 elf32.em
--- ld/emultempl/elf32.em	12 May 2005 07:32:03 -0000	1.147
+++ ld/emultempl/elf32.em	8 Jun 2005 23:58:40 -0000
@@ -1497,15 +1497,13 @@ gld${EMULATION_NAME}_layout_sections_aga
   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: ld/emultempl/ppc64elf.em
===================================================================
RCS file: /cvs/src/src/ld/emultempl/ppc64elf.em,v
retrieving revision 1.44
diff -u -p -r1.44 ppc64elf.em
--- ld/emultempl/ppc64elf.em	6 Jun 2005 12:59:59 -0000	1.44
+++ ld/emultempl/ppc64elf.em	8 Jun 2005 23:58:40 -0000
@@ -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 ();
 	}
 
Index: ld/testsuite/ld-scripts/empty-aligned.d
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-scripts/empty-aligned.d,v
retrieving revision 1.1
diff -u -p -r1.1 empty-aligned.d
--- ld/testsuite/ld-scripts/empty-aligned.d	17 May 2005 16:42:53 -0000	1.1
+++ ld/testsuite/ld-scripts/empty-aligned.d	8 Jun 2005 23:58:41 -0000
@@ -6,7 +6,9 @@
 Program Headers:
  +Type +Offset +VirtAddr +PhysAddr +FileSiz +MemSiz +Flg +Align
  +LOAD +0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ [RWE ]+ +0x[0-9a-f]+
+ +LOAD +0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ [RWE ]+ +0x[0-9a-f]+
 
  Section to Segment mapping:
  +Segment Sections\.\.\.
- +00.*\.text.*\.data.*
+ +00.*\.text.*\.text2.*
+ +01.*.data.*

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: PATCH: PR 992: regression: ld selective1 and selective2 fails, cris-elf
  2005-06-09  1:58     ` Alan Modra
@ 2005-06-09  2:58       ` Alan Modra
  0 siblings, 0 replies; 8+ messages in thread
From: Alan Modra @ 2005-06-09  2:58 UTC (permalink / raw)
  To: binutils

On Thu, Jun 09, 2005 at 11:28:12AM +0930, Alan Modra wrote:
> 	(fold_unary <ALIGN_K>): Ensure alignment is absolute.

Oops.  This was a last-minute change that didn't have the benefit of
being checked by multiple testsuite runs..  Reverting.

	* ldexp.c (fold_unary <ALIGN_K>): Revert last change.

Index: ld/ldexp.c
===================================================================
RCS file: /cvs/src/src/ld/ldexp.c,v
retrieving revision 1.52
diff -u -p -r1.52 ldexp.c
--- ld/ldexp.c	9 Jun 2005 02:05:46 -0000	1.52
+++ ld/ldexp.c	9 Jun 2005 02:57:25 -0000
@@ -207,10 +207,7 @@ fold_unary (etree_type *tree)
 	{
 	case ALIGN_K:
 	  if (expld.phase != lang_first_phase_enum)
-	    {
-	      make_abs ();
-	      new_rel_from_abs (align_n (expld.dot, expld.result.value));
-	    }
+	    new_rel_from_abs (align_n (expld.dot, expld.result.value));
 	  else
 	    expld.result.valid_p = FALSE;
 	  break;


-- 
Alan Modra
IBM OzLabs - Linux Technology Centre

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2005-06-09  2:58 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-06-04  6:35 PATCH: PR 992: regression: ld selective1 and selective2 fails, cris-elf H. J. Lu
2005-06-04 13:45 ` H. J. Lu
2005-06-04 15:08   ` Alan Modra
2005-06-04 19:58   ` H. J. Lu
2005-06-05  1:40     ` Hans-Peter Nilsson
2005-06-05  7:39     ` Nick Clifton
2005-06-09  1:58     ` Alan Modra
2005-06-09  2:58       ` Alan Modra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).