Index: bfd/elf32-xtensa.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-xtensa.c,v
retrieving revision 1.89
diff -u -p -r1.89 elf32-xtensa.c
--- bfd/elf32-xtensa.c	27 Apr 2007 20:10:47 -0000	1.89
+++ bfd/elf32-xtensa.c	8 Jun 2007 23:59:15 -0000
@@ -5541,7 +5541,7 @@ extend_ebb_bounds_forward (ebb_t *ebb)
 
       new_entry = &ebb->ptbl[ebb->end_ptbl_idx + 1];
       if (((new_entry->flags & XTENSA_PROP_INSN) == 0)
-	  || ((new_entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM) != 0)
+	  || ((new_entry->flags & XTENSA_PROP_NO_TRANSFORM) != 0)
 	  || ((the_entry->flags & XTENSA_PROP_ALIGN) != 0))
 	break;
 
@@ -5614,7 +5614,7 @@ extend_ebb_bounds_backward (ebb_t *ebb)
 
       new_entry = &ebb->ptbl[ebb->start_ptbl_idx - 1];
       if ((new_entry->flags & XTENSA_PROP_INSN) == 0
-	  || ((new_entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM) != 0)
+	  || ((new_entry->flags & XTENSA_PROP_NO_TRANSFORM) != 0)
 	  || ((new_entry->flags & XTENSA_PROP_ALIGN) != 0))
 	return TRUE;
       if (new_entry->address + new_entry->size != the_entry->address)
@@ -5822,7 +5822,8 @@ static bfd_boolean compute_removed_liter
 static Elf_Internal_Rela *get_irel_at_offset
   (asection *, Elf_Internal_Rela *, bfd_vma);
 static bfd_boolean is_removable_literal 
-  (const source_reloc *, int, const source_reloc *, int);
+  (const source_reloc *, int, const source_reloc *, int, asection *,
+   property_table_entry *, int);
 static bfd_boolean remove_dead_literal
   (bfd *, asection *, struct bfd_link_info *, Elf_Internal_Rela *,
    Elf_Internal_Rela *, source_reloc *, property_table_entry *, int); 
@@ -6480,7 +6481,7 @@ compute_text_actions (bfd *abfd,
 	  the_entry++;
 	}
 
-      if (the_entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM)
+      if (the_entry->flags & XTENSA_PROP_NO_TRANSFORM)
 	  /* NO_REORDER is OK */
 	continue;
 
@@ -6673,14 +6674,14 @@ compute_ebb_proposed_actions (ebb_constr
 	    goto decode_error;
 
 	  if ((entry->flags & XTENSA_PROP_INSN_NO_DENSITY) == 0
-	      && (entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM) == 0
+	      && (entry->flags & XTENSA_PROP_NO_TRANSFORM) == 0
 	      && can_narrow_instruction (slotbuf, fmt, opcode) != 0)
 	    {
 	      /* Add an instruction narrow action.  */
 	      ebb_propose_action (ebb_table, EBB_NO_ALIGN, 0,
 				  ta_narrow_insn, offset, 0, FALSE);
 	    }
-	  else if ((entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM) == 0
+	  else if ((entry->flags & XTENSA_PROP_NO_TRANSFORM) == 0
 		   && can_widen_instruction (slotbuf, fmt, opcode) != 0
 		   && ! prev_instr_is_a_loop (ebb->contents,
 					      ebb->content_length, offset))
@@ -7430,7 +7431,8 @@ compute_removed_literals (bfd *abfd,
       /* Check if the relocation was from an L32R that is being removed
 	 because a CALLX was converted to a direct CALL, and check if
 	 there are no other relocations to the literal.  */
-      if (is_removable_literal (rel, i, src_relocs, relax_info->src_count))
+      if (is_removable_literal (rel, i, src_relocs, relax_info->src_count, 
+				sec, prop_table, ptblsize))
 	{
 	  if (!remove_dead_literal (abfd, sec, link_info, internal_relocs,
 				    irel, rel, prop_table, ptblsize))
@@ -7514,12 +7516,22 @@ bfd_boolean
 is_removable_literal (const source_reloc *rel,
 		      int i,
 		      const source_reloc *src_relocs,
-		      int src_count)
+		      int src_count,
+		      asection *sec,
+		      property_table_entry *prop_table,
+		      int ptblsize)
 {
   const source_reloc *curr_rel;
+  property_table_entry *entry;
+
   if (!rel->is_null)
     return FALSE;
   
+  entry = elf_xtensa_find_property_entry (prop_table, ptblsize, 
+					  sec->vma + rel->r_rel.target_offset);
+  if (entry && (entry->flags & XTENSA_PROP_NO_TRANSFORM))
+    return FALSE;
+
   for (++i; i < src_count; ++i)
     {
       curr_rel = &src_relocs[i];
@@ -7809,7 +7821,7 @@ coalesce_shared_literal (asection *sec,
 
   entry = elf_xtensa_find_property_entry
     (prop_table, ptblsize, sec->vma + rel->r_rel.target_offset);
-  if (entry && (entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM))
+  if (entry && (entry->flags & XTENSA_PROP_NO_TRANSFORM))
     return TRUE;
 
   /* Mark that the literal will be coalesced.  */
@@ -9735,12 +9747,12 @@ xtensa_get_property_predef_flags (asecti
 {
   if (xtensa_is_insntable_section (sec))
     return (XTENSA_PROP_INSN
-	    | XTENSA_PROP_INSN_NO_TRANSFORM
+	    | XTENSA_PROP_NO_TRANSFORM
 	    | XTENSA_PROP_INSN_NO_REORDER);
 
   if (xtensa_is_littable_section (sec))
     return (XTENSA_PROP_LITERAL
-	    | XTENSA_PROP_INSN_NO_TRANSFORM
+	    | XTENSA_PROP_NO_TRANSFORM
 	    | XTENSA_PROP_INSN_NO_REORDER);
 
   return 0;
Index: gas/config/tc-xtensa.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-xtensa.c,v
retrieving revision 1.81
diff -u -p -r1.81 tc-xtensa.c
--- gas/config/tc-xtensa.c	21 Apr 2007 13:04:14 -0000	1.81
+++ gas/config/tc-xtensa.c	8 Jun 2007 23:59:19 -0000
@@ -187,7 +187,9 @@ int generating_literals = 0;
 /* Instruction only properties about code.  */
 #define XTENSA_PROP_INSN_NO_DENSITY	0x00000040
 #define XTENSA_PROP_INSN_NO_REORDER	0x00000080
-#define XTENSA_PROP_INSN_NO_TRANSFORM	0x00000100
+/* Historically, NO_TRANSFORM was a property of instructions,
+   but it should apply to literals under certain circumstances.  */
+#define XTENSA_PROP_NO_TRANSFORM	0x00000100
 
 /*  Branch target alignment information.  This transmits information
     to the linker optimization about the priority of aligning a
@@ -263,6 +265,9 @@ struct frag_flags_struct
   unsigned is_data : 1;
   unsigned is_unreachable : 1;
 
+  /* is_specific_opcode implies no_transform.  */
+  unsigned is_no_transform : 1;
+
   struct
   {
     unsigned is_loop_target : 1;
@@ -271,8 +276,6 @@ struct frag_flags_struct
 
     unsigned is_no_density : 1;
     /* no_longcalls flag does not need to be placed in the object file.  */
-    /* is_specific_opcode implies no_transform.  */
-    unsigned is_no_transform : 1;
 
     unsigned is_no_reorder : 1;
 
@@ -4690,6 +4693,55 @@ relaxable_section (asection *sec)
 
 
 static void
+xtensa_mark_frags_for_org (void)
+{
+  segT *seclist;
+
+  /* Walk over each fragment of all of the current segments.  If we find
+     a .org frag in any of the segments, mark all frags prior to it as
+     "no transform", which will prevent linker optimizations from messing
+     up the .org distance.  This should be done after
+     xtensa_find_unmarked_state_frags, because we don't want to worry here
+     about that function trashing the data we save here.  */
+
+  for (seclist = &stdoutput->sections;
+       seclist && *seclist;
+       seclist = &(*seclist)->next)
+    {
+      segT sec = *seclist;
+      segment_info_type *seginfo;
+      fragS *fragP;
+      flagword flags;
+      flags = bfd_get_section_flags (stdoutput, sec);
+      if (flags & SEC_DEBUGGING)
+	continue;
+      if (!(flags & SEC_ALLOC))
+	continue;
+
+      seginfo = seg_info (sec);
+      if (seginfo && seginfo->frchainP)
+	{
+	  fragS *last_fragP = seginfo->frchainP->frch_root;
+	  for (fragP = seginfo->frchainP->frch_root; fragP;
+	       fragP = fragP->fr_next)
+	    {
+	      /* cvt_frag_to_fill has changed the fr_type of org frags to
+		 rs_fill, so use the value as cached in rs_subtype here.  */
+	      if (fragP->fr_subtype == RELAX_ORG)
+		{
+		  while (last_fragP != fragP->fr_next)
+		    {
+		      last_fragP->tc_frag_data.is_no_transform = TRUE;
+		      last_fragP = last_fragP->fr_next;
+		    }
+		}
+	    }
+	}
+    }
+}
+
+
+static void
 xtensa_find_unmarked_state_frags (void)
 {
   segT *seclist;
@@ -5298,6 +5350,9 @@ xtensa_handle_align (fragS *fragP)
 	as_bad_where (fragP->fr_file, fragP->fr_line,
 		      _("unaligned entry instruction"));
     }
+
+  if (linkrelax && fragP->fr_type == rs_org)
+    fragP->fr_subtype = RELAX_ORG;
 }
 
 
@@ -10148,6 +10203,7 @@ xtensa_post_relax_hook (void)
   xtensa_move_seg_list_to_beginning (literal_head);
 
   xtensa_find_unmarked_state_frags ();
+  xtensa_mark_frags_for_org ();
 
   xtensa_create_property_segments (get_frag_is_literal,
 				   NULL,
@@ -10608,6 +10664,9 @@ get_frag_property_flags (const fragS *fr
   xtensa_frag_flags_init (prop_flags);
   if (fragP->tc_frag_data.is_literal)
     prop_flags->is_literal = TRUE;
+  if (fragP->tc_frag_data.is_specific_opcode
+      || fragP->tc_frag_data.is_no_transform)
+    prop_flags->is_no_transform = TRUE;
   if (fragP->tc_frag_data.is_unreachable)
     prop_flags->is_unreachable = TRUE;
   else if (fragP->tc_frag_data.is_insn)
@@ -10617,9 +10676,6 @@ get_frag_property_flags (const fragS *fr
 	prop_flags->insn.is_loop_target = TRUE;
       if (fragP->tc_frag_data.is_branch_target)
 	prop_flags->insn.is_branch_target = TRUE;
-      if (fragP->tc_frag_data.is_specific_opcode
-	  || fragP->tc_frag_data.is_no_transform)
-	prop_flags->insn.is_no_transform = TRUE;
       if (fragP->tc_frag_data.is_no_density)
 	prop_flags->insn.is_no_density = TRUE;
       if (fragP->tc_frag_data.use_absolute_literals)
@@ -10657,8 +10713,8 @@ frag_flags_to_number (const frag_flags *
 
   if (prop_flags->insn.is_no_density)
     num |= XTENSA_PROP_INSN_NO_DENSITY;
-  if (prop_flags->insn.is_no_transform)
-    num |= XTENSA_PROP_INSN_NO_TRANSFORM;
+  if (prop_flags->is_no_transform)
+    num |= XTENSA_PROP_NO_TRANSFORM;
   if (prop_flags->insn.is_no_reorder)
     num |= XTENSA_PROP_INSN_NO_REORDER;
   if (prop_flags->insn.is_abslit)
@@ -10697,8 +10753,8 @@ xtensa_frag_flags_combinable (const frag
       if (prop_flags_1->insn.is_no_density !=
 	  prop_flags_2->insn.is_no_density)
 	return FALSE;
-      if (prop_flags_1->insn.is_no_transform !=
-	  prop_flags_2->insn.is_no_transform)
+      if (prop_flags_1->is_no_transform !=
+	  prop_flags_2->is_no_transform)
 	return FALSE;
       if (prop_flags_1->insn.is_no_reorder !=
 	  prop_flags_2->insn.is_no_reorder)
Index: gas/config/tc-xtensa.h
===================================================================
RCS file: /cvs/src/src/gas/config/tc-xtensa.h,v
retrieving revision 1.22
diff -u -p -r1.22 tc-xtensa.h
--- gas/config/tc-xtensa.h	1 Feb 2007 23:54:59 -0000	1.22
+++ gas/config/tc-xtensa.h	8 Jun 2007 23:59:19 -0000
@@ -167,6 +167,13 @@ enum xtensa_relax_statesE
      branch is relaxed, then this frag will be converted to a
      RELAX_UNREACHABLE frag.  */
 
+  RELAX_ORG,
+  /* This marks the location as having previously been an rs_org frag.  
+     rs_org frags are converted to fill-zero frags immediately after
+     relaxation.  However, we need to remember where they were so we can
+     prevent the linker from changing the size of any frag between the
+     section start and the org frag.  */
+
   RELAX_NONE
 };
 
Index: include/elf/xtensa.h
===================================================================
RCS file: /cvs/src/src/include/elf/xtensa.h,v
retrieving revision 1.4
diff -u -p -r1.4 xtensa.h
--- include/elf/xtensa.h	10 May 2005 10:21:10 -0000	1.4
+++ include/elf/xtensa.h	8 Jun 2007 23:59:19 -0000
@@ -140,7 +140,9 @@ typedef struct property_table_entry_t
 /* Instruction-only properties about code. */
 #define XTENSA_PROP_INSN_NO_DENSITY	0x00000040
 #define XTENSA_PROP_INSN_NO_REORDER	0x00000080
-#define XTENSA_PROP_INSN_NO_TRANSFORM	0x00000100
+/* Historically, NO_TRANSFORM was a property of instructions, 
+   but it should apply to literals under certain circumstances.  */
+#define XTENSA_PROP_NO_TRANSFORM	0x00000100
 
 /*  Branch target alignment information.  This transmits information
     to the linker optimization about the priority of aligning a
Index: ld/emultempl/xtensaelf.em
===================================================================
RCS file: /cvs/src/src/ld/emultempl/xtensaelf.em,v
retrieving revision 1.17
diff -u -p -r1.17 xtensaelf.em
--- ld/emultempl/xtensaelf.em	27 Nov 2006 20:14:53 -0000	1.17
+++ ld/emultempl/xtensaelf.em	8 Jun 2007 23:59:20 -0000
@@ -194,7 +194,7 @@ replace_insn_sec_with_prop_sec (bfd *abf
   for (entry = 0; entry < entry_count; ++entry)
     {
       unsigned value;
-      unsigned flags = (XTENSA_PROP_INSN | XTENSA_PROP_INSN_NO_TRANSFORM
+      unsigned flags = (XTENSA_PROP_INSN | XTENSA_PROP_NO_TRANSFORM
 			| XTENSA_PROP_INSN_NO_REORDER);
       value = bfd_get_32 (abfd, insn_contents + entry * 8 + 0);
       bfd_put_32 (abfd, value, prop_contents + entry * 12 + 0);
