diff -ru binutils-2.25/bfd/elf-bfd.h binutils-2.25-patched/bfd/elf-bfd.h --- binutils-2.25/bfd/elf-bfd.h 2014-12-23 08:47:10.000000000 +0000 +++ binutils-2.25-patched/bfd/elf-bfd.h 2016-10-25 23:03:11.337158328 +0000 @@ -197,6 +197,14 @@ /* Symbol is a unique global symbol. */ unsigned int unique_global : 1; + /* FIXME: these 2 bits consume another 4 bytes. */ + /* Symbol is concrete, ie. non-vague if we can detect that, from the + .direct section. */ + unsigned int concrete_ref : 1; + /* Symbol is certainly vague (if we can detect that), from the + .direct section. */ + unsigned int vague_ref : 1; + /* String table index in .dynstr if this is a dynamic symbol. */ unsigned long dynstr_index; @@ -522,6 +530,9 @@ asection *tls_sec; bfd_size_type tls_size; + /* Direct linkage output section. */ + asection *direct_sec; + /* A linked list of BFD's loaded in the link. */ struct elf_link_loaded_list *loaded; @@ -1611,6 +1622,7 @@ name actually used, which will be the DT_SONAME entry if there is one. */ const char *dt_name; + int dt_needed_idx; /* The linker emulation needs to know what audit libs are used by a dynamic object. */ @@ -1726,6 +1738,7 @@ #define elf_local_got_offsets(bfd) (elf_tdata(bfd) -> local_got.offsets) #define elf_local_got_ents(bfd) (elf_tdata(bfd) -> local_got.ents) #define elf_dt_name(bfd) (elf_tdata(bfd) -> dt_name) +#define elf_dt_needed_idx(bfd) (elf_tdata(bfd) -> dt_needed_idx) #define elf_dt_audit(bfd) (elf_tdata(bfd) -> dt_audit) #define elf_dyn_lib_class(bfd) (elf_tdata(bfd) -> dyn_lib_class) #define elf_bad_symtab(bfd) (elf_tdata(bfd) -> bad_symtab) diff -ru binutils-2.25/bfd/elf.c binutils-2.25-patched/bfd/elf.c --- binutils-2.25/bfd/elf.c 2016-10-25 23:06:50.887159400 +0000 +++ binutils-2.25-patched/bfd/elf.c 2016-10-25 23:02:13.013158043 +0000 @@ -1331,6 +1331,7 @@ case DT_RELCOUNT: name = "RELCOUNT"; break; case DT_FLAGS_1: name = "FLAGS_1"; break; case DT_VERSYM: name = "VERSYM"; break; + case DT_SUSE_DIRECT: name = "SUSE_DIRECT"; break; case DT_VERDEF: name = "VERDEF"; break; case DT_VERDEFNUM: name = "VERDEFNUM"; break; case DT_VERNEED: name = "VERNEED"; break; diff -ru binutils-2.25/bfd/elflink.c binutils-2.25-patched/bfd/elflink.c --- binutils-2.25/bfd/elflink.c 2016-10-25 23:06:50.889159400 +0000 +++ binutils-2.25-patched/bfd/elflink.c 2016-10-25 23:04:21.384158670 +0000 @@ -221,6 +221,16 @@ return FALSE; } + if ( info->direct && !info->executable ) + { + s = bfd_make_section (abfd, ".suse.direct"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, 2)) + return FALSE; + elf_hash_table (info)->direct_sec = s; + } + /* Create sections to hold version informations. These are removed if they are not needed. */ s = bfd_make_section_anyway_with_flags (abfd, ".gnu.version_d", @@ -3085,6 +3095,7 @@ if (!_bfd_elf_add_dynamic_entry (info, DT_NEEDED, strindex)) return -1; + elf_dt_needed_idx (abfd) = ++(info->dt_needed_index); } else /* We were just checking for existence of the tag. */ @@ -3338,6 +3349,8 @@ bfd_boolean add_needed; struct elf_link_hash_table *htab; bfd_size_type amt; + asection *direct_sec; + unsigned char *direct_data; void *alloc_mark = NULL; struct bfd_hash_entry **old_table = NULL; unsigned int old_size = 0; @@ -3355,6 +3368,9 @@ htab = elf_hash_table (info); bed = get_elf_backend_data (abfd); + direct_sec = NULL; + direct_data = NULL; + if ((abfd->flags & DYNAMIC) == 0) dynamic = FALSE; else @@ -3374,6 +3390,16 @@ bfd_set_error (bfd_error_wrong_format); goto error_return; } + if (info->direct) + direct_sec = bfd_get_section_by_name (abfd, ".suse.direct"); + if (direct_sec != NULL) + { + direct_data = bfd_alloc (abfd, direct_sec->size); + if (direct_data == NULL + || ! bfd_get_section_contents (abfd, direct_sec, + direct_data, 0, direct_sec->size)) + goto error_return; + } } ehdr = elf_elfheader (abfd); @@ -4115,6 +4141,23 @@ && vernum > 1 && definition) h->verinfo.verdef = &elf_tdata (abfd)->verdef[vernum - 1]; + + if (direct_sec != NULL) + { + unsigned long d_idx = isym - isymbuf; + unsigned long direct_entry; + d_idx += extsymoff; + d_idx *= 2; + BFD_ASSERT (d_idx <= bfd_get_section_size (direct_sec)); + direct_entry = bfd_get_16 (abfd, direct_data + d_idx); + if ((direct_entry & DT_SUSE_DIRECT_VAGUE) != 0) + h->vague_ref = 1; + if (!h->vague_ref + && (direct_entry & DT_SUSE_DIRECT_MASK) != + DT_SUSE_DIRECT_UNKNOWN) + h->concrete_ref = 1; + } + } if (! (_bfd_generic_link_add_one_symbol @@ -4885,6 +4928,8 @@ if (isymbuf != NULL) free (isymbuf); error_return: + if (direct_data != NULL) + free (direct_data); return FALSE; } @@ -6402,6 +6447,24 @@ return FALSE; } + /* Create the direct bindings section - 1 entry per dynsym. */ + s = bfd_get_section_by_name (dynobj, ".suse.direct"); + if (s != NULL) + { + if (dynsymcount == 0) + s->flags |= SEC_EXCLUDE; + else + { + s->size = dynsymcount * sizeof (Elf_External_Direct); + s->contents = bfd_zalloc (output_bfd, s->size); + if (s->contents == NULL) + return FALSE; + memset (s->contents, 0xff, s->size); + if (!_bfd_elf_add_dynamic_entry (info, DT_SUSE_DIRECT, 0)) + return FALSE; + } + } + /* Set the size of the .dynsym and .hash sections. We counted the number of dynamic symbols in elf_link_add_object_symbols. We will build the contents of .dynsym and .hash when we build @@ -6869,6 +6932,7 @@ table->root.type = bfd_link_elf_hash_table; table->hash_table_id = target_id; + table->direct_sec = NULL; return ret; } @@ -7424,6 +7488,8 @@ asection *hash_sec; /* symbol version section (.gnu.version). */ asection *symver_sec; + /* .direct linkage section. */ + asection *direct_sec; /* Buffer large enough to hold contents of any section. */ bfd_byte *contents; /* Buffer large enough to hold external relocs of any section. */ @@ -8703,6 +8769,46 @@ eoinfo->file_sym_done = TRUE; } + + if (finfo->direct_sec != NULL) + { + int dt_index = DT_SUSE_DIRECT_UNKNOWN; + bfd_vma offset = 2 * h->dynindx; + BFD_ASSERT (offset <= finfo->direct_sec->size); + + if ((h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && h->root.u.def.section != NULL + && h->root.u.def.section->owner != NULL) + { + asection *sec = h->root.u.def.section; + + dt_index = elf_dt_needed_idx (sec->owner); + + if ((sec->owner->flags & DYNAMIC) == 0) + { + if (sec->name == NULL + || strncmp (sec->name, ".gnu.linkonce", + sizeof ".gnu.linkonce" - 1) == 0) + dt_index |= DT_SUSE_DIRECT_VAGUE; + + /* app -> library data references get turned into copy + relocs, so objects can migrate unpredictably into the + application itself. */ + else if (h->type == STT_OBJECT) + dt_index |= DT_SUSE_DIRECT_VAGUE; + } + else if (h->vague_ref) + dt_index |= DT_SUSE_DIRECT_VAGUE; + + else if (!h->concrete_ref) + dt_index = DT_SUSE_DIRECT_UNKNOWN; + + } + bfd_put_16 (finfo->output_bfd, + dt_index, + finfo->direct_sec->contents + offset); + } } else { @@ -10511,6 +10617,7 @@ if (! dynamic) { + finfo.direct_sec = NULL; flinfo.dynsym_sec = NULL; flinfo.hash_sec = NULL; flinfo.symver_sec = NULL; @@ -10518,6 +10625,7 @@ } else { + finfo.direct_sec = bfd_get_section_by_name (dynobj, ".suse.direct"); flinfo.dynsym_sec = bfd_get_linker_section (dynobj, ".dynsym"); flinfo.hash_sec = bfd_get_linker_section (dynobj, ".hash"); /* Note that dynsym_sec can be NULL (on VMS). */ @@ -11350,6 +11458,9 @@ case DT_VERNEED: name = ".gnu.version_r"; goto get_vma; + case DT_SUSE_DIRECT: + name = ".suse.direct"; + goto get_vma; case DT_VERSYM: name = ".gnu.version"; get_vma: diff -ru binutils-2.25/binutils/readelf.c binutils-2.25-patched/binutils/readelf.c --- binutils-2.25/binutils/readelf.c 2014-12-23 08:47:10.000000000 +0000 +++ binutils-2.25-patched/binutils/readelf.c 2016-10-25 23:05:05.774158887 +0000 @@ -194,6 +194,7 @@ static int do_syms; static int do_dyn_syms; static int do_reloc; +static int do_direct; static int do_sections; static int do_section_groups; static int do_section_details; @@ -1877,6 +1878,7 @@ case DT_SYMINFO: return "SYMINFO"; /* aka ADDRRNGHI */ case DT_VERSYM: return "VERSYM"; + case DT_SUSE_DIRECT: return "SUSE_DIRECT"; case DT_TLSDESC_GOT: return "TLSDESC_GOT"; case DT_TLSDESC_PLT: return "TLSDESC_PLT"; @@ -3722,6 +3724,7 @@ {"syms", no_argument, 0, 's'}, {"dyn-syms", no_argument, 0, OPTION_DYN_SYMS}, {"relocs", no_argument, 0, 'r'}, + {"direct", no_argument, 0, 'y'}, {"notes", no_argument, 0, 'n'}, {"dynamic", no_argument, 0, 'd'}, {"arch-specific", no_argument, 0, 'A'}, @@ -3767,6 +3770,7 @@ --dyn-syms Display the dynamic symbol table\n\ -n --notes Display the core notes (if present)\n\ -r --relocs Display the relocations (if present)\n\ + -y --direct Display direct linkage table (if present)\n\ -u --unwind Display the unwind info (if present)\n\ -d --dynamic Display the dynamic section (if present)\n\ -V --version-info Display the version sections (if present)\n\ @@ -3889,7 +3893,7 @@ usage (stderr); while ((c = getopt_long - (argc, argv, "ADHINR:SVWacdeghi:lnp:rstuvw::x:", options, NULL)) != EOF) + (argc, argv, "ADHINR:SVWacdeyghi:lnp:rstuvw::x:", options, NULL)) != EOF) { switch (c) { @@ -3903,6 +3907,7 @@ case 'a': do_syms++; do_reloc++; + do_direct++; do_unwind++; do_dynamic++; do_header++; @@ -3936,6 +3941,9 @@ case 'r': do_reloc++; break; + case 'y': + do_direct++; + break; case 'u': do_unwind++; break; @@ -4042,6 +4050,7 @@ && !do_segments && !do_header && !do_dump && !do_version && !do_histogram && !do_debugging && !do_arch && !do_notes && !do_section_groups && !do_archive_index + && !do_direct && !do_dyn_syms) usage (stderr); else if (argc < 3) @@ -6192,6 +6201,132 @@ return 1; } +static void +print_dt_needed_name (int idx) +{ + const char *name = NULL; + Elf_Internal_Dyn *entry; + + idx &= DT_SUSE_DIRECT_MASK; + + switch (idx) + { + case 0: + name = _(""); + break; + case DT_SUSE_DIRECT_UNKNOWN: + name = _(""); + break; + default: + idx--; + + for (entry = dynamic_section; + entry < dynamic_section + dynamic_nent && idx > 0; + entry++) + if (entry->d_tag == DT_NEEDED) + idx--; + + if (idx == 0) + { + if (VALID_DYNAMIC_NAME (entry->d_un.d_val)) + name = GET_DYNAMIC_NAME (entry->d_un.d_val); + else + name = NULL; + } + break; + } + + if (!name) + name = _(""); + if (do_wide) + printf ("%s", name); + else + printf ("%-25s", name); +} + +static int +process_direct (FILE *file) +{ + unsigned int i; + unsigned int si; + char *strtab; + unsigned char *directtab; + Elf_Internal_Sym *symtab = NULL; + Elf_Internal_Sym *psym; + Elf_Internal_Shdr *direct = NULL; + Elf_Internal_Shdr *dynsym = NULL; + Elf_Internal_Shdr *section; + + if (!do_direct) + return 1; + if (!dynamic_symbols || !dynamic_section || !dynamic_strings) + return 1; + + for (i = 0, section = section_headers; + i < elf_header.e_shnum; + i++, section++) + { + if (section->sh_type == SHT_DYNSYM) + dynsym = section; + if (!strcmp (SECTION_NAME (section), ".suse.direct")) + direct = section; + } + if (!dynsym || !direct) + return 1; + + symtab = GET_ELF_SYMBOLS (file, dynsym); + if (!symtab) + return 1; + + directtab = get_data (NULL, file, direct->sh_offset, + direct->sh_size, 1, _("direct linkage table")); + if (!symtab) + { + free (symtab); + return 1; + } + + if (dynsym->sh_link == elf_header.e_shstrndx) + strtab = string_table; + else + { + Elf_Internal_Shdr *string_sec; + + string_sec = SECTION_HEADER (dynsym->sh_link); + + strtab = get_data (NULL, file, string_sec->sh_offset, + string_sec->sh_size, 1, _("string table")); + } + + assert (strtab != NULL); + + printf (_("\nDirect relocations for image:\n")); + printf (_(" Num: Index Vague Binding Symbol\n")); + for (si = 0, psym = symtab; + si < dynsym->sh_size / dynsym->sh_entsize; + si++, psym++) + { + unsigned int field; + printf ("%6d: ", si); + field = byte_get (directtab + (si * 2), 2); + printf ("[0x%.4x] ", field); + printf ("%s", (field & DT_SUSE_DIRECT_VAGUE) ? "Vague" : " "); + printf (" "); + print_dt_needed_name (field); + printf (" "); + print_symbol (25, strtab + psym->st_name); + printf ("\n"); + } + + + free (symtab); + if (strtab != string_table) + free (strtab); + + return 1; +} + + /* Process the unwind section. */ #include "unwind-ia64.h" @@ -14981,6 +15116,8 @@ process_relocs (file); + process_direct (file); + process_unwind (file); process_symbol_table (file); diff -ru binutils-2.25/include/bfdlink.h binutils-2.25-patched/include/bfdlink.h --- binutils-2.25/include/bfdlink.h 2016-10-25 23:06:50.890159400 +0000 +++ binutils-2.25-patched/include/bfdlink.h 2016-10-25 23:05:24.225158977 +0000 @@ -277,6 +277,9 @@ Setting this true may result in a non-sharable text segment. */ unsigned int nocopyreloc: 1; + /* TRUE if BFD should bind symbols directly to resolved at link time. */ + unsigned int direct: 1; + /* TRUE if BFD should export all symbols in the dynamic symbol table of an executable, rather than only those used. */ unsigned int export_dynamic: 1; @@ -528,6 +531,9 @@ is explicitly requested by the user, -1 if enabled by default. */ int pei386_runtime_pseudo_reloc; + /* current max dtinfo section number. */ + int dt_needed_index; + /* How many spare .dynamic DT_NULL entries should be added? */ unsigned int spare_dynamic_tags; diff -ru binutils-2.25/include/elf/common.h binutils-2.25-patched/include/elf/common.h --- binutils-2.25/include/elf/common.h 2016-10-25 23:06:50.890159400 +0000 +++ binutils-2.25-patched/include/elf/common.h 2016-10-25 23:02:13.033158043 +0000 @@ -862,6 +862,11 @@ #define DF_BIND_NOW (1 << 3) #define DF_STATIC_TLS (1 << 4) +/* Constants for the DT_DIRECT entries. */ +#define DT_SUSE_DIRECT_VAGUE (1<<15) +#define DT_SUSE_DIRECT_MASK 0xfff +#define DT_SUSE_DIRECT_UNKNOWN DT_SUSE_DIRECT_MASK + /* These constants are used for the version number of a Elf32_Verdef structure. */ diff -ru binutils-2.25/include/elf/external.h binutils-2.25-patched/include/elf/external.h --- binutils-2.25/include/elf/external.h 2014-10-14 07:32:04.000000000 +0000 +++ binutils-2.25-patched/include/elf/external.h 2016-10-25 23:02:13.033158043 +0000 @@ -225,6 +225,10 @@ unsigned char vd_next[4]; } Elf_External_Verdef; +typedef struct { + unsigned char dir_libidx[2]; +} Elf_External_Direct; + /* This structure appears in a SHT_GNU_verdef section. */ typedef struct { diff -ru binutils-2.25/ld/ldlex.h binutils-2.25-patched/ld/ldlex.h --- binutils-2.25/ld/ldlex.h 2016-10-25 23:06:50.890159400 +0000 +++ binutils-2.25-patched/ld/ldlex.h 2016-10-25 23:06:14.289159222 +0000 @@ -32,6 +32,7 @@ OPTION_CREF, OPTION_DEFSYM, OPTION_DEMANGLE, + OPTION_DIRECT, OPTION_DYNAMIC_LINKER, OPTION_SYSROOT, OPTION_EB, diff -ru binutils-2.25/ld/lexsup.c binutils-2.25-patched/ld/lexsup.c --- binutils-2.25/ld/lexsup.c 2016-10-25 23:06:50.891159400 +0000 +++ binutils-2.25-patched/ld/lexsup.c 2016-10-25 23:05:56.087159133 +0000 @@ -277,6 +277,8 @@ '\0', NULL, N_("Bind global references locally"), ONE_DASH }, { {"Bsymbolic-functions", no_argument, NULL, OPTION_SYMBOLIC_FUNCTIONS}, '\0', NULL, N_("Bind global function references locally"), ONE_DASH }, + { {"Bdirect", no_argument, NULL, OPTION_DIRECT}, + '\0', NULL, N_("Direct-linkage the the shared libraries"), TWO_DASHES }, { {"check-sections", no_argument, NULL, OPTION_CHECK_SECTIONS}, '\0', NULL, N_("Check section addresses for overlaps (default)"), TWO_DASHES }, @@ -746,6 +748,9 @@ cplus_demangle_set_style (style); } break; + case OPTION_DIRECT: + link_info.direct = TRUE; + break; case 'I': /* Used on Solaris. */ case OPTION_DYNAMIC_LINKER: command_line.interpreter = optarg;