This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[committed] Don't create .loader sections for relocatable objects


I noticed while doing the earlier AIX patches that we create a .loader
section for relocatable objects.  This isn't what the native linker does,
and I think it can only cause confusion.  I finally decided to "fix" it
after I found that it caused a failure in the libtool testsuite: we had
two definitions of __rtinit, one created by the linker and one in an
input object.

Having a global static __rtinit symbol is a problem in itself, and I'll
fix it in a later patch.

Tested on powerpc-ibm-aix6.1 and applied.

Richard


bfd/
	* xcofflink.c (xcoff_link_create_extra_sections): Don't create
	a .loader section for relocatable links.
	(xcoff_need_ldrel_p): New function.
	(xcoff_mark): Use it.
	(bfd_xcoff_link_count_reloc): Only count loader relocs if there's
	a loader section.
	(xcoff_build_ldsym): New function, split out from...
	(xcoff_build_ldsyms): ...here.  Rename to...
	(xcoff_post_gc_symbol): ...this.  Only export symbols, and only
	call xcoff_build_ldsym, if there's a loader section.
	(xcoff_build_loader_section): New function, extracted verbatim from...
	(bfd_xcoff_size_dynamic_sections): ...here.  Only call it if
	there's a loader section.  Only add an __rtinit loader symbol
	if there's a loader section.  Update after above name change.
	(xcoff_symbol_section, xcoff_create_ldrel): New functions.
	(bfd_link_input_bfd): Use xcoff_need_ldrel_p, xcoff_symbol_section
	and xcoff_create_ldrel.
	(xcoff_write_global_symbol): Use xcoff_create_ldrel.
	(xcoff_reloc_link_order): Likewise, but only call it if there's
	a loader section.  Use xcoff_symbol_section.
	(_bfd_xcoff_bfd_final_link): Only use fdinfo.ldrel and fdinfo.ldsym
	if there's a loader section.

ld/testsuite/
	* ld-powerpc/aix-rel-1.s, ld-powerpc/aix-rel-1.od: New test.
	* ld-powerpc/aix52.exp: Run it.

Index: bfd/xcofflink.c
===================================================================
--- bfd/xcofflink.c	2009-04-01 19:20:59.000000000 +0100
+++ bfd/xcofflink.c	2009-04-01 19:29:37.000000000 +0100
@@ -814,7 +814,8 @@ xcoff_link_create_extra_sections (bfd * 
 	 won't work if we're producing an XCOFF output file with no
 	 XCOFF input files.  FIXME.  */
 
-      if (xcoff_hash_table (info)->loader_section == NULL)
+      if (!info->relocatable
+	  && xcoff_hash_table (info)->loader_section == NULL)
 	{
 	  asection *lsec;
 	  flagword flags = SEC_HAS_CONTENTS | SEC_IN_MEMORY;
@@ -2409,6 +2410,59 @@ xcoff_auto_export_p (struct xcoff_link_h
   return FALSE;
 }
 
+/* Return true if relocation REL needs to be copied to the .loader section.
+   If REL is against a global symbol, H is that symbol, otherwise it
+   is null.  */
+
+static bfd_boolean
+xcoff_need_ldrel_p (struct bfd_link_info *info, struct internal_reloc *rel,
+		    struct xcoff_link_hash_entry *h)
+{
+  if (!xcoff_hash_table (info)->loader_section)
+    return FALSE;
+
+  switch (rel->r_type)
+    {
+    case R_TOC:
+    case R_GL:
+    case R_TCL:
+    case R_TRL:
+    case R_TRLA:
+      /* We should never need a .loader reloc for a TOC-relative reloc.  */
+      return FALSE;
+
+    default:
+      /* In this case, relocations against defined symbols can be resolved
+	 statically.  */
+      if (h == NULL
+	  || h->root.type == bfd_link_hash_defined
+	  || h->root.type == bfd_link_hash_defweak
+	  || h->root.type == bfd_link_hash_common)
+	return FALSE;
+
+      /* We will always provide a local definition of function symbols,
+	 even if we don't have one yet.  */
+      if ((h->flags & XCOFF_CALLED) != 0)
+	return FALSE;
+
+      return TRUE;
+
+    case R_POS:
+    case R_NEG:
+    case R_RL:
+    case R_RLA:
+      /* Absolute relocations against absolute symbols can be
+	 resolved statically.  */
+      if (h != NULL
+	  && (h->root.type == bfd_link_hash_defined
+	      || h->root.type == bfd_link_hash_defweak)
+	  && bfd_is_abs_section (h->root.u.def.section))
+	return FALSE;
+
+      return TRUE;
+    }
+}
+
 /* Mark a symbol as not being garbage, including the section in which
    it is defined.  */
 
@@ -2681,39 +2735,11 @@ xcoff_mark (struct bfd_link_info *info, 
 
 	      /* See if this reloc needs to be copied into the .loader
 		 section.  */
-	      switch (rel->r_type)
+	      if (xcoff_need_ldrel_p (info, rel, h))
 		{
-		default:
-		  if (h == NULL
-		      || h->root.type == bfd_link_hash_defined
-		      || h->root.type == bfd_link_hash_defweak
-		      || h->root.type == bfd_link_hash_common
-		      /* We will always provide a local definition of
-			 function symbols.  */
-		      || (h->flags & XCOFF_CALLED) != 0)
-		    break;
-		  /* Fall through.  */
-		case R_POS:
-		case R_NEG:
-		case R_RL:
-		case R_RLA:
-		  if (h != NULL
-		      && (h->root.type == bfd_link_hash_defined
-			  || h->root.type == bfd_link_hash_defweak)
-		      && bfd_is_abs_section (h->root.u.def.section))
-		    break;
 		  ++xcoff_hash_table (info)->ldrel_count;
 		  if (h != NULL)
 		    h->flags |= XCOFF_LDREL;
-		  break;
-		case R_TOC:
-		case R_GL:
-		case R_TCL:
-		case R_TRL:
-		case R_TRLA:
-		  /* We should never need a .loader reloc for a TOC
-		     relative reloc.  */
-		  break;
 		}
 	    }
 
@@ -2941,8 +2967,12 @@ bfd_xcoff_link_count_reloc (bfd *output_
       return FALSE;
     }
 
-  h->flags |= XCOFF_REF_REGULAR | XCOFF_LDREL;
-  ++xcoff_hash_table (info)->ldrel_count;
+  h->flags |= XCOFF_REF_REGULAR;
+  if (xcoff_hash_table (info)->loader_section)
+    {
+      h->flags |= XCOFF_LDREL;
+      ++xcoff_hash_table (info)->ldrel_count;
+    }
 
   /* Mark the symbol to avoid garbage collection.  */
   if (! xcoff_mark_symbol (info, h))
@@ -3024,101 +3054,34 @@ xcoff_final_definition_p (bfd *input_bfd
     }
 }
 
+/* See if H should have a loader symbol associated with it.  */
+
 static bfd_boolean
-xcoff_build_ldsyms (struct xcoff_link_hash_entry *h, void * p)
+xcoff_build_ldsym (struct xcoff_loader_info *ldinfo,
+		   struct xcoff_link_hash_entry *h)
 {
-  struct xcoff_loader_info *ldinfo = (struct xcoff_loader_info *) p;
   bfd_size_type amt;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct xcoff_link_hash_entry *) h->root.u.i.link;
-
-  /* __rtinit, this symbol has special handling. */
-  if (h->flags & XCOFF_RTINIT)
-      return TRUE;
-
-  /* If this is a final link, and the symbol was defined as a common
-     symbol in a regular object file, and there was no definition in
-     any dynamic object, then the linker will have allocated space for
-     the symbol in a common section but the XCOFF_DEF_REGULAR flag
-     will not have been set.  */
-  if (h->root.type == bfd_link_hash_defined
-      && (h->flags & XCOFF_DEF_REGULAR) == 0
-      && (h->flags & XCOFF_REF_REGULAR) != 0
-      && (h->flags & XCOFF_DEF_DYNAMIC) == 0
-      && (bfd_is_abs_section (h->root.u.def.section)
-	  || (h->root.u.def.section->owner->flags & DYNAMIC) == 0))
-    h->flags |= XCOFF_DEF_REGULAR;
-
-  /* If all defined symbols should be exported, mark them now.  We
-     don't want to export the actual functions, just the function
-     descriptors.  */
-  if (xcoff_auto_export_p (h, ldinfo->auto_export_flags))
-    h->flags |= XCOFF_EXPORT;
-
-  /* We don't want to garbage collect symbols which are not defined in
-     XCOFF files.  This is a convenient place to mark them.  */
-  if (xcoff_hash_table (ldinfo->info)->gc
-      && (h->flags & XCOFF_MARK) == 0
-      && (h->root.type == bfd_link_hash_defined
-	  || h->root.type == bfd_link_hash_defweak)
-      && (h->root.u.def.section->owner == NULL
-	  || (h->root.u.def.section->owner->xvec
-	      != ldinfo->info->output_bfd->xvec)))
-    h->flags |= XCOFF_MARK;
-
-  /* If this symbol is exported, but not defined, we need to try to
-     define it.  */
+  /* Warn if this symbol is exported but not defined.  */
   if ((h->flags & XCOFF_EXPORT) != 0
       && (h->flags & XCOFF_WAS_UNDEFINED) != 0)
     {
       (*_bfd_error_handler)
 	(_("warning: attempt to export undefined symbol `%s'"),
 	 h->root.root.string);
-      h->ldsym = NULL;
       return TRUE;
     }
 
-  /* If this is still a common symbol, and it wasn't garbage
-     collected, we need to actually allocate space for it in the .bss
-     section.  */
-  if (h->root.type == bfd_link_hash_common
-      && (! xcoff_hash_table (ldinfo->info)->gc
-	  || (h->flags & XCOFF_MARK) != 0)
-      && h->root.u.c.p->section->size == 0)
-    {
-      BFD_ASSERT (bfd_is_com_section (h->root.u.c.p->section));
-      h->root.u.c.p->section->size = h->root.u.c.size;
-    }
-
   /* We need to add a symbol to the .loader section if it is mentioned
      in a reloc which we are copying to the .loader section and it was
      not defined or common, or if it is the entry point, or if it is
      being exported.  */
-
   if (((h->flags & XCOFF_LDREL) == 0
        || h->root.type == bfd_link_hash_defined
        || h->root.type == bfd_link_hash_defweak
        || h->root.type == bfd_link_hash_common)
       && (h->flags & XCOFF_ENTRY) == 0
       && (h->flags & XCOFF_EXPORT) == 0)
-    {
-      h->ldsym = NULL;
-      return TRUE;
-    }
-
-  /* We don't need to add this symbol if we did garbage collection and
-     we did not mark this symbol.  */
-  if (xcoff_hash_table (ldinfo->info)->gc
-      && (h->flags & XCOFF_MARK) == 0)
-    {
-      h->ldsym = NULL;
-      return TRUE;
-    }
-
-  /* We may have already processed this symbol due to the recursive
-     call above.  */
-  if ((h->flags & XCOFF_BUILT_LDSYM) != 0)
     return TRUE;
 
   /* We need to add this symbol to the .loader symbols.  */
@@ -3151,6 +3114,71 @@ xcoff_build_ldsyms (struct xcoff_link_ha
     return FALSE;
 
   h->flags |= XCOFF_BUILT_LDSYM;
+  return TRUE;
+}
+
+/* An xcoff_htab_traverse callback that is called for each symbol
+   once garbage collection is complete.  */
+
+static bfd_boolean
+xcoff_post_gc_symbol (struct xcoff_link_hash_entry *h, void * p)
+{
+  struct xcoff_loader_info *ldinfo = (struct xcoff_loader_info *) p;
+
+  if (h->root.type == bfd_link_hash_warning)
+    h = (struct xcoff_link_hash_entry *) h->root.u.i.link;
+
+  /* __rtinit, this symbol has special handling. */
+  if (h->flags & XCOFF_RTINIT)
+    return TRUE;
+
+  /* If this is a final link, and the symbol was defined as a common
+     symbol in a regular object file, and there was no definition in
+     any dynamic object, then the linker will have allocated space for
+     the symbol in a common section but the XCOFF_DEF_REGULAR flag
+     will not have been set.  */
+  if (h->root.type == bfd_link_hash_defined
+      && (h->flags & XCOFF_DEF_REGULAR) == 0
+      && (h->flags & XCOFF_REF_REGULAR) != 0
+      && (h->flags & XCOFF_DEF_DYNAMIC) == 0
+      && (bfd_is_abs_section (h->root.u.def.section)
+	  || (h->root.u.def.section->owner->flags & DYNAMIC) == 0))
+    h->flags |= XCOFF_DEF_REGULAR;
+
+  /* We don't want to garbage collect symbols which are not defined in
+     XCOFF files.  This is a convenient place to mark them.  */
+  if (xcoff_hash_table (ldinfo->info)->gc
+      && (h->flags & XCOFF_MARK) == 0
+      && (h->root.type == bfd_link_hash_defined
+	  || h->root.type == bfd_link_hash_defweak)
+      && (h->root.u.def.section->owner == NULL
+	  || (h->root.u.def.section->owner->xvec
+	      != ldinfo->info->output_bfd->xvec)))
+    h->flags |= XCOFF_MARK;
+
+  /* Skip discarded symbols.  */
+  if (xcoff_hash_table (ldinfo->info)->gc
+      && (h->flags & XCOFF_MARK) == 0)
+    return TRUE;
+
+  /* If this is still a common symbol, and it wasn't garbage
+     collected, we need to actually allocate space for it in the .bss
+     section.  */
+  if (h->root.type == bfd_link_hash_common
+      && h->root.u.c.p->section->size == 0)
+    {
+      BFD_ASSERT (bfd_is_com_section (h->root.u.c.p->section));
+      h->root.u.c.p->section->size = h->root.u.c.size;
+    }
+
+  if (xcoff_hash_table (ldinfo->info)->loader_section)
+    {
+      if (xcoff_auto_export_p (h, ldinfo->auto_export_flags))
+	h->flags |= XCOFF_EXPORT;
+
+      if (!xcoff_build_ldsym (ldinfo, h))
+	return FALSE;
+    }
 
   return TRUE;
 }
@@ -3246,6 +3274,119 @@ xcoff_keep_symbol_p (struct bfd_link_inf
   return 1;
 }
 
+/* Lay out the .loader section, filling in the header and the import paths.
+   LIBPATH is as for bfd_xcoff_size_dynamic_sections.  */
+
+static bfd_boolean
+xcoff_build_loader_section (struct xcoff_loader_info *ldinfo,
+			    const char *libpath)
+{
+  bfd *output_bfd;
+  struct xcoff_link_hash_table *htab;
+  struct internal_ldhdr *ldhdr;
+  struct xcoff_import_file *fl;
+  bfd_size_type stoff;
+  size_t impsize, impcount;
+  asection *lsec;
+  char *out;
+
+  /* Work out the size of the import file names.  Each import file ID
+     consists of three null terminated strings: the path, the file
+     name, and the archive member name.  The first entry in the list
+     of names is the path to use to find objects, which the linker has
+     passed in as the libpath argument.  For some reason, the path
+     entry in the other import file names appears to always be empty.  */
+  output_bfd = ldinfo->output_bfd;
+  htab = xcoff_hash_table (ldinfo->info);
+  impsize = strlen (libpath) + 3;
+  impcount = 1;
+  for (fl = htab->imports; fl != NULL; fl = fl->next)
+    {
+      ++impcount;
+      impsize += (strlen (fl->path)
+		  + strlen (fl->file)
+		  + strlen (fl->member)
+		  + 3);
+    }
+
+  /* Set up the .loader section header.  */
+  ldhdr = &htab->ldhdr;
+  ldhdr->l_version = bfd_xcoff_ldhdr_version(output_bfd);
+  ldhdr->l_nsyms = ldinfo->ldsym_count;
+  ldhdr->l_nreloc = htab->ldrel_count;
+  ldhdr->l_istlen = impsize;
+  ldhdr->l_nimpid = impcount;
+  ldhdr->l_impoff = (bfd_xcoff_ldhdrsz (output_bfd)
+		     + ldhdr->l_nsyms * bfd_xcoff_ldsymsz (output_bfd)
+		     + ldhdr->l_nreloc * bfd_xcoff_ldrelsz (output_bfd));
+  ldhdr->l_stlen = ldinfo->string_size;
+  stoff = ldhdr->l_impoff + impsize;
+  if (ldinfo->string_size == 0)
+    ldhdr->l_stoff = 0;
+  else
+    ldhdr->l_stoff = stoff;
+
+  /* 64 bit elements to ldhdr
+     The swap out routine for 32 bit will ignore them.
+     Nothing fancy, symbols come after the header and relocs come
+     after symbols.  */
+  ldhdr->l_symoff = bfd_xcoff_ldhdrsz (output_bfd);
+  ldhdr->l_rldoff = (bfd_xcoff_ldhdrsz (output_bfd)
+		     + ldhdr->l_nsyms * bfd_xcoff_ldsymsz (output_bfd));
+
+  /* We now know the final size of the .loader section.  Allocate
+     space for it.  */
+  lsec = htab->loader_section;
+  lsec->size = stoff + ldhdr->l_stlen;
+  lsec->contents = bfd_zalloc (output_bfd, lsec->size);
+  if (lsec->contents == NULL)
+    return FALSE;
+
+  /* Set up the header.  */
+  bfd_xcoff_swap_ldhdr_out (output_bfd, ldhdr, lsec->contents);
+
+  /* Set up the import file names.  */
+  out = (char *) lsec->contents + ldhdr->l_impoff;
+  strcpy (out, libpath);
+  out += strlen (libpath) + 1;
+  *out++ = '\0';
+  *out++ = '\0';
+  for (fl = htab->imports; fl != NULL; fl = fl->next)
+    {
+      const char *s;
+
+      s = fl->path;
+      while ((*out++ = *s++) != '\0')
+	;
+      s = fl->file;
+      while ((*out++ = *s++) != '\0')
+	;
+      s = fl->member;
+      while ((*out++ = *s++) != '\0')
+	;
+    }
+
+  BFD_ASSERT ((bfd_size_type) ((bfd_byte *) out - lsec->contents) == stoff);
+
+  /* Set up the symbol string table.  */
+  if (ldinfo->string_size > 0)
+    {
+      memcpy (out, ldinfo->strings, ldinfo->string_size);
+      free (ldinfo->strings);
+      ldinfo->strings = NULL;
+    }
+
+  /* We can't set up the symbol table or the relocs yet, because we
+     don't yet know the final position of the various sections.  The
+     .loader symbols are written out when the corresponding normal
+     symbols are written out in xcoff_link_input_bfd or
+     xcoff_write_global_symbol.  The .loader relocs are written out
+     when the corresponding normal relocs are handled in
+     xcoff_link_input_bfd.  */
+
+  return TRUE;
+}
+
 /* Build the .loader section.  This is called by the XCOFF linker
    emulation before_allocation routine.  We must set the size of the
    .loader section before the linker lays out the output file.
@@ -3277,14 +3418,8 @@ bfd_xcoff_size_dynamic_sections (bfd *ou
 				 asection **special_sections,
 				 bfd_boolean rtld)
 {
-  asection *lsec;
   struct xcoff_loader_info ldinfo;
   int i;
-  size_t impsize, impcount;
-  struct xcoff_import_file *fl;
-  struct internal_ldhdr *ldhdr;
-  bfd_size_type stoff;
-  char *out;
   asection *sec;
   bfd *sub;
   struct bfd_strtab_hash *debug_strtab;
@@ -3316,7 +3451,8 @@ bfd_xcoff_size_dynamic_sections (bfd *ou
   xcoff_hash_table (info)->rtld = rtld;
 
   /* __rtinit */
-  if (info->init_function || info->fini_function || rtld)
+  if (xcoff_hash_table (info)->loader_section
+      && (info->init_function || info->fini_function || rtld))
     {
       struct xcoff_link_hash_entry *hsym;
       struct internal_ldsym *ldsym;
@@ -3432,103 +3568,15 @@ bfd_xcoff_size_dynamic_sections (bfd *ou
     /* I'm not sure what to do in this bizarre case.  */
     return TRUE;
 
-  xcoff_link_hash_traverse (xcoff_hash_table (info), xcoff_build_ldsyms,
+  xcoff_link_hash_traverse (xcoff_hash_table (info), xcoff_post_gc_symbol,
 			    (void *) &ldinfo);
   if (ldinfo.failed)
     goto error_return;
 
-  /* Work out the size of the import file names.  Each import file ID
-     consists of three null terminated strings: the path, the file
-     name, and the archive member name.  The first entry in the list
-     of names is the path to use to find objects, which the linker has
-     passed in as the libpath argument.  For some reason, the path
-     entry in the other import file names appears to always be empty.  */
-  impsize = strlen (libpath) + 3;
-  impcount = 1;
-  for (fl = xcoff_hash_table (info)->imports; fl != NULL; fl = fl->next)
-    {
-      ++impcount;
-      impsize += (strlen (fl->path)
-		  + strlen (fl->file)
-		  + strlen (fl->member)
-		  + 3);
-    }
-
-  /* Set up the .loader section header.  */
-  ldhdr = &xcoff_hash_table (info)->ldhdr;
-  ldhdr->l_version = bfd_xcoff_ldhdr_version(output_bfd);
-  ldhdr->l_nsyms = ldinfo.ldsym_count;
-  ldhdr->l_nreloc = xcoff_hash_table (info)->ldrel_count;
-  ldhdr->l_istlen = impsize;
-  ldhdr->l_nimpid = impcount;
-  ldhdr->l_impoff = (bfd_xcoff_ldhdrsz(output_bfd)
-		     + ldhdr->l_nsyms * bfd_xcoff_ldsymsz(output_bfd)
-		     + ldhdr->l_nreloc * bfd_xcoff_ldrelsz(output_bfd));
-  ldhdr->l_stlen = ldinfo.string_size;
-  stoff = ldhdr->l_impoff + impsize;
-  if (ldinfo.string_size == 0)
-    ldhdr->l_stoff = 0;
-  else
-    ldhdr->l_stoff = stoff;
-
-  /* 64 bit elements to ldhdr
-     The swap out routine for 32 bit will ignore them.
-     Nothing fancy, symbols come after the header and relocs come
-     after symbols.  */
-  ldhdr->l_symoff = bfd_xcoff_ldhdrsz (output_bfd);
-  ldhdr->l_rldoff = (bfd_xcoff_ldhdrsz (output_bfd)
-		     + ldhdr->l_nsyms * bfd_xcoff_ldsymsz (output_bfd));
-
-  /* We now know the final size of the .loader section.  Allocate
-     space for it.  */
-  lsec = xcoff_hash_table (info)->loader_section;
-  lsec->size = stoff + ldhdr->l_stlen;
-  lsec->contents = bfd_zalloc (output_bfd, lsec->size);
-  if (lsec->contents == NULL)
+  if (xcoff_hash_table (info)->loader_section
+      && !xcoff_build_loader_section (&ldinfo, libpath))
     goto error_return;
 
-  /* Set up the header.  */
-  bfd_xcoff_swap_ldhdr_out (output_bfd, ldhdr, lsec->contents);
-
-  /* Set up the import file names.  */
-  out = (char *) lsec->contents + ldhdr->l_impoff;
-  strcpy (out, libpath);
-  out += strlen (libpath) + 1;
-  *out++ = '\0';
-  *out++ = '\0';
-  for (fl = xcoff_hash_table (info)->imports; fl != NULL; fl = fl->next)
-    {
-      const char *s;
-
-      s = fl->path;
-      while ((*out++ = *s++) != '\0')
-	;
-      s = fl->file;
-      while ((*out++ = *s++) != '\0')
-	;
-      s = fl->member;
-      while ((*out++ = *s++) != '\0')
-	;
-    }
-
-  BFD_ASSERT ((bfd_size_type) ((bfd_byte *) out - lsec->contents) == stoff);
-
-  /* Set up the symbol string table.  */
-  if (ldinfo.string_size > 0)
-    {
-      memcpy (out, ldinfo.strings, ldinfo.string_size);
-      free (ldinfo.strings);
-      ldinfo.strings = NULL;
-    }
-
-  /* We can't set up the symbol table or the relocs yet, because we
-     don't yet know the final position of the various sections.  The
-     .loader symbols are written out when the corresponding normal
-     symbols are written out in xcoff_link_input_bfd or
-     xcoff_write_global_symbol.  The .loader relocs are written out
-     when the corresponding normal relocs are handled in
-     xcoff_link_input_bfd.  */
-
   /* Allocate space for the magic sections.  */
   sec = xcoff_hash_table (info)->linkage_section;
   if (sec->size > 0)
@@ -3743,6 +3791,91 @@ bfd_xcoff_link_generate_rtinit (bfd *abf
   return TRUE;
 }
 
+/* Return the section that defines H.  Return null if no section does.  */
+
+static asection *
+xcoff_symbol_section (struct xcoff_link_hash_entry *h)
+{
+  switch (h->root.type)
+    {
+    case bfd_link_hash_defined:
+    case bfd_link_hash_defweak:
+      return h->root.u.def.section;
+
+    case bfd_link_hash_common:
+      return h->root.u.c.p->section;
+
+    default:
+      return NULL;
+    }
+}
+
+/* Add a .loader relocation for input relocation IREL.  If the loader
+   relocation should be against an output section, HSEC points to the
+   input section that IREL is against, otherwise HSEC is null.  H is the
+   symbol that IREL is against, or null if it isn't against a global symbol.
+   REFERENCE_BFD is the bfd to use in error messages about the relocation.  */
+
+static bfd_boolean
+xcoff_create_ldrel (bfd *output_bfd, struct xcoff_final_link_info *finfo,
+		    asection *output_section, bfd *reference_bfd,
+		    struct internal_reloc *irel, asection *hsec,
+		    struct xcoff_link_hash_entry *h)
+{
+  struct internal_ldrel ldrel;
+
+  ldrel.l_vaddr = irel->r_vaddr;
+  if (hsec != NULL)
+    {
+      const char *secname;
+
+      secname = hsec->output_section->name;
+      if (strcmp (secname, ".text") == 0)
+	ldrel.l_symndx = 0;
+      else if (strcmp (secname, ".data") == 0)
+	ldrel.l_symndx = 1;
+      else if (strcmp (secname, ".bss") == 0)
+	ldrel.l_symndx = 2;
+      else
+	{
+	  (*_bfd_error_handler)
+	    (_("%B: loader reloc in unrecognized section `%s'"),
+	     reference_bfd, secname);
+	  bfd_set_error (bfd_error_nonrepresentable_section);
+	  return FALSE;
+	}
+    }
+  else if (h != NULL)
+    {
+      if (h->ldindx < 0)
+	{
+	  (*_bfd_error_handler)
+	    (_("%B: `%s' in loader reloc but not loader sym"),
+	     reference_bfd, h->root.root.string);
+	  bfd_set_error (bfd_error_bad_value);
+	  return FALSE;
+	}
+      ldrel.l_symndx = h->ldindx;
+    }
+  else
+    ldrel.l_symndx = -(bfd_size_type) 1;
+
+  ldrel.l_rtype = (irel->r_size << 8) | irel->r_type;
+  ldrel.l_rsecnm = output_section->target_index;
+  if (xcoff_hash_table (finfo->info)->textro
+      && strcmp (output_section->name, ".text") == 0)
+    {
+      (*_bfd_error_handler)
+	(_("%B: loader reloc in read-only section %A"),
+	 reference_bfd, output_section);
+      bfd_set_error (bfd_error_invalid_operation);
+      return FALSE;
+    }
+  bfd_xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel);
+  finfo->ldrel += bfd_xcoff_ldrelsz (output_bfd);
+  return TRUE;
+}
+
 /* Link an input file into the linker output file.  This function
    handles all the sections and relocations of the input file at once.  */
 
@@ -4455,7 +4588,6 @@ #define N_BTSHFT n_btshft
 	  for (; irel < irelend; irel++, rel_hash++)
 	    {
 	      struct xcoff_link_hash_entry *h = NULL;
-	      struct internal_ldrel ldrel;
 
 	      *rel_hash = NULL;
 
@@ -4588,97 +4720,20 @@ #define N_BTSHFT n_btshft
 		    }
 		}
 
-	      switch (irel->r_type)
+	      if (xcoff_need_ldrel_p (finfo->info, irel, h))
 		{
-		default:
-		  if (h == NULL
-		      || h->root.type == bfd_link_hash_defined
-		      || h->root.type == bfd_link_hash_defweak
-		      || h->root.type == bfd_link_hash_common)
-		    break;
-		  /* Fall through.  */
-		case R_POS:
-		case R_NEG:
-		case R_RL:
-		case R_RLA:
-		  if (h != NULL
-		      && (h->root.type == bfd_link_hash_defined
-			  || h->root.type == bfd_link_hash_defweak)
-		      && bfd_is_abs_section (h->root.u.def.section))
-		    break;
-		  /* This reloc needs to be copied into the .loader
-		     section.  */
-		  ldrel.l_vaddr = irel->r_vaddr;
-		  if (r_symndx == -1)
-		    ldrel.l_symndx = -(bfd_size_type ) 1;
-		  else if (h == NULL
-			   || (h->root.type == bfd_link_hash_defined
-			       || h->root.type == bfd_link_hash_defweak
-			       || h->root.type == bfd_link_hash_common))
-		    {
-		      asection *sec;
+		  asection *sec;
 
-		      if (h == NULL)
-			sec = xcoff_data (input_bfd)->csects[r_symndx];
-		      else if (h->root.type == bfd_link_hash_common)
-			sec = h->root.u.c.p->section;
-		      else
-			sec = h->root.u.def.section;
-		      sec = sec->output_section;
-
-		      if (strcmp (sec->name, ".text") == 0)
-			ldrel.l_symndx = 0;
-		      else if (strcmp (sec->name, ".data") == 0)
-			ldrel.l_symndx = 1;
-		      else if (strcmp (sec->name, ".bss") == 0)
-			ldrel.l_symndx = 2;
-		      else
-			{
-			  (*_bfd_error_handler)
-			    (_("%B: loader reloc in unrecognized section `%A'"),
-			     input_bfd, sec);
-			  bfd_set_error (bfd_error_nonrepresentable_section);
-			  return FALSE;
-			}
-		    }
+		  if (r_symndx == -1)
+		    sec = NULL;
+		  else if (h == NULL)
+		    sec = xcoff_data (input_bfd)->csects[r_symndx];
 		  else
-		    {
-		      if (h->ldindx < 0)
-			{
-			  (*_bfd_error_handler)
-			    (_("%B: `%s' in loader reloc but not loader sym"),
-			     input_bfd,
-			     h->root.root.string);
-			  bfd_set_error (bfd_error_bad_value);
-			  return FALSE;
-			}
-		      ldrel.l_symndx = h->ldindx;
-		    }
-		  ldrel.l_rtype = (irel->r_size << 8) | irel->r_type;
-		  ldrel.l_rsecnm = o->output_section->target_index;
-		  if (xcoff_hash_table (finfo->info)->textro
-		      && strcmp (o->output_section->name, ".text") == 0)
-		    {
-		      (*_bfd_error_handler)
-			(_("%B: loader reloc in read-only section %A"),
-			 input_bfd, o->output_section);
-		      bfd_set_error (bfd_error_invalid_operation);
-		      return FALSE;
-		    }
-		  bfd_xcoff_swap_ldrel_out (output_bfd, &ldrel,
-					    finfo->ldrel);
-
-		  finfo->ldrel += bfd_xcoff_ldrelsz(output_bfd);
-		  break;
-
-		case R_TOC:
-		case R_GL:
-		case R_TCL:
-		case R_TRL:
-		case R_TRLA:
-		  /* We should never need a .loader reloc for a TOC
-		     relative reloc.  */
-		  break;
+		    sec = xcoff_symbol_section (h);
+		  if (!xcoff_create_ldrel (output_bfd, finfo,
+					   o->output_section, input_bfd,
+					   irel, sec, h))
+		    return FALSE;
 		}
 	    }
 
@@ -5035,7 +5090,6 @@ xcoff_write_global_symbol (struct xcoff_
       asection *osec;
       int oindx;
       struct internal_reloc *irel;
-      struct internal_ldrel ldrel;
       struct internal_syment irsym;
       union internal_auxent iraux;
 
@@ -5088,12 +5142,9 @@ xcoff_write_global_symbol (struct xcoff_
       finfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL;
       ++osec->reloc_count;
 
-      ldrel.l_vaddr = irel->r_vaddr;
-      ldrel.l_symndx = h->ldindx;
-      ldrel.l_rtype = (irel->r_size << 8) | R_POS;
-      ldrel.l_rsecnm = oindx;
-      bfd_xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel);
-      finfo->ldrel += bfd_xcoff_ldrelsz(output_bfd);
+      if (!xcoff_create_ldrel (output_bfd, finfo, osec,
+			       output_bfd, irel, NULL, h))
+	return FALSE;
 
       /* We need to emit a symbol to define a csect which holds
 	 the reloc.  */
@@ -5159,7 +5210,6 @@ xcoff_write_global_symbol (struct xcoff_
       struct xcoff_link_hash_entry *hentry;
       asection *esec;
       struct internal_reloc *irel;
-      struct internal_ldrel ldrel;
       asection *tsec;
       unsigned int reloc_size, byte_size;
 
@@ -5197,26 +5247,9 @@ xcoff_write_global_symbol (struct xcoff_
       finfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL;
       ++osec->reloc_count;
 
-      ldrel.l_vaddr = irel->r_vaddr;
-      if (strcmp (esec->output_section->name, ".text") == 0)
-	ldrel.l_symndx = 0;
-      else if (strcmp (esec->output_section->name, ".data") == 0)
-	ldrel.l_symndx = 1;
-      else if (strcmp (esec->output_section->name, ".bss") == 0)
-	ldrel.l_symndx = 2;
-      else
-	{
-	  (*_bfd_error_handler)
-	    (_("%s: loader reloc in unrecognized section `%s'"),
-	     bfd_get_filename (output_bfd),
-	     esec->output_section->name);
-	  bfd_set_error (bfd_error_nonrepresentable_section);
-	  return FALSE;
-	}
-      ldrel.l_rtype = (reloc_size << 8) | R_POS;
-      ldrel.l_rsecnm = oindx;
-      bfd_xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel);
-      finfo->ldrel += bfd_xcoff_ldrelsz(output_bfd);
+      if (!xcoff_create_ldrel (output_bfd, finfo, osec,
+			       output_bfd, irel, esec, NULL))
+	return FALSE;
 
       /* There are three items to write out,
 	 the address of the code
@@ -5259,26 +5292,9 @@ xcoff_write_global_symbol (struct xcoff_
       finfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL;
       ++osec->reloc_count;
 
-      ldrel.l_vaddr = irel->r_vaddr;
-      if (strcmp (tsec->output_section->name, ".text") == 0)
-	ldrel.l_symndx = 0;
-      else if (strcmp (tsec->output_section->name, ".data") == 0)
-	ldrel.l_symndx = 1;
-      else if (strcmp (tsec->output_section->name, ".bss") == 0)
-	ldrel.l_symndx = 2;
-      else
-	{
-	  (*_bfd_error_handler)
-	    (_("%s: loader reloc in unrecognized section `%s'"),
-	     bfd_get_filename (output_bfd),
-	     tsec->output_section->name);
-	  bfd_set_error (bfd_error_nonrepresentable_section);
-	  return FALSE;
-	}
-      ldrel.l_rtype = (reloc_size << 8) | R_POS;
-      ldrel.l_rsecnm = oindx;
-      bfd_xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel);
-      finfo->ldrel += bfd_xcoff_ldrelsz(output_bfd);
+      if (!xcoff_create_ldrel (output_bfd, finfo, osec,
+			       output_bfd, irel, tsec, NULL))
+	return FALSE;
     }
 
   if (h->indx >= 0 || finfo->info->strip == strip_all)
@@ -5440,7 +5456,6 @@ xcoff_reloc_link_order (bfd *output_bfd,
   bfd_vma addend;
   struct internal_reloc *irel;
   struct xcoff_link_hash_entry **rel_hash_ptr;
-  struct internal_ldrel ldrel;
 
   if (link_order->type == bfd_section_reloc_link_order)
     /* We need to somehow locate a symbol in the right section.  The
@@ -5468,22 +5483,12 @@ xcoff_reloc_link_order (bfd *output_bfd,
       return TRUE;
     }
 
-  if (h->root.type == bfd_link_hash_common)
-    {
-      hsec = h->root.u.c.p->section;
-      hval = 0;
-    }
-  else if (h->root.type == bfd_link_hash_defined
-	   || h->root.type == bfd_link_hash_defweak)
-    {
-      hsec = h->root.u.def.section;
-      hval = h->root.u.def.value;
-    }
+  hsec = xcoff_symbol_section (h);
+  if (h->root.type == bfd_link_hash_defined
+      || h->root.type == bfd_link_hash_defweak)
+    hval = h->root.u.def.value;
   else
-    {
-      hsec = NULL;
-      hval = 0;
-    }
+    hval = 0;
 
   addend = link_order->u.reloc.p->addend;
   if (hsec != NULL)
@@ -5558,49 +5563,13 @@ xcoff_reloc_link_order (bfd *output_bfd,
   ++output_section->reloc_count;
 
   /* Now output the reloc to the .loader section.  */
-
-  ldrel.l_vaddr = irel->r_vaddr;
-
-  if (hsec != NULL)
+  if (xcoff_hash_table (finfo->info)->loader_section)
     {
-      const char *secname;
-
-      secname = hsec->output_section->name;
-
-      if (strcmp (secname, ".text") == 0)
-	ldrel.l_symndx = 0;
-      else if (strcmp (secname, ".data") == 0)
-	ldrel.l_symndx = 1;
-      else if (strcmp (secname, ".bss") == 0)
-	ldrel.l_symndx = 2;
-      else
-	{
-	  (*_bfd_error_handler)
-	    (_("%s: loader reloc in unrecognized section `%s'"),
-	     bfd_get_filename (output_bfd), secname);
-	  bfd_set_error (bfd_error_nonrepresentable_section);
-	  return FALSE;
-	}
-    }
-  else
-    {
-      if (h->ldindx < 0)
-	{
-	  (*_bfd_error_handler)
-	    (_("%s: `%s' in loader reloc but not loader sym"),
-	     bfd_get_filename (output_bfd),
-	     h->root.root.string);
-	  bfd_set_error (bfd_error_bad_value);
-	  return FALSE;
-	}
-      ldrel.l_symndx = h->ldindx;
+      if (!xcoff_create_ldrel (output_bfd, finfo, output_section,
+			       output_bfd, irel, hsec, h))
+	return FALSE;
     }
 
-  ldrel.l_rtype = (irel->r_size << 8) | irel->r_type;
-  ldrel.l_rsecnm = output_section->target_index;
-  bfd_xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel);
-  finfo->ldrel += bfd_xcoff_ldrelsz(output_bfd);
-
   return TRUE;
 }
 
@@ -5646,12 +5615,20 @@ _bfd_xcoff_bfd_final_link (bfd *abfd, st
   finfo.contents = NULL;
   finfo.external_relocs = NULL;
 
-  finfo.ldsym = (xcoff_hash_table (info)->loader_section->contents
-		 + bfd_xcoff_ldhdrsz (abfd));
-  finfo.ldrel = (xcoff_hash_table (info)->loader_section->contents
-		 + bfd_xcoff_ldhdrsz(abfd)
-		 + (xcoff_hash_table (info)->ldhdr.l_nsyms
-		    * bfd_xcoff_ldsymsz(abfd)));
+  if (xcoff_hash_table (info)->loader_section)
+    {
+      finfo.ldsym = (xcoff_hash_table (info)->loader_section->contents
+		     + bfd_xcoff_ldhdrsz (abfd));
+      finfo.ldrel = (xcoff_hash_table (info)->loader_section->contents
+		     + bfd_xcoff_ldhdrsz (abfd)
+		     + (xcoff_hash_table (info)->ldhdr.l_nsyms
+			* bfd_xcoff_ldsymsz (abfd)));
+    }
+  else
+    {
+      finfo.ldsym = NULL;
+      finfo.ldrel = NULL;
+    }
 
   xcoff_data (abfd)->coff.link_info = info;
 
@@ -6138,13 +6115,16 @@ _bfd_xcoff_bfd_final_link (bfd *abfd, st
     }
 
   /* Write out the loader section contents.  */
-  BFD_ASSERT ((bfd_byte *) finfo.ldrel
-	      == (xcoff_hash_table (info)->loader_section->contents
-		  + xcoff_hash_table (info)->ldhdr.l_impoff));
   o = xcoff_hash_table (info)->loader_section;
-  if (! bfd_set_section_contents (abfd, o->output_section, o->contents,
-				  (file_ptr) o->output_offset, o->size))
-    goto error_return;
+  if (o)
+    {
+      BFD_ASSERT ((bfd_byte *) finfo.ldrel
+		  == (xcoff_hash_table (info)->loader_section->contents
+		      + xcoff_hash_table (info)->ldhdr.l_impoff));
+      if (!bfd_set_section_contents (abfd, o->output_section, o->contents,
+				     (file_ptr) o->output_offset, o->size))
+	goto error_return;
+    }
 
   /* Write out the magic sections.  */
   o = xcoff_hash_table (info)->linkage_section;
Index: ld/testsuite/ld-powerpc/aix-rel-1.s
===================================================================
--- /dev/null	2009-04-01 18:14:04.503808585 +0100
+++ ld/testsuite/ld-powerpc/aix-rel-1.s	2009-04-01 19:21:27.000000000 +0100
@@ -0,0 +1,5 @@
+	.globl	foo
+	.csect	foo[RW]
+foo:
+	.long	.puts
+	.long	foobar
Index: ld/testsuite/ld-powerpc/aix-rel-1.od
===================================================================
--- /dev/null	2009-04-01 18:14:04.503808585 +0100
+++ ld/testsuite/ld-powerpc/aix-rel-1.od	2009-04-01 19:21:27.000000000 +0100
@@ -0,0 +1,22 @@
+
+.*
+
+# It doesn't matter whether .text, .bss and .debug are listed, as long as
+# they're empty.  The important thing is that .loader shouldn't appear
+# at all.
+Sections:
+ *Idx Name * Size .*
+ *0 \.text * 0+0 .*
+ *ALLOC, LOAD, CODE
+ *1 \.data * 0+8 .*
+ *CONTENTS, ALLOC, LOAD, RELOC, DATA
+ *2 \.bss * 0+0 .*
+ *ALLOC
+ *3 \.debug * 0+0 .*
+                  
+RELOCATION RECORDS FOR \[\.data\]:
+OFFSET * TYPE  * VALUE 
+0+0 R_POS(|_32) * \.puts
+0+4 R_POS(|_32) * foobar
+
+
Index: ld/testsuite/ld-powerpc/aix52.exp
===================================================================
--- ld/testsuite/ld-powerpc/aix52.exp	2009-04-01 19:20:59.000000000 +0100
+++ ld/testsuite/ld-powerpc/aix52.exp	2009-04-01 19:21:27.000000000 +0100
@@ -171,6 +171,10 @@ set aix52tests {
      {{objdump -d aix-glink-2-SIZE.dd}}
      "aix-glink-2"}
 
+    {"Relocatable test 1" "-r"
+     "" {aix-rel-1.s}
+     {{objdump -hr aix-rel-1.od}} "aix-rel-1.ro"}
+
     {"Weak test 1 (rel)" "-r"
      "" {aix-weak-1a.s aix-weak-1b.s}
      {{nm {} aix-weak-1-rel.nd} {objdump -h aix-weak-1-rel.hd}}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]