Is it possible to hide some symbols in linking shared library?

mpsuzuki@hiroshima-u.ac.jp mpsuzuki@hiroshima-u.ac.jp
Wed Jan 27 02:14:00 GMT 2010


Dear Ian,

On Tue, 26 Jan 2010 07:56:49 -0800
Ian Lance Taylor <iant@google.com> wrote:

>mpsuzuki@hiroshima-u.ac.jp writes:
>
>> I want to realize following 2 conditions:
>>
>> C1) a shared library exports all symbols for runtime linker.
>>
>> C2) when a developer links new binary with a shared library,
>>     the linker ignores some "blacklisted" symbols as if they
>>     cannot be resolved.
>
>Sounds like you want a version script.  I admit I'm not sure how to
>move a shared library which does not use a version script to one that
>does without retaining the same set of symbols, but at least you can
>set yourself up for future fixes of this sort.

Thank you for kind advise to my silly question, I will try.
The most popular libraries using version script would be GNU
libc, FreeBSD libc etc, but they are huge and fundamental
project. If you know any small & portable library using symbol
versioning, please let me know.

Regards,
mpsuzuki


Anyway, I did a small experiment by introducing new command
"ERASE()" for GNU ld script. However, it is ugly implementation
and I'm not pushing. Just for the explanation what I wanted
to do.

diff --git a/ld/ldlex.l b/ld/ldlex.l
index c6a0254..b351575 100644
--- a/ld/ldlex.l
+++ b/ld/ldlex.l
@@ -259,6 +259,7 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
 <EXPRESSION,BOTH,SCRIPT>"ASSERT"	{ RTOKEN(ASSERT_K); }
 <BOTH,SCRIPT>"ENTRY"			{ RTOKEN(ENTRY);}
 <BOTH,SCRIPT,MRI>"EXTERN"		{ RTOKEN(EXTERN);}
+<BOTH,SCRIPT>"ERASE"			{ RTOKEN(ERASE);}
 <EXPRESSION,BOTH,SCRIPT>"NEXT"		{ RTOKEN(NEXT);}
 <EXPRESSION,BOTH,SCRIPT>"sizeof_headers"	{ RTOKEN(SIZEOF_HEADERS);}
 <EXPRESSION,BOTH,SCRIPT>"SIZEOF_HEADERS"	{ RTOKEN(SIZEOF_HEADERS);}
diff --git a/ld/ldgram.y b/ld/ldgram.y
index 49d9ff1..7dc8a42 100644
--- a/ld/ldgram.y
+++ b/ld/ldgram.y
@@ -145,7 +145,7 @@ static int error_index;
 %type <name>  filename
 %token CHIP LIST SECT ABSOLUTE  LOAD NEWLINE ENDWORD ORDER NAMEWORD ASSERT_K
 %token FORMAT PUBLIC DEFSYMEND BASE ALIAS TRUNCATE REL
-%token INPUT_SCRIPT INPUT_MRI_SCRIPT INPUT_DEFSYM CASE EXTERN START
+%token INPUT_SCRIPT INPUT_MRI_SCRIPT INPUT_DEFSYM CASE EXTERN ERASE START
 %token <name> VERS_TAG VERS_IDENTIFIER
 %token GLOBAL LOCAL VERSIONK INPUT_VERSION_SCRIPT
 %token KEEP ONLY_IF_RO ONLY_IF_RW SPECIAL
@@ -245,6 +245,7 @@ mri_script_command:
 		{ mri_truncate ((unsigned int) $2.integer); }
 	|	CASE casesymlist
 	|	EXTERN extern_name_list
+	|	ERASE erase_name_list
 	|	INCLUDE filename
 		{ ldlex_script (); ldfile_open_command_file($2); }
 		mri_script_lines END
@@ -294,6 +295,20 @@ extern_name_list_body:
 			{ ldlang_add_undef ($3); }
 	;
 
+erase_name_list:
+	{ ldlex_expression (); }
+	erase_name_list_body
+	{ ldlex_popstate (); }
+
+erase_name_list_body:
+	  NAME
+			{ ldlang_erase_a_defined_symbol ($1); }
+	| erase_name_list_body NAME
+			{ ldlang_erase_a_defined_symbol ($2); }
+	| erase_name_list_body ',' NAME
+			{ ldlang_erase_a_defined_symbol ($3); }
+	;
+
 script_file:
 	{ ldlex_both(); }
 	ifile_list
@@ -350,6 +365,7 @@ ifile_p1:
 		  lang_add_nocrossref ($3);
 		}
 	|	EXTERN '(' extern_name_list ')'
+	|	ERASE '(' erase_name_list ')'
 	|	INSERT_K AFTER NAME
 		{ lang_add_insert ($3, 0); }
 	|	INSERT_K BEFORE NAME
diff --git a/ld/ldlang.h b/ld/ldlang.h
index 58d03f0..df435b4 100644
--- a/ld/ldlang.h
+++ b/ld/ldlang.h
@@ -437,6 +437,7 @@ struct lang_definedness_hash_entry
 {
   struct bfd_hash_entry root;
   int iteration;
+  int erased; /* XXX: remove when BFD hash is enabled to delete an entry */
 };
 
 /* Used by place_orphan to keep track of orphan sections and statements.  */
@@ -563,6 +564,8 @@ extern lang_output_section_statement_type *lang_output_section_statement_lookup
   (const char *, int, bfd_boolean);
 extern lang_output_section_statement_type *next_matching_output_section_statement
   (lang_output_section_statement_type *, int);
+extern void ldlang_erase_a_defined_symbol
+  (const char *const);
 extern void ldlang_add_undef
   (const char *const);
 extern void lang_add_output_format
diff --git a/ld/ldlang.c b/ld/ldlang.c
index fd75a5b..9557a06 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -3204,6 +3204,7 @@ lang_definedness_newfunc (struct bfd_hash_entry *entry,
     einfo (_("%P%F: bfd_hash_allocate failed creating symbol %s\n"), name);
 
   ret->iteration = -1;
+  ret->erased = -1; /* XXX: remove when BFD hash is enabled to delete an entry */
   return &ret->root;
 }
 
@@ -3250,12 +3251,34 @@ lang_update_definedness (const char *name, struct bfd_link_hash_entry *h)
   if (h->type != bfd_link_hash_undefined
       && h->type != bfd_link_hash_common
       && h->type != bfd_link_hash_new
+      && defentry->erased < 1 /* XXX: remove when BFD hash is enabled to delete an entry */
       && defentry->iteration == -1)
     return;
 
   defentry->iteration = lang_statement_iteration;
 }
 
+void
+ldlang_erase_a_defined_symbol (const char *const name)
+{
+  struct lang_definedness_hash_entry *dh;
+  struct bfd_link_hash_entry *lh;
+
+  dh = (struct lang_definedness_hash_entry *)
+       bfd_hash_lookup (&lang_definedness_table, name, TRUE, FALSE);
+
+  if ( !dh ) /* inexistent symbol cannot be erased */
+    return;
+
+  dh->erased = 1; /* XXX: remove when BFD hash is enabled to delete an entry */
+
+  lh = bfd_wrapped_link_hash_lookup( link_info.output_bfd, &link_info, name, FALSE, FALSE, TRUE );
+  if ( !lh )
+    return;
+
+  lh->type = bfd_link_hash_undefined;
+}
+
 /* Add the supplied name to the symbol table as an undefined reference.
    This is a two step process as the symbol table doesn't even exist at
    the time the ld command line is processed.  First we put the name



More information about the Binutils mailing list