diff options
author | Jakub Jelinek <jakub@redhat.com> | 2001-08-23 15:14:18 +0000 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2001-08-23 15:14:18 +0000 |
commit | db6751f2e760a6a65ab297b83942951b9aea3b79 (patch) | |
tree | 54f3e4f79ab1a218ff657703ad47ff331d756dd2 | |
parent | da4d4077bcdd5d25d56c0d216a2ff9009cb60649 (diff) | |
download | gdb-db6751f2e760a6a65ab297b83942951b9aea3b79.zip gdb-db6751f2e760a6a65ab297b83942951b9aea3b79.tar.gz gdb-db6751f2e760a6a65ab297b83942951b9aea3b79.tar.bz2 |
* 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.
(elfNN_ia64_hash_table_create): Clear ia64_info.
(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.
-rw-r--r-- | bfd/ChangeLog | 41 | ||||
-rw-r--r-- | bfd/elf-bfd.h | 14 | ||||
-rw-r--r-- | bfd/elf.c | 7 | ||||
-rw-r--r-- | bfd/elf32-i386.c | 50 | ||||
-rw-r--r-- | bfd/elf32-sparc.c | 42 | ||||
-rw-r--r-- | bfd/elf64-sparc.c | 39 | ||||
-rw-r--r-- | bfd/elflink.h | 238 | ||||
-rw-r--r-- | bfd/elfxx-ia64.c | 51 | ||||
-rw-r--r-- | bfd/elfxx-target.h | 4 | ||||
-rw-r--r-- | include/ChangeLog | 5 | ||||
-rw-r--r-- | include/bfdlink.h | 9 | ||||
-rw-r--r-- | ld/ChangeLog | 24 | ||||
-rw-r--r-- | ld/NEWS | 6 | ||||
-rw-r--r-- | ld/emultempl/elf32.em | 32 | ||||
-rwxr-xr-x | ld/genscripts.sh | 44 | ||||
-rw-r--r-- | ld/ld.texinfo | 6 | ||||
-rw-r--r-- | ld/ldint.texinfo | 22 | ||||
-rw-r--r-- | ld/ldmain.c | 2 | ||||
-rw-r--r-- | ld/lexsup.c | 6 | ||||
-rw-r--r-- | ld/scripttempl/elf.sc | 27 |
20 files changed, 571 insertions, 98 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 7010dfa..551b9d0 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,44 @@ +2001-08-23 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. + (elfNN_ia64_hash_table_create): Clear ia64_info. + (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. + 2001-08-23 Nick Clifton <nickc@cambridge.redhat.com> * configure.in (x86-bsdi): No corefile support. diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 6609542..a048e6f 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -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; @@ -1008,6 +1018,8 @@ extern void bfd_elf_print_symbol PARAMS ((bfd *, PTR, asymbol *, 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 *)); extern bfd_reloc_status_type bfd_elf_generic_reloc PARAMS ((bfd *, @@ -6053,3 +6053,10 @@ _bfd_elf_fprintf_vma (abfd, stream, value) fprintf_vma ((FILE *) stream, value); #endif } + +enum elf_reloc_type_class +_bfd_elf_reloc_type_class (type) + int type; +{ + return reloc_class_normal; +} diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 00ca185..8c49559 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -63,6 +63,7 @@ static boolean elf_i386_finish_dynamic_sections 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, relocs) || ! 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 (h, inf) 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_bfd, info) /* 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_bfd, info) } 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_bfd, info) 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" diff --git a/bfd/elf32-sparc.c b/bfd/elf32-sparc.c index 76d0324..3129dd7 100644 --- a/bfd/elf32-sparc.c +++ b/bfd/elf32-sparc.c @@ -52,6 +52,8 @@ static boolean elf32_sparc_object_p PARAMS ((bfd *)); static void elf32_sparc_final_write_processing PARAMS ((bfd *, boolean)); +static enum elf_reloc_type_class elf32_sparc_reloc_type_class + PARAMS ((int)); /* The relocation "howto" table. */ @@ -592,6 +594,8 @@ elf32_sparc_check_relocs (abfd, info, sec, relocs) || ! 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, h) 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 (output_bfd, info) /* 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 (output_bfd, info) } 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 (output_bfd, info) 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, linker) break; } } + +static enum elf_reloc_type_class +elf32_sparc_reloc_type_class (type) + int type; +{ + switch (type) + { + case R_SPARC_RELATIVE: + return reloc_class_relative; + case R_SPARC_JMP_SLOT: + return reloc_class_plt; + case R_SPARC_COPY: + return reloc_class_copy; + default: + return reloc_class_normal; + } +} #define TARGET_BIG_SYM bfd_elf32_sparc_vec #define TARGET_BIG_NAME "elf32-sparc" @@ -2111,6 +2116,7 @@ elf32_sparc_final_write_processing (abfd, linker) 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 diff --git a/bfd/elf64-sparc.c b/bfd/elf64-sparc.c index c4248f7..e121126 100644 --- a/bfd/elf64-sparc.c +++ b/bfd/elf64-sparc.c @@ -96,6 +96,7 @@ static boolean sparc64_elf_slurp_reloc_table static long sparc64_elf_canonicalize_dynamic_reloc PARAMS ((bfd *, arelent **, asymbol **)); static void sparc64_elf_write_relocs PARAMS ((bfd *, asection *, PTR)); +static enum elf_reloc_type_class sparc64_elf_reloc_type_class PARAMS ((int)); /* The relocation "howto" table. */ @@ -1248,6 +1249,8 @@ sparc64_elf_check_relocs (abfd, info, sec, relocs) || ! 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); @@ -1666,7 +1669,6 @@ sparc64_elf_size_dynamic_sections (output_bfd, info) { bfd *dynobj; asection *s; - boolean reltext; boolean relplt; dynobj = elf_hash_table (info)->dynobj; @@ -1698,7 +1700,6 @@ sparc64_elf_size_dynamic_sections (output_bfd, info) /* 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) { @@ -1731,18 +1732,6 @@ sparc64_elf_size_dynamic_sections (output_bfd, info) } 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; @@ -1805,11 +1794,10 @@ sparc64_elf_size_dynamic_sections (output_bfd, info) 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 @@ -2909,6 +2897,23 @@ sparc64_elf_finish_dynamic_sections (output_bfd, info) return true; } + +static enum elf_reloc_type_class +sparc64_elf_reloc_type_class (type) + int type; +{ + switch (type) + { + case R_SPARC_RELATIVE: + return reloc_class_relative; + case R_SPARC_JMP_SLOT: + return reloc_class_plt; + case R_SPARC_COPY: + return reloc_class_copy; + default: + return reloc_class_normal; + } +} /* Functions for dealing with the e_flags field. */ @@ -3160,6 +3165,8 @@ const struct elf_size_info sparc64_elf_size_info = 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 diff --git a/bfd/elflink.h b/bfd/elflink.h index 1a6399b..4428767 100644 --- a/bfd/elflink.h +++ b/bfd/elflink.h @@ -67,6 +67,12 @@ static boolean elf_link_size_reloc_section 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) (output_bfd, soname, rpath, 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) (output_bfd, soname, rpath, 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, count, rel_hash) 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) @@ -4890,6 +5107,23 @@ elf_bfd_final_link (abfd, info) { 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; goto get_sym; diff --git a/bfd/elfxx-ia64.c b/bfd/elfxx-ia64.c index 8fdb9a0..0273610 100644 --- a/bfd/elfxx-ia64.c +++ b/bfd/elfxx-ia64.c @@ -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; }; @@ -299,6 +300,8 @@ static boolean elfNN_ia64_merge_private_bfd_data PARAMS ((bfd *ibfd, bfd *obfd)); static boolean elfNN_ia64_print_private_bfd_data PARAMS ((bfd *abfd, PTR ptr)); +static enum elf_reloc_type_class elfNN_ia64_reloc_type_class + PARAMS ((int)); /* ia64-specific relocation */ @@ -1571,7 +1574,7 @@ elfNN_ia64_hash_table_create (abfd) { struct elfNN_ia64_link_hash_table *ret; - ret = bfd_alloc (abfd, sizeof (*ret)); + ret = bfd_zalloc (abfd, sizeof (*ret)); if (!ret) return 0; if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, @@ -1916,6 +1919,9 @@ get_reloc_section (abfd, ia64_info, sec, create) return NULL; } + if (sec->flags & SEC_READONLY) + ia64_info->reltext = 1; + return srel; } @@ -2535,7 +2541,6 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info) struct elfNN_ia64_link_hash_table *ia64_info; asection *sec; bfd *dynobj; - boolean reltext = false; boolean relplt = false; dynobj = elf_hash_table(info)->dynobj; @@ -2692,24 +2697,6 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info) { 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; @@ -2763,7 +2750,7 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info) sizeof (ElfNN_External_Rela))) return false; - if (reltext) + if (ia64_info->reltext) { if (! bfd_elfNN_add_dynamic_entry (info, DT_TEXTREL, 0)) return false; @@ -4324,6 +4311,27 @@ elfNN_ia64_print_private_bfd_data (abfd, ptr) _bfd_elf_print_private_bfd_data (abfd, ptr); return true; } + +static enum elf_reloc_type_class +elfNN_ia64_reloc_type_class (type) + int type; +{ + switch (type) + { + case R_IA64_REL32MSB: + case R_IA64_REL32LSB: + case R_IA64_REL64MSB: + case R_IA64_REL64LSB: + return reloc_class_relative; + case R_IA64_IPLTMSB: + case R_IA64_IPLTLSB: + return reloc_class_plt; + case R_IA64_COPY: + return reloc_class_copy; + default: + return reloc_class_normal; + } +} #define TARGET_LITTLE_SYM bfd_elfNN_ia64_little_vec #define TARGET_LITTLE_NAME "elfNN-ia64-little" @@ -4400,6 +4408,7 @@ elfNN_ia64_print_private_bfd_data (abfd, ptr) #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" diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h index 6ba5b6e..a4c5e1d 100644 --- a/bfd/elfxx-target.h +++ b/bfd/elfxx-target.h @@ -339,6 +339,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #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 @@ -426,6 +429,7 @@ static CONST struct elf_backend_data elfNN_bed = 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, diff --git a/include/ChangeLog b/include/ChangeLog index 8025966..55f85ad 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,8 @@ +2001-08-23 Jakub Jelinek <jakub@redhat.com> + + * bfdlink.h (struct bfd_link_info): Add combreloc and + spare_dynamic_tags fields. + 2001-08-23 Lars Brinkhoff <lars@nocrew.org> * dyn-string.h, fibheap.h, partition.h, sort.h, splay-tree.h: diff --git a/include/bfdlink.h b/include/bfdlink.h index 56b1fe4..1dd2842 100644 --- a/include/bfdlink.h +++ b/include/bfdlink.h @@ -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 diff --git a/ld/ChangeLog b/ld/ChangeLog index b4a1302..c29a986 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,27 @@ +2001-08-23 Jakub Jelinek <jakub@redhat.com> + + * 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. + 2001-08-22 H.J. Lu <hjl@gnu.org> * emulparams/elf32fr30.sh: Add a newline. @@ -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 diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em index 93dc739..0e5cd99 100644 --- a/ld/emultempl/elf32.em +++ b/ld/emultempl/elf32.em @@ -1135,7 +1135,25 @@ gld${EMULATION_NAME}_place_orphan (file, s) 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.relocateable == true) return' >> e${EMULATION_NAME} 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 diff --git a/ld/genscripts.sh b/ld/genscripts.sh index d3ab768..f169132 100755 --- a/ld/genscripts.sh +++ b/ld/genscripts.sh @@ -84,6 +84,17 @@ LIB_SEARCH_DIRS=`echo ${LIB_PATH} | tr ':' ' ' | sed -e 's/\([^ ][^ ]*\)/SEARCH_ # 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"; then # 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 diff --git a/ld/ld.texinfo b/ld/ld.texinfo index 95785e0..5bc0a30 100644 --- a/ld/ld.texinfo +++ b/ld/ld.texinfo @@ -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 library search paths. @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 diff --git a/ld/ldint.texinfo b/ld/ldint.texinfo index 47a9817..489750a 100644 --- a/ld/ldint.texinfo +++ b/ld/ldint.texinfo @@ -239,7 +239,7 @@ If @code{SCRIPT_NAME} is set to @var{script}, @code{genscripts.sh} will 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_SCRIPT} is defined in the 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 generating the @code{-N} script. @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 diff --git a/ld/ldmain.c b/ld/ldmain.c index 0ec7891..b7114f9 100644 --- a/ld/ldmain.c +++ b/ld/ldmain.c @@ -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 (""); diff --git a/ld/lexsup.c b/ld/lexsup.c index 7e23a7d..5183b86 100644 --- a/ld/lexsup.c +++ b/ld/lexsup.c @@ -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}, @@ -1073,6 +1076,9 @@ the GNU General Public License. This program has absolutely no warranty.\n")); 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) config.split_by_reloc = strtoul (optarg, NULL, 0); diff --git a/ld/scripttempl/elf.sc b/ld/scripttempl/elf.sc index 84630bd..8ccf803 100644 --- a/ld/scripttempl/elf.sc +++ b/ld/scripttempl/elf.sc @@ -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} |