This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Re: Allow linker script on executable and hidden symbol
- From: "H. J. Lu" <hjl at lucon dot org>
- To: James E Wilson <wilson at specifixinc dot com>
- Cc: binutils at sources dot redhat dot com
- Date: Thu, 5 May 2005 12:20:46 -0700
- Subject: Re: Allow linker script on executable and hidden symbol
- References: <20050427234304.GA17151@lucon.org> <1114802435.31059.66.camel@aretha.corp.specifixinc.com> <20050430071827.GA5960@lucon.org> <1115085761.9191.43.camel@aretha.corp.specifixinc.com> <20050503025325.GA2721@lucon.org>
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;
}