diff -ru binutils-2.25/bfd/elf.c binutils-2.25-patched/bfd/elf.c --- binutils-2.25/bfd/elf.c 2014-12-23 08:47:10.000000000 +0000 +++ binutils-2.25-patched/bfd/elf.c 2016-10-25 17:54:09.297067784 +0000 @@ -1339,6 +1339,7 @@ case DT_USED: name = "USED"; break; case DT_FILTER: name = "FILTER"; stringp = TRUE; break; case DT_GNU_HASH: name = "GNU_HASH"; break; + case DT_SUSE_HASHVALS: name = "SUSE_HASHVALS"; break; } fprintf (f, " %-20s ", name); diff -ru binutils-2.25/bfd/elflink.c binutils-2.25-patched/bfd/elflink.c --- binutils-2.25/bfd/elflink.c 2014-12-23 08:47:10.000000000 +0000 +++ binutils-2.25-patched/bfd/elflink.c 2016-10-25 18:06:30.811071405 +0000 @@ -202,6 +202,15 @@ flags = bed->dynamic_sec_flags; + if (info->hashvals) + { + s = bfd_make_section (abfd, ".suse.hashvals"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, 2)) + return FALSE; + } + /* A dynamically linked executable has a .interp section, but a shared library does not. */ if (info->executable) @@ -6417,6 +6426,24 @@ elf_hash_table (info)->bucketcount = 0; + /* Create the direct bindings section - 1 entry per dynsym */ + s = bfd_get_section_by_name (dynobj, ".suse.hashvals"); + if (s) + { + if (dynsymcount == 0) + s->flags |= SEC_EXCLUDE; + else + { + s->size = dynsymcount * bed->s->sizeof_hash_entry; + s->contents = bfd_zalloc (output_bfd, s->size); + if (s->contents == NULL) + return FALSE; + memset (s->contents, 0xfe, s->size); + if (!_bfd_elf_add_dynamic_entry (info, DT_SUSE_HASHVALS, 0)) + return FALSE; + } + } + /* Compute the size of the hashing table. As a side effect this computes the hash values for all the names we export. */ if (info->emit_hash) @@ -7417,6 +7444,8 @@ /* Array large enough to hold a section pointer for each local symbol of any input BFD. */ asection **sections; + /* .suse.hashvals section */ + asection *hashvals_sec; /* Buffer to hold swapped out symbols. */ bfd_byte *symbuf; /* And one for symbol section indices. */ @@ -9043,6 +9072,19 @@ bfd_put (8 * hash_entry_size, flinfo->output_bfd, chain, ((bfd_byte *) flinfo->hash_sec->contents + (bucketcount + 2 + h->dynindx) * hash_entry_size)); + + bfd_vma offset = hash_entry_size * h->dynindx; + if (offset > flinfo->hashvals_sec->size) + { + fprintf (stderr, \ + "Out of bounds hashvals section index %d size %d\n", \ + (int) offset, (int) flinfo->hashvals_sec->size); + } + else + { + bfd_put (8 * hash_entry_size, flinfo->output_bfd, \ + h->u.elf_hash_value, flinfo->hashvals_sec->contents + offset); + } } if (flinfo->symver_sec != NULL && flinfo->symver_sec->contents != NULL) @@ -10472,6 +10514,7 @@ flinfo.dynsym_sec = NULL; flinfo.hash_sec = NULL; flinfo.symver_sec = NULL; + flinfo.hashvals_sec = NULL; } else { @@ -10480,6 +10523,7 @@ /* Note that dynsym_sec can be NULL (on VMS). */ flinfo.symver_sec = bfd_get_linker_section (dynobj, ".gnu.version"); /* Note that it is OK if symver_sec is NULL. */ + finfo.hashvals_sec = bfd_get_section_by_name (dynobj, ".suse.hashvals"); } flinfo.contents = NULL; @@ -11291,6 +11335,9 @@ case DT_GNU_HASH: name = ".gnu.hash"; goto get_vma; + case DT_SUSE_HASHVALS: + name = ".suse.hashvals"; + goto get_vma; case DT_STRTAB: name = ".dynstr"; goto get_vma; @@ -13062,3 +13109,4 @@ BFD_ASSERT (loc + bed->s->sizeof_rel <= s->contents + s->size); bed->s->swap_reloc_out (abfd, rel, loc); } + diff -ru binutils-2.25/include/bfdlink.h binutils-2.25-patched/include/bfdlink.h --- binutils-2.25/include/bfdlink.h 2014-12-23 08:47:10.000000000 +0000 +++ binutils-2.25-patched/include/bfdlink.h 2016-10-25 17:53:00.057067446 +0000 @@ -386,6 +386,10 @@ statics. */ unsigned int task_link: 1; + /* TRUE if we want to produced a section containing pre-computed + hash values. This consumes more space. */ + unsigned int hashvals: 1; + /* TRUE if ok to have multiple definition. */ unsigned int allow_multiple_definition: 1; diff -ru binutils-2.25/include/elf/common.h binutils-2.25-patched/include/elf/common.h --- binutils-2.25/include/elf/common.h 2014-10-14 07:32:04.000000000 +0000 +++ binutils-2.25-patched/include/elf/common.h 2016-10-25 17:53:00.058067446 +0000 @@ -807,6 +807,12 @@ #define DT_FILTER 0x7fffffff +/* Selected at random */ +#define DT_SUSE_LO 0x6cbdd030 +#define DT_SUSE_HASHVALS DT_SUSE_LO +#define DT_SUSE_DIRECT DT_SUSE_LO + 1 +#define DT_SUSE_HI 0x6cbdd040 + /* Values used in DT_FEATURE .dynamic entry. */ #define DTF_1_PARINIT 0x00000001 /* From diff -ru binutils-2.25/ld/ldlex.h binutils-2.25-patched/ld/ldlex.h --- binutils-2.25/ld/ldlex.h 2014-11-04 09:54:41.000000000 +0000 +++ binutils-2.25-patched/ld/ldlex.h 2016-10-25 18:12:04.812073036 +0000 @@ -38,6 +38,7 @@ OPTION_EL, OPTION_EMBEDDED_RELOCS, OPTION_EXPORT_DYNAMIC, + OPTION_HASHVALS, OPTION_NO_EXPORT_DYNAMIC, OPTION_HELP, OPTION_IGNORE, diff -ru binutils-2.25/ld/lexsup.c binutils-2.25-patched/ld/lexsup.c --- binutils-2.25/ld/lexsup.c 2014-11-04 09:54:41.000000000 +0000 +++ binutils-2.25-patched/ld/lexsup.c 2016-10-25 18:10:56.331072702 +0000 @@ -271,6 +271,8 @@ '\0', NULL, NULL, ONE_DASH }, { {"static", no_argument, NULL, OPTION_NON_SHARED}, '\0', NULL, NULL, ONE_DASH }, + { {"hashvals", no_argument, NULL, OPTION_HASHVALS}, + '\0', NULL, N_("Store pre-computed elf hash codes"), TWO_DASHES }, { {"Bsymbolic", no_argument, NULL, OPTION_SYMBOLIC}, '\0', NULL, N_("Bind global references locally"), ONE_DASH }, { {"Bsymbolic-functions", no_argument, NULL, OPTION_SYMBOLIC_FUNCTIONS}, @@ -1154,6 +1156,9 @@ case OPTION_SYMBOLIC_FUNCTIONS: command_line.symbolic = symbolic_functions; break; + case OPTION_HASHVALS: + link_info.hashvals = TRUE; + break; case 't': trace_files = TRUE; break;