How to avoid unnecessary R_IA64_FPTR64LSB in executable?

H. J. Lu hjl@lucon.org
Sat Apr 30 19:37:00 GMT 2005


On Fri, Apr 29, 2005 at 12:20:35PM -0700, James E Wilson wrote:
> On Wed, 2005-04-27 at 16:43, H. J. Lu wrote:
> > 1. When we export a function in executable, whose function pointer is
> > used in executable and which is referenced by a DSO, can we create a
> > R_IA64_FPTR64LSB in executable only when there is a dynamic
> > R_IA64_FPTR64LSB reference?
> 
> I don't know if I can help with this thread.  I don't have enough
> experience dealing with linker related issues.
> 
> However, it does occur to me to ask what happens with programs that use
> dlopen.  You are assuming you can detect all DSO references at link
> time, but can't we dlopen a library that wasn't initially linked in?  In
> that case, you would have to create the FPTR64LSB reloc for anything
> that might be usable from a DSO, regardless of whether we see a
> reference at link time.  That seems to be what Richard meant when he
> referred to --export-dynamic.
> 
> The Software Conventions and Runtime Architecture guide says an direct
> dynamically-linked call effectively is handled the same as an indirect
> call, which implies that it needs a function descriptor.  But I don't
> think this means we need an official function descriptor.
> 
> I see that i_prot1 got added to the dynamic symbol table, even though
> --export-dynamic wasn't used, simply because it was used in the so.so
> library.  This presumably means a dlopen'ed library could also use
> i_prot1.  Suppose that dlopen'ed library library takes the address of
> i_prot1, and then this address gets compared with the one we took in
> main.  We would have needed to create an official function descriptor
> for this to work.  This implies that anything that ended up in the
> dynamic symbol table needs an official function descriptor if there was
> an FPTR reloc in the executable, even if there are no dynamic FPTR
> relocs in any shared libraries referenced at the initial link time. 
> Again, this seems to agree with what Richard said.

You are right. I forgot about the dlopened DSOs. The problem I am
trying to solve is we want to allow dlopened DSOs to access some
symbols in executable, which happen to be accessed via function
pointers in executable. The only way to do it is use --export-dynamic,
which leads to thousands of R_IA64_FPTR64LSB. We need a way to
selectively make some symbols in executable dynamic.

It turns out that 2 patches I submitted:

http://sourceware.org/ml/binutils/2005-04/msg00617.html
http://sourceware.org/ml/binutils/2005-04/msg00822.html

may be useful. Here is an updated patch. It supports exporting
selected symbols from a DSO or an executable with a version script.


H.J.
----
2005-04-30  H.J. Lu  <hongjiu.lu@intel.com>

	* elf-bfd.h (elf_link_hash_entry): Add forced_global.

	* elflink.c (bfd_elf_link_record_dynamic_symbol): Don't check
	symbol visibilty when we force a forced local symbol to global.
	(_bfd_elf_link_renumber_dynsyms): Move forced local symbols
	just before global ones.
	(_bfd_elf_link_assign_sym_version): When building shared
	library, set the forced_global field and make it global dynamic
	if a forced local symbol is marked as global. When building
	executable, make a symbol dynamic if it is marked global. Allow
	hiding symbols in executable.
	(elf_link_output_extsym): Handle forced_global.

--- bfd/elf-bfd.h.exec	2005-04-28 12:21:40.000000000 -0700
+++ bfd/elf-bfd.h	2005-04-29 23:30:28.000000000 -0700
@@ -155,6 +155,8 @@ struct elf_link_hash_entry
   unsigned int hidden : 1;
   /* Symbol was forced to local scope due to a version script file.  */
   unsigned int forced_local : 1;
+  /* Symbol was forced to global scope due to a version script file.  */
+  unsigned int forced_global : 1;
   /* Symbol was marked during garbage collection.  */
   unsigned int mark : 1;
   /* Symbol is referenced by a non-GOT/non-PLT relocation.  This is
--- bfd/elflink.c.exec	2005-04-29 23:30:28.000000000 -0700
+++ bfd/elflink.c	2005-04-30 00:02:27.000000000 -0700
@@ -394,22 +394,24 @@ bfd_elf_link_record_dynamic_symbol (stru
       /* XXX: The ABI draft says the linker must turn hidden and
 	 internal symbols into STB_LOCAL symbols when producing the
 	 DSO. However, if ld.so honors st_other in the dynamic table,
-	 this would not be necessary.  */
-      switch (ELF_ST_VISIBILITY (h->other))
-	{
-	case STV_INTERNAL:
-	case STV_HIDDEN:
-	  if (h->root.type != bfd_link_hash_undefined
-	      && h->root.type != bfd_link_hash_undefweak)
-	    {
-	      h->forced_local = 1;
-	      if (!elf_hash_table (info)->is_relocatable_executable)
-		return TRUE;
-	    }
+	 this would not be necessary.  Don't check symbol visibilty
+	 when we force a forced local symbol to global.  */
+      if (!h->forced_global)
+	switch (ELF_ST_VISIBILITY (h->other))
+	  {
+	  case STV_INTERNAL:
+	  case STV_HIDDEN:
+	    if (h->root.type != bfd_link_hash_undefined
+		&& h->root.type != bfd_link_hash_undefweak)
+	      {
+		h->forced_local = 1;
+		if (!elf_hash_table (info)->is_relocatable_executable)
+		  return TRUE;
+	      }
 
-	default:
-	  break;
-	}
+	  default:
+	    break;
+	  }
 
       h->dynindx = elf_hash_table (info)->dynsymcount;
       ++elf_hash_table (info)->dynsymcount;
@@ -719,9 +721,9 @@ _bfd_elf_link_omit_section_dynsym (bfd *
 }
 
 /* Assign dynsym indices.  In a shared library we generate a section
-   symbol for each output section, which come first.  Next come symbols
-   which have been forced to local binding.  Then all of the back-end
-   allocated local dynamic syms, followed by the rest of the global
+   symbol for each output section, which come first.  Next come all of
+   the back-end allocated local dynamic syms.  Then symbols which have
+   been forced to local binding, followed by the rest of the global
    symbols.  */
 
 static unsigned long
@@ -743,10 +745,6 @@ _bfd_elf_link_renumber_dynsyms (bfd *out
     }
   *section_sym_count = dynsymcount;
 
-  elf_link_hash_traverse (elf_hash_table (info),
-			  elf_link_renumber_local_hash_table_dynsyms,
-			  &dynsymcount);
-
   if (elf_hash_table (info)->dynlocal)
     {
       struct elf_link_local_dynamic_entry *p;
@@ -755,6 +753,10 @@ _bfd_elf_link_renumber_dynsyms (bfd *out
     }
 
   elf_link_hash_traverse (elf_hash_table (info),
+			  elf_link_renumber_local_hash_table_dynsyms,
+			  &dynsymcount);
+
+  elf_link_hash_traverse (elf_hash_table (info),
 			  elf_link_renumber_hash_table_dynsyms,
 			  &dynsymcount);
 
@@ -1745,6 +1747,7 @@ _bfd_elf_link_assign_sym_version (struct
   struct elf_info_failed eif;
   char *p;
   bfd_size_type amt;
+  bfd_boolean global;
 
   sinfo = data;
   info = sinfo->info;
@@ -1767,6 +1770,9 @@ _bfd_elf_link_assign_sym_version (struct
   if (!h->def_regular)
     return TRUE;
 
+  /* Check if a symbol is marked as global in version script.  */
+  global = FALSE;
+
   bed = get_elf_backend_data (sinfo->output_bfd);
   p = strchr (h->root.root.string, ELF_VER_CHR);
   if (p != NULL && h->verinfo.vertree == NULL)
@@ -1825,10 +1831,11 @@ _bfd_elf_link_assign_sym_version (struct
 		  d = (*t->match) (&t->locals, NULL, alc);
 		  if (d != NULL
 		      && h->dynindx != -1
-		      && info->shared
 		      && ! info->export_dynamic)
 		    (*bed->elf_backend_hide_symbol) (info, h, TRUE);
 		}
+	      else if (d)
+		global = TRUE;
 
 	      free (alc);
 	      break;
@@ -1919,6 +1926,7 @@ _bfd_elf_link_assign_sym_version (struct
 		    h->verinfo.vertree = t;
 		    local_ver = NULL;
 		    d->script = 1;
+		    global = TRUE;
 		    break;
 		  }
 	      if (d != NULL)
@@ -1952,14 +1960,24 @@ _bfd_elf_link_assign_sym_version (struct
 	{
 	  h->verinfo.vertree = local_ver;
 	  if (h->dynindx != -1
-	      && info->shared
 	      && ! info->export_dynamic)
 	    {
+	      global = FALSE;
 	      (*bed->elf_backend_hide_symbol) (info, h, TRUE);
 	    }
 	}
     }
 
+  if (global && (info->executable || h->forced_local))
+    {
+      if (h->forced_local)
+	h->forced_global = 1;
+
+      if (h->dynindx == -1
+	  && ! bfd_elf_link_record_dynamic_symbol (info, h))
+	return FALSE;
+    }
+
   return TRUE;
 }
 
@@ -6392,12 +6410,12 @@ elf_link_output_extsym (struct elf_link_
   /* Decide whether to output this symbol in this pass.  */
   if (eoinfo->localsyms)
     {
-      if (!h->forced_local)
+      if (!h->forced_local || h->forced_global)
 	return TRUE;
     }
   else
     {
-      if (h->forced_local)
+      if (h->forced_local && !h->forced_global)
 	return TRUE;
     }
 
@@ -6427,6 +6445,7 @@ elf_link_output_extsym (struct elf_link_
   if (! finfo->info->relocatable
       && (! finfo->info->shared)
       && h->forced_local
+      && !h->forced_global
       && h->ref_dynamic
       && !h->dynamic_def
       && !h->dynamic_weak
@@ -6480,7 +6499,14 @@ elf_link_output_extsym (struct elf_link_
   sym.st_value = 0;
   sym.st_size = h->size;
   sym.st_other = h->other;
-  if (h->forced_local)
+  if (h->forced_global)
+    {
+      /* A forced global symbol has the default visibility.  */
+      sym.st_other
+	= STV_DEFAULT | (h->other & ~ ELF_ST_VISIBILITY (-1));
+      sym.st_info = ELF_ST_INFO (STB_GLOBAL, h->type);
+    }
+  else if (h->forced_local)
     sym.st_info = ELF_ST_INFO (STB_LOCAL, h->type);
   else if (h->root.type == bfd_link_hash_undefweak
 	   || h->root.type == bfd_link_hash_defweak)



More information about the Binutils mailing list