This patch omits the DT_SUSE_DIRECT define and hence depends on binutils-suse-hashvals.diff - it should be applied in conjunction with that patch. diff -u -r -x texis -x Makeconfig -x version.h -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' binutils-2.16/bfd/elf-bfd.h binutils.current/bfd/elf-bfd.h --- binutils-2.16/bfd/elf-bfd.h 2005-03-03 20:52:31.000000000 +0000 +++ binutils.current/bfd/elf-bfd.h 2005-11-23 11:04:04.000000000 +0000 @@ -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; @@ -396,6 +404,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; @@ -1238,6 +1249,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; @@ -1338,6 +1350,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) Only in binutils.current/bfd: elf-bfd.h~ diff -u -r -x texis -x Makeconfig -x version.h -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' binutils-2.16/bfd/elf.c binutils.current/bfd/elf.c --- binutils-2.16/bfd/elf.c 2005-03-06 02:02:15.000000000 +0000 +++ binutils.current/bfd/elf.c 2005-11-18 17:08:51.000000000 +0000 @@ -1145,6 +1145,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; @@ -1495,6 +1496,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 -u -r -x texis -x Makeconfig -x version.h -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' binutils-2.16/bfd/elflink.c binutils.current/bfd/elflink.c --- binutils-2.16/bfd/elflink.c 2005-04-29 14:40:22.000000000 +0100 +++ binutils.current/bfd/elflink.c 2005-11-30 15:07:38.000000000 +0000 @@ -172,6 +172,16 @@ elf_hash_table (info)->eh_info.hdr_sec = s; } + 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 (abfd, ".gnu.version_d"); @@ -2193,7 +2203,9 @@ return TRUE; } + + /* Fix up the flags for a symbol. This handles various cases which can only be fixed after all the input files are seen. This is currently called by both adjust_dynamic_symbol and @@ -2848,6 +2860,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. */ @@ -3143,6 +3158,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); @@ -3150,6 +3167,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 @@ -3169,6 +3189,14 @@ bfd_set_error (bfd_error_wrong_format); goto error_return; } + if (info->direct && + (direct_sec = bfd_get_section_by_name (abfd, ".suse.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 @@ -3817,6 +3845,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_SUSE_DIRECT_VAGUE)) + h->vague_ref = 1; + if (!h->vague_ref && + (direct_entry & DT_SUSE_DIRECT_MASK) != DT_SUSE_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 @@ -3830,6 +3889,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 @@ -4450,6 +4511,8 @@ if (isymbuf != NULL) free (isymbuf); error_return: + if (direct_data != NULL) + free (direct_data); return FALSE; } @@ -5671,6 +5734,24 @@ return FALSE; } + /* Create the direct bindings section - 1 entry per dynsym */ + s = bfd_get_section_by_name (dynobj, ".suse.direct"); + if (s) + { + 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 @@ -5749,6 +5830,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. */ @@ -6603,6 +6704,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_SUSE_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_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; + +#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_SUSE_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 @@ -7732,6 +7891,7 @@ if (! dynamic) { + finfo.direct_sec = NULL; finfo.dynsym_sec = NULL; finfo.hash_sec = NULL; finfo.symver_sec = NULL; @@ -7740,6 +7900,7 @@ } else { + finfo.direct_sec = bfd_get_section_by_name (dynobj, ".suse.direct"); finfo.dynsym_sec = bfd_get_section_by_name (dynobj, ".dynsym"); finfo.hash_sec = bfd_get_section_by_name (dynobj, ".hash"); BFD_ASSERT (finfo.dynsym_sec != NULL && finfo.hash_sec != NULL); @@ -8492,6 +8653,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 -u -r -x texis -x Makeconfig -x version.h -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' binutils-2.16/binutils/readelf.c binutils.current/binutils/readelf.c --- binutils-2.16/binutils/readelf.c 2005-04-20 19:43:36.000000000 +0100 +++ binutils.current/binutils/readelf.c 2005-11-23 11:10:06.000000000 +0000 @@ -143,6 +143,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; @@ -1519,6 +1520,7 @@ case DT_SYMINFO: return "SYMINFO"; /* aka ADDRRNGHI */ case DT_VERSYM: return "VERSYM"; + case DT_SUSE_DIRECT: return "SUSE_DIRECT"; case DT_RELACOUNT: return "RELACOUNT"; case DT_RELCOUNT: return "RELCOUNT"; @@ -2590,6 +2592,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'}, @@ -2626,6 +2629,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\ @@ -2693,7 +2697,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; @@ -2710,6 +2714,7 @@ case 'a': do_syms++; do_reloc++; + do_direct++; do_unwind++; do_dynamic++; do_header++; @@ -2738,6 +2743,9 @@ case 'r': do_reloc++; break; + case 'y': + do_direct++; + break; case 'u': do_unwind++; break; @@ -2943,7 +2951,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) @@ -4328,6 +4336,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" @@ -11784,6 +11918,8 @@ process_relocs (file); + process_direct (file); + process_unwind (file); process_symbol_table (file); Only in binutils.current/binutils: readelf.c~ Files binutils-2.16/binutils/size and binutils.current/binutils/size differ Files binutils-2.16/binutils/strings and binutils.current/binutils/strings differ Files binutils-2.16/binutils/strip-new and binutils.current/binutils/strip-new differ Files binutils-2.16/gas/as-new and binutils.current/gas/as-new differ Files binutils-2.16/gprof/gprof and binutils.current/gprof/gprof differ diff -u -r -x texis -x Makeconfig -x version.h -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' binutils-2.16/include/bfdlink.h binutils.current/include/bfdlink.h --- binutils-2.16/include/bfdlink.h 2005-03-03 11:58:00.000000000 +0000 +++ binutils.current/include/bfdlink.h 2005-11-23 10:31:37.000000000 +0000 @@ -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; @@ -416,6 +419,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 -u -r -x texis -x Makeconfig -x version.h -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' binutils-2.16/include/elf/common.h binutils.current/include/elf/common.h --- binutils-2.16/include/elf/common.h 2004-10-08 14:55:08.000000000 +0100 +++ binutils.current/include/elf/common.h 2005-11-22 14:12:53.000000000 +0000 @@ -635,6 +636,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. */ Only in binutils.current/include/elf: common.h~ diff -u -r -x texis -x Makeconfig -x version.h -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' binutils-2.16/include/elf/external.h binutils.current/include/elf/external.h --- binutils-2.16/include/elf/external.h 2005-03-03 11:58:05.000000000 +0000 +++ binutils.current/include/elf/external.h 2005-11-18 17:08:51.000000000 +0000 @@ -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 { Files binutils-2.16/ld/ld-new and binutils.current/ld/ld-new differ diff -u -r -x texis -x Makeconfig -x version.h -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' binutils-2.16/ld/lexsup.c binutils.current/ld/lexsup.c --- binutils-2.16/ld/lexsup.c 2005-03-03 11:52:00.000000000 +0000 +++ binutils.current/ld/lexsup.c 2005-11-23 10:32:20.000000000 +0000 @@ -70,6 +70,7 @@ OPTION_CREF, OPTION_DEFSYM, OPTION_DEMANGLE, + OPTION_DIRECT, OPTION_DEMANGLER, OPTION_DYNAMIC_LINKER, OPTION_SYSROOT, @@ -341,6 +342,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 @@ 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;