diff -ruN binutils-2.16.91.0.5.orig/bfd/elf-bfd.h binutils-2.16.91.0.5/bfd/elf-bfd.h --- binutils-2.16.91.0.5.orig/bfd/elf-bfd.h 2005-12-21 04:43:55.000000000 +0600 +++ binutils-2.16.91.0.5/bfd/elf-bfd.h 2006-01-22 23:11:53.807377894 +0600 @@ -170,6 +170,14 @@ matters. */ unsigned int pointer_equality_needed : 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; @@ -398,6 +406,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; @@ -1276,6 +1287,7 @@ name actually used, which will be the DT_SONAME entry if there is one. */ const char *dt_name; + int dt_needed_idx; /* Records the result of `get_program_header_size'. */ bfd_size_type program_header_size; @@ -1376,6 +1388,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_dyn_lib_class(bfd) (elf_tdata(bfd) -> dyn_lib_class) #define elf_bad_symtab(bfd) (elf_tdata(bfd) -> bad_symtab) #define elf_flags_init(bfd) (elf_tdata(bfd) -> flags_init) diff -ruN binutils-2.16.91.0.5.orig/bfd/elf.c binutils-2.16.91.0.5/bfd/elf.c --- binutils-2.16.91.0.5.orig/bfd/elf.c 2005-12-21 04:43:55.000000000 +0600 +++ binutils-2.16.91.0.5/bfd/elf.c 2006-01-22 23:11:53.830372167 +0600 @@ -1220,6 +1220,7 @@ case DT_RELCOUNT: name = "RELCOUNT"; break; case DT_FLAGS_1: name = "FLAGS_1"; break; case DT_VERSYM: name = "VERSYM"; break; + case DT_DIRECT: name = "DIRECT"; break; case DT_VERDEF: name = "VERDEF"; break; case DT_VERDEFNUM: name = "VERDEFNUM"; break; case DT_VERNEED: name = "VERNEED"; break; @@ -1573,6 +1574,7 @@ table->runpath = NULL; table->tls_sec = NULL; table->tls_size = 0; + table->direct_sec = NULL; table->loaded = NULL; table->is_relocatable_executable = FALSE; diff -ruN binutils-2.16.91.0.5.orig/bfd/elflink.c binutils-2.16.91.0.5/bfd/elflink.c --- binutils-2.16.91.0.5.orig/bfd/elflink.c 2005-12-21 04:43:55.000000000 +0600 +++ binutils-2.16.91.0.5/bfd/elflink.c 2006-01-22 23:11:53.907352993 +0600 @@ -194,6 +194,16 @@ elf_hash_table (info)->eh_info.hdr_sec = s; } + if ( info->direct && !info->executable ) + { + s = bfd_make_section (abfd, ".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_with_flags (abfd, ".gnu.version_d", @@ -2844,6 +2854,9 @@ if (!_bfd_elf_add_dynamic_entry (info, DT_NEEDED, strindex)) return -1; + elf_dt_needed_idx (abfd) = ++(info->dt_needed_index); +/* fprintf (stderr, "Set soname '%s' as index %d\n", + soname, info->dt_needed_index); */ } else /* We were just checking for existence of the tag. */ @@ -3139,6 +3152,8 @@ bfd_boolean add_needed; struct elf_link_hash_table * hash_table; bfd_size_type amt; + asection *direct_sec; + unsigned char *direct_data; hash_table = elf_hash_table (info); @@ -3146,6 +3161,9 @@ add_symbol_hook = bed->elf_add_symbol_hook; collect = bed->collect; + direct_sec = NULL; + direct_data = NULL; + if ((abfd->flags & DYNAMIC) == 0) dynamic = FALSE; else @@ -3165,6 +3183,14 @@ bfd_set_error (bfd_error_wrong_format); goto error_return; } + if (info->direct && + (direct_sec = bfd_get_section_by_name (abfd, ".direct"))) + { + 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; + } } /* As a GNU extension, any input sections which are named @@ -3814,6 +3840,37 @@ && vernum > 1 && definition) h->verinfo.verdef = &elf_tdata (abfd)->verdef[vernum - 1]; + + if (direct_sec) + { + unsigned long d_idx = isym - isymbuf; + /* FIXME: does bfd_elf_get_elf_syms read dynsym or the symbol + table ? */ + d_idx += extsymoff; + d_idx *= 2; + if (d_idx > bfd_get_section_size (direct_sec)) + fprintf (stderr, "Warning - strange error on '%s': 0x%x 0x%x\n", + h->root.root.string, (int)d_idx, + (int)bfd_get_section_size (direct_sec)); + else + { + unsigned int direct_entry; + direct_entry = bfd_get_16 (abfd, direct_data + d_idx); + if ((direct_entry & DT_DIRECT_VAGUE)) + h->vague_ref = 1; + if (!h->vague_ref && + (direct_entry & DT_DIRECT_MASK) != DT_DIRECT_UNKNOWN) + h->concrete_ref = 1; +#if 0 + fprintf (stderr, "symbol '%s': %s direct entry 0x%x (index %d) section '%s' : '%s'\n", + h->root.root.string, + h->vague_ref ? "vague " : h->concrete_ref ? "concrete" : "unknown", + direct_entry, (int)d_idx/2, + new_sec ? new_sec->name : "", + new_sec && new_sec->owner ? new_sec->owner->filename : ""); +#endif + } + } } if (! (_bfd_generic_link_add_one_symbol @@ -3827,6 +3884,8 @@ h = (struct elf_link_hash_entry *) h->root.u.i.link; *sym_hash = h; + /* FIXME: move direct bits here ? - seem fine where they are ... */ + new_weakdef = FALSE; if (dynamic && definition @@ -4446,6 +4505,8 @@ if (isymbuf != NULL) free (isymbuf); error_return: + if (direct_data != NULL) + free (direct_data); return FALSE; } @@ -5695,6 +5756,24 @@ return FALSE; } + /* Create the direct bindings section - 1 entry per dynsym */ + s = bfd_get_section_by_name (dynobj, ".direct"); + if (s) + { + if (dynsymcount == 0) + _bfd_strip_section_from_output (info, s); + 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_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 @@ -5769,6 +5848,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. */ @@ -6625,6 +6706,64 @@ eversym += h->dynindx; _bfd_elf_swap_versym_out (finfo->output_bfd, &iversym, eversym); } + + if (finfo->direct_sec) + { + bfd_vma offset = 2 * h->dynindx; + if (offset > finfo->direct_sec->size) + fprintf (stderr, "Out of bounds direct section index %d\n", + (int) offset); + else + { + int dt_index = DT_DIRECT_UNKNOWN; + +#if 0 + fprintf (stderr, "Symbol '%s' type %d\n", + h->root.root.string, h->root.type); +#endif + 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)) + { + if (!sec->name || + !strncmp (sec->name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1)) + dt_index |= DT_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_DIRECT_VAGUE; + } + else if (h->vague_ref) + dt_index |= DT_DIRECT_VAGUE; + + else if (!h->concrete_ref) + dt_index = DT_DIRECT_UNKNOWN; + +#if 0 + fprintf (stderr, "Sym '%s' (type %d) [type %d] section %s [%s] owner '%s' [%d] offset %d resolves '%s'\n", + h->root.root.string, h->root.type, h->type, + sec->name ? sec->name : "", + sec->owner->flags & DYNAMIC ? "dynamic" : "static", + sec->owner ? sec->owner->filename : "", + dt_index, (int) offset, + dt_index & DT_DIRECT_VAGUE ? "" : "concrete"); +#endif + } + bfd_put_16 (finfo->output_bfd, + dt_index, + finfo->direct_sec->contents + offset); + } + } } /* If we're stripping it, then it was just a dynamic symbol, and @@ -7768,6 +7907,7 @@ finfo.dynsym_sec = NULL; finfo.hash_sec = NULL; finfo.symver_sec = NULL; + finfo.direct_sec = NULL; } else { @@ -7776,6 +7916,7 @@ BFD_ASSERT (finfo.dynsym_sec != NULL && finfo.hash_sec != NULL); finfo.symver_sec = bfd_get_section_by_name (dynobj, ".gnu.version"); /* Note that it is OK if symver_sec is NULL. */ + finfo.direct_sec = bfd_get_section_by_name (dynobj, ".direct"); } finfo.contents = NULL; @@ -8527,6 +8668,9 @@ case DT_VERNEED: name = ".gnu.version_r"; goto get_vma; + case DT_DIRECT: + name = ".direct"; + goto get_vma; case DT_VERSYM: name = ".gnu.version"; get_vma: diff -ruN binutils-2.16.91.0.5.orig/binutils/readelf.c binutils-2.16.91.0.5/binutils/readelf.c --- binutils-2.16.91.0.5.orig/binutils/readelf.c 2005-12-21 04:43:55.000000000 +0600 +++ binutils-2.16.91.0.5/binutils/readelf.c 2006-01-22 23:14:39.997975434 +0600 @@ -145,6 +145,7 @@ static int do_dynamic; static int do_syms; static int do_reloc; +static int do_direct; static int do_sections; static int do_section_groups; static int do_section_details; @@ -1477,6 +1478,7 @@ case DT_SYMINFO: return "SYMINFO"; /* aka ADDRRNGHI */ case DT_VERSYM: return "VERSYM"; + case DT_DIRECT: return "DIRECT"; case DT_RELACOUNT: return "RELACOUNT"; case DT_RELCOUNT: return "RELCOUNT"; @@ -2573,6 +2575,7 @@ {"symbols", no_argument, 0, 's'}, {"syms", no_argument, 0, 's'}, {"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'}, @@ -2610,6 +2613,7 @@ --symbols An alias for --syms\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\ @@ -2699,7 +2703,7 @@ usage (); while ((c = getopt_long - (argc, argv, "ersuahnldSDAINtgw::x:i:vVWH", options, NULL)) != EOF) + (argc, argv, "erysuahnldSDAINtgw::x:i:vVWH", options, NULL)) != EOF) { char *cp; int section; @@ -2716,6 +2720,7 @@ case 'a': do_syms++; do_reloc++; + do_direct++; do_unwind++; do_dynamic++; do_header++; @@ -2749,6 +2754,9 @@ case 'r': do_reloc++; break; + case 'y': + do_direct++; + break; case 'u': do_unwind++; break; @@ -2955,7 +2963,7 @@ } } - if (!do_dynamic && !do_syms && !do_reloc && !do_unwind && !do_sections + if (!do_dynamic && !do_syms && !do_reloc && !do_direct && !do_unwind && !do_sections && !do_segments && !do_header && !do_dump && !do_version && !do_histogram && !do_debugging && !do_arch && !do_notes && !do_section_groups) @@ -4599,6 +4607,132 @@ return 1; } +static void +print_dt_needed_name (int idx) +{ + const char *name = NULL; + Elf_Internal_Dyn *entry; + + idx &= DT_DIRECT_MASK; + + switch (idx) + { + case 0: + name = _(""); + break; + case DT_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), ".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, _("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, _("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_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" @@ -8934,6 +9068,8 @@ process_relocs (file); + process_direct (file); + process_unwind (file); process_symbol_table (file); diff -ruN binutils-2.16.91.0.5.orig/include/bfdlink.h binutils-2.16.91.0.5/include/bfdlink.h --- binutils-2.16.91.0.5.orig/include/bfdlink.h 2005-11-13 23:16:37.000000000 +0600 +++ binutils-2.16.91.0.5/include/bfdlink.h 2006-01-22 23:11:53.969337555 +0600 @@ -244,6 +244,9 @@ /* TRUE if BFD should pre-bind symbols in a shared object. */ unsigned int symbolic: 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; @@ -419,6 +422,9 @@ /* Start and end of RELRO region. */ bfd_vma relro_start, relro_end; + + /* current max dtinfo section number */ + int dt_needed_index; }; /* This structures holds a set of callback functions. These are diff -ruN binutils-2.16.91.0.5.orig/include/elf/common.h binutils-2.16.91.0.5/include/elf/common.h --- binutils-2.16.91.0.5.orig/include/elf/common.h 2005-12-21 04:43:57.000000000 +0600 +++ binutils-2.16.91.0.5/include/elf/common.h 2006-01-22 23:11:53.984333820 +0600 @@ -592,6 +592,7 @@ /* This tag is a GNU extension to the Solaris version scheme. */ #define DT_VERSYM 0x6ffffff0 +#define DT_DIRECT 0x6ffffff1 /* FIXME - how are these allocated ? */ #define DT_LOPROC 0x70000000 #define DT_HIPROC 0x7fffffff @@ -641,6 +642,11 @@ #define DF_BIND_NOW (1 << 3) #define DF_STATIC_TLS (1 << 4) +/* Constants for the DT_DIRECT entries. */ +#define DT_DIRECT_VAGUE (1<<15) +#define DT_DIRECT_MASK 0x3ff +#define DT_DIRECT_UNKNOWN DT_DIRECT_MASK + /* These constants are used for the version number of a Elf32_Verdef structure. */ diff -ruN binutils-2.16.91.0.5.orig/include/elf/external.h binutils-2.16.91.0.5/include/elf/external.h --- binutils-2.16.91.0.5.orig/include/elf/external.h 2005-06-23 03:53:35.000000000 +0700 +++ binutils-2.16.91.0.5/include/elf/external.h 2006-01-22 23:11:53.997330583 +0600 @@ -213,6 +213,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 -ruN binutils-2.16.91.0.5.orig/ld/lexsup.c binutils-2.16.91.0.5/ld/lexsup.c --- binutils-2.16.91.0.5.orig/ld/lexsup.c 2005-11-13 23:16:37.000000000 +0600 +++ binutils-2.16.91.0.5/ld/lexsup.c 2006-01-22 23:12:33.008613663 +0600 @@ -72,6 +72,7 @@ OPTION_DEFSYM, OPTION_DEMANGLE, OPTION_DEMANGLER, + OPTION_DIRECT, OPTION_DYNAMIC_LINKER, OPTION_SYSROOT, OPTION_EB, @@ -343,6 +344,8 @@ '\0', NULL, NULL, ONE_DASH }, { {"Bsymbolic", no_argument, NULL, OPTION_SYMBOLIC}, '\0', NULL, N_("Bind global references locally"), ONE_DASH }, + { {"Bdirect", no_argument, NULL, OPTION_DIRECT}, + '\0', NULL, N_("Direct-linkage the the shared libraries"), ONE_DASH }, { {"check-sections", no_argument, NULL, OPTION_CHECK_SECTIONS}, '\0', NULL, N_("Check section addresses for overlaps (default)"), TWO_DASHES }, @@ -746,6 +749,9 @@ case OPTION_DEMANGLER: demangler = optarg; break; + case OPTION_DIRECT: + link_info.direct = TRUE; + break; case 'I': /* Used on Solaris. */ case OPTION_DYNAMIC_LINKER: command_line.interpreter = optarg;