RFC: Add dynamic list to version script

H. J. Lu hjl@lucon.org
Fri Jul 28 17:40:00 GMT 2006


On Fri, Jul 28, 2006 at 03:13:49PM +0200, Michael Matz wrote:
> Hi,
> 
> On Thu, 27 Jul 2006, H. J. Lu wrote:
> 
> > > (no JUMP_SLOT, as expected that's now bound locally).  With -Bsymbolic the 
> > > _ZTI1A reloc goes away, but the _ZTS1A remains.
> > 
> > Can you show me your example?

This updated patch fixes it.

> 
> 
> > > I find the overloading of semantics a bit confusing.  I mean that 
> > > using a version script with the "dynamic" tag implicitely has the 
> > > effect of -Bsymbolic without actually mentioning that flag.  This 
> > > means that an empty version script using the "dynamic" tag is the 
> > > opposite of using no version script.  Perhaps such version script 
> > > should only have an effect if the user also specifies -Bsymbolic (i.e. 
> > > creating exceptions to the -Bsymbolic symbol set).  OTOH it's 
> > > documented so it's not that important.
> > > 
> > 
> > The dynamic verion script doesn't imply -Bsymbolic and shouldn't be used 
> > together with -Bsymbolic since -Bsymbolic will set DF_SYMBOLIC and 
> > dynamic linker will treat the DSO differently.
> 
> Ah yes, I only mean the effect of -Bsymbolic to bind self-defined symbols 
> locally.  I wonder if DT_SYMBOLIC makes a difference in the end.  During 
> link editing all references to symbols defined in the DSO are bound 
> locally by ld.  So there's no reference left for ld.so which could be 
> satisfied by the DSO itself, hence it shouldn't matter that it comes first 
> in the symbol search order with DT_SYMBOLIC.  Hmm.
> 
> > What it does is to bind all symbols locally except for which are 
> > undefined or on the dynamic list.
> 
> With an empty dynamic list, isn't that exactly what -Bsymbolic does, 
> ignoring the setting of DT_SYMBOLIC?

The current scheme won't allow empty dynamic list. How useful is empty
dynamic list?

> 
> > BTW, I'd like to have a new option name and I am thinking to add an 
> > option to make C++ symbols dynamic automatically. Does anyone have any 
> > suggestions for new option name?
> 
> How do you envision should it work?  Would you implement a rule of what 
> C++ symbols are in ld (i.e. something like the globs), or would you 
> somehow mark the symbols in the compiler?  How about -dynamic-only-cpp or 
> similar?
> 

I am thinking a special section containing a dynamic list and we can
have a builtin dynamic list for C++. How about --dynamic-list and
--dynamic-list-cpp?


H.J.
-----
bfd/

2006-07-24  H.J. Lu  <hongjiu.lu@intel.com>

	* elf-bfd.h (elf_link_hash_entry): Add a dynamic field.
	(bfd_elf_link_mark_dynamic_symbol): New.

	* elf32-i386.c (elf_i386_check_relocs): Also check the dynamic
	field.
	(elf_i386_relocate_section): Likewise.
	* elf64-x86-64.c (elf64_x86_64_check_relocs): Likewise.
	(elf64_x86_64_relocate_section): Likewise.
	* elflink.c (_bfd_elf_merge_symbol): Likewise.
	(_bfd_elf_fix_symbol_flags): Likewise.
	(_bfd_elf_dynamic_symbol_p): Likewise.
	(_bfd_elf_symbol_refs_local_p): Likewise.
	* elfxx-ia64.c (elfNN_ia64_check_relocs): Likewise.

	* elflink.c (bfd_elf_link_mark_dynamic_symbol): New.
	(bfd_elf_record_link_assignment): Call
	bfd_elf_link_mark_dynamic_symbol on new entry.
	(_bfd_elf_merge_symbol): Likewise.
	(_bfd_elf_export_symbol): Return if the symbol isn't exported.
	(_bfd_elf_link_assign_sym_version): Don't hide a symbol if it
	is marked dynamic.
	(bfd_elf_size_dynamic_sections): Updated.

include/

2006-07-24  H.J. Lu  <hongjiu.lu@intel.com>

	* bfdlink.h (bfd_elf_dynamic_list): New.
	(bfd_link_info): Add a dynamic field.

	* ld.texinfo: Updated.

	* ldgram.y: Support dynamic list.
	* ldlex.l: Likewise.

	* ldlang.c (lang_register_vers_node): Handle dynamic list.
	(lang_new_dynamic_list): New.
	* ldlang.h (lang_new_dynamic_list): Likewise.

	* ldmain.c (main): Initialize link_info.dynamic.

--- binutils/bfd/elf-bfd.h.dynamic	2006-07-18 13:26:51.000000000 -0700
+++ binutils/bfd/elf-bfd.h	2006-07-24 12:40:19.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 be dynamic due to a version script file.  */
+  unsigned int dynamic : 1;
   /* Symbol was marked during garbage collection.  */
   unsigned int mark : 1;
   /* Symbol is referenced by a non-GOT/non-PLT relocation.  This is
@@ -1833,6 +1835,9 @@ extern bfd_boolean bfd_elf_link_record_d
 extern int bfd_elf_link_record_local_dynamic_symbol
   (struct bfd_link_info *, bfd *, long);
 
+extern void bfd_elf_link_mark_dynamic_symbol
+  (struct bfd_link_info *, struct elf_link_hash_entry *);
+
 extern bfd_boolean _bfd_elf_close_and_cleanup
   (bfd *);
 
--- binutils/bfd/elf32-i386.c.dynamic	2006-07-11 12:53:42.000000000 -0700
+++ binutils/bfd/elf32-i386.c	2006-07-28 10:09:01.000000000 -0700
@@ -1150,7 +1150,8 @@ elf_i386_check_relocs (bfd *abfd,
 	       && (sec->flags & SEC_ALLOC) != 0
 	       && (r_type != R_386_PC32
 		   || (h != NULL
-		       && (! info->symbolic
+		       && (! (info->symbolic
+			      || (info->dynamic && !h->dynamic))
 			   || h->root.type == bfd_link_hash_defweak
 			   || !h->def_regular))))
 	      || (ELIMINATE_COPY_RELOCS
@@ -2629,7 +2630,8 @@ elf_i386_relocate_section (bfd *output_b
 		       && h->dynindx != -1
 		       && (r_type == R_386_PC32
 			   || !info->shared
-			   || !info->symbolic
+			   || !(info->symbolic
+				|| (info->dynamic && !h->dynamic))
 			   || !h->def_regular))
 		outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
 	      else
--- binutils/bfd/elf64-x86-64.c.dynamic	2006-07-11 12:53:42.000000000 -0700
+++ binutils/bfd/elf64-x86-64.c	2006-07-28 10:09:49.000000000 -0700
@@ -997,7 +997,8 @@ elf64_x86_64_check_relocs (bfd *abfd, st
 		    && (r_type != R_X86_64_PC32)
 		    && (r_type != R_X86_64_PC64))
 		   || (h != NULL
-		       && (! info->symbolic
+		       && (! (info->symbolic
+			      || (info->dynamic && !h->dynamic))
 			   || h->root.type == bfd_link_hash_defweak
 			   || !h->def_regular))))
 	      || (ELIMINATE_COPY_RELOCS
@@ -2445,7 +2446,8 @@ elf64_x86_64_relocate_section (bfd *outp
 			   || r_type == R_X86_64_PC32
 			   || r_type == R_X86_64_PC64
 			   || !info->shared
-			   || !info->symbolic
+			   || !(info->symbolic
+				|| (info->dynamic && !h->dynamic))
 			   || !h->def_regular))
 		{
 		  outrel.r_info = ELF64_R_INFO (h->dynindx, r_type);
--- binutils/bfd/elflink.c.dynamic	2006-07-18 13:26:51.000000000 -0700
+++ binutils/bfd/elflink.c	2006-07-24 13:52:56.000000000 -0700
@@ -444,6 +444,21 @@ bfd_elf_link_record_dynamic_symbol (stru
   return TRUE;
 }
 
+/* Mark a symbol dynamic.  */
+
+void
+bfd_elf_link_mark_dynamic_symbol (struct bfd_link_info *info,
+				  struct elf_link_hash_entry *h)
+{
+  struct bfd_elf_dynamic_list *d = info->dynamic;
+
+  if (d == NULL || info->relocatable)
+    return;
+
+  if ((*d->match) (&d->head, NULL, h->root.root.string))
+    h->dynamic = 1;
+}
+
 /* Record an assignment to a symbol made by a linker script.  We need
    this in case some dynamic object refers to this symbol.  */
 
@@ -477,7 +492,10 @@ bfd_elf_record_link_assignment (bfd *out
     }
 
   if (h->root.type == bfd_link_hash_new)
-    h->non_elf = 0;
+    {
+      bfd_elf_link_mark_dynamic_symbol (info, h);
+      h->non_elf = 0;
+    }
 
   /* If this symbol is being provided by the linker script, and it is
      currently defined by a dynamic object, but not by a regular
@@ -840,6 +858,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
 
   if (h->root.type == bfd_link_hash_new)
     {
+      bfd_elf_link_mark_dynamic_symbol (info, h);
       h->non_elf = 0;
       return TRUE;
     }
@@ -914,6 +933,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
   if (pold_alignment == NULL
       && !info->shared
       && !info->export_dynamic
+      && !h->dynamic
       && !h->ref_dynamic
       && newdyn
       && newdef
@@ -1626,6 +1646,10 @@ _bfd_elf_export_symbol (struct elf_link_
 {
   struct elf_info_failed *eif = data;
 
+  /* Ignore this if we won't export it.  */
+  if (!eif->info->export_dynamic && !h->dynamic)
+    return TRUE;
+
   /* Ignore indirect symbols.  These are added by the versioning code.  */
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
@@ -1842,6 +1866,7 @@ _bfd_elf_link_assign_sym_version (struct
 		  d = (*t->match) (&t->locals, NULL, alc);
 		  if (d != NULL
 		      && h->dynindx != -1
+		      && ! h->dynamic
 		      && ! info->export_dynamic)
 		    (*bed->elf_backend_hide_symbol) (info, h, TRUE);
 		}
@@ -1968,6 +1993,7 @@ _bfd_elf_link_assign_sym_version (struct
 	{
 	  h->verinfo.vertree = local_ver;
 	  if (h->dynindx != -1
+	      && ! h->dynamic
 	      && ! info->export_dynamic)
 	    {
 	      (*bed->elf_backend_hide_symbol) (info, h, TRUE);
@@ -2380,6 +2406,7 @@ _bfd_elf_fix_symbol_flags (struct elf_li
       && eif->info->shared
       && is_elf_hash_table (eif->info->hash)
       && (eif->info->symbolic
+	  || (eif->info->dynamic && !h->dynamic)
 	  || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
       && h->def_regular)
     {
@@ -2608,7 +2635,9 @@ _bfd_elf_dynamic_symbol_p (struct elf_li
 
   /* Identify the cases where name binding rules say that a
      visible symbol resolves locally.  */
-  binding_stays_local_p = info->executable || info->symbolic;
+  binding_stays_local_p = (info->executable
+			   || info->symbolic
+			   || (info->dynamic && !h->dynamic));
 
   switch (ELF_ST_VISIBILITY (h->other))
     {
@@ -2671,7 +2700,9 @@ _bfd_elf_symbol_refs_local_p (struct elf
   /* At this point, we know the symbol is defined and dynamic.  In an
      executable it must resolve locally, likewise when building symbolic
      shared libraries.  */
-  if (info->executable || info->symbolic)
+  if (info->executable
+      || info->symbolic 
+      || (info->dynamic && !h->dynamic))
     return TRUE;
 
   /* Now deal with defined dynamic symbols in shared libraries.  Ones
@@ -5306,7 +5337,7 @@ bfd_elf_size_dynamic_sections (bfd *outp
 
       /* If we are supposed to export all symbols into the dynamic symbol
 	 table (this is not the normal case), then do so.  */
-      if (info->export_dynamic)
+      if (info->export_dynamic || info->dynamic)
 	{
 	  elf_link_hash_traverse (elf_hash_table (info),
 				  _bfd_elf_export_symbol,
--- binutils/bfd/elfxx-ia64.c.dynamic	2006-06-20 11:59:14.000000000 -0700
+++ binutils/bfd/elfxx-ia64.c	2006-07-28 10:12:44.000000000 -0700
@@ -2741,7 +2741,8 @@ elfNN_ia64_check_relocs (abfd, info, sec
 	 have yet been processed.  Do something with what we know, as
 	 this may help reduce memory usage and processing time later.  */
       maybe_dynamic = (h && ((!info->executable
-			      && (!info->symbolic
+			      && (!(info->symbolic
+				    || (info->dynamic && !h->dynamic))
 				  || info->unresolved_syms_in_shared_libs == RM_IGNORE))
 			     || !h->def_regular
 			     || h->root.type == bfd_link_hash_defweak));
@@ -2913,7 +2914,8 @@ elfNN_ia64_check_relocs (abfd, info, sec
 	 have yet been processed.  Do something with what we know, as
 	 this may help reduce memory usage and processing time later.  */
       maybe_dynamic = (h && ((!info->executable
-			      && (!info->symbolic
+			      && (!(info->symbolic
+				    || (info->dynamic && !h->dynamic))
 				  || info->unresolved_syms_in_shared_libs == RM_IGNORE))
 			     || !h->def_regular
 			     || h->root.type == bfd_link_hash_defweak));
--- binutils/include/bfdlink.h.dynamic	2006-07-11 12:53:43.000000000 -0700
+++ binutils/include/bfdlink.h	2006-07-24 11:16:17.000000000 -0700
@@ -221,6 +221,8 @@ enum report_method
   RM_GENERATE_ERROR
 };
 
+struct bfd_elf_dynamic_list;
+
 /* This structure holds all the information needed to communicate
    between BFD and the linker when doing a link.  */
 
@@ -428,6 +430,9 @@ struct bfd_link_info
 
   /* Start and end of RELRO region.  */
   bfd_vma relro_start, relro_end;
+
+  /* List of symbols should be dynamic.  */
+  struct bfd_elf_dynamic_list *dynamic;
 };
 
 /* This structures holds a set of callback functions.  These are
@@ -721,4 +726,12 @@ struct bfd_elf_version_tree
      struct bfd_elf_version_expr *prev, const char *sym);
 };
 
+struct bfd_elf_dynamic_list
+{
+  struct bfd_elf_version_expr_head head;
+  struct bfd_elf_version_expr *(*match)
+    (struct bfd_elf_version_expr_head *head,
+     struct bfd_elf_version_expr *prev, const char *sym);
+};
+
 #endif
--- binutils/ld/ld.texinfo.dynamic	2006-07-11 12:53:43.000000000 -0700
+++ binutils/ld/ld.texinfo	2006-07-24 14:16:15.000000000 -0700
@@ -485,11 +485,11 @@ 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 in th executable or keep the dynamic
+relocation in the dynamic object.  See the description of
+@samp{--version-script} in @ref{VERSION}.
 
 @ifclear SingleFormat
 @cindex big-endian objects
@@ -1128,7 +1128,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 use the version
+script to control which symbols shouldn't 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
@@ -4464,6 +4467,24 @@ might change in the future, even if the 
 should check that all of your version directives are behaving as you
 expect when you upgrade.
 
+The nameless version node in the version script can be used to control
+which symbols should be exported in an executable or which symbols
+shouldn't be bound within a shared library.
+
+@smallexample
+@{ dynamic: foo; bar; @};
+@end smallexample
+
+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.  When a symbol in a shared library
+is listed as dynamic in a version script, its reference won't be bound
+to the definition within the shared library.  If a symbol isn't listed
+as dynamic, its reference will be bound to the definition within
+the shared library.  It is similar to @samp{-Bsymbolic}, except for
+that those symbols listed as dynamic won't be bound to their
+definitions.
+
 @node Expressions
 @section Expressions in Linker Scripts
 @cindex expressions
--- binutils/ld/ldgram.y.dynamic	2006-06-08 22:37:07.000000000 -0700
+++ binutils/ld/ldgram.y	2006-07-24 11:37:07.000000000 -0700
@@ -150,6 +150,7 @@ static int error_index;
 %token INPUT_SCRIPT INPUT_MRI_SCRIPT INPUT_DEFSYM CASE EXTERN START
 %token <name> VERS_TAG VERS_IDENTIFIER
 %token GLOBAL LOCAL VERSIONK INPUT_VERSION_SCRIPT
+%token LD_DYNAMIC
 %token KEEP ONLY_IF_RO ONLY_IF_RW SPECIAL
 %token EXCLUDE_FILE
 %token CONSTANT
@@ -1217,6 +1218,10 @@ vers_tag:
 		{
 		  $$ = lang_new_vers_node ($3, $7);
 		}
+	|	LD_DYNAMIC ':' vers_defns ';'
+		{
+		  $$ = lang_new_dynamic_list ($3);
+		}
 	;
 
 vers_defns:
@@ -1283,6 +1288,14 @@ vers_defns:
 		{
 		  $$ = lang_new_vers_pattern ($1, "extern", ldgram_vers_current_lang, FALSE);
 		}
+	|	LD_DYNAMIC
+		{
+		  $$ = lang_new_vers_pattern (NULL, "dynamic", ldgram_vers_current_lang, FALSE);
+		}
+	|	vers_defns ';' LD_DYNAMIC
+		{
+		  $$ = lang_new_vers_pattern ($1, "dynamic", ldgram_vers_current_lang, FALSE);
+		}
 	;
 
 opt_semicolon:
--- binutils/ld/ldlang.c.dynamic	2006-07-18 13:26:51.000000000 -0700
+++ binutils/ld/ldlang.c	2006-07-24 14:49:20.000000000 -0700
@@ -6599,6 +6599,15 @@ lang_register_vers_node (const char *nam
   if (name == NULL)
     name = "";
 
+  if (version == NULL)
+    {
+      ASSERT (deps == NULL);
+      if (name[0] != '\0')
+	einfo (_("%F%P: Invalid version tag `%s'. Only anonymous "
+		 "version tag is allowed for dynamic list.\n"), name);
+      return;
+    }
+
   if ((name[0] == '\0' && lang_elf_version_info != NULL)
       || (lang_elf_version_info && lang_elf_version_info->name[0] == '\0'))
     {
@@ -6763,3 +6772,23 @@ lang_add_unique (const char *name)
   ent->next = unique_section_list;
   unique_section_list = ent;
 }
+
+/* Create a list of dynamic symbols.  */
+
+struct bfd_elf_version_tree *
+lang_new_dynamic_list (struct bfd_elf_version_expr *dynamic)
+{
+  struct bfd_elf_dynamic_list *d;
+
+  if (link_info.dynamic != NULL)
+    einfo (_("%F%P: Duplicated dynamic lists.\n"));
+
+  d = xcalloc (1, sizeof *d);
+  d->head.list = dynamic;
+  d->match = lang_vers_match;
+  link_info.dynamic = d;
+
+  lang_finalize_version_expr_head (&d->head);
+
+  return NULL;
+}
--- binutils/ld/ldlang.h.dynamic	2006-06-20 11:59:15.000000000 -0700
+++ binutils/ld/ldlang.h	2006-07-24 11:17:44.000000000 -0700
@@ -591,6 +591,8 @@ extern struct bfd_elf_version_deps *lang
   (struct bfd_elf_version_deps *, const char *);
 extern void lang_register_vers_node
   (const char *, struct bfd_elf_version_tree *, struct bfd_elf_version_deps *);
+extern struct bfd_elf_version_tree *lang_new_dynamic_list
+  (struct bfd_elf_version_expr *);
 bfd_boolean unique_section_p
   (const asection *);
 extern void lang_add_unique
--- binutils/ld/ldlex.l.dynamic	2006-05-30 09:45:42.000000000 -0700
+++ binutils/ld/ldlex.l	2006-07-23 15:30:01.000000000 -0700
@@ -405,6 +405,8 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([
 
 <VERS_NODE>local		{ RTOKEN(LOCAL); }
 
+<VERS_NODE>dynamic		{ RTOKEN(LD_DYNAMIC); }
+
 <VERS_NODE>extern		{ RTOKEN(EXTERN); }
 
 <VERS_NODE>{V_IDENTIFIER}	{ yylval.name = xstrdup (yytext);
--- binutils/ld/ldmain.c.dynamic	2006-07-11 12:53:43.000000000 -0700
+++ binutils/ld/ldmain.c	2006-07-24 11:22:55.000000000 -0700
@@ -318,6 +318,7 @@ main (int argc, char **argv)
   link_info.relax_pass = 1;
   link_info.warn_shared_textrel = FALSE;
   link_info.gc_sections = FALSE;
+  link_info.dynamic = NULL;
 
   config.maxpagesize = 0;
   config.commonpagesize = 0;



More information about the Binutils mailing list