This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Allow linker script on executable and hidden symbol


On Mon, May 02, 2005 at 07:53:25PM -0700, H. J. Lu wrote:
> On Mon, May 02, 2005 at 07:02:41PM -0700, James E Wilson wrote:
> > On Sat, 2005-04-30 at 00:18, H. J. Lu wrote:
> > > 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
> > 
> > The first patch is for turning hidden protected symbols into global
> > symbols.  The thread says that this will break function pointer
> > comparisons.  This doesn't seem like a good idea.  Nor does it seem
> > necessary to fix this particular problem.
> 
> When you mark a symbol hidden, it is done on purpose. The only
> reasonable way to get a function pointer of a hidden symbol is using
> a function call. This is similar to -Bsymbloc. The differences are
> you can do it on selective symbols and compiler can take advantage of
> it.
> 
> > 
> > The second patch is for applying a version script to an executable
> > instead of a shared library, so that you can globalize a symbol in an
> > executable.  This seems harmless enough, and seems sufficient to solve
> > the problem.  It is adding a new feature that doesn't seem to conflict
> > with any existing ones.  However, we probably need some documentation
> > updates.  The docs only talk about using version scripts with shared
> > libraries.  What exactly does it mean to apply a version script to an
> > executable?  Does specifying a version number in the version script do
> > anything?  I don't think it does.  Perhaps all we need is to modify the
> > paragraph that starts "Node name can be omited ..." to mention that this
> > form can also be used when linking executables.  Should we add some
> > checking code here maybe?  I.e. complain if !info->shared and there is a
> > version node name?  That might help catch version script mistakes.
> 
> I will give it a try.
> 

Here is the updated patch.


H.J.
----
bfd/

2005-05-05  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.
	(elf_link_output_extsym): Handle forced_global.

ld/

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

	* ld.texinfo: Document similarity between version script and
	--export-dynamicr/-Bsymbolic.

	* ldlang.c (lang_final): Don't allow named version tag on
	executables.

--- binutils/bfd/elf-bfd.h.exec	2005-05-05 07:44:33.000000000 -0700
+++ binutils/bfd/elf-bfd.h	2005-05-05 10:53:45.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
--- binutils/bfd/elflink.c.exec	2005-05-05 10:52:50.000000000 -0700
+++ binutils/bfd/elflink.c	2005-05-05 10:53:45.000000000 -0700
@@ -375,22 +375,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;
@@ -700,9 +702,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
@@ -724,10 +726,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;
@@ -736,6 +734,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);
 
@@ -1696,6 +1698,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;
@@ -1718,6 +1721,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)
@@ -1779,6 +1785,8 @@ _bfd_elf_link_assign_sym_version (struct
 		      && ! info->export_dynamic)
 		    (*bed->elf_backend_hide_symbol) (info, h, TRUE);
 		}
+	      else if (d)
+		global = TRUE;
 
 	      free (alc);
 	      break;
@@ -1869,6 +1877,7 @@ _bfd_elf_link_assign_sym_version (struct
 		    h->verinfo.vertree = t;
 		    local_ver = NULL;
 		    d->script = 1;
+		    global = TRUE;
 		    break;
 		  }
 	      if (d != NULL)
@@ -1904,11 +1913,22 @@ _bfd_elf_link_assign_sym_version (struct
 	  if (h->dynindx != -1
 	      && ! 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;
 }
 
@@ -6337,12 +6357,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;
     }
 
@@ -6372,6 +6392,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
@@ -6425,7 +6446,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)
--- binutils/ld/ld.texinfo.exec	2005-04-19 10:43:06.000000000 -0700
+++ binutils/ld/ld.texinfo	2005-05-05 12:18:44.000000000 -0700
@@ -476,11 +476,10 @@ mentioned in the link.
 If you use @code{dlopen} to load a dynamic object which needs to refer
 back to the symbols defined by the program, rather than some other
 dynamic object, then you will probably need to use this option when
-linking the program itself.
-
-You can also use the version script to control what symbols should
-be added to the dynamic symbol table if the output format supports it.
-See the description of @samp{--version-script} in @ref{VERSION}.
+linking the program itself.  If the output format supports the version
+script, you can also use it to add the symbols needed by the dynamic
+object to the dynamic symbol table.  See the description of
+@samp{--version-script} in @ref{VERSION}.
 
 @ifclear SingleFormat
 @cindex big-endian objects
@@ -1057,7 +1056,10 @@ When creating a shared library, bind ref
 definition within the shared library, if any.  Normally, it is possible
 for a program linked against a shared library to override the definition
 within the shared library.  This option is only meaningful on ELF
-platforms which support shared libraries.
+platforms which support shared libraries.  You can also use the version
+script to control which symbols should be bound to the definitions
+within the shared library.  See the description of
+@samp{--version-script} in @ref{VERSION}.
 
 @kindex --check-sections
 @kindex --no-check-sections
@@ -4257,12 +4259,22 @@ However, this would be a confusing way t
 Node name can be omited, provided it is the only version node
 in the version script.  Such version script doesn't assign any versions to
 symbols, only selects which symbols will be globally visible out and which
-won't.
+won't.  It can be used on executables to control which symbols will be
+exported and which won't.  When it is used to export symbols in
+executables, it is similar to @samp{--export-dynamic}, except for that
+symbols can be exported selectively with a version script.
 
 @smallexample
 @{ global: foo; bar; local: *; @};
 @end smallexample
 
+When a hidden symbol in a shared library is listed as global in a
+version script, its reference will be bound to the definition within
+the shared library and it will be exported.  It is similar to
+@samp{-Bsymbolic}, except for that symbols can be selectively bound
+their definitions.  If compiler is aware of symbol visibility, it can
+perform optimization which can't be done with @samp{-Bsymbolic} alone.
+
 When you link an application against a shared library that has versioned
 symbols, the application itself knows which version of each symbol it
 requires, and it also knows which version nodes it needs from each
--- binutils/ld/ldlang.c.exec	2005-05-05 10:53:45.000000000 -0700
+++ binutils/ld/ldlang.c	2005-05-05 11:20:33.000000000 -0700
@@ -5150,9 +5150,20 @@ lang_enter_output_section_statement (con
 void
 lang_final (void)
 {
-  lang_output_statement_type *new =
-    new_stat (lang_output_statement, stat_ptr);
+  lang_output_statement_type *new;
 
+  /* Check if version tag is valid for executable.  */
+  if (link_info.executable)
+    {
+      struct bfd_elf_version_tree *t;
+
+      for (t = lang_elf_version_info; t; t = t->next)
+	if (t->name [0] != '\0')
+	  einfo (_("%F%P: Invalid version tag `%s'. Only anonymous "
+		   "version tag is allowed in executable.\n"), t->name);
+    }
+
+  new = new_stat (lang_output_statement, stat_ptr);
   new->name = output_filename;
 }
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]