This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
[PATCH] Support -z combreloc in binutils
- To: binutils at sources dot redhat dot com, drepper at redhat dot com
- Subject: [PATCH] Support -z combreloc in binutils
- From: Jakub Jelinek <jakub at redhat dot com>
- Date: Wed, 15 Aug 2001 17:30:30 +0200
- Reply-To: Jakub Jelinek <jakub at redhat dot com>
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