[RFC,3/3] Add a solution to prevent conflict between symbols loaded from dependencies

Message ID 20260421090020.59726-4-l.stelmach@samsung.com (mailing list archive)
State New
Headers
Series Use multiple ld.so caches to separate execution environments |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch fail Patch failed to apply to master at the time it was sent
redhat-pt-bot/TryBot-32bit fail Patch series failed to apply

Commit Message

Lukasz Stelmach April 21, 2026, 9 a.m. UTC
  From: Mateusz Moscicki <m.moscicki2@samsung.com>

Each section in the dlconf configuration file such as:

    [some1]
    path=/usr/lib/some1/
    cache=/etc/ld-some1.so.cache

    [some2]
    path=/usr/lib/some2/
    cache=/etc/ld-some2.so.cache

gets its own unique number.

During linking, each object (struct link_map) is assigned the number of the
section it comes from. Additionally, it also has a list of objects it is
directly linked with (those in its DT_NEEDED list).

Based on these data, during the symbol resolution process, it is checked
whether a given object can use a symbol from another object.

The goal is to allow objects to use symbols from objects in the same section
or from other sections if it is a direct dependency (DT_NEEDED). This makes
it possible for a library from /usr/lib/some1/ to use its own version of, for
example, libpng.so, while it loads another dependency from /usr/lib/ that requires /usr/lib/libpng.so.

Signed-off-by: Mateusz Mościcki <m.moscicki2@samsung.com>
Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
---
 elf/dl-call-libc-early-init.c |  3 ++
 elf/dl-close.c                |  9 ++++
 elf/dl-deps.c                 | 21 +++++++++
 elf/dl-load.c                 | 30 +++++++++++-
 elf/dl-lookup.c               | 24 ++++++++++
 elf/dl-object.c               |  5 ++
 elf/dl-open.c                 |  1 +
 elf/dlconf-print.c            |  3 ++
 elf/dlconf.c                  | 86 +++++++++++++++++++++++++++++++++--
 elf/dlconf.h                  | 11 ++++-
 elf/rtld.c                    | 10 ++++
 include/link.h                | 18 ++++++++
 12 files changed, 212 insertions(+), 9 deletions(-)
  

Patch

diff --git a/elf/dl-call-libc-early-init.c b/elf/dl-call-libc-early-init.c
index 38b7ec0a42..c2cc0391a2 100644
--- a/elf/dl-call-libc-early-init.c
+++ b/elf/dl-call-libc-early-init.c
@@ -28,6 +28,9 @@  _dl_call_libc_early_init (struct link_map *libc_map, _Bool initial)
   /* There is nothing to do if we did not actually load libc.so.  */
   if (libc_map == NULL)
     return;
+#ifdef DLCONF
+  libc_map->l_crossvisible = true;
+#endif /* DLCONF */
 
   const ElfW(Sym) *sym
     = _dl_lookup_direct (libc_map, "__libc_early_init",
diff --git a/elf/dl-close.c b/elf/dl-close.c
index 88226245eb..a63f533570 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -662,6 +662,15 @@  _dl_close_worker (struct link_map *map, bool force)
 	    free ((char *) imap->l_origin);
 
 	  free (imap->l_reldeps);
+#ifdef DLCONF
+	  struct dep_list *depele = imap->l_crossdep;
+	  while (depele)
+	    {
+	      struct dep_list *depele_next = depele->next;
+	      free(depele);
+	      depele = depele_next;
+	    }
+#endif
 
 	  /* Print debugging message.  */
 	  if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
index eb1d3416a9..568933fd0b 100644
--- a/elf/dl-deps.c
+++ b/elf/dl-deps.c
@@ -153,6 +153,11 @@  _dl_map_object_deps (struct link_map *map,
   /* No loaded object so far.  */
   nlist = 0;
 
+#ifdef DLCONF
+  if (map->l_type == lt_executable)
+    map->l_crossvisible = true;
+#endif
+
   /* First load MAP itself.  */
   preload (known, &nlist, map);
 
@@ -240,6 +245,22 @@  _dl_map_object_deps (struct link_map *map,
 		  }
 		else
 		  dep = args.aux;
+#ifdef DLCONF
+		if (dep->l_crossns != runp->map->l_crossns)
+		  {
+		    struct dep_list *depele
+			= malloc (sizeof (struct dep_list));
+		    if (depele == NULL)
+		      {
+			_dl_signal_error (
+			    ENOMEM, map->l_name, NULL,
+			    N_ ("cannot allocate cross dependency list"));
+		      }
+		    depele->map = dep;
+		    depele->next = runp->map->l_crossdep;
+		    runp->map->l_crossdep = depele;
+		  }
+#endif /* DLCONF */
 
 		if (! dep->l_reserved)
 		  {
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 997e1f0d1d..6acdf615e8 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -1917,6 +1917,7 @@  _dl_map_object (struct link_map *loader, const char *name,
   assert (nsid < GL(dl_nns));
 
 #ifdef DLCONF
+  size_t crossns = 0;
   bool try_default = true;
   char full_path_buff[PATH_MAX];
   const char *full_path = NULL;
@@ -1939,7 +1940,8 @@  _dl_map_object (struct link_map *loader, const char *name,
 	}
     }
 
-  char *cached = dlconf_get_cached_path (full_path, name, &try_default);
+  char *cached = dlconf_get_cached_path(full_path, name, &crossns, &try_default);
+  bool name_is_libc = strcmp (name, LIBC_SO) == 0 || strcmp (name, LD_SO) == 0;
 #endif /* DLCONF */
 
 
@@ -1951,6 +1953,25 @@  _dl_map_object (struct link_map *loader, const char *name,
 	 yet been opened.  */
       if (__glibc_unlikely ((l->l_faked | l->l_removed) != 0))
 	continue;
+
+#ifdef DLCONF
+      if (cached != NULL)
+	{
+	  /* ld.so and libc.so can always by found regardless of the section in
+	   * which they are located. So crossns check is performed for all
+	   * other libraries */
+	  if (!name_is_libc)
+	    {
+	      if (l->l_crossns != crossns)
+		continue;
+
+	      /* Here we compare the full path of the library */
+	      if (strcmp (cached, l->l_name) != 0)
+		continue;
+	    }
+	}
+#endif /* DLCONF */
+
       if (!_dl_name_match_p (name, l))
 	{
 	  const char *soname;
@@ -2232,8 +2253,13 @@  _dl_map_object (struct link_map *loader, const char *name,
     }
 
   void *stack_end = __libc_stack_end;
-  return _dl_map_object_from_fd (name, origname, fd, &fb, realname, loader,
+  l =  _dl_map_object_from_fd (name, origname, fd, &fb, realname, loader,
 				 type, mode, &stack_end, nsid);
+#ifdef DLCONF
+  if (l != NULL)
+    l->l_crossns = dlconf_get_section_id(l->l_name);
+#endif
+  return l;
 }
 
 struct add_path_state
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index 19ad2a25c5..9f29861559 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -31,6 +31,9 @@ 
 #include <atomic.h>
 #include <elf_machine_sym_no_match.h>
 
+#ifdef DLCONF
+#include <dlconf.h>
+#endif
 #include <assert.h>
 
 #define VERSTAG(tag)	(DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag))
@@ -357,6 +360,27 @@  do_lookup_x (const char *undef_name, unsigned int new_hash,
     {
       const struct link_map *map = list[i]->l_real;
 
+#ifdef DLCONF
+      if (undef_map != NULL && !map->l_crossvisible
+	  && map->l_crossns != undef_map->l_crossns)
+	{
+	  bool found = false;
+	  struct dep_list *dep = NULL;
+
+	  for (dep = undef_map->l_crossdep; dep; dep = dep->next)
+	    {
+	      if (dep->map == map)
+		{
+		  found = true;
+		  break;
+		}
+	    }
+
+	  if (!found)
+	    continue;
+	}
+#endif /* DLCONF */
+
       /* Here come the extra test needed for `_dl_lookup_symbol_skip'.  */
       if (map == skip)
 	continue;
diff --git a/elf/dl-object.c b/elf/dl-object.c
index 931ad308e6..f8199db2fc 100644
--- a/elf/dl-object.c
+++ b/elf/dl-object.c
@@ -98,6 +98,11 @@  _dl_new_object (char *realname, const char *libname, int type,
   new->l_real = new;
   new->l_symbolic_searchlist.r_list = (struct link_map **) ((char *) (new + 1)
 							    + audit_space);
+#ifdef DLCONF
+  new->l_crossns = 0;
+  new->l_crossdep = NULL;
+  new->l_crossvisible = false;
+#endif
 
   new->l_libname = newname
     = (struct libname_list *) (new->l_symbolic_searchlist.r_list + 1);
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 70d190a246..d323ca93fa 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -588,6 +588,7 @@  dl_open_worker_begin (void *a)
     {
       _dl_signal_error (EINVAL, file, NULL, N_ ("prohibited loading path"));
     }
+  new->l_crossns = dlconf_get_section_id(new->l_name);
 #endif /* DLCONF */
 
   /* If the pointer returned is NULL this means the RTLD_NOLOAD flag is
diff --git a/elf/dlconf-print.c b/elf/dlconf-print.c
index ba009e8ef6..c4e8425203 100644
--- a/elf/dlconf-print.c
+++ b/elf/dlconf-print.c
@@ -176,6 +176,7 @@  static int _print_conf_dat_tree (const struct conf_dat_entry_with_children *tree
       _dl_printf("%s%s%s%s\n", prefix, conn, tree->children[i]->name, addon);
       _dl_printf("%s%s%sisolation: %d\n", prefix, conn2, conn3, tree->children[i]->conf_dat_entry->isolation);
       _dl_printf("%s%s%sdlopen_isolation: %d\n", prefix, conn2, conn3, tree->children[i]->conf_dat_entry->dlopen_isolation);
+      _dl_printf("%s%s%ssection_id: %d\n", prefix, conn2, conn3, tree->children[i]->conf_dat_entry->section_id);
       list = tree->children[i]->conf_dat_entry->caches;
       _print_list(list, "caches", prefix, conn2, conn3);
 
@@ -193,6 +194,7 @@  static int print_conf_dat_tree (const struct conf_dat_entry_with_children *centr
   _dl_printf("/\n");
   _dl_printf("|   isolation: %d\n", centry->conf_dat_entry->isolation);
   _dl_printf("|   dlopen_isolation: %d\n", centry->conf_dat_entry->dlopen_isolation);
+  _dl_printf("|   section_id: %d\n", centry->conf_dat_entry->section_id);
   _print_list(centry->conf_dat_entry->caches, "caches", "|   ", "", "");
   _print_list(centry->conf_dat_entry->dlopen_paths, "dlopen_paths", "|   ", "", "");
 
@@ -263,3 +265,4 @@  exit:
   close(fd);
 
 }
+
diff --git a/elf/dlconf.c b/elf/dlconf.c
index c02d1ec1be..765ad6203b 100644
--- a/elf/dlconf.c
+++ b/elf/dlconf.c
@@ -15,6 +15,7 @@ 
    You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
+#include "ldsodefs.h"
 #include <assert.h>
 #include <stdlib.h>
 #include <stdbool.h>
@@ -52,6 +53,7 @@  struct cache_info {
   struct string_list *caches;
   bool isolation;
   bool dlopen_isolation;
+  int32_t section_id;
   struct cache_info *next;
 };
 
@@ -64,6 +66,7 @@  struct node {
   int32_t caches_idx;
   int32_t isolation;
   int32_t dlopen_isolation;
+  int32_t section_id;
   struct node **children;
   int32_t children_count;
 };
@@ -123,6 +126,7 @@  struct section {
   struct section_string_list *paths;
   struct section_string_list *caches;
   struct section_string_list *dlopen_paths;
+  int32_t id;
   bool isolation;
   bool dlopen_isolation;
   bool processing; /* Field for cycle detection */
@@ -365,6 +369,7 @@  static void print_cinfo (struct cache_info *cinfo)
 
       _dl_debug_printf("  isolation: %d\n", cinfo->isolation);
       _dl_debug_printf("  dlopen_isolation: %d\n", cinfo->dlopen_isolation);
+      _dl_debug_printf("  section_id: %d\n", cinfo->section_id);
       cinfo = cinfo->next;
     }
 
@@ -1138,14 +1143,18 @@  static int add_new_cinfo(struct cache_info **cinfo,
                          struct section_string_list *caches,
                          struct section_string_list *dlopen_paths,
                          bool isolation,
-                         bool dlopen_isolation)
+                         bool dlopen_isolation,
+                         int32_t *section_id)
 {
   struct section_string_list *l;
   const struct section_string_list *cur_path = paths;
 
-  if (cinfo == NULL)
+  if (cinfo == NULL || section_id == NULL)
       return DLCONF_ERR_INVAL;
 
+  if (cur_path != NULL)
+      (*section_id)++;
+
   /* If more paths than one were defined in the section, we need to create more
      objects because one cache_info object can store only one path (for later
      optimizations). */
@@ -1179,6 +1188,7 @@  static int add_new_cinfo(struct cache_info **cinfo,
       cinfo_new->dlopen_paths = dlopen_paths_new;
       cinfo_new->isolation = isolation;
       cinfo_new->dlopen_isolation = dlopen_isolation;
+      cinfo_new->section_id = *section_id;
       cinfo_new->next = NULL;
 
       if (*cinfo == NULL)
@@ -1231,6 +1241,7 @@  static int add_new_cinfo(struct cache_info **cinfo,
 static int convert_sections_to_cache_info(struct sections *sections, struct cache_info **cache_info)
 {
   int result = DLCONF_ERR_OK;
+  int32_t section_id = -1;
   for (size_t i = 0; i < sections->count; i++)
     {
       struct section *section = sections->sections[i];
@@ -1242,10 +1253,12 @@  static int convert_sections_to_cache_info(struct sections *sections, struct cach
                                   section->caches,
                                   section->dlopen_paths,
                                   section->isolation,
-                                  section->dlopen_isolation)) != DLCONF_ERR_OK)
+                                  section->dlopen_isolation,
+                                  &section_id)) != DLCONF_ERR_OK)
         {
           goto exit;
         }
+      section->id = section_id;
     }
 exit:
   if (result != DLCONF_ERR_OK)
@@ -1397,6 +1410,7 @@  static int parse_paraini (const char *content, size_t content_len, struct sectio
 	key_len--;
 
       key_len++;
+
       if (key_len == 0)
 	continue;
 
@@ -1724,6 +1738,7 @@  static int insert_to_trie (struct node *base_node, char *token, const struct cac
       new_child->dlopen_isolation = base_node->dlopen_isolation;
       new_child->caches_idx = base_node->caches_idx;
       new_child->dlopen_paths_idx = base_node->dlopen_paths_idx;
+      new_child->section_id = base_node->section_id;
 
      if ((result = insert_to_trie(new_child, new_token, cinfo, saveptr)) != DLCONF_ERR_OK)
       {
@@ -1744,6 +1759,7 @@  static int insert_to_trie (struct node *base_node, char *token, const struct cac
 
       new_child->isolation = cinfo->isolation;
       new_child->dlopen_isolation = cinfo->dlopen_isolation;
+      new_child->section_id = cinfo->section_id;
     }
 
 exit:
@@ -1789,6 +1805,7 @@  static struct node *convert_to_trie (const struct cache_info *cinfo)
   base_node->isolation = 0;
   base_node->dlopen_isolation = 0;
   base_node->dlopen_paths_idx = -1;
+  base_node->section_id = -1;
   base_node->caches_idx = -1;
 
   while (cinfo != NULL)
@@ -1809,6 +1826,7 @@  static struct node *convert_to_trie (const struct cache_info *cinfo)
             }
           base_node->isolation = cinfo->isolation;
           base_node->dlopen_isolation = cinfo->dlopen_isolation;
+          base_node->section_id = cinfo->section_id;
         }
       else
         {
@@ -1987,6 +2005,7 @@  static int _save_trie (const struct node *node, int fd, int32_t *name_offset, in
 
   write_or_return(fd, &node->isolation, sizeof(node->isolation));
   write_or_return(fd, &node->dlopen_isolation, sizeof(node->dlopen_isolation));
+  write_or_return(fd, &node->section_id, sizeof(node->section_id));
 
   *name_offset += strlen(node->name)+1;
 
@@ -2174,7 +2193,7 @@  int load_conf_dat (const char *path)
   return 0;
 }
 
-static struct conf_dat_entry *dlconf_find_proper_conf_dat_entry (const char *path)
+struct conf_dat_entry *dlconf_find_proper_conf_dat_entry (const char *path)
 {
   if (__glibc_unlikely(conf_data == NULL))
     {
@@ -2246,6 +2265,7 @@  struct conf_dat_entry *dlconf_read_one_conf_dat_entry (void *file, int start)
 
   node->isolation = rnode->isolation;
   node->dlopen_isolation = rnode->dlopen_isolation;
+  node->section_id = rnode->section_id;
   node->dlopen_paths = NULL;
   node->caches = NULL;
 
@@ -2347,7 +2367,48 @@  bool dlconf_allowed_dlopen (const char *file, const void *caller_dlopen)
   return false;
 }
 
-char *dlconf_get_cached_path(const char *name, const char *libname, bool *try_default)
+size_t dlconf_get_section_id(const char *name)
+{
+  size_t result;
+  struct conf_dat_entry *centry;
+
+  if (name == NULL)
+    return 0;
+
+  centry = dlconf_find_proper_conf_dat_entry(name);
+
+  if (centry == NULL)
+    return 0;
+
+  result = centry->section_id;
+  dlconf_free_string_list(centry->caches, false);
+  dlconf_free_string_list(centry->dlopen_paths, false);
+  free(centry);
+  return result;
+}
+
+bool dlconf_have_access(const char *name, const char *libname)
+{
+  struct conf_dat_entry *centry = dlconf_find_proper_conf_dat_entry(name);
+  bool result = false;
+
+  if (centry)
+    {
+      char *cached = dlconf_find_cached_path (libname, centry->caches);
+      if (cached)
+	{
+	  result = true;
+	  free (cached);
+	}
+
+      dlconf_free_string_list (centry->caches, false);
+      dlconf_free_string_list (centry->dlopen_paths, false);
+      free (centry);
+    }
+  return result;
+}
+
+char *dlconf_get_cached_path(const char *name, const char *libname, size_t *crossns, bool *try_default)
 {
   struct conf_dat_entry *centry;
   char *cached;
@@ -2374,6 +2435,20 @@  char *dlconf_get_cached_path(const char *name, const char *libname, bool *try_de
 
   cached = dlconf_find_cached_path(libname, centry->caches);
 
+  if (cached != NULL)
+    {
+      struct conf_dat_entry *libcentry = dlconf_find_proper_conf_dat_entry (cached);
+
+      if (libcentry)
+	{
+	  if (crossns != NULL)
+	    *crossns = libcentry->section_id;
+
+	  dlconf_free_string_list (libcentry->caches, false);
+	  dlconf_free_string_list (libcentry->dlopen_paths, false);
+	  free (libcentry);
+	}
+    }
   if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
     {
       if (cached != NULL)
@@ -2439,3 +2514,4 @@  int dlconf_generate_conf_dat (void)
 
   return result;
 }
+
diff --git a/elf/dlconf.h b/elf/dlconf.h
index 00f408a839..31b537dd6e 100644
--- a/elf/dlconf.h
+++ b/elf/dlconf.h
@@ -69,6 +69,7 @@  struct conf_dat_raw_entry {
     int32_t dlopen_paths_offset;
     int32_t isolation;
     int32_t dlopen_isolation;
+    int32_t section_id;
 };
 
 /*
@@ -85,6 +86,7 @@  struct string_list {
 struct conf_dat_entry {
   bool isolation;
   bool dlopen_isolation;
+  int32_t section_id;
 
   struct string_list *caches;
   struct string_list *dlopen_paths;
@@ -110,7 +112,8 @@  struct conf_dat_entry {
 #define DLCONF_DLPATHS_START_OFFSET offsetof(struct conf_dat_raw_entry, dlopen_paths_offset)
 #define DLCONF_ISO_OFFSET offsetof(struct conf_dat_raw_entry, isolation)
 #define DLCONF_DLOPEN_ISO_OFFSET offsetof(struct conf_dat_raw_entry, dlopen_isolation)
-#define DLCONF_NODE_FIELDS_COUNT 7
+#define DLCONF_SECTION_ID_OFFSET offsetof(struct conf_dat_raw_entry, section_id)
+#define DLCONF_NODE_FIELDS_COUNT 8
 #define DLCONF_NODE_SIZE_IN_BYTES DLCONF_NODE_FIELDS_COUNT*sizeof(int32_t)
 
 /*
@@ -155,7 +158,7 @@  extern bool dlconf_allowed_dlopen (const char *file, const void *caller_dlopen)
  * name argument is a program name with a path, for which the library is loading.
  * try_default will be set to true or false depending on whether isolation is true or false.
  */
-extern char *dlconf_get_cached_path(const char *name, const char *libname, bool *try_default) attribute_hidden;
+extern char *dlconf_get_cached_path(const char *name, const char *libname, size_t *crossns, bool *try_default) attribute_hidden;
 
 /*
  * Generate ldconfig.dat from /etc/ldconfig.conf and /etc/ldconfig.conf.d/* files
@@ -172,4 +175,8 @@  extern void dlconf_print_conf_dat (void) attribute_hidden;
  */
 char *dlconf_get_executable_path (char *buff, size_t bufflen) attribute_hidden;
 
+struct conf_dat_entry *dlconf_find_proper_conf_dat_entry (const char *path);
+
+size_t dlconf_get_section_id(const char *name);
+bool dlconf_have_access(const char *name, const char *libname);
 #endif /* _DLCONF_H */
diff --git a/elf/rtld.c b/elf/rtld.c
index f70bc7e18c..bc133667be 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1374,6 +1374,9 @@  dl_main (const ElfW(Phdr) *phdr,
   _dl_starting_up = 1;
 #endif
 
+#ifdef DLCONF
+  GL(dl_rtld_map).l_crossvisible = true;
+#endif /* DLCONF */
   const char *ld_so_name = _dl_argv[0];
   if (*user_entry == (ElfW(Addr)) ENTRY_POINT)
     {
@@ -1670,6 +1673,13 @@  dl_main (const ElfW(Phdr) *phdr,
 	 This will be what dlopen on "" returns.  */
       main_map = _dl_new_object ((char *) "", "", lt_executable, NULL,
 				 __RTLD_OPENEXEC, LM_ID_BASE);
+#ifdef DLCONF
+      char full_path_buff[PATH_MAX];
+      const char *full_path = NULL;
+      full_path = dlconf_get_executable_path(full_path_buff, sizeof(full_path_buff));
+      main_map->l_crossns = dlconf_get_section_id(full_path);
+#endif /* DLCONF */
+
       assert (main_map != NULL);
       main_map->l_phdr = phdr;
       main_map->l_phnum = phnum;
diff --git a/include/link.h b/include/link.h
index cb0d7d8e2f..a3da3fe146 100644
--- a/include/link.h
+++ b/include/link.h
@@ -71,6 +71,17 @@  struct r_scope_elem
   unsigned int r_nlist;
 };
 
+#ifdef DLCONF
+struct dep_list {
+  struct link_map *map;
+  struct dep_list *next;
+};
+
+struct ns_list {
+  size_t ns;
+  struct ns_list *next;
+};
+#endif // DLCONF
 
 /* Structure to record search path and allocation mechanism.  */
 struct r_search_path_struct
@@ -114,6 +125,13 @@  struct link_map
     /* Number of the namespace this link map belongs to.  */
     Lmid_t l_ns;
 
+#ifdef DLCONF
+    size_t l_crossns;            /* Identifier of cross-namespace */
+    struct dep_list *l_crossdep; /* List of direct dependencies */
+    bool l_crossvisible;         /* Flag indication whether a given object is visible
+			            from all cross-namespaces */
+#endif /* DLCONF */
+
     struct libname_list *l_libname;
     /* Indexed pointers to dynamic section.
        [0,DT_NUM) are indexed by the processor-independent tags.