diff -Nur glibc-2.3.6/elf/dl-close.c glibc-2.3.6.bdirect/elf/dl-close.c
--- glibc-2.3.6/elf/dl-close.c	2005-07-18 01:19:47.000000000 +0000
+++ glibc-2.3.6.bdirect/elf/dl-close.c	2005-12-06 11:38:51.000000000 +0000
@@ -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);
diff -Nur glibc-2.3.6/elf/dl-deps.c glibc-2.3.6.bdirect/elf/dl-deps.c
--- glibc-2.3.6/elf/dl-deps.c	2005-04-06 02:50:10.000000000 +0000
+++ glibc-2.3.6.bdirect/elf/dl-deps.c	2005-12-06 11:38:51.000000000 +0000
@@ -39,6 +39,9 @@
 #define FILTERTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
 		   + DT_EXTRATAGIDX (DT_FILTER))
 
+#ifndef VERSYMIDX
+# define VERSYMIDX(sym)	(DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym))
+#endif
 
 /* When loading auxiliary objects we must ignore errors.  It's ok if
    an object is missing.  */
@@ -139,6 +142,65 @@
     __result; })
 
 
+static void
+setup_direct (struct link_map *map, struct r_scope_elem *scope)
+{
+  if (map->l_info[VERSYMIDX(DT_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 : "<null>");
+
+      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 : "<null>");
+      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 +617,16 @@
 	}
     }
 
+  if (__builtin_expect (GLRO(dl_direct), 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)
diff -Nur glibc-2.3.6/elf/dl-lookup.c glibc-2.3.6.bdirect/elf/dl-lookup.c
--- glibc-2.3.6/elf/dl-lookup.c	2005-04-06 02:49:48.000000000 +0000
+++ glibc-2.3.6.bdirect/elf/dl-lookup.c	2005-12-06 11:38:51.000000000 +0000
@@ -32,6 +32,10 @@
 
 #define VERSTAG(tag)	(DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag))
 
+#ifndef VERSYMIDX
+# define VERSYMIDX(sym)	(DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym))
+#endif
+
 /* We need this string more than once.  */
 static const char undefined_msg[] = "undefined symbol: ";
 
@@ -209,6 +213,7 @@
   const unsigned long int hash = _dl_elf_hash (undef_name);
   struct sym_val current_value = { NULL, NULL };
   struct r_scope_elem **scope = symbol_scope;
+  size_t i = 0;
 
   bump_num_relocations ();
 
@@ -216,7 +221,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[VERSYMIDX(DT_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 : "<noname>",
+			  undef_name ? undef_name : "<undef>",
+			  (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_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_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, &current_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_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 : "<undef>");
+	    }
+	  else
+	    {
+	      _dl_debug_printf ("Error: foo symbol '%s' 0 < %u < %u\n",
+				undef_name ? undef_name : "<undef>",
+				noffset, undef_map->l_dtneeded.r_nlist);
+	    }
+	}
+    }
+ normal_lookup:
+
   if (__builtin_expect (skip_map != NULL, 0))
     {
       /* Search the relevant loaded objects for a definition.  */
@@ -258,7 +337,7 @@
 	  return 0;
 	}
     }
-
+ match:
   if (__builtin_expect (current_value.s == NULL, 0))
     {
       if ((*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
diff -Nur glibc-2.3.6/elf/dl-support.c glibc-2.3.6.bdirect/elf/dl-support.c
--- glibc-2.3.6/elf/dl-support.c	2004-11-06 00:24:49.000000000 +0000
+++ glibc-2.3.6.bdirect/elf/dl-support.c	2005-12-06 11:38:51.000000000 +0000
@@ -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;
 
@@ -242,6 +243,8 @@
 
   _dl_bind_not = *(getenv ("LD_BIND_NOT") ?: "") != '\0';
 
+  _dl_direct = *(getenv ("LD_BIND_DIRECT") ?: "") == '\0';
+
   _dl_dynamic_weak = *(getenv ("LD_DYNAMIC_WEAK") ?: "") == '\0';
 
   _dl_profile_output = getenv ("LD_PROFILE_OUTPUT");
diff -Nur glibc-2.3.6/elf/dynamic-link.h glibc-2.3.6.bdirect/elf/dynamic-link.h
--- glibc-2.3.6/elf/dynamic-link.h	2005-10-17 04:52:23.000000000 +0000
+++ glibc-2.3.6.bdirect/elf/dynamic-link.h	2005-12-06 11:38:51.000000000 +0000
@@ -135,6 +135,7 @@
       ADJUST_DYN_INFO (DT_PLTGOT);
       ADJUST_DYN_INFO (DT_STRTAB);
       ADJUST_DYN_INFO (DT_SYMTAB);
+      ADJUST_DYN_INFO (VERSYMIDX(DT_DIRECT));
 # if ! ELF_MACHINE_NO_RELA
       ADJUST_DYN_INFO (DT_RELA);
 # endif
diff -Nur glibc-2.3.6/elf/elf.h glibc-2.3.6.bdirect/elf/elf.h
--- glibc-2.3.6/elf/elf.h	2005-12-06 11:38:27.000000000 +0000
+++ glibc-2.3.6.bdirect/elf/elf.h	2005-12-06 11:38:51.000000000 +0000
@@ -727,6 +727,7 @@
 /* The versioning entry types.  The next are defined as part of the
    GNU extension.  */
 #define DT_VERSYM	0x6ffffff0
+#define DT_DIRECT	0x6ffffff1 /* FIXME - how are these allocated ? */
 
 #define DT_RELACOUNT	0x6ffffff9
 #define DT_RELCOUNT	0x6ffffffa
@@ -756,6 +757,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_DIRECT entries. */
+#define DT_DIRECT_VAGUE   (1<<15)
+#define DT_DIRECT_MASK     0x3ff
+#define DT_DIRECT_UNKNOWN  DT_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.  */
diff -Nur glibc-2.3.6/elf/rtld.c glibc-2.3.6.bdirect/elf/rtld.c
--- glibc-2.3.6/elf/rtld.c	2005-04-06 02:49:51.000000000 +0000
+++ glibc-2.3.6.bdirect/elf/rtld.c	2005-12-06 11:38:51.000000000 +0000
@@ -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:
diff -Nur glibc-2.3.6/include/link.h glibc-2.3.6.bdirect/include/link.h
--- glibc-2.3.6/include/link.h	2005-04-06 02:50:11.000000000 +0000
+++ glibc-2.3.6.bdirect/include/link.h	2005-12-06 11:38:51.000000000 +0000
@@ -299,6 +299,10 @@
        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
diff -Nur glibc-2.3.6/sysdeps/generic/ldsodefs.h glibc-2.3.6.bdirect/sysdeps/generic/ldsodefs.h
--- glibc-2.3.6/sysdeps/generic/ldsodefs.h	2005-04-06 02:50:21.000000000 +0000
+++ glibc-2.3.6.bdirect/sysdeps/generic/ldsodefs.h	2005-12-06 11:38:51.000000000 +0000
@@ -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;
 
