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
signature.asc
Description: This is a digitally signed message part