This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: RFC: Add dynamic list to version script
- From: "H. J. Lu" <hjl at lucon dot org>
- To: Michael Matz <matz at suse dot de>
- Cc: binutils at sources dot redhat dot com
- Date: Tue, 8 Aug 2006 09:59:50 -0700
- Subject: Re: RFC: Add dynamic list to version script
- References: <20060724221020.GA22024@lucon.org> <Pine.LNX.4.64.0607261822590.25141@wotan.suse.de> <20060727171133.GA14609@lucon.org> <Pine.LNX.4.64.0607281452000.25141@wotan.suse.de> <20060728174040.GA24620@lucon.org>
On Fri, Jul 28, 2006 at 10:40:40AM -0700, H. J. Lu wrote:
>
> 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?
>
>
This patch adds a new linker --dynamic-list option. You can have
as many --dynamic-list as you need. I can add a builtin option for
C++, something like --dynamic-list-cpp. I will add a few testcases if
this patch is accepted.
H.J.
----
bfd/
2006-08-08 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-08-08 H.J. Lu <hongjiu.lu@intel.com>
* bfdlink.h (bfd_elf_dynamic_list): New.
(bfd_link_info): Add a dynamic field.
ld/
2006-08-08 H.J. Lu <hongjiu.lu@intel.com>
* NEWS: Mention --dynamic-list.
* ld.texinfo: Document --dynamic-list.
* ldgram.y: Support dynamic list.
* ldlang.c (lang_process): Call lang_finalize_version_expr_head
on link_info.dynamic if needed.
(lang_append_dynamic_list): New.
* ldlang.h (lang_append_dynamic_list): Likewise.
* ldlex.h (input_enum): Add input_dynamic_list.
* ldlex.l: Handle it.
* ldmain.c (main): Initialize link_info.dynamic.
* lexsup.c (option_values): Add OPTION_DYNAMIC_LIST.
(ld_options): Add an entry for OPTION_DYNAMIC_LIST.
(parse_args): Handle OPTION_DYNAMIC_LIST.
--- binutils/bfd/elf-bfd.h.dynamic 2006-08-07 15:34:30.000000000 -0700
+++ binutils/bfd/elf-bfd.h 2006-08-07 15:34:30.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-08-07 15:34:30.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-08-07 08:43:40.000000000 -0700
+++ binutils/bfd/elf64-x86-64.c 2006-08-07 15:34:30.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-08-07 15:34:30.000000000 -0700
+++ binutils/bfd/elflink.c 2006-08-07 15:34:30.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
@@ -5322,7 +5353,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-07-28 13:51:45.000000000 -0700
+++ binutils/bfd/elfxx-ia64.c 2006-08-07 15:34:30.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-08-07 08:43:40.000000000 -0700
+++ binutils/include/bfdlink.h 2006-08-07 15:34:30.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. */
@@ -431,6 +433,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
@@ -724,4 +729,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/NEWS.dynamic 2006-08-07 08:43:40.000000000 -0700
+++ binutils/ld/NEWS 2006-08-08 09:49:22.000000000 -0700
@@ -1,4 +1,9 @@
-*- text -*-
+* ELF: Add --dynamic-list option to specify a list of global symbols
+ whose references shouldn't be bound to the definition within the
+ shared library, or a list of symbols which should be added to the
+ symbol table in the executable.
+
* New switch: --print-gc-sections to list any sections removed by garabge
collection.
--- binutils/ld/ld.texinfo.dynamic 2006-08-07 08:43:40.000000000 -0700
+++ binutils/ld/ld.texinfo 2006-08-08 09:47:22.000000000 -0700
@@ -487,9 +487,9 @@ back to the symbols defined by the progr
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
+You can also use the dynamic list 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}.
+See the description of @samp{--dynamic-list}.
@ifclear SingleFormat
@cindex big-endian objects
@@ -1130,6 +1130,19 @@ for a program linked against a shared li
within the shared library. This option is only meaningful on ELF
platforms which support shared libraries.
+@kindex --dynamic-list=@var{dynamic-list-file}
+@item --dynamic-list=@var{dynamic-list-file}
+Specify the name of a dynamic list file to the linker. This is
+typically used when creating shared libraries to specify a list of
+global symbols whose references shouldn't be bound to the definition
+within the shared library, or creating dynamically linked executables
+to specify a list of symbols which should be added to the symbol table
+in the executable. This option is only meaningful on ELF platforms
+which support shared libraries.
+
+The format of the dynamic list is the same as the version node without
+scope and node name. See @ref{VERSION} for more information.
+
@kindex --check-sections
@kindex --no-check-sections
@item --check-sections
--- binutils/ld/ldgram.y.dynamic 2006-06-08 22:37:07.000000000 -0700
+++ binutils/ld/ldgram.y 2006-08-08 08:58:33.000000000 -0700
@@ -156,6 +156,7 @@ static int error_index;
%type <versyms> vers_defns
%type <versnode> vers_tag
%type <deflist> verdep
+%token INPUT_DYNAMIC_LIST
%%
@@ -163,6 +164,7 @@ file:
INPUT_SCRIPT script_file
| INPUT_MRI_SCRIPT mri_script_file
| INPUT_VERSION_SCRIPT version_script_file
+ | INPUT_DYNAMIC_LIST dynamic_list_file
| INPUT_DEFSYM defsym_expr
;
@@ -1139,6 +1141,34 @@ phdr_val:
}
;
+dynamic_list_file:
+ {
+ ldlex_version_file ();
+ PUSH_ERROR (_("dynamic list"));
+ }
+ dynamic_list_nodes
+ {
+ ldlex_popstate ();
+ POP_ERROR ();
+ }
+ ;
+
+dynamic_list_nodes:
+ dynamic_list_node
+ | dynamic_list_nodes dynamic_list_node
+ ;
+
+dynamic_list_node:
+ '{' dynamic_list_tag '}' ';'
+ ;
+
+dynamic_list_tag:
+ vers_defns ';'
+ {
+ lang_append_dynamic_list ($1);
+ }
+ ;
+
/* This syntax is used within an external version script file. */
version_script_file:
--- binutils/ld/ldlang.c.dynamic 2006-08-07 15:34:30.000000000 -0700
+++ binutils/ld/ldlang.c 2006-08-08 08:52:25.000000000 -0700
@@ -83,6 +83,8 @@ static void print_input_section (asectio
static bfd_boolean lang_one_common (struct bfd_link_hash_entry *, void *);
static void lang_record_phdrs (void);
static void lang_do_version_exports_section (void);
+static void lang_finalize_version_expr_head
+ (struct bfd_elf_version_expr_head *);
/* Exported variables. */
lang_output_section_statement_type *abs_output_section;
@@ -5583,6 +5585,10 @@ relax_sections (void)
void
lang_process (void)
{
+ /* Finalize dynamic list. */
+ if (link_info.dynamic)
+ lang_finalize_version_expr_head (&link_info.dynamic->head);
+
current_target = default_target;
/* Open the output file. */
@@ -6885,3 +6891,24 @@ lang_add_unique (const char *name)
ent->next = unique_section_list;
unique_section_list = ent;
}
+
+/* Append the list of dynamic symbols to the existing one. */
+
+void
+lang_append_dynamic_list (struct bfd_elf_version_expr *dynamic)
+{
+ if (link_info.dynamic)
+ {
+ dynamic->next = link_info.dynamic->head.list;
+ link_info.dynamic->head.list = dynamic;
+ }
+ else
+ {
+ struct bfd_elf_dynamic_list *d;
+
+ d = xcalloc (1, sizeof *d);
+ d->head.list = dynamic;
+ d->match = lang_vers_match;
+ link_info.dynamic = d;
+ }
+}
--- binutils/ld/ldlang.h.dynamic 2006-08-07 15:34:30.000000000 -0700
+++ binutils/ld/ldlang.h 2006-08-08 08:52:51.000000000 -0700
@@ -601,6 +601,7 @@ 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 void lang_append_dynamic_list (struct bfd_elf_version_expr *);
bfd_boolean unique_section_p
(const asection *);
extern void lang_add_unique
--- binutils/ld/ldlex.h.dynamic 2005-05-16 11:04:40.000000000 -0700
+++ binutils/ld/ldlex.h 2006-08-07 18:44:47.000000000 -0700
@@ -30,6 +30,7 @@ typedef enum input_enum {
input_script,
input_mri_script,
input_version_script,
+ input_dynamic_list,
input_defsym
} input_type;
--- binutils/ld/ldlex.l.dynamic 2006-05-30 09:45:42.000000000 -0700
+++ binutils/ld/ldlex.l 2006-08-07 19:25:59.000000000 -0700
@@ -132,6 +132,7 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([
case input_script: return INPUT_SCRIPT; break;
case input_mri_script: return INPUT_MRI_SCRIPT; break;
case input_version_script: return INPUT_VERSION_SCRIPT; break;
+ case input_dynamic_list: return INPUT_DYNAMIC_LIST; break;
case input_defsym: return INPUT_DEFSYM; break;
default: abort ();
}
--- binutils/ld/ldmain.c.dynamic 2006-08-07 08:43:40.000000000 -0700
+++ binutils/ld/ldmain.c 2006-08-07 15:34:31.000000000 -0700
@@ -319,6 +319,7 @@ main (int argc, char **argv)
link_info.warn_shared_textrel = FALSE;
link_info.gc_sections = FALSE;
link_info.print_gc_sections = FALSE;
+ link_info.dynamic = NULL;
config.maxpagesize = 0;
config.commonpagesize = 0;
--- binutils/ld/lexsup.c.dynamic 2006-08-07 08:43:40.000000000 -0700
+++ binutils/ld/lexsup.c 2006-08-07 18:49:50.000000000 -0700
@@ -107,6 +107,7 @@ enum option_values
OPTION_VERSION,
OPTION_VERSION_SCRIPT,
OPTION_VERSION_EXPORTS_SECTION,
+ OPTION_DYNAMIC_LIST,
OPTION_WARN_COMMON,
OPTION_WARN_CONSTRUCTORS,
OPTION_WARN_FATAL,
@@ -501,6 +502,8 @@ static const struct ld_option ld_options
OPTION_VERSION_EXPORTS_SECTION },
'\0', N_("SYMBOL"), N_("Take export symbols list from .exports, using\n"
"\t\t\t\tSYMBOL as the version."), TWO_DASHES },
+ { {"dynamic-list", required_argument, NULL, OPTION_DYNAMIC_LIST},
+ '\0', N_("FILE"), N_("Read dynamic list"), TWO_DASHES },
{ {"warn-common", no_argument, NULL, OPTION_WARN_COMMON},
'\0', NULL, N_("Warn about duplicate common symbols"), TWO_DASHES },
{ {"warn-constructors", no_argument, NULL, OPTION_WARN_CONSTRUCTORS},
@@ -1236,6 +1239,20 @@ parse_args (unsigned argc, char **argv)
.exports sections. */
command_line.version_exports_section = optarg;
break;
+ case OPTION_DYNAMIC_LIST:
+ /* This option indicates a small script that only specifies
+ a dynamic list. Read it, but don't assume that we've
+ seen a linker script. */
+ {
+ FILE *hold_script_handle;
+
+ hold_script_handle = saved_script_handle;
+ ldfile_open_command_file (optarg);
+ saved_script_handle = hold_script_handle;
+ parser_input = input_dynamic_list;
+ yyparse ();
+ }
+ break;
case OPTION_WARN_COMMON:
config.warn_common = TRUE;
break;