public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] Support -z combreloc in binutils
@ 2001-08-15  8:27 Jakub Jelinek
  2001-08-15 23:56 ` Andreas Jaeger
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Jakub Jelinek @ 2001-08-15  8:27 UTC (permalink / raw)
  To: binutils, drepper

Hi!

This patch adds support for ld -z combreloc, which instead of creating usual
zillions of .rel* resp. .rela* sections just creates one big (in addition to
.rel.plt/.rela.plt or PLT-like rela section) .rel.dyn resp. .rela.dyn
section with all dynamic relocations.
This section is sorted if possible by increasing r_offset, with the
exception that if there are multiple relocs against the same symbol, they
are grouped together (which allows the dynamic linker to have a single entry
cache for symbol lookups).
In addition to this, it sets DT_RELCOUNT resp. DT_RELACOUNT dynamic tag in
the way Solaris linker uses it (and compatible to the Solaris way, which is
IMHO broken - R_*_RELATIVE symbols come last, not first), so that if a
library has l_addr 0, all the R_*_RELATIVE relocs can be skipped for free.
I tried to implement this so that only minimal changes in elf backends are
needed (each backend just needs to provide function which categorizes reloc
types: relative, plt, copy relocs or other relocs).
Also, it reserves a few entries for use in prelinking, but user can disable
this (this is necessary for DT_REL*COUNT too, since I don't want to create
it if no relative relocs are found).

2001-08-15  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_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.

--- bfd/elf-bfd.h.jj	Mon Aug 13 13:05:23 2001
+++ bfd/elf-bfd.h	Wed Aug 15 17:16:55 2001
@@ -331,6 +331,14 @@ 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 +644,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 +1016,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 15 17:16:55 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 */
 
@@ -2215,6 +2216,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 +2263,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 15 17:16:55 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,212 @@ 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 +4510,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 +5082,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 +5108,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;
--- include/bfdlink.h.jj	Mon Aug 13 13:05:43 2001
+++ include/bfdlink.h	Wed Aug 15 17:16:55 2001
@@ -278,6 +278,13 @@ struct bfd_link_info
   /* 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 15 17:16:55 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=
+  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,16 @@ 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
+    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	Wed Aug 15 17:16:55 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)

	Jakub

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

* Re: [PATCH] Support -z combreloc in binutils
  2001-08-15  8:27 [PATCH] Support -z combreloc in binutils Jakub Jelinek
@ 2001-08-15 23:56 ` Andreas Jaeger
  2001-08-16  0:08   ` Jakub Jelinek
  2001-08-16  0:17   ` H . J . Lu
  2001-08-16  2:22 ` Andreas Jaeger
  2001-08-21  9:45 ` Nick Clifton
  2 siblings, 2 replies; 9+ messages in thread
From: Andreas Jaeger @ 2001-08-15 23:56 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: binutils, drepper

Jakub Jelinek <jakub@redhat.com> writes:

> Hi!
>
> This patch adds support for ld -z combreloc, which instead of creating usual
> zillions of .rel* resp. .rela* sections just creates one big (in addition to
> .rel.plt/.rela.plt or PLT-like rela section) .rel.dyn resp. .rela.dyn
> section with all dynamic relocations.
> This section is sorted if possible by increasing r_offset, with the
> exception that if there are multiple relocs against the same symbol, they
> are grouped together (which allows the dynamic linker to have a single entry
> cache for symbol lookups).
> In addition to this, it sets DT_RELCOUNT resp. DT_RELACOUNT dynamic tag in
> the way Solaris linker uses it (and compatible to the Solaris way, which is
> IMHO broken - R_*_RELATIVE symbols come last, not first), so that if a
> library has l_addr 0, all the R_*_RELATIVE relocs can be skipped for free.
> I tried to implement this so that only minimal changes in elf backends are
> needed (each backend just needs to provide function which categorizes reloc
> types: relative, plt, copy relocs or other relocs).
> Also, it reserves a few entries for use in prelinking, but user can disable
> this (this is necessary for DT_REL*COUNT too, since I don't want to create
> it if no relative relocs are found).

Shouldn't combreloc be the default - at least on glibc platforms?
After changing the dynamic linker to cache the last value used for
relocation, this option would speed up relocations at system start up.

Thanks for a great patch,
Andreas
-- 
 Andreas Jaeger
  SuSE Labs aj@suse.de
   private aj@arthur.inka.de
    http://www.suse.de/~aj

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

* Re: [PATCH] Support -z combreloc in binutils
  2001-08-15 23:56 ` Andreas Jaeger
@ 2001-08-16  0:08   ` Jakub Jelinek
  2001-08-16  0:17   ` H . J . Lu
  1 sibling, 0 replies; 9+ messages in thread
From: Jakub Jelinek @ 2001-08-16  0:08 UTC (permalink / raw)
  To: Andreas Jaeger; +Cc: binutils, drepper

On Thu, Aug 16, 2001 at 08:56:16AM +0200, Andreas Jaeger wrote:
> Shouldn't combreloc be the default - at least on glibc platforms?
> After changing the dynamic linker to cache the last value used for
> relocation, this option would speed up relocations at system start up.

Sure, it should. That's why I added -z nocombreloc which Solaris ld doesn't
have.
But I'd prefer this tested a lot before making it the default.
E.g. it is unclear how it will work together on mips with its own .rel.dyn
handling. I think it should and perhaps the mips special cases could go away
(with the exception of adding a R_MIPS_NONE reloc first), but it needs some
mips hacker to test it out...
(note that unlike this -z combreloc, mips .rel.dyn is sorted strictly by
increasing ELF_R_SYM, which is IMHO a bad decision because of locality).

	Jakub

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

* Re: [PATCH] Support -z combreloc in binutils
  2001-08-15 23:56 ` Andreas Jaeger
  2001-08-16  0:08   ` Jakub Jelinek
@ 2001-08-16  0:17   ` H . J . Lu
  1 sibling, 0 replies; 9+ messages in thread
From: H . J . Lu @ 2001-08-16  0:17 UTC (permalink / raw)
  To: Andreas Jaeger; +Cc: Jakub Jelinek, binutils, drepper

On Thu, Aug 16, 2001 at 08:56:16AM +0200, Andreas Jaeger wrote:
> 
> Shouldn't combreloc be the default - at least on glibc platforms?
> After changing the dynamic linker to cache the last value used for
> relocation, this option would speed up relocations at system start up.
> 

I prefer to do it in the gcc driver, just like how we handle ld.so.
In this way, we have fewer linkers on a given arch/format.


H.J.

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

* Re: [PATCH] Support -z combreloc in binutils
  2001-08-15  8:27 [PATCH] Support -z combreloc in binutils Jakub Jelinek
  2001-08-15 23:56 ` Andreas Jaeger
@ 2001-08-16  2:22 ` Andreas Jaeger
  2001-08-21  9:45 ` Nick Clifton
  2 siblings, 0 replies; 9+ messages in thread
From: Andreas Jaeger @ 2001-08-16  2:22 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: binutils, drepper

Jakub,

I tested the patch on i686-linux with current CVS.  The patch itself
passed the testsuite but then I changed ldmain.c to always use
combreloc:
  link_info.combreloc = true;

Now I get lots of test failures in the ld testsuite:
                === ld Summary ===

# of expected passes            92
# of unexpected failures        14
# of expected failures          1

$ grep -B1 FAIL ld.log 
child killed: segmentation violation
FAIL: visibility (hidden_normal) (non PIC)
--
child killed: segmentation violation
FAIL: visibility (hidden_normal) (PIC main, non PIC so)
--
child killed: segmentation violation
FAIL: visibility (hidden_weak) (non PIC)
--
child killed: segmentation violation
FAIL: visibility (hidden_weak) (PIC main, non PIC so)
--
child killed: segmentation violation
FAIL: visibility (protected) (non PIC)
--
child killed: segmentation violation
FAIL: visibility (protected) (PIC main, non PIC so)
--
child killed: segmentation violation
FAIL: visibility (protected_undef_def) (non PIC)
--
child killed: segmentation violation
FAIL: visibility (protected_undef_def) (PIC main, non PIC so)
--
child killed: segmentation violation
FAIL: visibility (protected_weak) (non PIC)
--
child killed: segmentation violation
FAIL: visibility (protected_weak) (PIC main, non PIC so)
--
child killed: segmentation violation
FAIL: visibility (normal) (non PIC)
--
child killed: segmentation violation
FAIL: visibility (normal) (PIC main, non PIC so)
--
selective6: A::foo() == nm_output(A::foo(void))
XFAIL: selective6
--
child killed: segmentation violation
FAIL: shared (non PIC)
--
child killed: segmentation violation
FAIL: shared (PIC main, non PIC so)

It looks like -z combreloc is either broken - or will not work with an
unpatched glibc 2.2.2,

Andreas
-- 
 Andreas Jaeger
  SuSE Labs aj@suse.de
   private aj@arthur.inka.de
    http://www.suse.de/~aj

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

* Re: [PATCH] Support -z combreloc in binutils
  2001-08-15  8:27 [PATCH] Support -z combreloc in binutils Jakub Jelinek
  2001-08-15 23:56 ` Andreas Jaeger
  2001-08-16  2:22 ` Andreas Jaeger
@ 2001-08-21  9:45 ` Nick Clifton
  2001-08-21  9:51   ` Jakub Jelinek
  2001-08-22 23:16   ` [PATCH] Support -z combreloc in binutils (take 2) Jakub Jelinek
  2 siblings, 2 replies; 9+ messages in thread
From: Nick Clifton @ 2001-08-21  9:45 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: binutils, drepper

Hi Jakub,

> This patch adds support for ld -z combreloc, which instead of
> creating usual zillions of .rel* resp. .rela* sections just creates
> one big (in addition to .rel.plt/.rela.plt or PLT-like rela section)
> .rel.dyn resp. .rela.dyn section with all dynamic relocations.

> 2001-08-15  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_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.

Approved.  Please apply this patch, but if possible, please also make
the following minor formatting changes:

> +enum elf_reloc_type_class
> +{
> +  reloc_class_normal,
> +  reloc_class_relative,
> +  reloc_class_plt,
> +  reloc_class_copy
> +};

This violates the GNU coding standard.  Either indent the curly braces
so that they are not in column one (my preferred solution) or move the
opening curly brace to the end of the previous line (the more common
solution).

> +struct elf_link_sort_rela
> +{
> +  bfd_vma offset;
> +  enum elf_reloc_type_class type;
> +  union
> +    {
> +      Elf_Internal_Rel rel;
> +      Elf_Internal_Rela rela;
> +    } u;
> +};

Ditto.

> +  /* 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;

Despite the example in the comment before this one, I believe that
this sentence should start with a capital letter.


Also - please could you an entry to ld.texinfo documenting the new
command line switch, an entry to ldint.texinfo describing the new .xc
file and an entry to NEWS describing the new linker feature.

Cheers
        Nick

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

* Re: [PATCH] Support -z combreloc in binutils
  2001-08-21  9:45 ` Nick Clifton
@ 2001-08-21  9:51   ` Jakub Jelinek
  2001-08-22 23:16   ` [PATCH] Support -z combreloc in binutils (take 2) Jakub Jelinek
  1 sibling, 0 replies; 9+ messages in thread
From: Jakub Jelinek @ 2001-08-21  9:51 UTC (permalink / raw)
  To: Nick Clifton; +Cc: binutils, drepper

On Tue, Aug 21, 2001 at 05:41:52PM +0100, Nick Clifton wrote:
> Approved.  Please apply this patch, but if possible, please also make
> the following minor formatting changes:

Unfortunately, the patch does not work properly as pointed out by AJ.
Namely, it fails to set DT_TEXTREL with -z combreloc due the way reltext is
computed which does not work any longer. The last solution I tried did not
pass ld bootstrap test, so it has to wait till I find more time for it
(hopefully this week).
I'll incorporate those changes in once I get it working.

	Jakub

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

* [PATCH] Support -z combreloc in binutils (take 2)
  2001-08-21  9:45 ` Nick Clifton
  2001-08-21  9:51   ` Jakub Jelinek
@ 2001-08-22 23:16   ` Jakub Jelinek
  2001-08-23  1:34     ` Nick Clifton
  1 sibling, 1 reply; 9+ messages in thread
From: Jakub Jelinek @ 2001-08-22 23:16 UTC (permalink / raw)
  To: Nick Clifton, aj, drepper; +Cc: binutils

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));
 \f
 /* 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;
+    }
+}
 \f
 #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));
 \f
 /* 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;
+    }
+}
 \f
 /* 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));
 \f
 /* 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;
+    }
+}
 \f
 #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

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

* Re: [PATCH] Support -z combreloc in binutils (take 2)
  2001-08-22 23:16   ` [PATCH] Support -z combreloc in binutils (take 2) Jakub Jelinek
@ 2001-08-23  1:34     ` Nick Clifton
  0 siblings, 0 replies; 9+ messages in thread
From: Nick Clifton @ 2001-08-23  1:34 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: aj, drepper, binutils

Hi Jakub,

> 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.

Approved.  Please check in at your leisure!

Cheers
        Nick

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

end of thread, other threads:[~2001-08-23  1:34 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-08-15  8:27 [PATCH] Support -z combreloc in binutils Jakub Jelinek
2001-08-15 23:56 ` Andreas Jaeger
2001-08-16  0:08   ` Jakub Jelinek
2001-08-16  0:17   ` H . J . Lu
2001-08-16  2:22 ` Andreas Jaeger
2001-08-21  9:45 ` Nick Clifton
2001-08-21  9:51   ` Jakub Jelinek
2001-08-22 23:16   ` [PATCH] Support -z combreloc in binutils (take 2) Jakub Jelinek
2001-08-23  1:34     ` Nick Clifton

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