--- glibc-2.3.6.orig/elf/dl-close.c 2005-07-18 08:19:47.000000000 +0700 +++ glibc-2.3.6.orig/elf/dl-close.c 2006-01-26 22:47:58.919216272 +0600 @@ -506,6 +506,9 @@ /* Remove the searchlists. */ free (imap->l_initfini); + /* Remove the dtneeded list */ + free (imap->l_dtneeded.r_list); + /* Remove the scope array if we allocated it. */ if (imap->l_scope != imap->l_scope_mem) free (imap->l_scope); --- glibc-2.3.6.orig/elf/dl-deps.c 2005-04-06 09:50:10.000000000 +0700 +++ glibc-2.3.6.orig/elf/dl-deps.c 2006-01-26 22:47:58.920216014 +0600 @@ -39,6 +39,10 @@ #define FILTERTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \ + DT_EXTRATAGIDX (DT_FILTER)) +#ifndef SUSEIDX +# define SUSEIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM + \ + DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM + DT_SUSE_TAGIDX (sym)) +#endif /* When loading auxiliary objects we must ignore errors. It's ok if an object is missing. */ @@ -139,6 +143,65 @@ __result; }) +static void +setup_direct (struct link_map *map, struct r_scope_elem *scope) +{ + if (map->l_info[SUSEIDX(DT_SUSE_DIRECT)] && map->l_info[DT_NEEDED]) + { + const ElfW(Dyn) *d; + unsigned int i; + const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]); + + if (GLRO(dl_debug_mask) & DL_DEBUG_DIRECT) + _dl_debug_printf ("** direct linkage section in '%s' **\n", + map->l_name ? map->l_name : ""); + + map->l_dtneeded.r_nlist = 1; + for (d = map->l_ld; d->d_tag != DT_NULL; ++d) + { + if (__builtin_expect (d->d_tag, DT_NEEDED) == DT_NEEDED) + map->l_dtneeded.r_nlist++; + } + + map->l_dtneeded.r_list = (struct link_map **) + malloc (map->l_dtneeded.r_nlist * sizeof (struct link_map *)); + + map->l_dtneeded.r_list[0] = map; + for (i = 1, d = map->l_ld; d->d_tag != DT_NULL; ++d) + { + const char *name; + unsigned int j; + + if (d->d_tag != DT_NEEDED) + continue; + + name = expand_dst (map, strtab + d->d_un.d_val, 0); + if (GLRO(dl_debug_mask) & DL_DEBUG_DIRECT) + _dl_debug_printf (" direct index %u object '%s'\n", i, name); + for (j = 0; j < scope->r_nlist; j++) + { + if (scope->r_list[j] && + _dl_name_match_p (name, scope->r_list[j])) + { + map->l_dtneeded.r_list[i] = scope->r_list[j]; + break; + } + } + if (!map->l_dtneeded.r_list[i]) + _dl_debug_printf (" impossible error - can't find '%s'\n", name); + i++; + } + } + else + { + if (GLRO(dl_debug_mask) & DL_DEBUG_DIRECT) + _dl_debug_printf ("no direct linkage section in '%s'\n", + map->l_name ? map->l_name : ""); + map->l_dtneeded.r_nlist = 0; + map->l_dtneeded.r_list = NULL; + } +} + void internal_function _dl_map_object_deps (struct link_map *map, @@ -555,6 +618,16 @@ } } + if (__builtin_expect (GLRO(dl_direct), 0) && npreloads == 0) + { + /* Setup direct linkage dtneeded table */ + for (i = 0; i < nlist; ++i) + setup_direct (map->l_searchlist.r_list[i], &map->l_searchlist); + } + else + if (GLRO(dl_debug_mask) & DL_DEBUG_DIRECT) + _dl_debug_printf (" no dl_direct set %u\n", GLRO(dl_direct)); + /* Maybe we can remove some relocation dependencies now. */ assert (map->l_searchlist.r_list[0] == map); for (i = 0; i < map->l_reldepsact; ++i) --- glibc-2.3.6.orig/elf/dl-lookup.c 2006-01-26 22:46:43.000000000 +0600 +++ glibc-2.3.6.orig/elf/dl-lookup.c 2006-01-26 22:47:58.936211878 +0600 @@ -32,6 +32,11 @@ #define VERSTAG(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag)) +#ifndef SUSEIDX +# define SUSEIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM + \ + DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM + DT_SUSE_TAGIDX (sym)) +#endif + /* We need this string more than once. */ static const char undefined_msg[] = "undefined symbol: "; @@ -209,6 +214,7 @@ unsigned long int hash; struct sym_val current_value = { NULL, NULL }; struct r_scope_elem **scope = symbol_scope; + size_t i = 0; /* This sucks mostly - but people sadly don't pass a symtab index, or hashvals ptr in */ const Elf_Symndx *hashvals; @@ -244,7 +250,81 @@ up a versioned symbol. */ assert (version == NULL || flags == 0 || flags == DL_LOOKUP_ADD_DEPENDENCY); - size_t i = 0; + if (__builtin_expect (undef_map != NULL, 1) && + __builtin_expect (undef_map->l_dtneeded.r_nlist != NULL, 0) && + __builtin_expect (*ref != NULL, 1)) + { + unsigned int idx, noffset; + const ElfW(Sym) *symtab; + ElfW(Addr) direct; + + /* We need a dynsym index ... */ + symtab = (const void *) D_PTR (undef_map, l_info[DT_SYMTAB]); + direct = D_PTR (undef_map, l_info[SUSEIDX(DT_SUSE_DIRECT)]); + + idx = *ref - symtab; + if (__builtin_expect ((GLRO(dl_debug_mask) & DL_DEBUG_DIRECT) != 0, 0)) + _dl_debug_printf ("dynamic symbol index %u from '%s' for %s base direct 0x%x start 0x%x\n", idx, + undef_map->l_name ? undef_map->l_name : "", + undef_name ? undef_name : "", + (int) direct, (int) undef_map->l_map_start); + direct += idx * 2; + if (direct >= undef_map->l_map_end || direct <= undef_map->l_map_start) + _dl_debug_printf ("broken: off end of map 0x%x\n", (int) direct); + else + { + noffset = *(uint16_t *)direct; + if (__builtin_expect ((GLRO(dl_debug_mask) & DL_DEBUG_DIRECT) != 0, 0)) + _dl_debug_printf ("dynamic symbol offset %u from 0x%x\n", noffset, (int) direct); + if (noffset & DT_SUSE_DIRECT_VAGUE) + { + if (__builtin_expect ((GLRO(dl_debug_mask) & DL_DEBUG_DIRECT) != 0, 0)) + _dl_debug_printf ("vague symbol\n"); + goto normal_lookup; + } + + noffset &= DT_SUSE_DIRECT_MASK; + + if (__builtin_expect (noffset < undef_map->l_dtneeded.r_nlist, 1)) + { + int res; + struct r_scope_elem direct_elem; + + /* FIXME - requires LD_PRELOAD support ... */ + direct_elem.r_list = undef_map->l_dtneeded.r_list + noffset; + direct_elem.r_nlist = 1; + + if (direct_elem.r_list[0] == skip_map) + goto normal_lookup; /* FIXME - correct ? */ + + res = do_lookup_x (undef_name, hash, *ref, ¤t_value, &direct_elem, + 0, version, flags, skip_map, type_class); + if (res > 0) + { + if (__builtin_expect ((GLRO(dl_debug_mask) & DL_DEBUG_DIRECT) != 0, 0)) + _dl_debug_printf ("direct lookup ...\n"); + goto match; + } + else + _dl_debug_printf ("Error in lookup %u - missing (?) - fallback " + "to deps & then global ? ...\n", res); + } + else if (noffset == DT_SUSE_DIRECT_UNKNOWN) + { + if (__builtin_expect ((GLRO(dl_debug_mask) & DL_DEBUG_DIRECT) != 0, 0)) + _dl_debug_printf ("unknown/undefined symbol '%s'\n", + undef_name ? undef_name : ""); + } + else + { + _dl_debug_printf ("Error: foo symbol '%s' 0 < %u < %u\n", + undef_name ? undef_name : "", + noffset, undef_map->l_dtneeded.r_nlist); + } + } + } + normal_lookup: + if (__builtin_expect (skip_map != NULL, 0)) { /* Search the relevant loaded objects for a definition. */ @@ -286,7 +366,7 @@ return 0; } } - + match: if (__builtin_expect (current_value.s == NULL, 0)) { if ((*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK) --- glibc-2.3.6.orig/elf/dl-support.c 2004-11-06 06:24:49.000000000 +0600 +++ glibc-2.3.6.orig/elf/dl-support.c 2006-01-26 22:49:42.626411857 +0600 @@ -41,6 +41,7 @@ int _dl_debug_mask; int _dl_lazy; +int _dl_direct; ElfW(Addr) _dl_use_load_bias = -2; int _dl_dynamic_weak; @@ -240,6 +241,8 @@ _dl_lazy = *(getenv ("LD_BIND_NOW") ?: "") == '\0'; + _dl_direct = *(getenv ("LD_BIND_DIRECT") ?: "") == '\0'; + _dl_bind_not = *(getenv ("LD_BIND_NOT") ?: "") != '\0'; _dl_dynamic_weak = *(getenv ("LD_DYNAMIC_WEAK") ?: "") == '\0'; --- glibc-2.3.6.orig/elf/elf.h 2006-01-26 22:46:43.000000000 +0600 +++ glibc-2.3.6.orig/elf/elf.h 2006-01-26 22:47:58.981200247 +0600 @@ -764,6 +764,11 @@ #define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ #define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ +/* Constants for the DT_SUSE_DIRECT entries. */ +#define DT_SUSE_DIRECT_VAGUE (1<<15) +#define DT_SUSE_DIRECT_MASK 0xfff +#define DT_SUSE_DIRECT_UNKNOWN DT_SUSE_DIRECT_MASK + /* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 entry in the dynamic section. */ #define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ --- glibc-2.3.6.orig/elf/rtld.c 2005-04-06 09:49:51.000000000 +0700 +++ glibc-2.3.6.orig/elf/rtld.c 2006-01-26 22:47:59.010192751 +0600 @@ -123,6 +123,7 @@ ._dl_correct_cache_id = _DL_CACHE_DEFAULT_ID, ._dl_hwcap_mask = HWCAP_IMPORTANT, ._dl_lazy = 1, + ._dl_direct = 0, ._dl_fpu_control = _FPU_DEFAULT, /* Function pointers. */ @@ -2005,11 +2006,13 @@ DL_DEBUG_SYMBOLS | DL_DEBUG_IMPCALLS }, { LEN_AND_STR ("bindings"), "display information about symbol binding", DL_DEBUG_BINDINGS | DL_DEBUG_IMPCALLS }, + { LEN_AND_STR ("direct"), "display information about direct binding", + DL_DEBUG_DIRECT | DL_DEBUG_IMPCALLS }, { LEN_AND_STR ("versions"), "display version dependencies", DL_DEBUG_VERSIONS | DL_DEBUG_IMPCALLS }, { LEN_AND_STR ("all"), "all previous options combined", DL_DEBUG_LIBS | DL_DEBUG_RELOC | DL_DEBUG_FILES | DL_DEBUG_SYMBOLS - | DL_DEBUG_BINDINGS | DL_DEBUG_VERSIONS | DL_DEBUG_IMPCALLS }, + | DL_DEBUG_BINDINGS | DL_DEBUG_DIRECT | DL_DEBUG_VERSIONS | DL_DEBUG_IMPCALLS }, { LEN_AND_STR ("statistics"), "display relocation statistics", DL_DEBUG_STATISTICS }, { LEN_AND_STR ("unused"), "determined unused DSOs", @@ -2171,6 +2174,8 @@ if (!INTUSE(__libc_enable_secure) && memcmp (envline, "ORIGIN_PATH", 11) == 0) GLRO(dl_origin_path) = &envline[12]; + if (memcmp (envline, "BIND_DIRECT", 11) == 0) + GLRO(dl_direct) = envline[12] != '\0'; break; case 12: --- glibc-2.3.6.orig/include/link.h 2006-01-26 22:46:43.000000000 +0600 +++ glibc-2.3.6.orig/include/link.h 2006-01-26 22:51:21.472879352 +0600 @@ -299,6 +299,9 @@ done. */ ElfW(Addr) l_relro_addr; size_t l_relro_size; + /* Array of DT_NEEDED dependencies in order for use in + direct linkage - l_dtneeded[0] entry is self */ + struct r_scope_elem l_dtneeded; }; struct dl_phdr_info --- glibc-2.3.6.orig/sysdeps/generic/ldsodefs.h 2005-04-06 09:50:21.000000000 +0700 +++ glibc-2.3.6.orig/sysdeps/generic/ldsodefs.h 2006-01-26 22:50:34.598985225 +0600 @@ -388,6 +388,7 @@ /* These two are used only internally. */ #define DL_DEBUG_HELP (1 << 9) #define DL_DEBUG_PRELINK (1 << 10) +#define DL_DEBUG_DIRECT (1 << 11) /* Cached value of `getpagesize ()'. */ EXTERN size_t _dl_pagesize; @@ -413,6 +414,9 @@ /* Do we do lazy relocations? */ EXTERN int _dl_lazy; + /* Do we do direct relocations? */ + EXTERN int _dl_direct; + /* Nonzero if runtime lookups should not update the .got/.plt. */ EXTERN int _dl_bind_not;