This is a proposal (including patches) for a GNU extension to the ELF
executable format that adds a flag that causes the dynamic loader to
start searching for symbols referenced by modules with the flag set from
the module itself and its immediate dependencies. If the symbol is not
found in this way, the dynamic linker continues the search as usual. 

This extension would be useful to allow to load in the same address
space multiple libraries that define identical symbols, that would be
used by different modules possibly unaware of each other's use of such
symbols. 

As a practical example, libpng.so.2 and libpng.so.3 define several
symbols with identical names. 
With the current ELF format, other libraries that want to use libpng
symbols will use the symbols of the libpng library that is used by the
main program rather than the one they are compiled with. 
Since GTK+ 2.0 uses libpng, this causes a major problem since GTK+
application must be recompiled to use the same libpng version that GTK+
uses. 
With this extension, GTK+ could be recompiled with the new flag set and
this problem would be solved. 

The extension is implemented using bit 0 of the value attached to the
DT_SYMBOLIC dynamic section entry. Current versions of the GNU dynamic
loader ignore this value and thus consider the object like one compiled
with the -Bsymbolic option. 

An option is added to the GNU linker to allow it to produce executables
with the flag set. The proposed name for the option is -Blocal. 
This option is treated like -Bsymbolic, but will cause the value
attached to the DT_SYMBOLIC entry to be written as 1 rather than 0. 

The attached patches implement the two modifications. The libc patch
also changes the -Bsymbolic list to be statically allocated rather than
malloc'ed and leaked. 


Patch for GNU binutils:

--- a/bfd/elflink.h     2002-07-17 20:38:29.000000000 +0200
+++ b/bfd/elflink.h     2002-08-21 15:27:17.000000000 +0200
@@ -3042,7 +3042,7 @@ NAME(bfd_elf,size_dynamic_sections) (out
       if (info->symbolic)
        {
          if (! elf_add_dynamic_entry (info, (bfd_vma) DT_SYMBOLIC,
-                                      (bfd_vma) 0))
+                                      (bfd_vma) (info->local ? 1 : 0)))
            return false;
          info->flags |= DF_SYMBOLIC;
        }
--- a/include/bfdlink.h 2002-07-17 20:38:29.000000000 +0200
+++ b/include/bfdlink.h 2002-08-21 15:27:58.000000000 +0200
@@ -216,6 +216,10 @@ struct bfd_link_info
   /* true if BFD should pre-bind symbols in a shared object.  */
   boolean symbolic;
 
+  /* true if BFD should pre-bind symbols in a shared object and tell
+     dynamic linker to start searching from local dependencies.  */
+  boolean local;
+       
   /* true if BFD should export all symbols in the dynamic symbol table
      of an executable, rather than only those used.  */
   boolean export_dynamic;
--- a/ld/ldmain.c       2002-07-17 20:38:29.000000000 +0200
+++ b/ld/ldmain.c       2002-08-21 15:27:08.000000000 +0200
@@ -234,6 +234,7 @@ main (argc, argv)
   link_info.emitrelocations = false;
   link_info.shared = false;
   link_info.symbolic = false;
+  link_info.local = false;  
   link_info.export_dynamic = false;
   link_info.static_link = false;
   link_info.traditional_format = false;
--- a/ld/lexsup.c       2002-05-24 00:10:11.000000000 +0200
+++ b/ld/lexsup.c       2002-08-21 15:26:52.000000000 +0200
@@ -133,6 +133,7 @@ int parsing_defsym = 0;
 #define OPTION_NO_DEFINE_COMMON                (OPTION_SPARE_DYNAMIC_TAGS + 1)
 #define OPTION_NOSTDLIB                        (OPTION_NO_DEFINE_COMMON + 1)
 #define OPTION_MULTILIB_DIR            (OPTION_NOSTDLIB + 1)
+#define OPTION_LOCAL                   (OPTION_MULTILIB_DIR + 1)
 
 /* The long options.  This structure is used for both the option
    parsing and the help text.  */
@@ -283,6 +284,8 @@ static const struct ld_option ld_options
       '\0', NULL, NULL, ONE_DASH },
   { {"Bsymbolic", no_argument, NULL, OPTION_SYMBOLIC},
       '\0', NULL, N_("Bind global references locally"), ONE_DASH },
+  { {"Blocal", no_argument, NULL, OPTION_LOCAL},
+      '\0', NULL, N_("Bind global references locally and start searching from 
local dependencies"), ONE_DASH },  
   { {"check-sections", no_argument, NULL, OPTION_CHECK_SECTIONS},
       '\0', NULL, N_("Check section addresses for overlaps (default)"), 
TWO_DASHES },
   { {"no-check-sections", no_argument, NULL, OPTION_NO_CHECK_SECTIONS},
@@ -924,6 +927,10 @@ parse_args (argc, argv)
        case OPTION_SYMBOLIC:
          link_info.symbolic = true;
          break;
+       case OPTION_LOCAL:
+         link_info.symbolic = true;            
+         link_info.local = true;
+         break;                  
        case 't':
          trace_files = true;
          break;


Patch for GNU libc:

--- a/elf/dl-deps.c     2001-09-21 16:52:54.000000000 +0200
+++ b/elf/dl-deps.c     2002-08-21 14:55:17.000000000 +0200
@@ -261,7 +261,8 @@ _dl_map_object_deps (struct link_map *ma
 
                /* Remember this dependency.  */
                if (needed != NULL)
-                 needed[nneeded++] = dep;
+                 needed[nneeded] = dep;
+               ++nneeded;
              }
            else if (d->d_tag == DT_AUXILIARY || d->d_tag == DT_FILTER)
              {
@@ -341,7 +342,8 @@ _dl_map_object_deps (struct link_map *ma
 
                /* Remember this dependency.  */
                if (needed != NULL)
-                 needed[nneeded++] = args.aux;
+                 needed[nneeded] = args.aux;
+               ++nneeded;
 
                /* We must handle two situations here: the map is new,
                   so we must add it in all three lists.  If the map
@@ -432,10 +434,11 @@ _dl_map_object_deps (struct link_map *ma
              }
        }
 
+      ++nneeded;
       /* Terminate the list of dependencies and store the array address.  */
       if (needed != NULL)
        {
-         needed[nneeded++] = NULL;
+         needed[nneeded - 1] = NULL;
 
          l->l_initfini = (struct link_map **)
            malloc ((nneeded + 1) * sizeof needed[0]);
@@ -446,6 +449,12 @@ _dl_map_object_deps (struct link_map *ma
          memcpy (&l->l_initfini[1], needed, nneeded * sizeof needed[0]);
        }
 
+      if(((needed != NULL) || (l == map)) && (l->l_scope[0] == 
&l->l_symbolic_searchlist) && (l->l_info[DT_SYMBOLIC] != l->l_info[DT_FLAGS]) 
&& (l->l_info[DT_SYMBOLIC]->d_un.d_val & 1))      
+       {
+         l->l_symbolic_searchlist.r_list = l->l_initfini;
+         l->l_symbolic_searchlist.r_nlist = nneeded;
+       }
+      
       /* If we have no auxiliary objects just go on to the next map.  */
       if (runp->done)
        do
@@ -478,6 +487,11 @@ _dl_map_object_deps (struct link_map *ma
   map->l_searchlist.r_list = &map->l_initfini[nlist + 1];
   map->l_searchlist.r_nlist = nlist;
 
+  if((map->l_scope[0] == &map->l_symbolic_searchlist) && 
(map->l_info[DT_SYMBOLIC] != map->l_info[DT_FLAGS]) && 
(map->l_info[DT_SYMBOLIC]->d_un.d_val & 1))      
+  {
+    map->l_symbolic_searchlist.r_list = map->l_searchlist.r_list + npreloads;
+  }
+
   for (nlist = 0, runp = known; runp; runp = runp->next)
     {
       if (__builtin_expect (trace_mode, 0) && runp->map->l_faked)
--- a/elf/dl-load.c     2002-08-20 18:06:06.000000000 +0200
+++ b/elf/dl-load.c     2002-08-21 15:12:04.000000000 +0200
@@ -1156,14 +1156,8 @@ _dl_map_object_from_fd (const char *name
         GNU ld.so implementation had a different interpretation which
         is more reasonable.  We are prepared to add this possibility
         back as part of a GNU extension of the ELF format.  */
-      l->l_symbolic_searchlist.r_list =
-       (struct link_map **) malloc (sizeof (struct link_map *));
 
-      if (l->l_symbolic_searchlist.r_list == NULL)
-       {
-         errstring = N_("cannot create searchlist");
-         goto call_lose_errno;
-       }
+      l->l_symbolic_searchlist.r_list = &l->l_symbolic_searchlist_mem;
 
       l->l_symbolic_searchlist.r_list[0] = l;
       l->l_symbolic_searchlist.r_nlist = 1;
--- a/include/link.h    2001-09-07 19:58:22.000000000 +0200
+++ b/include/link.h    2002-08-21 02:19:31.000000000 +0200
@@ -248,6 +248,8 @@ struct link_map
 #endif
       const ElfW(Sym) *ret;
     } l_lookup_cache;
+
+    struct link_map* l_symbolic_searchlist_mem;
   };
 
 struct dl_phdr_info

Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to