diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 477d2f7af5a..3a8c0e646e6 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,18 @@
+2009-03-14  Richard Sandiford  <r.sandiford@uk.ibm.com>
+
+	* libcoff-in.h (xcoff_section_tdata): Update commentary.
+	* libcoff.h: Regenerate.
+	* xcofflink.c (xcoff_link_add_symbols): Set the csect of XTY_ER
+	symbols to bfd_und_section_ptr or bfd_abs_section_ptr, rather than
+	the previous symbol's csect.  Treat last_symndx as an inclusive value
+	and simplify its handling.
+	(xcoff_mark): Treat last_symndx as an inclusive value.  Only mark
+	symbols with the right csect.  Don't mark rsec when processing
+	relocations against undefined or absolute sections.  
+	(bfd_xcoff_size_dynamic_sections): Don't check the SEC_MARK flag
+	of bfd_und_section_ptr.
+	(xcoff_link_input_bfd): Likewise.
+
 2009-03-14  Richard Sandiford  <r.sandiford@uk.ibm.com>
 
 	* coff-rs6000.c (xcoff_ppc_relocate_section): Report relocations
diff --git a/bfd/libcoff-in.h b/bfd/libcoff-in.h
index 8c65158af0c..b1a6b598831 100644
--- a/bfd/libcoff-in.h
+++ b/bfd/libcoff-in.h
@@ -215,8 +215,7 @@ struct xcoff_section_tdata
   /* The lineno_count field for the enclosing section, because we are
      going to clobber it there.  */
   unsigned int lineno_count;
-  /* The first and one past the last symbol indices for symbols used
-     by this csect.  */
+  /* The first and last symbol indices for symbols used by this csect.  */
   unsigned long first_symndx;
   unsigned long last_symndx;
 };
diff --git a/bfd/libcoff.h b/bfd/libcoff.h
index c594d4b1ed3..7b37d574440 100644
--- a/bfd/libcoff.h
+++ b/bfd/libcoff.h
@@ -219,8 +219,7 @@ struct xcoff_section_tdata
   /* The lineno_count field for the enclosing section, because we are
      going to clobber it there.  */
   unsigned int lineno_count;
-  /* The first and one past the last symbol indices for symbols used
-     by this csect.  */
+  /* The first and last symbol indices for symbols used by this csect.  */
   unsigned long first_symndx;
   unsigned long last_symndx;
 };
diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c
index d651e3a323a..d12ed51a988 100644
--- a/bfd/xcofflink.c
+++ b/bfd/xcofflink.c
@@ -1092,17 +1092,9 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
 	     Normally csect is a .pr, .rw  etc. created in the loop
 	     If C_FILE or first time, handle special
 
-	     Advance esym, sym_hash, csect_hash ptr's
-	     Keep track of the last_symndx for the current file.  */
-	  if (sym.n_sclass == C_FILE && csect != NULL)
-	    {
-	      xcoff_section_data (abfd, csect)->last_symndx =
-		((esym
-		  - (bfd_byte *) obj_coff_external_syms (abfd))
-		 / symesz);
-	      csect = NULL;
-	    }
-
+	     Advance esym, sym_hash, csect_hash ptrs.  */
+	  if (sym.n_sclass == C_FILE)
+	    csect = NULL;
 	  if (csect != NULL)
 	    *csect_cache = csect;
 	  else if (first_csect == NULL || sym.n_sclass == C_FILE)
@@ -1253,13 +1245,6 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
 	  break;
 
 	case XTY_SD:
-	  /* This is a csect definition.  */
-	  if (csect != NULL)
-	    {
-	      xcoff_section_data (abfd, csect)->last_symndx =
-		((esym - (bfd_byte *) obj_coff_external_syms (abfd)) / symesz);
-	    }
-
 	  csect = NULL;
 	  csect_index = -(unsigned) 1;
 
@@ -1541,14 +1526,6 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
 	     named .tocbss, and rely on the linker script to put that
 	     in the TOC area.  */
 
-	  if (csect != NULL)
-	    {
-	      xcoff_section_data (abfd, csect)->last_symndx =
-		((esym
-		  - (bfd_byte *) obj_coff_external_syms (abfd))
-		 / symesz);
-	    }
-
 	  if (aux.x_csect.x_smclas == XMC_TD)
 	    {
 	      /* The linker script puts the .td section in the data
@@ -1805,7 +1782,15 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
 	    }
 	}
 
-      *csect_cache = csect;
+      if (smtyp == XTY_ER)
+	*csect_cache = section;
+      else
+	{
+	  *csect_cache = csect;
+	  if (csect != NULL)
+	    xcoff_section_data (abfd, csect)->last_symndx
+	      = (esym - (bfd_byte *) obj_coff_external_syms (abfd)) / symesz;
+	}
 
       esym += (sym.n_numaux + 1) * symesz;
       sym_hash += sym.n_numaux + 1;
@@ -2472,26 +2457,24 @@ xcoff_mark (struct bfd_link_info *info, asection *sec)
       && coff_section_data (sec->owner, sec) != NULL
       && xcoff_section_data (sec->owner, sec) != NULL)
     {
-      struct xcoff_link_hash_entry **hp, **hpend;
+      struct xcoff_link_hash_entry **syms;
       struct internal_reloc *rel, *relend;
+      asection **csects;
+      unsigned long i, first, last;
 
       /* Mark all the symbols in this section.  */
-      hp = (obj_xcoff_sym_hashes (sec->owner)
-	    + xcoff_section_data (sec->owner, sec)->first_symndx);
-      hpend = (obj_xcoff_sym_hashes (sec->owner)
-	       + xcoff_section_data (sec->owner, sec)->last_symndx);
-      for (; hp < hpend; hp++)
-	{
-	  struct xcoff_link_hash_entry *h;
-
-	  h = *hp;
-	  if (h != NULL
-	      && (h->flags & XCOFF_MARK) == 0)
-	    {
-	      if (! xcoff_mark_symbol (info, h))
-		return FALSE;
-	    }
-	}
+      syms = obj_xcoff_sym_hashes (sec->owner);
+      csects = xcoff_data (sec->owner)->csects;
+      first = xcoff_section_data (sec->owner, sec)->first_symndx;
+      last = xcoff_section_data (sec->owner, sec)->last_symndx;
+      for (i = first; i <= last; i++)
+	if (csects[i] == sec
+	    && syms[i] != NULL
+	    && (syms[i]->flags & XCOFF_MARK) == 0)
+	  {
+	    if (!xcoff_mark_symbol (info, syms[i]))
+	      return FALSE;
+	  }
 
       /* Look through the section relocs.  */
       if ((sec->flags & SEC_RELOC) != 0
@@ -2521,6 +2504,8 @@ xcoff_mark (struct bfd_link_info *info, asection *sec)
 
 	      rsec = xcoff_data (sec->owner)->csects[rel->r_symndx];
 	      if (rsec != NULL
+		  && !bfd_is_und_section (rsec)
+		  && !bfd_is_abs_section (rsec)
 		  && (rsec->flags & SEC_MARK) == 0)
 		{
 		  if (! xcoff_mark (info, rsec))
@@ -3358,8 +3343,9 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd,
 	      if (sym._n._n_n._n_zeroes == 0
 		  && *csectpp != NULL
 		  && (! gc
-		      || ((*csectpp)->flags & SEC_MARK) != 0
-		      || *csectpp == bfd_abs_section_ptr)
+		      || bfd_is_abs_section (*csectpp)
+		      || bfd_is_und_section (*csectpp)
+		      || ((*csectpp)->flags & SEC_MARK) != 0)
 		  && bfd_coff_symname_in_debug (sub, &sym))
 		{
 		  char *name;
@@ -3648,8 +3634,9 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
 	 symbol.  */
       if (! skip
 	  && xcoff_hash_table (finfo->info)->gc
-	  && ((*csectpp)->flags & SEC_MARK) == 0
-	  && *csectpp != bfd_abs_section_ptr)
+	  && !bfd_is_abs_section (*csectpp)
+	  && !bfd_is_und_section (*csectpp)
+	  && ((*csectpp)->flags & SEC_MARK) == 0)
 	skip = TRUE;
 
       /* An XCOFF linker always skips C_STAT symbols.  */