From 93c5619ecc88c2d3b7fbdc05a903e223094a2671 Mon Sep 17 00:00:00 2001 From: Rahul Chaudhry Date: Tue, 19 Dec 2017 15:31:31 -0800 Subject: gold, readelf: add experimental support for SHT_RELR sections. This change adds experimental support for SHT_RELR sections, proposed here: https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg SHT_RELR sections are supported for arm, aarch64, and x86_64 targets. To enable them, pass '--experimental-use-relr' flag to gold. Definitions for the new ELF section type and dynamic array tags, as well as the encoding used in the new section are all under discussion and are subject to change. Use with caution! Bug: None Test: 'gold --experimental-use-relr' creates PIE binaries with '.relr.dyn' sections to store relative relocations. Change-Id: Iefb4ef5ad95852f4964adf6c8e9b3708a9bdb5f8 --- binutils-2.27/bfd/elf-bfd.h | 2 +- binutils-2.27/bfd/elf.c | 27 ++- binutils-2.27/bfd/elf32-arm.c | 1 + binutils-2.27/bfd/elfcode.h | 2 + binutils-2.27/bfd/elfnn-aarch64.c | 1 + binutils-2.27/binutils/readelf.c | 128 ++++++++++++- binutils-2.27/elfcpp/elfcpp.h | 55 ++++++ binutils-2.27/elfcpp/elfcpp_internal.h | 6 + binutils-2.27/gold/aarch64.cc | 170 ++++++++++++---- binutils-2.27/gold/arm.cc | 156 ++++++++++++--- binutils-2.27/gold/layout.cc | 14 +- binutils-2.27/gold/layout.h | 3 +- binutils-2.27/gold/options.h | 4 + binutils-2.27/gold/output.cc | 63 ++++++ binutils-2.27/gold/output.h | 341 ++++++++++++++++++++++++++++++++- binutils-2.27/gold/reloc-types.h | 20 ++ binutils-2.27/gold/x86_64.cc | 187 ++++++++++++++---- binutils-2.27/include/elf/common.h | 11 ++ binutils-2.27/include/elf/external.h | 8 + 19 files changed, 1076 insertions(+), 123 deletions(-) diff --git a/binutils-2.27/bfd/elf-bfd.h b/binutils-2.27/bfd/elf-bfd.h index af3d9ece..dc994a6d 100644 --- a/binutils-2.27/bfd/elf-bfd.h +++ b/binutils-2.27/bfd/elf-bfd.h @@ -638,7 +638,7 @@ struct sym_cache struct elf_size_info { unsigned char sizeof_ehdr, sizeof_phdr, sizeof_shdr; - unsigned char sizeof_rel, sizeof_rela, sizeof_sym, sizeof_dyn, sizeof_note; + unsigned char sizeof_rel, sizeof_rela, sizeof_relr, sizeof_sym, sizeof_dyn, sizeof_note; /* The size of entries in the .hash section. */ unsigned char sizeof_hash_entry; diff --git a/binutils-2.27/bfd/elf.c b/binutils-2.27/bfd/elf.c index cb4de50a..2af46a96 100644 --- a/binutils-2.27/bfd/elf.c +++ b/binutils-2.27/bfd/elf.c @@ -1624,6 +1624,9 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg) case DT_RELA: name = "RELA"; break; case DT_RELASZ: name = "RELASZ"; break; case DT_RELAENT: name = "RELAENT"; break; + case DT_RELR: name = "RELR"; break; + case DT_RELRSZ: name = "RELRSZ"; break; + case DT_RELRENT: name = "RELRENT"; break; case DT_STRSZ: name = "STRSZ"; break; case DT_SYMENT: name = "SYMENT"; break; case DT_INIT: name = "INIT"; break; @@ -1661,6 +1664,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg) case DT_PLTPAD: name = "PLTPAD"; break; case DT_MOVETAB: name = "MOVETAB"; break; case DT_SYMINFO: name = "SYMINFO"; break; + case DT_RELRCOUNT: name = "RELRCOUNT"; break; case DT_RELACOUNT: name = "RELACOUNT"; break; case DT_RELCOUNT: name = "RELCOUNT"; break; case DT_FLAGS_1: name = "FLAGS_1"; break; @@ -2221,16 +2225,30 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) case SHT_REL: case SHT_RELA: + case SHT_RELR: /* *These* do a lot of work -- but build no sections! */ { asection *target_sect; Elf_Internal_Shdr *hdr2, **p_hdr; unsigned int num_sec = elf_numsections (abfd); struct bfd_elf_section_data *esdt; + bfd_size_type size; - if (hdr->sh_entsize - != (bfd_size_type) (hdr->sh_type == SHT_REL - ? bed->s->sizeof_rel : bed->s->sizeof_rela)) + switch (hdr->sh_type) + { + case SHT_REL: + size = bed->s->sizeof_rel; + break; + case SHT_RELA: + size = bed->s->sizeof_rela; + break; + case SHT_RELR: + size = bed->s->sizeof_relr; + break; + default: + goto fail; + } + if (hdr->sh_entsize != size) goto fail; /* Check for a bogus link to avoid crashing. */ @@ -2296,7 +2314,8 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) || hdr->sh_info == SHN_UNDEF || hdr->sh_info >= num_sec || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_REL - || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_RELA) + || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_RELA + || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_RELR) { ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); diff --git a/binutils-2.27/bfd/elf32-arm.c b/binutils-2.27/bfd/elf32-arm.c index 682b6a11..33fe7a94 100644 --- a/binutils-2.27/bfd/elf32-arm.c +++ b/binutils-2.27/bfd/elf32-arm.c @@ -17966,6 +17966,7 @@ const struct elf_size_info elf32_arm_size_info = sizeof (Elf32_External_Shdr), sizeof (Elf32_External_Rel), sizeof (Elf32_External_Rela), + sizeof (Elf32_External_Relr), sizeof (Elf32_External_Sym), sizeof (Elf32_External_Dyn), sizeof (Elf_External_Note), diff --git a/binutils-2.27/bfd/elfcode.h b/binutils-2.27/bfd/elfcode.h index 79a14f3e..31ecf1c4 100644 --- a/binutils-2.27/bfd/elfcode.h +++ b/binutils-2.27/bfd/elfcode.h @@ -80,6 +80,7 @@ #define Elf_External_Phdr NAME(Elf,External_Phdr) #define Elf_External_Rel NAME(Elf,External_Rel) #define Elf_External_Rela NAME(Elf,External_Rela) +#define Elf_External_Relr NAME(Elf,External_Relr) #define Elf_External_Dyn NAME(Elf,External_Dyn) #define elf_core_file_failing_command NAME(bfd_elf,core_file_failing_command) @@ -1881,6 +1882,7 @@ const struct elf_size_info NAME(_bfd_elf,size_info) = { sizeof (Elf_External_Shdr), sizeof (Elf_External_Rel), sizeof (Elf_External_Rela), + sizeof (Elf_External_Relr), sizeof (Elf_External_Sym), sizeof (Elf_External_Dyn), sizeof (Elf_External_Note), diff --git a/binutils-2.27/bfd/elfnn-aarch64.c b/binutils-2.27/bfd/elfnn-aarch64.c index 3435a3d6..649d1ccf 100644 --- a/binutils-2.27/bfd/elfnn-aarch64.c +++ b/binutils-2.27/bfd/elfnn-aarch64.c @@ -9257,6 +9257,7 @@ const struct elf_size_info elfNN_aarch64_size_info = sizeof (ElfNN_External_Shdr), sizeof (ElfNN_External_Rel), sizeof (ElfNN_External_Rela), + sizeof (ElfNN_External_Relr), sizeof (ElfNN_External_Sym), sizeof (ElfNN_External_Dyn), sizeof (Elf_External_Note), diff --git a/binutils-2.27/binutils/readelf.c b/binutils-2.27/binutils/readelf.c index 3b5ba611..3bd6d452 100644 --- a/binutils-2.27/binutils/readelf.c +++ b/binutils-2.27/binutils/readelf.c @@ -1019,6 +1019,80 @@ slurp_rel_relocs (FILE * file, return 1; } +static bfd_boolean +slurp_relr_relocs (FILE * file, + unsigned long relr_offset, + unsigned long relr_size, + Elf_Internal_Rela ** relrsp, + unsigned long * nrelrsp) +{ + Elf_Internal_Rela * relrs; + size_t nrelrs; + unsigned int i; + + if (is_32bit_elf) + { + Elf32_External_Relr * erelrs; + + erelrs = (Elf32_External_Relr *) get_data (NULL, file, relr_offset, 1, + relr_size, _("32-bit relocation data")); + if (!erelrs) + return FALSE; + + nrelrs = relr_size / sizeof (Elf32_External_Relr); + + relrs = (Elf_Internal_Rela *) cmalloc (nrelrs, sizeof (Elf_Internal_Rela)); + + if (relrs == NULL) + { + free (erelrs); + error (_("out of memory parsing relocs\n")); + return FALSE; + } + + for (i = 0; i < nrelrs; i++) + { + relrs[i].r_offset = BYTE_GET (erelrs[i].r_data); + relrs[i].r_info = 0; + relrs[i].r_addend = 0; + } + + free (erelrs); + } + else + { + Elf64_External_Relr * erelrs; + + erelrs = (Elf64_External_Relr *) get_data (NULL, file, relr_offset, 1, + relr_size, _("64-bit relocation data")); + if (!erelrs) + return FALSE; + + nrelrs = relr_size / sizeof (Elf64_External_Relr); + + relrs = (Elf_Internal_Rela *) cmalloc (nrelrs, sizeof (Elf_Internal_Rela)); + + if (relrs == NULL) + { + free (erelrs); + error (_("out of memory parsing relocs\n")); + return FALSE; + } + + for (i = 0; i < nrelrs; i++) + { + relrs[i].r_offset = BYTE_GET (erelrs[i].r_data); + relrs[i].r_info = 0; + relrs[i].r_addend = 0; + } + + free (erelrs); + } + *relrsp = relrs; + *nrelrsp = nrelrs; + return 1; +} + /* Returns the reloc type extracted from the reloc info field. */ static unsigned int @@ -1072,6 +1146,7 @@ dump_relocations (FILE * file, char * strtab, unsigned long strtablen, int is_rela, + int is_relr, int is_dynsym) { unsigned int i; @@ -1085,6 +1160,11 @@ dump_relocations (FILE * file, if (!slurp_rela_relocs (file, rel_offset, rel_size, &rels, &rel_size)) return; } + else if (is_relr) + { + if (!slurp_relr_relocs (file, rel_offset, rel_size, &rels, &rel_size)) + return; + } else { if (!slurp_rel_relocs (file, rel_offset, rel_size, &rels, &rel_size)) @@ -1100,6 +1180,13 @@ dump_relocations (FILE * file, else printf (_(" Offset Info Type Sym.Value Sym. Name + Addend\n")); } + else if (is_relr) + { + if (do_wide) + printf (_(" Data Info Type\n")); + else + printf (_(" Data Info Type\n")); + } else { if (do_wide) @@ -1117,6 +1204,13 @@ dump_relocations (FILE * file, else printf (_(" Offset Info Type Sym. Value Sym. Name + Addend\n")); } + else if (is_relr) + { + if (do_wide) + printf (_(" Data Info Type\n")); + else + printf (_(" Data Info Type\n")); + } else { if (do_wide) @@ -1478,7 +1572,9 @@ dump_relocations (FILE * file, break; } - if (rtype == NULL) + if (is_relr) + printf (do_wide ? "RELATIVE COMPRESSED" : "RELR"); + else if (rtype == NULL) printf (_("unrecognized: %-7lx"), (unsigned long) type & 0xffffffff); else printf (do_wide ? "%-22.22s" : "%-17.17s", rtype); @@ -1996,6 +2092,9 @@ get_dynamic_type (unsigned long type) case DT_REL: return "REL"; case DT_RELSZ: return "RELSZ"; case DT_RELENT: return "RELENT"; + case DT_RELR: return "RELR"; + case DT_RELRSZ: return "RELRSZ"; + case DT_RELRENT: return "RELRENT"; case DT_PLTREL: return "PLTREL"; case DT_DEBUG: return "DEBUG"; case DT_TEXTREL: return "TEXTREL"; @@ -2032,6 +2131,7 @@ get_dynamic_type (unsigned long type) case DT_TLSDESC_GOT: return "TLSDESC_GOT"; case DT_TLSDESC_PLT: return "TLSDESC_PLT"; + case DT_RELRCOUNT: return "RELRCOUNT"; case DT_RELACOUNT: return "RELACOUNT"; case DT_RELCOUNT: return "RELCOUNT"; case DT_FLAGS_1: return "FLAGS_1"; @@ -3992,6 +4092,7 @@ get_section_type_name (unsigned int sh_type) case SHT_SYMTAB: return "SYMTAB"; case SHT_STRTAB: return "STRTAB"; case SHT_RELA: return "RELA"; + case SHT_RELR: return "RELR"; case SHT_HASH: return "HASH"; case SHT_DYNAMIC: return "DYNAMIC"; case SHT_NOTE: return "NOTE"; @@ -6604,11 +6705,13 @@ static struct int reloc; int size; int rela; + int relr; } dynamic_relocations [] = { - { "REL", DT_REL, DT_RELSZ, FALSE }, - { "RELA", DT_RELA, DT_RELASZ, TRUE }, - { "PLT", DT_JMPREL, DT_PLTRELSZ, UNKNOWN } + { "REL", DT_REL, DT_RELSZ, FALSE, FALSE }, + { "RELA", DT_RELA, DT_RELASZ, TRUE, FALSE }, + { "RELR", DT_RELR, DT_RELRSZ, FALSE, TRUE }, + { "PLT", DT_JMPREL, DT_PLTRELSZ, UNKNOWN, FALSE } }; /* Process the reloc section. */ @@ -6625,7 +6728,7 @@ process_relocs (FILE * file) if (do_using_dynamic) { - int is_rela; + int is_rela, is_relr; const char * name; int has_dynamic_reloc; unsigned int i; @@ -6635,6 +6738,7 @@ process_relocs (FILE * file) for (i = 0; i < ARRAY_SIZE (dynamic_relocations); i++) { is_rela = dynamic_relocations [i].rela; + is_relr = dynamic_relocations [i].relr; name = dynamic_relocations [i].name; rel_size = dynamic_info [dynamic_relocations [i].size]; rel_offset = dynamic_info [dynamic_relocations [i].reloc]; @@ -6666,7 +6770,7 @@ process_relocs (FILE * file) rel_size, dynamic_symbols, num_dynamic_syms, dynamic_strings, dynamic_strings_length, - is_rela, 1); + is_rela, is_relr, 1); } } @@ -6687,7 +6791,8 @@ process_relocs (FILE * file) i++, section++) { if ( section->sh_type != SHT_RELA - && section->sh_type != SHT_REL) + && section->sh_type != SHT_REL + && section->sh_type != SHT_RELR) continue; rel_offset = section->sh_offset; @@ -6696,7 +6801,7 @@ process_relocs (FILE * file) if (rel_size) { Elf_Internal_Shdr * strsec; - int is_rela; + int is_rela, is_relr; printf (_("\nRelocation section ")); @@ -6709,6 +6814,7 @@ process_relocs (FILE * file) rel_offset, (unsigned long) (rel_size / section->sh_entsize)); is_rela = section->sh_type == SHT_RELA; + is_relr = section->sh_type == SHT_RELR; if (section->sh_link != 0 && section->sh_link < elf_header.e_shnum) @@ -6742,7 +6848,7 @@ process_relocs (FILE * file) dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, strtablen, - is_rela, + is_rela, is_relr, symsec->sh_type == SHT_DYNSYM); if (strtab) free (strtab); @@ -6750,7 +6856,9 @@ process_relocs (FILE * file) } else dump_relocations (file, rel_offset, rel_size, - NULL, 0, NULL, 0, is_rela, 0); + NULL, 0, NULL, 0, + is_rela, is_relr, + 0); found = 1; } diff --git a/binutils-2.27/elfcpp/elfcpp.h b/binutils-2.27/elfcpp/elfcpp.h index 7469bd8f..a09ddc47 100644 --- a/binutils-2.27/elfcpp/elfcpp.h +++ b/binutils-2.27/elfcpp/elfcpp.h @@ -385,6 +385,10 @@ enum SHT SHT_SUNW_versym = 0x6fffffff, SHT_GNU_versym = 0x6fffffff, + // Experimental support for SHT_RELR sections. For details, see proposal + // at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg + SHT_RELR = 0x6fffff00, + SHT_SPARC_GOTDATA = 0x70000000, // ARM-specific section types. @@ -762,6 +766,13 @@ enum DT DT_VERSYM = 0x6ffffff0, + // Experimental support for SHT_RELR sections. For details, see proposal + // at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg + DT_RELR = 0x6fffe000, + DT_RELRSZ = 0x6fffe001, + DT_RELRENT = 0x6fffe003, + DT_RELRCOUNT = 0x6fffe005, + // Specify the value of _GLOBAL_OFFSET_TABLE_. DT_PPC_GOT = 0x70000000, @@ -1020,6 +1031,7 @@ struct Elf_sizes // Sizes of ELF reloc entries. static const int rel_size = sizeof(internal::Rel_data); static const int rela_size = sizeof(internal::Rela_data); + static const int relr_size = sizeof(internal::Relr_data); // Size of ELF dynamic entry. static const int dyn_size = sizeof(internal::Dyn_data); // Size of ELF version structures. @@ -1665,6 +1677,49 @@ class Rela_write internal::Rela_data* p_; }; +// Accessor class for an ELF Relr relocation. + +template +class Relr +{ + public: + Relr(const unsigned char* p) + : p_(reinterpret_cast*>(p)) + { } + + template + Relr(File* file, typename File::Location loc) + : p_(reinterpret_cast*>( + file->view(loc.file_offset, loc.data_size).data())) + { } + + typename Elf_types::Elf_Addr + get_r_data() const + { return Convert::convert_host(this->p_->r_data); } + + private: + const internal::Relr_data* p_; +}; + +// Writer class for an ELF Relr relocation. + +template +class Relr_write +{ + public: + Relr_write(unsigned char* p) + : p_(reinterpret_cast*>(p)) + { } + + void + put_r_data(typename Elf_types::Elf_Addr v) + { this->p_->r_data = Convert::convert_host(v); } + + private: + internal::Relr_data* p_; +}; + + // MIPS-64 has a non-standard relocation layout. template diff --git a/binutils-2.27/elfcpp/elfcpp_internal.h b/binutils-2.27/elfcpp/elfcpp_internal.h index 2aaeeba8..da2c1a97 100644 --- a/binutils-2.27/elfcpp/elfcpp_internal.h +++ b/binutils-2.27/elfcpp/elfcpp_internal.h @@ -180,6 +180,12 @@ struct Rela_data typename Elf_types::Elf_Swxword r_addend; }; +template +struct Relr_data +{ + typename Elf_types::Elf_WXword r_data; +}; + // MIPS-64 has a non-standard layout for relocations. struct Mips64_rel_data diff --git a/binutils-2.27/gold/aarch64.cc b/binutils-2.27/gold/aarch64.cc index b1c88137..2b3d3a8e 100644 --- a/binutils-2.27/gold/aarch64.cc +++ b/binutils-2.27/gold/aarch64.cc @@ -2867,6 +2867,8 @@ class Target_aarch64 : public Sized_target typedef Target_aarch64 This; typedef Output_data_reloc Reloc_section; + typedef Output_data_reloc + Relr_section; typedef Relocate_info The_relocate_info; typedef typename elfcpp::Elf_types::Elf_Addr Address; typedef AArch64_relobj The_aarch64_relobj; @@ -2888,8 +2890,8 @@ class Target_aarch64 : public Sized_target : Sized_target(info), got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL), got_tlsdesc_(NULL), global_offset_table_(NULL), rela_dyn_(NULL), - rela_irelative_(NULL), copy_relocs_(elfcpp::R_AARCH64_COPY), - got_mod_index_offset_(-1U), + rela_irelative_(NULL), relr_dyn_(NULL), + copy_relocs_(elfcpp::R_AARCH64_COPY), got_mod_index_offset_(-1U), tlsdesc_reloc_info_(), tls_base_symbol_defined_(false), stub_tables_(), stub_group_size_(0), aarch64_input_section_map_() { } @@ -3150,11 +3152,17 @@ class Target_aarch64 : public Sized_target return this->do_make_data_plt(layout, got, got_plt, got_irelative); } - // We only need to generate stubs, and hence perform relaxation if we are - // not doing relocatable linking. virtual bool do_may_relax() const - { return !parameters->options().relocatable(); } + { + // If generating '.relr.dyn' section, we need a relaxation pass + // to do the shrinking after all the offsets have been populated. + if (parameters->options().experimental_use_relr()) + return true; + // We need to generate stubs, and hence perform relaxation if we are + // not doing relocatable linking. + return !parameters->options().relocatable(); + } // Relaxation hook. This is where we do stub generation. virtual bool @@ -3425,6 +3433,10 @@ class Target_aarch64 : public Sized_target Reloc_section* rela_irelative_section(Layout*); + // Get the RELR dynamic reloc section, creating it if necessary. + Relr_section* + relr_dyn_section(Layout*); + // Add a potential copy relocation. void copy_reloc(Symbol_table* symtab, Layout* layout, @@ -3489,6 +3501,8 @@ class Target_aarch64 : public Sized_target Reloc_section* rela_dyn_; // The section to use for IRELATIVE relocs. Reloc_section* rela_irelative_; + // The RELR dynamic reloc section. + Relr_section* relr_dyn_; // Relocs saved to avoid a COPY reloc. Copy_relocs copy_relocs_; // Offset of the GOT entry for the TLS module index. @@ -3756,6 +3770,23 @@ Target_aarch64::rela_irelative_section(Layout* layout) return this->rela_irelative_; } +// Get the RELR dynamic reloc section, creating it if necessary. + +template +typename Target_aarch64::Relr_section* +Target_aarch64::relr_dyn_section(Layout* layout) +{ + if (this->relr_dyn_ == NULL) + { + gold_assert(layout != NULL); + this->relr_dyn_ = new Relr_section(); + layout->add_output_section_data(".relr.dyn", elfcpp::SHT_RELR, + elfcpp::SHF_ALLOC, this->relr_dyn_, + ORDER_DYNAMIC_RELOCS, false); + } + return this->relr_dyn_; +} + // do_make_elf_object to override the same function in the base class. We need // to use a target-specific sub-class of Sized_relobj_file to @@ -5596,8 +5627,34 @@ Target_aarch64::do_relax( Layout* layout , const Task* task) { - gold_assert(!parameters->options().relocatable()); if (pass == 1) + { + Layout::Section_list::const_iterator p = layout->section_list().begin(); + for ( ; p != layout->section_list().end(); ++p) + { + if (is_prefix_of(".relr.dyn", (*p)->name())) + break; + } + + if (p != layout->section_list().end()) + { + Output_section * const os = *p; + for (Output_section::Input_section_list::iterator ip = os->input_sections().begin(); + ip != os->input_sections().end(); + ++ip) + { + Relr_section *od = static_cast(ip->output_section_data()); + od->shrink_relocs(); + } + } + + return true; + } + + if (parameters->options().relocatable()) + return false; + + if (pass == 2) { // We don't handle negative stub_group_size right now. this->stub_group_size_ = abs(parameters->options().stub_group_size()); @@ -5613,7 +5670,7 @@ Target_aarch64::do_relax( } else { - // If this is not the first pass, addresses and file offsets have + // If this is not the second pass, addresses and file offsets have // been reset at this point, set them here. for (Stub_table_iterator sp = this->stub_tables_.begin(); sp != this->stub_tables_.end(); ++sp) @@ -6075,14 +6132,22 @@ Target_aarch64::Scan::local( // reloction, so that the dynamic loader can relocate it. if (parameters->options().output_is_position_independent()) { - Reloc_section* rela_dyn = target->rela_dyn_section(layout); - rela_dyn->add_local_relative(object, r_sym, - elfcpp::R_AARCH64_RELATIVE, - output_section, - data_shndx, - rela.get_r_offset(), - rela.get_r_addend(), - is_ifunc); + if (parameters->options().experimental_use_relr()) + { + Relr_section* relr_dyn = target->relr_dyn_section(layout); + relr_dyn->add_local_relative(object, r_sym, output_section, + data_shndx, rela.get_r_offset()); + } + else + { + Reloc_section* rela_dyn = target->rela_dyn_section(layout); + rela_dyn->add_local_relative(object, r_sym, + elfcpp::R_AARCH64_RELATIVE, + output_section, data_shndx, + rela.get_r_offset(), + rela.get_r_addend(), + is_ifunc); + } } break; @@ -6105,15 +6170,22 @@ Target_aarch64::Scan::local( else is_new = got->add_local(object, r_sym, GOT_TYPE_STANDARD); if (is_new && parameters->options().output_is_position_independent()) - target->rela_dyn_section(layout)-> - add_local_relative(object, - r_sym, - elfcpp::R_AARCH64_RELATIVE, - got, - object->local_got_offset(r_sym, - GOT_TYPE_STANDARD), - 0, - false); + { + unsigned int got_offset = + object->local_got_offset(r_sym, GOT_TYPE_STANDARD); + if (parameters->options().experimental_use_relr()) + { + Relr_section* relr_dyn = target->relr_dyn_section(layout); + relr_dyn->add_local_relative(object, r_sym, got, got_offset); + } + else + { + Reloc_section* rela_dyn = target->rela_dyn_section(layout); + rela_dyn->add_local_relative(object, r_sym, + elfcpp::R_AARCH64_RELATIVE, + got, got_offset, 0, false); + } + } } break; @@ -6369,15 +6441,25 @@ Target_aarch64::Scan::global( else if (r_type == elfcpp::R_AARCH64_ABS64 && gsym->can_use_relative_reloc(false)) { - Reloc_section* rela_dyn = target->rela_dyn_section(layout); - rela_dyn->add_global_relative(gsym, - elfcpp::R_AARCH64_RELATIVE, - output_section, - object, - data_shndx, - rela.get_r_offset(), - rela.get_r_addend(), - false); + if (parameters->options().experimental_use_relr()) + { + Relr_section* relr_dyn = + target->relr_dyn_section(layout); + relr_dyn->add_global_relative(gsym, output_section, + object, data_shndx, + rela.get_r_offset()); + } + else + { + Reloc_section* rela_dyn = target->rela_dyn_section(layout); + rela_dyn->add_global_relative(gsym, + elfcpp::R_AARCH64_RELATIVE, + output_section, object, + data_shndx, + rela.get_r_offset(), + rela.get_r_addend(), + false); + } } else { @@ -6488,12 +6570,19 @@ Target_aarch64::Scan::global( } if (is_new) { - rela_dyn->add_global_relative( - gsym, elfcpp::R_AARCH64_RELATIVE, - got, - gsym->got_offset(GOT_TYPE_STANDARD), - 0, - false); + unsigned int got_off = gsym->got_offset(GOT_TYPE_STANDARD); + if (parameters->options().experimental_use_relr()) + { + Relr_section* relr_dyn = + target->relr_dyn_section(layout); + relr_dyn->add_global_relative(gsym, got, got_off); + } + else + { + rela_dyn->add_global_relative(gsym, + elfcpp::R_AARCH64_RELATIVE, + got, got_off, 0, false); + } } } } @@ -6835,7 +6924,8 @@ Target_aarch64::do_finalize_sections( ? NULL : this->plt_->rela_plt()); layout->add_target_dynamic_tags(false, this->got_plt_, rel_plt, - this->rela_dyn_, true, false); + this->rela_dyn_, true, false, + this->relr_dyn_); // Emit any relocs we saved in an attempt to avoid generating COPY // relocs. diff --git a/binutils-2.27/gold/arm.cc b/binutils-2.27/gold/arm.cc index b314fa1b..2dcb104d 100644 --- a/binutils-2.27/gold/arm.cc +++ b/binutils-2.27/gold/arm.cc @@ -2120,6 +2120,8 @@ class Target_arm : public Sized_target<32, big_endian> public: typedef Output_data_reloc Reloc_section; + typedef Output_data_reloc + Relr_section; // When were are relocating a stub, we pass this as the relocation number. static const size_t fake_relnum_for_stubs = static_cast(-1); @@ -2127,7 +2129,8 @@ class Target_arm : public Sized_target<32, big_endian> Target_arm(const Target::Target_info* info = &arm_info) : Sized_target<32, big_endian>(info), got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL), - rel_dyn_(NULL), rel_irelative_(NULL), copy_relocs_(elfcpp::R_ARM_COPY), + rel_dyn_(NULL), rel_irelative_(NULL), relr_dyn_(NULL), + copy_relocs_(elfcpp::R_ARM_COPY), got_mod_index_offset_(-1U), tls_base_symbol_defined_(false), stub_tables_(), stub_factory_(Stub_factory::get_instance()), should_force_pic_veneer_(false), @@ -2520,11 +2523,17 @@ class Target_arm : public Sized_target<32, big_endian> void do_adjust_elf_header(unsigned char* view, int len); - // We only need to generate stubs, and hence perform relaxation if we are - // not doing relocatable linking. bool do_may_relax() const - { return !parameters->options().relocatable(); } + { + // If generating '.relr.dyn' section, we need a relaxation pass + // to do the shrinking after all the offsets have been populated. + if (parameters->options().experimental_use_relr()) + return true; + // We need to generate stubs, and hence perform relaxation if we are + // not doing relocatable linking. + return !parameters->options().relocatable(); + } bool do_relax(int, const Input_objects*, Symbol_table*, Layout*, const Task*); @@ -2822,6 +2831,10 @@ class Target_arm : public Sized_target<32, big_endian> Reloc_section* rel_tls_desc_section(Layout*) const; + // Get the RELR dynamic reloc section, creating it if necessary. + Relr_section* + relr_dyn_section(Layout*); + // Return true if the symbol may need a COPY relocation. // References from an executable object to non-function symbols // defined in a dynamic object may need a COPY relocation. @@ -2986,6 +2999,8 @@ class Target_arm : public Sized_target<32, big_endian> Reloc_section* rel_dyn_; // The section to use for IRELATIVE relocs. Reloc_section* rel_irelative_; + // The RELR dynamic reloc section. + Relr_section* relr_dyn_; // Relocs saved to avoid a COPY reloc. Copy_relocs copy_relocs_; // Offset of the GOT entry for the TLS module index. @@ -4384,6 +4399,23 @@ Target_arm::rel_irelative_section(Layout* layout) return this->rel_irelative_; } +// Get the RELR dynamic reloc section, creating it if necessary. + +template +typename Target_arm::Relr_section* +Target_arm::relr_dyn_section(Layout* layout) +{ + if (this->relr_dyn_ == NULL) + { + gold_assert(layout != NULL); + this->relr_dyn_ = new Relr_section(); + layout->add_output_section_data(".relr.dyn", elfcpp::SHT_RELR, + elfcpp::SHF_ALLOC, this->relr_dyn_, + ORDER_DYNAMIC_RELOCS, false); + } + return this->relr_dyn_; +} + // Insn_template methods. @@ -8504,13 +8536,22 @@ Target_arm::Scan::local(Symbol_table* symtab, // relocate it easily. if (parameters->options().output_is_position_independent()) { - Reloc_section* rel_dyn = target->rel_dyn_section(layout); unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); - // If we are to add more other reloc types than R_ARM_ABS32, - // we need to add check_non_pic(object, r_type) here. - rel_dyn->add_local_relative(object, r_sym, elfcpp::R_ARM_RELATIVE, - output_section, data_shndx, - reloc.get_r_offset(), is_ifunc); + if (parameters->options().experimental_use_relr()) + { + Relr_section* relr_dyn = target->relr_dyn_section(layout); + relr_dyn->add_local_relative(object, r_sym, output_section, + data_shndx, reloc.get_r_offset()); + } + else + { + Reloc_section* rel_dyn = target->rel_dyn_section(layout); + // If we are to add more other reloc types than R_ARM_ABS32, + // we need to add check_non_pic(object, r_type) here. + rel_dyn->add_local_relative(object, r_sym, elfcpp::R_ARM_RELATIVE, + output_section, data_shndx, + reloc.get_r_offset(), is_ifunc); + } } break; @@ -8633,11 +8674,23 @@ Target_arm::Scan::local(Symbol_table* symtab, // dynamic RELATIVE relocation for this symbol's GOT entry. if (parameters->options().output_is_position_independent()) { - Reloc_section* rel_dyn = target->rel_dyn_section(layout); + unsigned int got_offset = + object->local_got_offset(r_sym, GOT_TYPE_STANDARD); unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); - rel_dyn->add_local_relative( - object, r_sym, elfcpp::R_ARM_RELATIVE, got, - object->local_got_offset(r_sym, GOT_TYPE_STANDARD)); + if (parameters->options().experimental_use_relr()) + { + Relr_section* relr_dyn = + target->relr_dyn_section(layout); + relr_dyn->add_local_relative(object, r_sym, + got, got_offset); + } + else + { + Reloc_section* rel_dyn = target->rel_dyn_section(layout); + rel_dyn->add_local_relative(object, r_sym, + elfcpp::R_ARM_RELATIVE, + got, got_offset); + } } } } @@ -8946,10 +8999,22 @@ Target_arm::Scan::global(Symbol_table* symtab, || r_type == elfcpp::R_ARM_ABS32_NOI) && gsym->can_use_relative_reloc(false)) { - Reloc_section* rel_dyn = target->rel_dyn_section(layout); - rel_dyn->add_global_relative(gsym, elfcpp::R_ARM_RELATIVE, - output_section, object, - data_shndx, reloc.get_r_offset()); + if (parameters->options().experimental_use_relr()) + { + Relr_section* relr_dyn = + target->relr_dyn_section(layout); + relr_dyn->add_global_relative(gsym, output_section, + object, data_shndx, + reloc.get_r_offset()); + } + else + { + Reloc_section* rel_dyn = target->rel_dyn_section(layout); + rel_dyn->add_global_relative(gsym, elfcpp::R_ARM_RELATIVE, + output_section, object, + data_shndx, + reloc.get_r_offset()); + } } else { @@ -9116,9 +9181,21 @@ Target_arm::Scan::global(Symbol_table* symtab, gsym->set_needs_dynsym_value(); } if (is_new) - rel_dyn->add_global_relative( - gsym, elfcpp::R_ARM_RELATIVE, got, - gsym->got_offset(GOT_TYPE_STANDARD)); + { + unsigned int got_off = gsym->got_offset(GOT_TYPE_STANDARD); + if (parameters->options().experimental_use_relr()) + { + Relr_section* relr_dyn = + target->relr_dyn_section(layout); + relr_dyn->add_global_relative(gsym, got, got_off); + } + else + { + rel_dyn->add_global_relative(gsym, + elfcpp::R_ARM_RELATIVE, + got, got_off); + } + } } } } @@ -9388,7 +9465,8 @@ Target_arm::do_finalize_sections( ? NULL : this->plt_->rel_plt()); layout->add_target_dynamic_tags(true, this->got_plt_, rel_plt, - this->rel_dyn_, true, false); + this->rel_dyn_, true, false, + this->relr_dyn_); // Emit any relocs we saved in an attempt to avoid generating COPY // relocs. @@ -12256,14 +12334,38 @@ Target_arm::do_relax( Layout* layout, const Task* task) { - // No need to generate stubs if this is a relocatable link. - gold_assert(!parameters->options().relocatable()); + if (pass == 1) + { + Layout::Section_list::const_iterator p = layout->section_list().begin(); + for ( ; p != layout->section_list().end(); ++p) + { + if (is_prefix_of(".relr.dyn", (*p)->name())) + break; + } + + if (p != layout->section_list().end()) + { + Output_section * const os = *p; + for (Output_section::Input_section_list::iterator ip = os->input_sections().begin(); + ip != os->input_sections().end(); + ++ip) + { + Relr_section *od = static_cast(ip->output_section_data()); + od->shrink_relocs(); + } + } + + return true; + } - // If this is the first pass, we need to group input sections into + if (parameters->options().relocatable()) + return false; + + // If this is the second pass, we need to group input sections into // stub groups. bool done_exidx_fixup = false; typedef typename Stub_table_list::iterator Stub_table_iterator; - if (pass == 1) + if (pass == 2) { // Determine the stub group size. The group size is the absolute // value of the parameter --stub-group-size. If --stub-group-size @@ -12333,7 +12435,7 @@ Target_arm::do_relax( } else { - // If this is not the first pass, addresses and file offsets have + // If this is not the second pass, addresses and file offsets have // been reset at this point, set them here. for (Stub_table_iterator sp = this->stub_tables_.begin(); sp != this->stub_tables_.end(); diff --git a/binutils-2.27/gold/layout.cc b/binutils-2.27/gold/layout.cc index 38d67e7a..9403f895 100644 --- a/binutils-2.27/gold/layout.cc +++ b/binutils-2.27/gold/layout.cc @@ -4710,7 +4710,8 @@ void Layout::add_target_dynamic_tags(bool use_rel, const Output_data* plt_got, const Output_data* plt_rel, const Output_data_reloc_generic* dyn_rel, - bool add_debug, bool dynrel_includes_plt) + bool add_debug, bool dynrel_includes_plt, + const Output_data_reloc_generic* dyn_relr) { Output_data_dynamic* odyn = this->dynamic_data_; if (odyn == NULL) @@ -4783,6 +4784,17 @@ Layout::add_target_dynamic_tags(bool use_rel, const Output_data* plt_got, } } + if (dyn_relr != NULL && dyn_relr->output_section() != NULL) + { + const int size = parameters->target().get_size(); + odyn->add_section_address(elfcpp::DT_RELR, dyn_relr->output_section()); + odyn->add_section_size(elfcpp::DT_RELRSZ, dyn_relr->output_section()); + odyn->add_constant(elfcpp::DT_RELRENT, size / 8); + if (parameters->options().combreloc()) + odyn->add_constant(elfcpp::DT_RELRCOUNT, + dyn_relr->relative_reloc_count()); + } + if (add_debug && !parameters->options().shared()) { // The value of the DT_DEBUG tag is filled in by the dynamic diff --git a/binutils-2.27/gold/layout.h b/binutils-2.27/gold/layout.h index b2d699fc..63defa11 100644 --- a/binutils-2.27/gold/layout.h +++ b/binutils-2.27/gold/layout.h @@ -900,7 +900,8 @@ class Layout add_target_dynamic_tags(bool use_rel, const Output_data* plt_got, const Output_data* plt_rel, const Output_data_reloc_generic* dyn_rel, - bool add_debug, bool dynrel_includes_plt); + bool add_debug, bool dynrel_includes_plt, + const Output_data_reloc_generic* dyn_relr = NULL); // Add a target-specific dynamic tag with constant value. void diff --git a/binutils-2.27/gold/options.h b/binutils-2.27/gold/options.h index bb9797ff..01fbf0be 100644 --- a/binutils-2.27/gold/options.h +++ b/binutils-2.27/gold/options.h @@ -770,6 +770,10 @@ class General_options N_("Exclude libraries from automatic export"), N_(("lib,lib ..."))); + DEFINE_bool(experimental_use_relr, options::TWO_DASHES, '\0', false, + N_("Generate RELR dynamic relocations"), + N_("Do not generate RELR dynamic relocations")); + DEFINE_bool(export_dynamic, options::TWO_DASHES, 'E', false, N_("Export all dynamic symbols"), N_("Do not export all dynamic symbols (default)")); diff --git a/binutils-2.27/gold/output.cc b/binutils-2.27/gold/output.cc index 0a9e58f7..95b6eab1 100644 --- a/binutils-2.27/gold/output.cc +++ b/binutils-2.27/gold/output.cc @@ -1224,6 +1224,38 @@ Output_reloc::write( orel.put_r_addend(addend); } +// Write out a Relr relocation. + +template +void +Output_reloc::write( + unsigned char* pov) const +{ + typedef Output_data_reloc_base Base; + elfcpp::Relr_write orel(pov); + + if (this->jump_ == 0) + { + // Delta from previous offset is either too big, + // or is not a multiple of word_size. Encode as + // two words: relocations bitmap and the offset. + orel.put_r_data(this->bits_); + pov += Base::reloc_size; + elfcpp::Relr_write orel(pov); + orel.put_r_data(this->rel_.get_address()); + return; + } + + // Encode jump:bits in a relr relocation entry. + // High order 8-bits always encode the jump. + // The remaining bits encode the bitmap. + Relr_Data data; + data = this->jump_ << (size - 8); + data = data | this->bits_; + orel.put_r_data(data); +} + // Output_data_reloc_base methods. // Adjust the output section. @@ -1237,6 +1269,8 @@ Output_data_reloc_base os->set_entsize(elfcpp::Elf_sizes::rel_size); else if (sh_type == elfcpp::SHT_RELA) os->set_entsize(elfcpp::Elf_sizes::rela_size); + else if (sh_type == elfcpp::SHT_RELR) + os->set_entsize(elfcpp::Elf_sizes::relr_size); else gold_unreachable(); @@ -1276,6 +1310,15 @@ Output_data_reloc_base::do_write( this->do_write_generic(of); } +template +void +Output_data_reloc::do_write( + Output_file* of) +{ + typedef Output_reloc_writer Writer; + this->template do_write_generic(of); +} + // Class Output_relocatable_relocs. template @@ -5493,6 +5536,26 @@ template class Output_data_reloc; #endif +#ifdef HAVE_TARGET_32_LITTLE +template +class Output_data_reloc; +#endif + +#ifdef HAVE_TARGET_32_BIG +template +class Output_data_reloc; +#endif + +#ifdef HAVE_TARGET_64_LITTLE +template +class Output_data_reloc; +#endif + +#ifdef HAVE_TARGET_64_BIG +template +class Output_data_reloc; +#endif + #ifdef HAVE_TARGET_32_LITTLE template class Output_relocatable_relocs; diff --git a/binutils-2.27/gold/output.h b/binutils-2.27/gold/output.h index 6b9186b9..a28d1899 100644 --- a/binutils-2.27/gold/output.h +++ b/binutils-2.27/gold/output.h @@ -558,7 +558,6 @@ class Output_data void set_current_data_size_for_child(off_t data_size) { - gold_assert(!this->is_data_size_valid_); this->data_size_ = data_size; } @@ -1500,6 +1499,118 @@ class Output_reloc Addend addend_; }; +// The SHT_RELR version of Output_reloc<>. This is a relative reloc, +// and holds nothing but an offset. Rather than duplicate all the fields +// of the SHT_REL version except for the symbol and relocation type, we +// simply use an SHT_REL as a proxy. + +template +class Output_reloc +{ + public: + typedef typename elfcpp::Elf_types::Elf_Addr Address; + typedef typename elfcpp::Elf_types::Elf_WXword Relr_Data; + + // An uninitialized entry. + Output_reloc() + : rel_() + { } + + // A reloc against a global symbol. + + Output_reloc(Symbol* gsym, Output_data* od, Address address) + : rel_(gsym, 0, od, address, true, true, false), + jump_(0), bits_(0) + { } + + Output_reloc(Symbol* gsym, Sized_relobj* relobj, + unsigned int shndx, Address address) + : rel_(gsym, 0, relobj, shndx, address, true, true, false), + jump_(0), bits_(0) + { } + + // A reloc against a local symbol. + + Output_reloc(Sized_relobj* relobj, + unsigned int local_sym_index, Output_data* od, Address address, + bool is_section_symbol) + : rel_(relobj, local_sym_index, 0, od, address, true, + true, is_section_symbol, false), + jump_(0), bits_(0) + { } + + Output_reloc(Sized_relobj* relobj, + unsigned int local_sym_index, unsigned int shndx, + Address address, bool is_section_symbol) + : rel_(relobj, local_sym_index, 0, shndx, address, true, + true, is_section_symbol, false), + jump_(0), bits_(0) + { } + + // A reloc against the STT_SECTION symbol of an output section. + + Output_reloc(Output_section* os, Output_data* od, Address address) + : rel_(os, 0, od, address, true), + jump_(0), bits_(0) { } + + Output_reloc(Output_section* os, Sized_relobj* relobj, + unsigned int shndx, Address address) + : rel_(os, 0, relobj, shndx, address, true), + jump_(0), bits_(0) { } + + // A relative relocation with no symbol. + + Output_reloc(Output_data* od, Address address) + : rel_(0, od, address, true), + jump_(0), bits_(0) + { } + + Output_reloc(Sized_relobj* relobj, + unsigned int shndx, Address address) + : rel_(0, relobj, shndx, address, true), + jump_(0), bits_(0) + { } + + // Return whether this is a RELATIVE relocation. + bool + is_relative() const + { return true; } + + // Return whether this is a relocation which should not use + // a symbol, but which obtains its addend from a symbol. + bool + is_symbolless() const + { return true; } + + // If this relocation is against an input section, return the + // relocatable object containing the input section. + Sized_relobj* + get_relobj() const + { return this->rel_.get_relobj(); } + + // Write the reloc entry to an output view. + void + write(unsigned char* pov) const; + + // Return whether this reloc should be sorted before the argument + // when sorting dynamic relocs. + bool + sort_before(const Output_reloc& + r2) const + { return this->rel_.compare(r2.rel_) < 0; } + + public: + // The basic reloc. + Output_reloc rel_; + + // Number of words to jump since last offset, maximum 0xff. + Relr_Data jump_; + + // Relocations bitmap for addresses starting at the offset, + // 24-bits/56-bits. + Relr_Data bits_; +}; + // Output_data_reloc_generic is a non-template base class for // Output_data_reloc_base. This gives the generic code a way to hold // a pointer to a reloc section. @@ -1675,7 +1786,7 @@ class Output_data_reloc_base : public Output_data_reloc_generic relobj->add_dyn_reloc(this->relocs_.size() - 1); } - private: + protected: typedef std::vector Relocs; // The class used to sort the relocations. @@ -2344,6 +2455,232 @@ class Output_data_reloc } }; +// The SHT_RELR version of Output_data_reloc. + +template +class Output_data_reloc + : public Output_data_reloc_base +{ + private: + typedef Output_data_reloc_base Base; + typedef typename elfcpp::Elf_types::Elf_WXword Relr_Data; + + public: + typedef typename Base::Output_reloc_type Output_reloc_type; + typedef typename Output_reloc_type::Address Address; + typedef typename Base::Sort_relocs_comparison Sort_relocs_comparison; + typedef typename Base::Relocs Relocs; + + Output_data_reloc() + : Output_data_reloc_base(false) + { } + + void do_write(Output_file *); + + template + void + do_write_generic(Output_file *of) + { + const off_t off = this->offset(); + const off_t oview_size = this->data_size(); + unsigned char* const oview = of->get_output_view(off, oview_size); + + unsigned char* pov = oview; + for (typename Relocs::const_iterator p = this->relocs_.begin(); + p != this->relocs_.end(); + ++p) + { + Output_reloc_writer::write(p, pov); + pov += Base::reloc_size; + if (p->jump_ == 0) + pov += Base::reloc_size; + } + + gold_assert(pov - oview == oview_size); + + of->write_output_view(off, oview_size, oview); + + // We no longer need the relocation entries. + this->relocs_.clear(); + } + + void shrink_relocs() + { + Relocs shrink_relocs; + gold_assert(dynamic); + shrink_relocs.clear(); + + // Always sort the relocs_ vector for RELR relocs. + std::sort(this->relocs_.begin(), this->relocs_.end(), Sort_relocs_comparison()); + + // Word size in number of bytes, used for computing jump/bits. + unsigned int word_size = size / 8; + + // Number of bits to use for the relocations bitmap + // (jump field is always 8-bit wide). + unsigned int n_bits = size - 8; + + Address prev = 0; + off_t addnl_relocs_size = 0; + typename Relocs::iterator curr = this->relocs_.begin(); + while (curr != this->relocs_.end()) + { + Address delta = curr->rel_.get_address() - prev; + Relr_Data jump = delta / word_size; + bool aligned = (delta % word_size) == 0; + + // Compute bitmap for next relocations that can be folded into curr. + Relr_Data bits = 0; + typename Relocs::iterator next = curr; + while (next != this->relocs_.end()) + { + Address diff = next->rel_.get_address() - curr->rel_.get_address(); + // If next is too far out, it cannot be folded into curr. + if (diff >= (n_bits * word_size)) + break; + // If next is not a multiple of word_size away, it cannot + // be folded into curr. + if ((diff % word_size) != 0) + break; + // next can be folded into curr, update the bitmap to include it. + bits |= 1ULL << (diff / word_size); + ++next; + } + + // If jump is too big, or if the delta between curr and prev is not a + // multiple of word_size, we need to fallback to using two entries in + // the output: the relocations bitmap, followed by the full offset. + // This is signaled by setting jump to 0. + if (jump > 0xff || !aligned) + { + jump = 0; + addnl_relocs_size += Base::reloc_size; + } + + curr->jump_ = jump; + curr->bits_ = bits; + shrink_relocs.push_back(*curr); + + prev = curr->rel_.get_address(); + curr = next; + } + + // Copy shrink_relocs vector to relocs_ + this->relocs_.clear(); + for (typename Relocs::const_iterator p = shrink_relocs.begin(); + p != shrink_relocs.end(); + ++p) + { + this->relocs_.push_back(*p); + } + this->set_current_data_size(addnl_relocs_size + + (this->relocs_.size() * Base::reloc_size)); + } + + void + add_global_generic(Symbol*, unsigned int, Output_data*, uint64_t, uint64_t) + { + gold_unreachable(); + } + + void + add_global_generic(Symbol*, unsigned int, Output_data*, Relobj*, + unsigned int, uint64_t, uint64_t) + { + gold_unreachable(); + } + + // Add a RELATIVE reloc against a global symbol. The final relocation + // will not reference the symbol. + + void + add_global_relative(Symbol* gsym, Output_data* od, Address address) + { + this->add(od, Output_reloc_type(gsym, od, address)); + } + + void + add_global_relative(Symbol* gsym, Output_data* od, + Sized_relobj* relobj, + unsigned int shndx, Address address) + { + this->add(od, Output_reloc_type(gsym, relobj, shndx, address)); + } + + void + add_local_generic(Relobj*, unsigned int, unsigned int, Output_data*, uint64_t, + uint64_t) + { + gold_unreachable(); + } + + void + add_local_generic(Relobj*, unsigned int, unsigned int, Output_data*, + unsigned int, uint64_t, uint64_t) + { + gold_unreachable(); + } + + // Add a RELATIVE reloc against a local symbol. + + void + add_local_relative(Sized_relobj* relobj, + unsigned int local_sym_index, Output_data* od, + Address address) + { + this->add(od, Output_reloc_type(relobj, local_sym_index, od, address, + false)); + } + + void + add_local_relative(Sized_relobj* relobj, + unsigned int local_sym_index, Output_data* od, + unsigned int shndx, Address address) + { + this->add(od, Output_reloc_type(relobj, local_sym_index, shndx, address, + false)); + } + + void + add_output_section_generic(Output_section*, unsigned int, Output_data*, + uint64_t, uint64_t) + { + gold_unreachable(); + } + + void + add_output_section_generic(Output_section*, unsigned int, Output_data*, + Relobj*, unsigned int, uint64_t, uint64_t) + { + gold_unreachable(); + } + + // Add a RELATIVE reloc against an output section symbol. + + void + add_output_section_relative(Output_section* os, Output_data* od, + Address address) + { this->add(od, Output_reloc_type(os, od, address)); } + + void + add_output_section_relative(Output_section* os, Output_data* od, + Sized_relobj* relobj, + unsigned int shndx, Address address) + { this->add(od, Output_reloc_type(os, relobj, shndx, address)); } + + // Add a relative relocation + + void + add_relative(Output_data* od, Address address) + { this->add(od, Output_reloc_type(od, address)); } + + void + add_relative(Output_data* od, Sized_relobj* relobj, + unsigned int shndx, Address address) + { this->add(od, Output_reloc_type(relobj, shndx, address)); } +}; + // Output_relocatable_relocs represents a relocation section in a // relocatable link. The actual data is written out in the target // hook relocate_relocs. This just saves space for it. diff --git a/binutils-2.27/gold/reloc-types.h b/binutils-2.27/gold/reloc-types.h index 7334b9f6..269e49db 100644 --- a/binutils-2.27/gold/reloc-types.h +++ b/binutils-2.27/gold/reloc-types.h @@ -79,6 +79,26 @@ struct Reloc_types { p->put_r_addend(val); } }; +template +struct Reloc_types +{ + typedef typename elfcpp::Relr Reloc; + typedef typename elfcpp::Relr_write Reloc_write; + static const int reloc_size = elfcpp::Elf_sizes::relr_size; + + static inline typename elfcpp::Elf_types::Elf_Swxword + get_reloc_addend(const Reloc*) + { gold_unreachable(); } + + static inline typename elfcpp::Elf_types::Elf_Swxword + get_reloc_addend_noerror(const Reloc*) + { return 0; } + + static inline void + set_reloc_addend(Reloc_write*, + typename elfcpp::Elf_types::Elf_Swxword) + { gold_unreachable(); } +}; }; // End namespace gold. #endif // !defined(GOLD_RELOC_TYPE_SH) diff --git a/binutils-2.27/gold/x86_64.cc b/binutils-2.27/gold/x86_64.cc index 83fa130f..7b736188 100644 --- a/binutils-2.27/gold/x86_64.cc +++ b/binutils-2.27/gold/x86_64.cc @@ -444,14 +444,15 @@ class Target_x86_64 : public Sized_target // In the x86_64 ABI (p 68), it says "The AMD64 ABI architectures // uses only Elf64_Rela relocation entries with explicit addends." typedef Output_data_reloc Reloc_section; + typedef Output_data_reloc Relr_section; Target_x86_64(const Target::Target_info* info = &x86_64_info) : Sized_target(info), got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL), got_tlsdesc_(NULL), global_offset_table_(NULL), rela_dyn_(NULL), - rela_irelative_(NULL), copy_relocs_(elfcpp::R_X86_64_COPY), - got_mod_index_offset_(-1U), tlsdesc_reloc_info_(), - tls_base_symbol_defined_(false) + rela_irelative_(NULL), relr_dyn_(NULL), + copy_relocs_(elfcpp::R_X86_64_COPY), got_mod_index_offset_(-1U), + tlsdesc_reloc_info_(), tls_base_symbol_defined_(false) { } // The safe value for data segment size for PIE links. @@ -740,6 +741,43 @@ class Target_x86_64 : public Sized_target plt_count); } + bool + do_may_relax() const + { + // If generating '.relr.dyn' section, we need a relaxation pass + // to do the shrinking after all the offsets have been populated. + return parameters->options().experimental_use_relr(); + } + + bool + do_relax (int pass, const Input_objects*, Symbol_table*, Layout* layout, const Task*) + { + if (pass > 1) + return false; + + Layout::Section_list::const_iterator p = layout->section_list().begin(); + for ( ; p != layout->section_list().end(); ++p) + { + if (is_prefix_of(".relr.dyn", (*p)->name())) + break; + } + + if (p == layout->section_list().end()) + return false; + + Output_section * const os = *p; + for (Output_section::Input_section_list::iterator ip = os->input_sections().begin(); + ip != os->input_sections().end(); + ++ip) + { + Relr_section *od = static_cast(ip->output_section_data()); + od->shrink_relocs(); + } + + return true; + } + + private: // The class which scans relocations. class Scan @@ -1044,6 +1082,10 @@ class Target_x86_64 : public Sized_target Reloc_section* rela_irelative_section(Layout*); + // Get the RELR dynamic reloc section, creating it if necessary. + Relr_section* + relr_dyn_section(Layout*); + // Add a potential copy relocation. void copy_reloc(Symbol_table* symtab, Layout* layout, @@ -1107,6 +1149,8 @@ class Target_x86_64 : public Sized_target Reloc_section* rela_dyn_; // The section to use for IRELATIVE relocs. Reloc_section* rela_irelative_; + // The RELR dynamic reloc section. + Relr_section* relr_dyn_; // Relocs saved to avoid a COPY reloc. Copy_relocs copy_relocs_; // Offset of the GOT entry for the TLS module index. @@ -1303,6 +1347,23 @@ Target_x86_64::rela_irelative_section(Layout* layout) return this->rela_irelative_; } +// Get the RELR dynamic reloc section, creating it if necessary. + +template +typename Target_x86_64::Relr_section* +Target_x86_64::relr_dyn_section(Layout* layout) +{ + if (this->relr_dyn_ == NULL) + { + gold_assert(layout != NULL); + this->relr_dyn_ = new Relr_section(); + layout->add_output_section_data(".relr.dyn", elfcpp::SHT_RELR, + elfcpp::SHF_ALLOC, this->relr_dyn_, + ORDER_DYNAMIC_RELOCS, false); + } + return this->relr_dyn_; +} + // Write the first three reserved words of the .got.plt section. // The remainder of the section is written while writing the PLT // in Output_data_plt_i386::do_write. @@ -2486,14 +2547,25 @@ Target_x86_64::Scan::local(Symbol_table* symtab, if (parameters->options().output_is_position_independent()) { unsigned int r_sym = elfcpp::elf_r_sym(reloc.get_r_info()); - Reloc_section* rela_dyn = target->rela_dyn_section(layout); - rela_dyn->add_local_relative(object, r_sym, - (size == 32 - ? elfcpp::R_X86_64_RELATIVE64 - : elfcpp::R_X86_64_RELATIVE), - output_section, data_shndx, - reloc.get_r_offset(), - reloc.get_r_addend(), is_ifunc); + if (size == 64 + && !is_ifunc + && parameters->options().experimental_use_relr()) + { + Relr_section* relr_dyn = target->relr_dyn_section(layout); + relr_dyn->add_local_relative(object, r_sym, output_section, + data_shndx, reloc.get_r_offset()); + } + else + { + Reloc_section* rela_dyn = target->rela_dyn_section(layout); + rela_dyn->add_local_relative(object, r_sym, + (size == 32 + ? elfcpp::R_X86_64_RELATIVE64 + : elfcpp::R_X86_64_RELATIVE), + output_section, data_shndx, + reloc.get_r_offset(), + reloc.get_r_addend(), is_ifunc); + } } break; @@ -2511,12 +2583,22 @@ Target_x86_64::Scan::local(Symbol_table* symtab, if (size == 32 && r_type == elfcpp::R_X86_64_32) { unsigned int r_sym = elfcpp::elf_r_sym(reloc.get_r_info()); - Reloc_section* rela_dyn = target->rela_dyn_section(layout); - rela_dyn->add_local_relative(object, r_sym, - elfcpp::R_X86_64_RELATIVE, - output_section, data_shndx, - reloc.get_r_offset(), - reloc.get_r_addend(), is_ifunc); + if (!is_ifunc && parameters->options().experimental_use_relr()) + { + Relr_section* relr_dyn = target->relr_dyn_section(layout); + relr_dyn->add_local_relative(object, r_sym, output_section, + data_shndx, + reloc.get_r_offset()); + } + else + { + Reloc_section* rela_dyn = target->rela_dyn_section(layout); + rela_dyn->add_local_relative(object, r_sym, + elfcpp::R_X86_64_RELATIVE, + output_section, data_shndx, + reloc.get_r_offset(), + reloc.get_r_addend(), is_ifunc); + } break; } @@ -2617,24 +2699,33 @@ Target_x86_64::Scan::local(Symbol_table* symtab, // dynamic relocation for this symbol's GOT entry. if (parameters->options().output_is_position_independent()) { + unsigned int got_offset = + object->local_got_offset(r_sym, GOT_TYPE_STANDARD); Reloc_section* rela_dyn = target->rela_dyn_section(layout); // R_X86_64_RELATIVE assumes a 64-bit relocation. - if (r_type != elfcpp::R_X86_64_GOT32) - { - unsigned int got_offset = - object->local_got_offset(r_sym, GOT_TYPE_STANDARD); - rela_dyn->add_local_relative(object, r_sym, - elfcpp::R_X86_64_RELATIVE, - got, got_offset, 0, is_ifunc); - } - else + if (r_type == elfcpp::R_X86_64_GOT32) { this->check_non_pic(object, r_type, NULL); gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION); rela_dyn->add_local( object, r_sym, r_type, got, - object->local_got_offset(r_sym, GOT_TYPE_STANDARD), 0); + got_offset, 0); + } + else if (size == 64 + && !is_ifunc + && parameters->options().experimental_use_relr()) + { + Relr_section* relr_dyn = + target->relr_dyn_section(layout); + relr_dyn->add_local_relative(object, r_sym, + got, got_offset); + } + else + { + rela_dyn->add_local_relative(object, r_sym, + elfcpp::R_X86_64_RELATIVE, + got, got_offset, 0, is_ifunc); } } } @@ -2998,12 +3089,24 @@ Target_x86_64::Scan::global(Symbol_table* symtab, || (size == 32 && r_type == elfcpp::R_X86_64_32)) && gsym->can_use_relative_reloc(false)) { - Reloc_section* rela_dyn = target->rela_dyn_section(layout); - rela_dyn->add_global_relative(gsym, elfcpp::R_X86_64_RELATIVE, - output_section, object, - data_shndx, - reloc.get_r_offset(), - reloc.get_r_addend(), false); + if (parameters->options().experimental_use_relr()) + { + Relr_section* relr_dyn = + target->relr_dyn_section(layout); + relr_dyn->add_global_relative(gsym, output_section, + object, data_shndx, + reloc.get_r_offset()); + } + else + { + Reloc_section* rela_dyn = target->rela_dyn_section(layout); + rela_dyn->add_global_relative(gsym, + elfcpp::R_X86_64_RELATIVE, + output_section, object, + data_shndx, + reloc.get_r_offset(), + reloc.get_r_addend(), false); + } } else { @@ -3135,9 +3238,18 @@ Target_x86_64::Scan::global(Symbol_table* symtab, if (is_new) { unsigned int got_off = gsym->got_offset(GOT_TYPE_STANDARD); - rela_dyn->add_global_relative(gsym, - elfcpp::R_X86_64_RELATIVE, - got, got_off, 0, false); + if (parameters->options().experimental_use_relr()) + { + Relr_section* relr_dyn = + target->relr_dyn_section(layout); + relr_dyn->add_global_relative(gsym, got, got_off); + } + else + { + rela_dyn->add_global_relative(gsym, + elfcpp::R_X86_64_RELATIVE, + got, got_off, 0, false); + } } } } @@ -3406,7 +3518,8 @@ Target_x86_64::do_finalize_sections( ? NULL : this->plt_->rela_plt()); layout->add_target_dynamic_tags(false, this->got_plt_, rel_plt, - this->rela_dyn_, true, false); + this->rela_dyn_, true, false, + this->relr_dyn_); // Fill in some more dynamic tags. Output_data_dynamic* const odyn = layout->dynamic_data(); diff --git a/binutils-2.27/include/elf/common.h b/binutils-2.27/include/elf/common.h index d2da009d..833190ca 100644 --- a/binutils-2.27/include/elf/common.h +++ b/binutils-2.27/include/elf/common.h @@ -490,6 +490,10 @@ #define SHT_GNU_verneed SHT_SUNW_verneed #define SHT_GNU_versym SHT_SUNW_versym +/* Experimental support for SHT_RELR sections. For details, see proposal + at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg */ +#define SHT_RELR 0x6fffff00 /* Relative relocations, only offsets */ + #define SHT_LOPROC 0x70000000 /* Processor-specific semantics, lo */ #define SHT_HIPROC 0x7FFFFFFF /* Processor-specific semantics, hi */ #define SHT_LOUSER 0x80000000 /* Application-specific semantics */ @@ -831,6 +835,13 @@ /* This tag is a GNU extension to the Solaris version scheme. */ #define DT_VERSYM 0x6ffffff0 +/* Experimental support for SHT_RELR sections. For details, see proposal + at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg */ +#define DT_RELR 0x6fffe000 +#define DT_RELRSZ 0x6fffe001 +#define DT_RELRENT 0x6fffe003 +#define DT_RELRCOUNT 0x6fffe005 + #define DT_LOPROC 0x70000000 #define DT_HIPROC 0x7fffffff diff --git a/binutils-2.27/include/elf/external.h b/binutils-2.27/include/elf/external.h index d4d83ef8..098de3a6 100644 --- a/binutils-2.27/include/elf/external.h +++ b/binutils-2.27/include/elf/external.h @@ -195,6 +195,10 @@ typedef struct { unsigned char r_addend[4]; /* Constant addend used to compute value */ } Elf32_External_Rela; +typedef struct { + unsigned char r_data[4]; /* jump and bitmap for relative relocations */ +} Elf32_External_Relr; + typedef struct { unsigned char r_offset[8]; /* Location at which to apply the action */ unsigned char r_info[8]; /* index and type of relocation */ @@ -206,6 +210,10 @@ typedef struct { unsigned char r_addend[8]; /* Constant addend used to compute value */ } Elf64_External_Rela; +typedef struct { + unsigned char r_data[8]; /* jump and bitmap for relative relocations */ +} Elf64_External_Relr; + /* dynamic section structure */ typedef struct { -- cgit v1.2.3