This is the mail archive of the binutils@sources.redhat.com 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]

[PATCH] Support -z combreloc in binutils (take 2)


Hi!

Here is an updated version of the -z combreloc patch.
It incorporates Nick's comments, plus handles a few more arches than last
time (i386, sparc32, sparc64, ia64).
The last patch did not work properly, because DT_TEXTREL was not set when
-z combreloc was used. DT_TEXTREL was usually computed with code like:
                  /* If this relocation section applies to a read only
                     section, then we probably need a DT_TEXTREL
                     entry.  The entries in the .rel.plt section
                     really apply to the .got section, which we
                     created ourselves and so know is not readonly.  */
                  outname = bfd_get_section_name (output_bfd,
                                                  s->output_section);
                  target = bfd_get_section_by_name (output_bfd, outname + 4);
                  if (target != NULL
                      && (target->flags & SEC_READONLY) != 0
                      && (target->flags & SEC_ALLOC) != 0)
                    reltext = true;
But with -z combreloc, s->output_section is for non-PLT relocs always either
.rela.dyn or .rel.dyn, so this cannot work.
Instead I mark them when creating a reloc section during check_relocs if the
reloc section is against read-only section. I'm not sure if this does not
pessimize DT_TEXTREL setting (like if some reloc section cannot be killed by
linker script), but at least in my testing I never saw this.
Tested on i686 and sparc.

2001-08-22  Jakub Jelinek  <jakub@redhat.com>

	* elf-bfd.h (enum elf_reloc_type_class): New.
	(struct elf_backend_data): Add elf_backend_reloc_type_class.
	(_bfd_elf_reloc_type_class): New.
	* elfxx-target.h (elf_backend_reloc_type_class): Define.
	(elfNN_bed): Add elf_backend_reloc_type_class.
	* elf.c (_bfd_elf_reloc_type_class): New.
	* elf32-i386.c (elf_i386_check_relocs): Set DF_TEXTREL if the reloc
	is against read-only section.
	(elf_i386_size_dynamic_sections): Use DF_TEXTREL flag instead of
	looking up section names for DT_TEXTREL.
	(elf_i386_reloc_type_class): New.
	(elf_backend_reloc_type_class): Define.
	* elf32-sparc.c (elf32_sparc_check_relocs): Set DF_TEXTREL if the
	reloc is against read-only section.
	(elf32_sparc_size_dynamic_sections): Use DF_TEXTREL flag instead of
	looking up section names for DT_TEXTREL.
	(elf32_sparc_reloc_type_class): New.
	(elf_backend_reloc_type_class): Define.
	* elf64-sparc.c (sparc64_elf_check_relocs): Set DF_TEXTREL if the
	reloc is against read-only section.
	(sparc64_elf_size_dynamic_sections): Use DF_TEXTREL flag instead of
	looking up section names for DT_TEXTREL.
	(sparc64_elf_reloc_type_class): New.
	(elf_backend_reloc_type_class): Define.
	* elfxx-ia64.c (struct elfNN_ia64_link_hash_table): Add reltext field.
	(get_reloc_section): Set DF_TEXTREL if the reloc is against read-only
	section.
	(elfNN_ia64_size_dynamic_sections): Use ia64_info->reltext flag
	instead of looking up section names for DT_TEXTREL.
	(elfNN_ia64_reloc_type_class): New.
	(elf_backend_reloc_type_class): Define.
	* elflink.h (size_dynamic_sections): Add spare DT_NULL tags.
	(struct elf_link_sort_rela): New.
	(elf_link_sort_cmp1, elf_link_sort_cmp2, elf_link_sort_relocs): New.
	(elf_bfd_final_link): Call elf_link_sort_relocs.
	Convert one spare DT_NULL into DT_RELCOUNT resp. DT_RELACOUNT if
	necessary.

	* bfdlink.h (struct bfd_link_info): Add combreloc and
	spare_dynamic_tags fields.

	* emultempl/elf32.em (place_orphan): Place orphan .rel* sections
	into .rel.dyn resp. .rela.dyn if combreloc.
	(get_script): If .x linker script is equal to .xn, only put it
	once into the binary.
	Add .xc and .xsc scripts.
	(parse_args): Handle -z combreloc and -z nocombreloc.
	* scripttempl/elf.sc (.rela.sbss): Fix a typo.
	For .xc and .xsc scripts put all .rel* or .rela* input sections
	but .rel*.plt and PLT-like sections into .rel.dyn resp. .rela.dyn.
	* genscripts.sh (GENERATE_COMBRELOC_SCRIPT): Set if SCRIPT_NAME
	is elf.
	Strip trailing whitespace from script.
	Generate .xc and .xsc scripts if requested.
	* ldmain.c (main): Initialize link_info.combreloc and
	link_info.spare_dynamic_tags.
	* lexsup.c (OPTION_SPARE_DYNAMIC_TAGS): Define.
	(ld_options): Add --spare-dynamic-tags option.
	(parse_args): Likewise.
	* ld.texinfo: Document -z combreloc and -z nocombreloc.
	* ldint.texinfo: Document .xc and .xsc linker scripts.
	* NEWS: Add notes about -z combreloc and SHF_MERGE.

--- bfd/elf-bfd.h.jj	Mon Aug 13 13:05:23 2001
+++ bfd/elf-bfd.h	Wed Aug 22 18:15:39 2001
@@ -331,6 +331,13 @@ struct elf_size_info {
 	 ? (elf_symbol_type *) (S) \
 	 : 0)
 
+enum elf_reloc_type_class {
+  reloc_class_normal,
+  reloc_class_relative,
+  reloc_class_plt,
+  reloc_class_copy
+};
+
 struct elf_backend_data
 {
   /* The architecture for this backend.  */
@@ -636,10 +643,13 @@ struct elf_backend_data
      note is found in a core file. */
   boolean (*elf_backend_grok_psinfo) PARAMS ((bfd *, Elf_Internal_Note *));
 
-    /* Functions to print VMAs.  Special code to handle 64 bit ELF files.  */
+  /* Functions to print VMAs.  Special code to handle 64 bit ELF files.  */
   void (* elf_backend_sprintf_vma) PARAMS ((bfd *, char *, bfd_vma));
   void (* elf_backend_fprintf_vma) PARAMS ((bfd *, PTR, bfd_vma));
 
+  /* This function returns class of a reloc type.  */
+  enum elf_reloc_type_class (* elf_backend_reloc_type_class) PARAMS ((int));
+
   /* The swapping table to use when dealing with ECOFF information.
      Used for the MIPS ELF .mdebug section.  */
   const struct ecoff_debug_swap *elf_backend_ecoff_debug_swap;
@@ -1005,6 +1015,8 @@ extern void bfd_elf_print_symbol PARAMS 
 
 extern void _bfd_elf_sprintf_vma PARAMS ((bfd *, char *, bfd_vma));
 extern void _bfd_elf_fprintf_vma PARAMS ((bfd *, PTR, bfd_vma));
+
+extern enum elf_reloc_type_class _bfd_elf_reloc_type_class PARAMS ((int));
 
 extern unsigned long bfd_elf_hash PARAMS ((const char *));
 
--- bfd/elfxx-target.h.jj	Mon Aug 13 13:05:23 2001
+++ bfd/elfxx-target.h	Wed Aug 15 17:16:55 2001
@@ -344,6 +344,9 @@ Foundation, Inc., 59 Temple Place - Suit
 #ifndef elf_backend_fprintf_vma
 #define elf_backend_fprintf_vma			_bfd_elf_fprintf_vma
 #endif
+#ifndef elf_backend_reloc_type_class
+#define elf_backend_reloc_type_class		_bfd_elf_reloc_type_class
+#endif
 
 /* Previously, backends could only use SHT_REL or SHT_RELA relocation
    sections, but not both.  They defined USE_REL to indicate SHT_REL
@@ -431,6 +434,7 @@ static CONST struct elf_backend_data elf
   elf_backend_grok_psinfo,
   elf_backend_sprintf_vma,
   elf_backend_fprintf_vma,
+  elf_backend_reloc_type_class,
   elf_backend_ecoff_debug_swap,
   ELF_MACHINE_ALT1,
   ELF_MACHINE_ALT2,
--- bfd/elf.c.jj	Mon Aug 13 13:05:23 2001
+++ bfd/elf.c	Wed Aug 15 17:16:55 2001
@@ -6057,3 +6057,10 @@ _bfd_elf_fprintf_vma (abfd, stream, valu
   fprintf_vma ((FILE *) stream, value);
 #endif
 }
+
+enum elf_reloc_type_class
+_bfd_elf_reloc_type_class (type)
+     int type;
+{
+  return reloc_class_normal;
+}
--- bfd/elf32-i386.c.jj	Mon Aug 13 13:05:23 2001
+++ bfd/elf32-i386.c	Wed Aug 22 20:54:37 2001
@@ -63,6 +63,7 @@ static boolean elf_i386_finish_dynamic_s
   PARAMS ((bfd *, struct bfd_link_info *));
 static boolean elf_i386_fake_sections
   PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *));
+static enum elf_reloc_type_class elf_i386_reloc_type_class PARAMS ((int));
 
 #define USE_REL	1		/* 386 uses REL relocations instead of RELA */
 
@@ -767,6 +768,8 @@ elf_i386_check_relocs (abfd, info, sec, 
 			  || ! bfd_set_section_alignment (dynobj, sreloc, 2))
 			return false;
 		    }
+		  if (sec->flags & SEC_READONLY)
+		    info->flags |= DF_TEXTREL;
 		}
 
 	      sreloc->_raw_size += sizeof (Elf32_External_Rel);
@@ -1243,14 +1246,13 @@ allocate_plt_and_got_and_discard_relocs 
 
 static boolean
 elf_i386_size_dynamic_sections (output_bfd, info)
-     bfd *output_bfd;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
      struct bfd_link_info *info;
 {
   struct elf_i386_link_hash_table *htab;
   bfd *dynobj;
   asection *s;
   boolean relocs;
-  boolean reltext;
   bfd *i;
 
   htab = elf_i386_hash_table (info);
@@ -1315,7 +1317,6 @@ elf_i386_size_dynamic_sections (output_b
   /* We now have determined the sizes of the various dynamic sections.
      Allocate memory for them.  */
   relocs = false;
-  reltext = false;
   for (s = dynobj->sections; s != NULL; s = s->next)
     {
       if ((s->flags & SEC_LINKER_CREATED) == 0)
@@ -1344,29 +1345,8 @@ elf_i386_size_dynamic_sections (output_b
 	    }
 	  else
 	    {
-	      asection *target;
-
-	      /* Remember whether there are any reloc sections other
-		 than .rel.plt.  */
 	      if (s != htab->srelplt)
-		{
-		  const char *outname;
-
-		  relocs = true;
-
-		  /* If this relocation section applies to a read only
-		     section, then we probably need a DT_TEXTREL
-		     entry.  The entries in the .rel.plt section
-		     really apply to the .got section, which we
-		     created ourselves and so know is not readonly.  */
-		  outname = bfd_get_section_name (output_bfd,
-						  s->output_section);
-		  target = bfd_get_section_by_name (output_bfd, outname + 4);
-		  if (target != NULL
-		      && (target->flags & SEC_READONLY) != 0
-		      && (target->flags & SEC_ALLOC) != 0)
-		    reltext = true;
-		}
+		relocs = true;
 
 	      /* We use the reloc_count field as a counter if we need
 		 to copy relocs into the output file.  */
@@ -1426,11 +1406,10 @@ elf_i386_size_dynamic_sections (output_b
 	    return false;
 	}
 
-      if (reltext)
+      if ((info->flags & DF_TEXTREL) != 0)
 	{
 	  if (! bfd_elf32_add_dynamic_entry (info, DT_TEXTREL, 0))
 	    return false;
-	  info->flags |= DF_TEXTREL;
 	}
     }
 
@@ -2215,6 +2194,22 @@ elf_i386_fake_sections (abfd, hdr, sec)
   return true;
 }
 
+static enum elf_reloc_type_class
+elf_i386_reloc_type_class (type)
+     int type;
+{
+  switch (type)
+    {
+    case R_386_RELATIVE:
+      return reloc_class_relative;
+    case R_386_JUMP_SLOT:
+      return reloc_class_plt;
+    case R_386_COPY:
+      return reloc_class_copy;
+    default:
+      return reloc_class_normal;
+    }
+}
 
 #define TARGET_LITTLE_SYM		bfd_elf32_i386_vec
 #define TARGET_LITTLE_NAME		"elf32-i386"
@@ -2246,5 +2241,6 @@ elf_i386_fake_sections (abfd, hdr, sec)
 #define elf_backend_relocate_section	      elf_i386_relocate_section
 #define elf_backend_size_dynamic_sections     elf_i386_size_dynamic_sections
 #define elf_backend_fake_sections	      elf_i386_fake_sections
+#define elf_backend_reloc_type_class	      elf_i386_reloc_type_class
 
 #include "elf32-target.h"
--- bfd/elflink.h.jj	Mon Aug 13 13:05:23 2001
+++ bfd/elflink.h	Wed Aug 22 18:16:40 2001
@@ -67,6 +67,12 @@ static boolean elf_link_size_reloc_secti
 static void elf_link_adjust_relocs
   PARAMS ((bfd *, Elf_Internal_Shdr *, unsigned int,
 	   struct elf_link_hash_entry **));
+static int elf_link_sort_cmp1
+  PARAMS ((const void *, const void *));
+static int elf_link_sort_cmp2
+  PARAMS ((const void *, const void *));
+static size_t elf_link_sort_relocs
+  PARAMS ((bfd *, struct bfd_link_info *, asection **));
 
 /* Given an ELF BFD, add symbols to the global hash table as
    appropriate.  */
@@ -3065,6 +3071,7 @@ NAME(bfd_elf,size_dynamic_sections) (out
       asection *s;
       size_t bucketcount = 0;
       size_t hash_entry_size;
+      unsigned int dtagcount;
 
       /* Set up the version definition section.  */
       s = bfd_get_section_by_name (dynobj, ".gnu.version_d");
@@ -3439,8 +3446,9 @@ NAME(bfd_elf,size_dynamic_sections) (out
       BFD_ASSERT (s != NULL);
       s->_raw_size = _bfd_stringtab_size (elf_hash_table (info)->dynstr);
 
-      if (! elf_add_dynamic_entry (info, DT_NULL, 0))
-	return false;
+      for (dtagcount = 0; dtagcount <= info->spare_dynamic_tags; ++dtagcount)
+	if (! elf_add_dynamic_entry (info, DT_NULL, 0))
+	  return false;
     }
 
   return true;
@@ -4270,6 +4278,210 @@ elf_link_adjust_relocs (abfd, rel_hdr, c
   free (irela);
 }
 
+struct elf_link_sort_rela {
+  bfd_vma offset;
+  enum elf_reloc_type_class type;
+  union {
+    Elf_Internal_Rel rel;
+    Elf_Internal_Rela rela;
+  } u;
+};
+
+static int
+elf_link_sort_cmp1 (A, B)
+     const PTR A;
+     const PTR B;
+{
+  struct elf_link_sort_rela *a = (struct elf_link_sort_rela *)A;
+  struct elf_link_sort_rela *b = (struct elf_link_sort_rela *)B;
+  int relativea, relativeb;
+
+  relativea = a->type == reloc_class_relative;
+  relativeb = b->type == reloc_class_relative;
+
+  if (relativea < relativeb)
+    return -1;
+  if (relativea > relativeb)
+    return 1;
+  if (ELF_R_SYM (a->u.rel.r_info) < ELF_R_SYM (b->u.rel.r_info))
+    return -1;
+  if (ELF_R_SYM (a->u.rel.r_info) > ELF_R_SYM (b->u.rel.r_info))
+    return 1;
+  if (a->u.rel.r_offset < b->u.rel.r_offset)
+    return -1;
+  if (a->u.rel.r_offset > b->u.rel.r_offset)
+    return 1;
+  return 0;
+}
+
+static int
+elf_link_sort_cmp2 (A, B)
+     const PTR A;
+     const PTR B;
+{
+  struct elf_link_sort_rela *a = (struct elf_link_sort_rela *)A;
+  struct elf_link_sort_rela *b = (struct elf_link_sort_rela *)B;
+  int copya, copyb;
+
+  if (a->offset < b->offset)
+    return -1;
+  if (a->offset > b->offset)
+    return 1;
+  copya = a->type == reloc_class_copy;
+  copyb = b->type == reloc_class_copy;
+  if (copya < copyb)
+    return -1;
+  if (copya > copyb)
+    return 1;
+  if (a->u.rel.r_offset < b->u.rel.r_offset)
+    return -1;
+  if (a->u.rel.r_offset > b->u.rel.r_offset)
+    return 1;
+  return 0;
+}
+
+static size_t
+elf_link_sort_relocs (abfd, info, psec)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     asection **psec;
+{
+  bfd *dynobj = elf_hash_table (info)->dynobj;
+  asection *reldyn, *o;
+  boolean rel = false;
+  size_t count, size, i, j, ret;
+  struct elf_link_sort_rela *rela;
+  struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+  reldyn = bfd_get_section_by_name (abfd, ".rela.dyn");
+  if (reldyn == NULL || reldyn->_raw_size == 0)
+    {
+      reldyn = bfd_get_section_by_name (abfd, ".rel.dyn");
+      if (reldyn == NULL || reldyn->_raw_size == 0)
+	return 0;
+      rel = true;
+      count = reldyn->_raw_size / sizeof (Elf_External_Rel);
+    }
+  else
+    count = reldyn->_raw_size / sizeof (Elf_External_Rela);
+
+  size = 0;
+  for (o = dynobj->sections; o != NULL; o = o->next)
+    if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED))
+	== (SEC_HAS_CONTENTS|SEC_LINKER_CREATED)
+	&& o->output_section == reldyn)
+      size += o->_raw_size;
+
+  if (size != reldyn->_raw_size)
+    return 0;
+
+  rela = (struct elf_link_sort_rela *) calloc (sizeof (*rela), count);
+  if (rela == NULL)
+    {
+      (*info->callbacks->warning)
+	(info, _("Not enough memory to sort relocations"), 0, abfd, 0, 0);
+      return 0;
+    }
+
+  for (o = dynobj->sections; o != NULL; o = o->next)
+    if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED))
+	== (SEC_HAS_CONTENTS|SEC_LINKER_CREATED)
+	&& o->output_section == reldyn)
+      {
+	if (rel)
+	  {
+	    Elf_External_Rel *erel, *erelend;
+	    struct elf_link_sort_rela *s;
+
+	    erel = (Elf_External_Rel *) o->contents;
+	    erelend = (Elf_External_Rel *) ((PTR) o->contents + o->_raw_size);
+	    s = rela + o->output_offset / sizeof (Elf_External_Rel);
+	    for (; erel < erelend; erel++, s++)
+	      {
+		if (bed->s->swap_reloc_in)
+		  (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel, &s->u.rel);
+		else
+		  elf_swap_reloc_in (abfd, erel, &s->u.rel);
+
+		s->type = (*bed->elf_backend_reloc_type_class)
+			    (ELF_R_TYPE (s->u.rel.r_info));
+	      }	    
+	  }
+	else
+	  {
+	    Elf_External_Rela *erela, *erelaend;
+	    struct elf_link_sort_rela *s;
+
+	    erela = (Elf_External_Rela *) o->contents;
+	    erelaend = (Elf_External_Rela *) ((PTR) o->contents + o->_raw_size);
+	    s = rela + o->output_offset / sizeof (Elf_External_Rela);
+	    for (; erela < erelaend; erela++, s++)
+	      {
+		if (bed->s->swap_reloca_in)
+		  (*bed->s->swap_reloca_in) (dynobj, (bfd_byte *) erela, &s->u.rela);
+		else
+		  elf_swap_reloca_in (dynobj, erela, &s->u.rela);
+
+		s->type = (*bed->elf_backend_reloc_type_class)
+			    (ELF_R_TYPE (s->u.rel.r_info));
+	      }	    
+	  }
+      }
+
+  qsort (rela, count, sizeof (*rela), elf_link_sort_cmp1);
+  for (i = 0, j = 0; i < count && rela[i].type != reloc_class_relative; i++)
+    {
+      if (ELF_R_SYM (rela[i].u.rel.r_info) != ELF_R_SYM (rela[j].u.rel.r_info))
+	j = i;
+      rela[i].offset = rela[j].u.rel.r_offset;
+    }
+  ret = count - i;
+  qsort (rela, i, sizeof (*rela), elf_link_sort_cmp2);
+  
+  for (o = dynobj->sections; o != NULL; o = o->next)
+    if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED))
+	== (SEC_HAS_CONTENTS|SEC_LINKER_CREATED)
+	&& o->output_section == reldyn)
+      {
+	if (rel)
+	  {
+	    Elf_External_Rel *erel, *erelend;
+	    struct elf_link_sort_rela *s;
+
+	    erel = (Elf_External_Rel *) o->contents;
+	    erelend = (Elf_External_Rel *) ((PTR) o->contents + o->_raw_size);
+	    s = rela + o->output_offset / sizeof (Elf_External_Rel);
+	    for (; erel < erelend; erel++, s++)
+	      {
+		if (bed->s->swap_reloc_out)
+		  (*bed->s->swap_reloc_out) (abfd, &s->u.rel, (bfd_byte *) erel);
+		else
+		  elf_swap_reloc_out (abfd, &s->u.rel, erel);
+	      }
+	  }
+	else
+	  {
+	    Elf_External_Rela *erela, *erelaend;
+	    struct elf_link_sort_rela *s;
+
+	    erela = (Elf_External_Rela *) o->contents;
+	    erelaend = (Elf_External_Rela *) ((PTR) o->contents + o->_raw_size);
+	    s = rela + o->output_offset / sizeof (Elf_External_Rela);
+	    for (; erela < erelaend; erela++, s++)
+	      {
+		if (bed->s->swap_reloca_out)
+		  (*bed->s->swap_reloca_out) (dynobj, &s->u.rela, (bfd_byte *) erela);
+		else
+		  elf_swap_reloca_out (dynobj, &s->u.rela, erela);
+	      }	    
+	  }
+      }
+
+  free (rela);
+  *psec = reldyn;
+  return ret;
+}
+
 /* Do the final step of an ELF link.  */
 
 boolean
@@ -4296,6 +4508,8 @@ elf_bfd_final_link (abfd, info)
   struct elf_backend_data *bed = get_elf_backend_data (abfd);
   struct elf_outext_info eoinfo;
   boolean merged;
+  size_t relativecount = 0;
+  asection *reldyn = 0;
 
   if (info->shared)
     abfd->flags |= DYNAMIC;
@@ -4866,6 +5080,9 @@ elf_bfd_final_link (abfd, info)
       o->reloc_count = 0;
     }
 
+  if (dynamic && info->combreloc && dynobj != NULL)
+    relativecount = elf_link_sort_relocs (abfd, info, &reldyn);
+
   /* If we are linking against a dynamic object, or generating a
      shared library, finish up the dynamic linking information.  */
   if (dynamic)
@@ -4889,6 +5106,23 @@ elf_bfd_final_link (abfd, info)
 	  switch (dyn.d_tag)
 	    {
 	    default:
+	      break;
+	    case DT_NULL:
+	      if (relativecount > 0 && dyncon + 1 < dynconend)
+		{
+		  switch (elf_section_data (reldyn)->this_hdr.sh_type)
+		    {
+		    case SHT_REL: dyn.d_tag = DT_RELCOUNT; break;
+		    case SHT_RELA: dyn.d_tag = DT_RELACOUNT; break;
+		    default: break;
+		    }
+		  if (dyn.d_tag != DT_NULL)
+		    {
+		      dyn.d_un.d_val = relativecount;
+		      elf_swap_dyn_out (dynobj, &dyn, dyncon);
+		      relativecount = 0;
+		    }
+		}
 	      break;
 	    case DT_INIT:
 	      name = info->init_function;
--- bfd/elf32-sparc.c.jj	Wed Jul 11 16:59:53 2001
+++ bfd/elf32-sparc.c	Wed Aug 22 21:00:08 2001
@@ -52,6 +52,8 @@ static boolean elf32_sparc_object_p
   PARAMS ((bfd *));
 static void elf32_sparc_final_write_processing
   PARAMS ((bfd *, boolean));
+static enum elf_reloc_type_class elf32_sparc_reloc_type_class
+  PARAMS ((int));
 
 /* The relocation "howto" table.  */
 
@@ -592,6 +594,8 @@ elf32_sparc_check_relocs (abfd, info, se
 			  || ! bfd_set_section_alignment (dynobj, sreloc, 2))
 			return false;
 		    }
+		  if (sec->flags & SEC_READONLY)
+		    info->flags |= DF_TEXTREL;
 		}
 
 	      sreloc->_raw_size += sizeof (Elf32_External_Rela);
@@ -909,12 +913,11 @@ elf32_sparc_adjust_dynamic_symbol (info,
 
 static boolean
 elf32_sparc_size_dynamic_sections (output_bfd, info)
-     bfd *output_bfd;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
      struct bfd_link_info *info;
 {
   bfd *dynobj;
   asection *s;
-  boolean reltext;
   boolean relplt;
 
   dynobj = elf_hash_table (info)->dynobj;
@@ -952,7 +955,6 @@ elf32_sparc_size_dynamic_sections (outpu
   /* The check_relocs and adjust_dynamic_symbol entry points have
      determined the sizes of the various dynamic sections.  Allocate
      memory for them.  */
-  reltext = false;
   relplt = false;
   for (s = dynobj->sections; s != NULL; s = s->next)
     {
@@ -985,19 +987,6 @@ elf32_sparc_size_dynamic_sections (outpu
 	    }
 	  else
 	    {
-	      const char *outname;
-	      asection *target;
-
-	      /* If this relocation section applies to a read only
-		 section, then we probably need a DT_TEXTREL entry.  */
-	      outname = bfd_get_section_name (output_bfd,
-					      s->output_section);
-	      target = bfd_get_section_by_name (output_bfd, outname + 5);
-	      if (target != NULL
-		  && (target->flags & SEC_READONLY) != 0
-		  && (target->flags & SEC_ALLOC) != 0)
-		reltext = true;
-
 	      if (strcmp (name, ".rela.plt") == 0)
 		relplt = true;
 
@@ -1058,11 +1047,10 @@ elf32_sparc_size_dynamic_sections (outpu
 					    sizeof (Elf32_External_Rela)))
 	return false;
 
-      if (reltext)
+      if (info->flags & DF_TEXTREL)
 	{
 	  if (! bfd_elf32_add_dynamic_entry (info, DT_TEXTREL, 0))
 	    return false;
-	  info->flags |= DF_TEXTREL;
 	}
     }
 
@@ -2081,6 +2069,23 @@ elf32_sparc_final_write_processing (abfd
       break;
     }
 }
+
+static enum elf_reloc_type_class
+elf32_sparc_reloc_type_class (type)
+     int type;
+{
+  switch (type)
+    {
+    case R_SPARC_RELATIVE:
+      return reloc_class_relative;
+    case R_SPARC_JMP_SLOT:
+      return reloc_class_plt;
+    case R_SPARC_COPY:
+      return reloc_class_copy;
+    default:
+      return reloc_class_normal;
+    }
+}
 
 #define TARGET_BIG_SYM	bfd_elf32_sparc_vec
 #define TARGET_BIG_NAME	"elf32-sparc"
@@ -2111,6 +2116,7 @@ elf32_sparc_final_write_processing (abfd
 					elf32_sparc_final_write_processing
 #define elf_backend_gc_mark_hook        elf32_sparc_gc_mark_hook
 #define elf_backend_gc_sweep_hook       elf32_sparc_gc_sweep_hook
+#define elf_backend_reloc_type_class	elf32_sparc_reloc_type_class
 
 #define elf_backend_can_gc_sections 1
 #define elf_backend_want_got_plt 0
--- bfd/elf64-sparc.c.jj	Mon Aug 13 13:05:23 2001
+++ bfd/elf64-sparc.c	Wed Aug 22 20:51:38 2001
@@ -93,6 +93,7 @@ static boolean sparc64_elf_slurp_reloc_t
 static long sparc64_elf_canonicalize_dynamic_reloc
   PARAMS ((bfd *, arelent **, asymbol **));
 static void sparc64_elf_write_relocs PARAMS ((bfd *, asection *, PTR));
+static enum elf_reloc_type_class sparc64_elf_reloc_type_class PARAMS ((int));
 
 /* The relocation "howto" table.  */
 
@@ -1245,6 +1246,8 @@ sparc64_elf_check_relocs (abfd, info, se
 			  || ! bfd_set_section_alignment (dynobj, sreloc, 3))
 			return false;
 		    }
+		  if (sec->flags & SEC_READONLY)
+		    info->flags |= DF_TEXTREL;
 		}
 
 	      sreloc->_raw_size += sizeof (Elf64_External_Rela);
@@ -1663,7 +1666,6 @@ sparc64_elf_size_dynamic_sections (outpu
 {
   bfd *dynobj;
   asection *s;
-  boolean reltext;
   boolean relplt;
 
   dynobj = elf_hash_table (info)->dynobj;
@@ -1695,7 +1697,6 @@ sparc64_elf_size_dynamic_sections (outpu
   /* The check_relocs and adjust_dynamic_symbol entry points have
      determined the sizes of the various dynamic sections.  Allocate
      memory for them.  */
-  reltext = false;
   relplt = false;
   for (s = dynobj->sections; s != NULL; s = s->next)
     {
@@ -1728,18 +1729,6 @@ sparc64_elf_size_dynamic_sections (outpu
 	    }
 	  else
 	    {
-	      const char *outname;
-	      asection *target;
-
-	      /* If this relocation section applies to a read only
-		 section, then we probably need a DT_TEXTREL entry.  */
-	      outname = bfd_get_section_name (output_bfd,
-					      s->output_section);
-	      target = bfd_get_section_by_name (output_bfd, outname + 5);
-	      if (target != NULL
-		  && (target->flags & SEC_READONLY) != 0)
-		reltext = true;
-
 	      if (strcmp (name, ".rela.plt") == 0)
 		relplt = true;
 
@@ -1802,11 +1791,10 @@ sparc64_elf_size_dynamic_sections (outpu
 					    sizeof (Elf64_External_Rela)))
 	return false;
 
-      if (reltext)
+      if (info->flags & DF_TEXTREL)
 	{
 	  if (! bfd_elf64_add_dynamic_entry (info, DT_TEXTREL, 0))
 	    return false;
-	  info->flags |= DF_TEXTREL;
 	}
 
       /* Add dynamic STT_REGISTER symbols and corresponding DT_SPARC_REGISTER
@@ -2906,6 +2894,23 @@ sparc64_elf_finish_dynamic_sections (out
 
   return true;
 }
+
+static enum elf_reloc_type_class
+sparc64_elf_reloc_type_class (type)
+     int type;
+{
+  switch (type)
+    {
+    case R_SPARC_RELATIVE:
+      return reloc_class_relative;
+    case R_SPARC_JMP_SLOT:
+      return reloc_class_plt;
+    case R_SPARC_COPY:
+      return reloc_class_copy;
+    default:
+      return reloc_class_normal;
+    }
+}
 
 /* Functions for dealing with the e_flags field.  */
 
@@ -3157,6 +3162,8 @@ const struct elf_size_info sparc64_elf_s
   sparc64_elf_size_info
 #define elf_backend_object_p \
   sparc64_elf_object_p
+#define elf_backend_reloc_type_class \
+  sparc64_elf_reloc_type_class
 
 #define elf_backend_want_got_plt 0
 #define elf_backend_plt_readonly 0
--- bfd/elfxx-ia64.c.jj	Mon Aug 13 13:05:23 2001
+++ bfd/elfxx-ia64.c	Wed Aug 22 21:47:39 2001
@@ -138,6 +138,7 @@ struct elfNN_ia64_link_hash_table
   asection *rel_pltoff_sec;	/* dynamic relocation section for same */
 
   bfd_size_type minplt_entries;	/* number of minplt entries */
+  unsigned reltext : 1;		/* are there relocs against readonly sections? */
 
   struct elfNN_ia64_local_hash_table loc_hash_table;
 };
@@ -285,6 +286,8 @@ static boolean elfNN_ia64_merge_private_
   PARAMS ((bfd *ibfd, bfd *obfd));
 static boolean elfNN_ia64_print_private_bfd_data
   PARAMS ((bfd *abfd, PTR ptr));
+static enum elf_reloc_type_class elfNN_ia64_reloc_type_class
+  PARAMS ((int));
 
 /* ia64-specific relocation */
 
@@ -1901,6 +1904,9 @@ get_reloc_section (abfd, ia64_info, sec,
 	return NULL;
     }
 
+  if (sec->flags & SEC_READONLY)
+    ia64_info->reltext = 1;
+
   return srel;
 }
 
@@ -2520,7 +2526,6 @@ elfNN_ia64_size_dynamic_sections (output
   struct elfNN_ia64_link_hash_table *ia64_info;
   asection *sec;
   bfd *dynobj;
-  boolean reltext = false;
   boolean relplt = false;
 
   dynobj = elf_hash_table(info)->dynobj;
@@ -2677,24 +2682,6 @@ elfNN_ia64_size_dynamic_sections (output
 	    {
 	      if (!strip)
 		{
-		  const char *outname;
-		  asection *target;
-
-		  /* If this relocation section applies to a read only
-		     section, then we probably need a DT_TEXTREL entry.  */
-		  outname = bfd_get_section_name (output_bfd,
-						  sec->output_section);
-		  if (outname[4] == 'a')
-		    outname += 5;
-		  else
-		    outname += 4;
-
-		  target = bfd_get_section_by_name (output_bfd, outname);
-		  if (target != NULL
-		      && (target->flags & SEC_READONLY) != 0
-		      && (target->flags & SEC_ALLOC) != 0)
-		    reltext = true;
-
 		  /* We use the reloc_count field as a counter if we need to
 		     copy relocs into the output file.  */
 		  sec->reloc_count = 0;
@@ -2748,7 +2735,7 @@ elfNN_ia64_size_dynamic_sections (output
 					    sizeof (ElfNN_External_Rela)))
 	return false;
 
-      if (reltext)
+      if (ia64_info->reltext)
 	{
 	  if (! bfd_elfNN_add_dynamic_entry (info, DT_TEXTREL, 0))
 	    return false;
@@ -4309,6 +4296,27 @@ elfNN_ia64_print_private_bfd_data (abfd,
   _bfd_elf_print_private_bfd_data (abfd, ptr);
   return true;
 }
+
+static enum elf_reloc_type_class
+elfNN_ia64_reloc_type_class (type)
+     int type;
+{
+  switch (type)
+    {
+    case R_IA64_REL32MSB:
+    case R_IA64_REL32LSB:
+    case R_IA64_REL64MSB:
+    case R_IA64_REL64LSB:
+      return reloc_class_relative;
+    case R_IA64_IPLTMSB:
+    case R_IA64_IPLTLSB:
+      return reloc_class_plt;
+    case R_IA64_COPY:
+      return reloc_class_copy;
+    default:
+      return reloc_class_normal;
+    }
+}
 
 #define TARGET_LITTLE_SYM		bfd_elfNN_ia64_little_vec
 #define TARGET_LITTLE_NAME		"elfNN-ia64-little"
@@ -4385,6 +4393,7 @@ elfNN_ia64_print_private_bfd_data (abfd,
 #define elf_backend_want_dynbss		0
 #define elf_backend_copy_indirect_symbol elfNN_ia64_hash_copy_indirect
 #define elf_backend_hide_symbol		elfNN_ia64_hash_hide_symbol
+#define elf_backend_reloc_type_class	elfNN_ia64_reloc_type_class
 
 #include "elfNN-target.h"
 
--- include/bfdlink.h.jj	Mon Aug 13 13:05:43 2001
+++ include/bfdlink.h	Wed Aug 22 18:17:05 2001
@@ -275,9 +275,16 @@ struct bfd_link_info
   /* May be used to set DT_FLAGS_1 for ELF. */
   bfd_vma flags_1;
 
-  /* true if auto-import thunks for DATA items in pei386 DLLs 
+  /* True if auto-import thunks for DATA items in pei386 DLLs 
      should be generated/linked against.  */
   boolean pei386_auto_import;
+
+  /* True if non-PLT relocs should be merged into one reloc section
+     and sorted so that relocs against the same symbol come together.  */
+  boolean combreloc;
+
+  /* How many spare .dynamic DT_NULL entries should be added?  */
+  int spare_dynamic_tags;
 };
 
 /* This structures holds a set of callback functions.  These are
--- ld/emultempl/elf32.em.jj	Wed Aug 15 17:16:15 2001
+++ ld/emultempl/elf32.em	Wed Aug 15 17:17:30 2001
@@ -1135,7 +1135,25 @@ gld${EMULATION_NAME}_place_orphan (file,
   else if (strncmp (secname, ".rel", 4) == 0
 	   && (hold_rel.os != NULL
 	       || (hold_rel.os = output_rel_find ()) != NULL))
-    place = &hold_rel;
+    {
+      if (! link_info.relocateable && link_info.combreloc)
+	{
+	  if (strncmp (secname, ".rela", 5) == 0)
+	    os = lang_output_section_find (".rela.dyn");
+	  else
+	    os = lang_output_section_find (".rel.dyn");
+
+	  if (os != NULL
+	      && os->bfd_section != NULL
+	      && ((s->flags ^ os->bfd_section->flags)
+		  & (SEC_LOAD | SEC_ALLOC)) == 0)
+	    {
+	      lang_add_section (&os->children, s, os, file);
+	      return true;
+	    }
+	}
+      place = &hold_rel;
+    }
   else if ((s->flags & (SEC_CODE | SEC_READONLY)) == SEC_READONLY
 	   && HAVE_SECTION (hold_rodata, ".rodata"))
     place = &hold_rodata;
@@ -1332,14 +1350,18 @@ echo '  ; else if (link_info.relocateabl
 sed $sc ldscripts/${EMULATION_NAME}.xr                     >> e${EMULATION_NAME}.c
 echo '  ; else if (!config.text_read_only) return'         >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xbn                    >> e${EMULATION_NAME}.c
+if ! cmp -s ldscripts/${EMULATION_NAME}.x ldscripts/${EMULATION_NAME}.xn; then
 echo '  ; else if (!config.magic_demand_paged) return'     >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xn                     >> e${EMULATION_NAME}.c
-
+fi
 if test -n "$GENERATE_SHLIB_SCRIPT" ; then
+echo '  ; else if (link_info.shared && link_info.combreloc) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xsc                    >> e${EMULATION_NAME}.c
 echo '  ; else if (link_info.shared) return'		   >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xs                     >> e${EMULATION_NAME}.c
 fi
-
+echo '  ; else if (link_info.combreloc) return'            >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xc                     >> e${EMULATION_NAME}.c
 echo '  ; else return'                                     >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.x                      >> e${EMULATION_NAME}.c
 echo '; }'                                                 >> e${EMULATION_NAME}.c
@@ -1492,6 +1514,10 @@ cat >>e${EMULATION_NAME}.c <<EOF
 	}
       else if (strcmp (optarg, "defs") == 0)
 	link_info.no_undefined = true;
+      else if (strcmp (optarg, "combreloc") == 0)
+	link_info.combreloc = true;
+      else if (strcmp (optarg, "nocombreloc") == 0)
+	link_info.combreloc = false;
       /* What about the other Solaris -z options? FIXME.  */
       break;
 EOF
--- ld/scripttempl/elf.sc.jj	Mon Aug 13 13:05:58 2001
+++ ld/scripttempl/elf.sc	Wed Aug 15 17:16:55 2001
@@ -145,6 +145,13 @@ SECTIONS
   .gnu.version_d ${RELOCATING-0} : { *(.gnu.version_d)	}
   .gnu.version_r ${RELOCATING-0} : { *(.gnu.version_r)	}
 
+EOF
+if [ "x$COMBRELOC" = x ]; then
+  COMBRELOCCAT=cat
+else
+  COMBRELOCCAT="cat > $COMBRELOC"
+fi
+eval $COMBRELOCCAT <<EOF
   .rel.init    ${RELOCATING-0} : { *(.rel.init)	}
   .rela.init   ${RELOCATING-0} : { *(.rela.init)	}
   .rel.text    ${RELOCATING-0} :
@@ -215,7 +222,7 @@ SECTIONS
     {
       *(.rela.sbss)
       ${RELOCATING+*(.rela.sbss.*)}
-      ${RELOCATING+*(.rel.gnu.linkonce.sb.*)}
+      ${RELOCATING+*(.rela.gnu.linkonce.sb.*)}
     }
   .rel.sdata2  ${RELOCATING-0} : 
     { 
@@ -253,6 +260,24 @@ SECTIONS
       ${RELOCATING+*(.rela.bss.*)}
       ${RELOCATING+*(.rela.gnu.linkonce.b.*)}
     }
+EOF
+if [ -n "$COMBRELOC" ]; then
+cat <<EOF
+  .rel.dyn	 :
+    {
+EOF
+sed -e '/^[ 	]*[{}][ 	]*$/d;/:[ 	]*$/d;/\.rela\./d;s/^.*: { *\(.*\)}$/      \1/' $COMBRELOC
+cat <<EOF
+    }
+  .rela.dyn	 :
+    {
+EOF
+sed -e '/^[ 	]*[{}][ 	]*$/d;/:[ 	]*$/d;/\.rel\./d;s/^.*: { *\(.*\)}/      \1/' $COMBRELOC
+cat <<EOF
+    }
+EOF
+fi
+cat <<EOF
   .rel.plt     ${RELOCATING-0} : { *(.rel.plt)		}
   .rela.plt    ${RELOCATING-0} : { *(.rela.plt)		}
   ${OTHER_PLT_RELOC_SECTIONS}
--- ld/genscripts.sh.jj	Mon Aug 13 13:05:50 2001
+++ ld/genscripts.sh	Wed Aug 22 18:22:30 2001
@@ -84,6 +84,17 @@ LIB_SEARCH_DIRS=`echo ${LIB_PATH} | tr '
 # A .xs script is for generating a shared library with the --shared
 #   flag; it is only generated if $GENERATE_SHLIB_SCRIPT is set by the
 #   emulation parameters.
+# A .xc script is for linking with -z combreloc; it is only generated if
+#   $GENERATE_COMBRELOC_SCRIPT is set by the emulation parameters or
+#   $SCRIPT_NAME is "elf".
+# A .xsc script is for linking with --shared -z combreloc; it is generated
+#   if $GENERATE_COMBRELOC_SCRIPT is set by the emulation parameters or
+#   $SCRIPT_NAME is "elf" and $GENERATE_SHLIB_SCRIPT is set by the emulation
+#   parameters too.
+
+if [ "x$SCRIPT_NAME" = "xelf" ]; then
+  GENERATE_COMBRELOC_SCRIPT=yes
+fi
 
 SEGMENT_SIZE=${SEGMENT_SIZE-${TARGET_PAGE_SIZE}}
 
@@ -101,34 +112,45 @@ DATA_ALIGNMENT=${DATA_ALIGNMENT_r}
 DEFAULT_DATA_ALIGNMENT="ALIGN(${SEGMENT_SIZE})"
 ( . ${srcdir}/emulparams/${EMULATION_NAME}.sh
   . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
-) | sed -e '/^ *$/d' > ldscripts/${EMULATION_NAME}.xr
+) | sed -e '/^ *$/d;s/[ 	]*$//' > ldscripts/${EMULATION_NAME}.xr
 
 LD_FLAG=u
 DATA_ALIGNMENT=${DATA_ALIGNMENT_u}
 CONSTRUCTING=" "
 ( . ${srcdir}/emulparams/${EMULATION_NAME}.sh
   . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
-) | sed -e '/^ *$/d' > ldscripts/${EMULATION_NAME}.xu
+) | sed -e '/^ *$/d;s/[ 	]*$//' > ldscripts/${EMULATION_NAME}.xu
 
 LD_FLAG=
 DATA_ALIGNMENT=${DATA_ALIGNMENT_}
 RELOCATING=" "
 ( . ${srcdir}/emulparams/${EMULATION_NAME}.sh
   . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
-) | sed -e '/^ *$/d' > ldscripts/${EMULATION_NAME}.x
+) | sed -e '/^ *$/d;s/[ 	]*$//' > ldscripts/${EMULATION_NAME}.x
 
 LD_FLAG=n
 DATA_ALIGNMENT=${DATA_ALIGNMENT_n}
 TEXT_START_ADDR=${NONPAGED_TEXT_START_ADDR-${TEXT_START_ADDR}}
 ( . ${srcdir}/emulparams/${EMULATION_NAME}.sh
   . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
-) | sed -e '/^ *$/d' > ldscripts/${EMULATION_NAME}.xn
+) | sed -e '/^ *$/d;s/[ 	]*$//' > ldscripts/${EMULATION_NAME}.xn
 
 LD_FLAG=N
 DATA_ALIGNMENT=${DATA_ALIGNMENT_N}
 ( . ${srcdir}/emulparams/${EMULATION_NAME}.sh
   . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
-) | sed -e '/^ *$/d' > ldscripts/${EMULATION_NAME}.xbn
+) | sed -e '/^ *$/d;s/[ 	]*$//' > ldscripts/${EMULATION_NAME}.xbn
+
+if test -n "$GENERATE_COMBRELOC_SCRIPT"; then
+  DATA_ALIGNMENT=${DATA_ALIGNMENT_c-${DATA_ALIGNMENT_}}
+  LD_FLAG=c
+  COMBRELOC=ldscripts/${EMULATION_NAME}.xc.tmp
+  ( . ${srcdir}/emulparams/${EMULATION_NAME}.sh
+    . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+  ) | sed -e '/^ *$/d;s/[ 	]*$//' > ldscripts/${EMULATION_NAME}.xc
+  rm -f ${COMBRELOC}
+  COMBRELOC=
+fi
 
 if test -n "$GENERATE_SHLIB_SCRIPT"; then
   LD_FLAG=shared
@@ -137,7 +159,17 @@ if test -n "$GENERATE_SHLIB_SCRIPT"; the
   # Note that TEXT_START_ADDR is set to NONPAGED_TEXT_START_ADDR.
   ( . ${srcdir}/emulparams/${EMULATION_NAME}.sh
     . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
-  ) | sed -e '/^ *$/d' > ldscripts/${EMULATION_NAME}.xs
+  ) | sed -e '/^ *$/d;s/[ 	]*$//' > ldscripts/${EMULATION_NAME}.xs
+  if test -n "$GENERATE_COMBRELOC_SCRIPT"; then
+    LD_FLAG=cshared
+    DATA_ALIGNMENT=${DATA_ALIGNMENT_sc-${DATA_ALIGNMENT}}
+    COMBRELOC=ldscripts/${EMULATION_NAME}.xc.tmp
+    ( . ${srcdir}/emulparams/${EMULATION_NAME}.sh
+      . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+    ) | sed -e '/^ *$/d;s/[ 	]*$//' > ldscripts/${EMULATION_NAME}.xsc
+    rm -f ${COMBRELOC}
+    COMBRELOC=
+  fi
 fi
 
 for i in $EMULATION_LIBPATH ; do
--- ld/ldmain.c.jj	Mon Aug 13 13:10:57 2001
+++ ld/ldmain.c	Fri Aug 17 21:08:03 2001
@@ -244,6 +244,8 @@ main (argc, argv)
   link_info.flags = (bfd_vma) 0;
   link_info.flags_1 = (bfd_vma) 0;
   link_info.pei386_auto_import = false;
+  link_info.combreloc = false;
+  link_info.spare_dynamic_tags = 5;
 
   ldfile_add_arch ("");
 
--- ld/lexsup.c.jj	Mon Aug 13 13:05:50 2001
+++ ld/lexsup.c	Wed Aug 15 17:16:55 2001
@@ -131,6 +131,7 @@ int parsing_defsym = 0;
 #define OPTION_TARGET_HELP              (OPTION_UNIQUE + 1)
 #define OPTION_ALLOW_SHLIB_UNDEFINED	(OPTION_TARGET_HELP + 1)
 #define OPTION_DISCARD_NONE		(OPTION_ALLOW_SHLIB_UNDEFINED + 1)
+#define OPTION_SPARE_DYNAMIC_TAGS	(OPTION_DISCARD_NONE + 1)
 
 /* The long options.  This structure is used for both the option
    parsing and the help text.  */
@@ -347,6 +348,8 @@ static const struct ld_option ld_options
       '\0', NULL, N_("Sort common symbols by size"), TWO_DASHES },
   { {"sort_common", no_argument, NULL, OPTION_SORT_COMMON},
       '\0', NULL, NULL, NO_HELP },
+  { {"spare-dynamic-tags", required_argument, NULL, OPTION_SPARE_DYNAMIC_TAGS},
+      '\0', N_("COUNT"), N_("How many tags to reserve in .dynamic section"), TWO_DASHES },
   { {"split-by-file", optional_argument, NULL, OPTION_SPLIT_BY_FILE},
       '\0', N_("[=SIZE]"), N_("Split output sections every SIZE octets"), TWO_DASHES },
   { {"split-by-reloc", optional_argument, NULL, OPTION_SPLIT_BY_RELOC},
@@ -1072,6 +1075,9 @@ the GNU General Public License.  This pr
 	  break;
 	case 'y':
 	  add_ysym (optarg);
+	  break;
+	case OPTION_SPARE_DYNAMIC_TAGS:
+	  link_info.spare_dynamic_tags = strtoul (optarg, NULL, 0);
 	  break;
 	case OPTION_SPLIT_BY_RELOC:
 	  if (optarg != NULL)
--- ld/ld.texinfo.jj	Mon Aug 13 13:05:50 2001
+++ ld/ld.texinfo	Wed Aug 22 18:20:17 2001
@@ -840,7 +840,8 @@ for Solaris compatibility.
 @item -z @var{keyword}
 The recognized keywords are @code{initfirst}, @code{interpose},
 @code{loadfltr}, @code{nodefaultlib}, @code{nodelete}, @code{nodlopen},
-@code{nodump}, @code{now} and @code{origin}. The other keywords are
+@code{nodump}, @code{now}, @code{origin}, @code{combreloc} and
+@code{nocombreloc}. The other keywords are
 ignored for Solaris compatibility. @code{initfirst} marks the object
 to be initialized first at runtime before any other objects.
 @code{interpose} marks the object that its symbol table interposes
@@ -854,6 +855,9 @@ of this object will ignore any default l
 @code{now} marks the object with the non-lazy runtime binding.
 @code{origin} marks the object may contain $ORIGIN.
 @code{defs} disallows undefined symbols.
+@code{combreloc} combines multiple reloc sections and sorts them
+to make dynamic symbol lookup caching possible.
+@code{nocombreloc} disables multiple reloc sections combining.
 
 @kindex -(
 @cindex groups of archives
--- ld/ldint.texinfo.jj	Mon Aug 13 13:05:50 2001
+++ ld/ldint.texinfo	Wed Aug 22 18:35:46 2001
@@ -239,7 +239,7 @@ If @code{SCRIPT_NAME} is set to @var{scr
 invoke @file{scripttempl/@var{script}.sc}.
 
 The @file{genscripts.sh} script will invoke the @file{scripttempl}
-script 5 or 6 times.  Each time it will set the shell variable
+script 5 to 8 times.  Each time it will set the shell variable
 @code{LD_FLAG} to a different value.  When the linker is run, the
 options used will direct it to select a particular script.  (Script
 selection is controlled by the @code{get_script} emulation entry point;
@@ -278,6 +278,22 @@ this value if @code{GENERATE_SHLIB_SCRIP
 this script at the appropriate time, normally when the linker is invoked
 with the @code{-shared} option.  The output has an extension of
 @file{.xs}.
+@item c
+The @file{scripttempl} script is only invoked with @code{LD_FLAG} set to
+this value if @code{GENERATE_COMBRELOC_SCRIPT} is defined in the
+@file{emulparams} file or if @code{SCRIPT_NAME} is @code{elf}. The
+@file{emultempl} script must arrange to use this script at the appropriate
+time, normally when the linker is invoked with the @code{-z combreloc}
+option.  The output has an extension of
+@file{.xc}.
+@item cshared
+The @file{scripttempl} script is only invoked with @code{LD_FLAG} set to
+this value if @code{GENERATE_COMBRELOC_SCRIPT} is defined in the
+@file{emulparams} file or if @code{SCRIPT_NAME} is @code{elf} and
+@code{GENERATE_SHLIB_SCRIPT} is defined in the @file{emulparms} file.
+The @file{emultempl} script must arrange to use this script at the
+appropriate time, normally when the linker is invoked with the @code{-shared
+-z combreloc} option.  The output has an extension of @file{.xsc}.
 @end table
 
 Besides the shell variables set by the @file{emulparams} script, and the
@@ -301,6 +317,10 @@ page aligned, or to @samp{.} when genera
 @item CREATE_SHLIB
 This will be set to a non-empty string when generating a @code{-shared}
 script.
+
+@item COMBRELOC
+This will be set to a non-empty string when generating @code{-z combreloc}
+scripts to a temporary file name which can be used during script generation.
 @end table
 
 The conventional way to write a @file{scripttempl} script is to first
--- ld/NEWS.jj	Mon Dec 11 14:49:46 2000
+++ ld/NEWS	Wed Aug 22 18:45:13 2001
@@ -1,5 +1,11 @@
 -*- text -*-
 
+* Support for -z combreloc in the ELF linker, which puts dynamic
+  relocations against the same symbol together, so that dynamic linker
+  can use an one-entry symbol lookup cache.
+
+* Support for ELF SHF_MERGE section merging, by Jakub Jelinek.
+
 * Support for AMD x86-64 architecture, by Jan Hubicka, SuSE Labs.
 
 * Support added for eliminating duplicate DWARF2 debug information by


	Jakub


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