This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: Is it possible to hide some symbols in linking shared library?
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