This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
PATCH: Force a hidden symbol global
- From: "H. J. Lu" <hjl at lucon dot org>
- To: binutils at sources dot redhat dot com
- Date: Thu, 21 Apr 2005 14:06:04 -0700
- Subject: PATCH: Force a hidden symbol global
- References: <20050303041459.GA31146@lucon.org> <20050303124913.GE376@bubble.modra.org> <20050303155504.GA9120@lucon.org> <20050303165510.GA10048@lucon.org> <20050303215444.GF376@bubble.modra.org> <20050304013720.GA17563@lucon.org>
On Thu, Mar 03, 2005 at 05:37:20PM -0800, H. J. Lu wrote:
> On Fri, Mar 04, 2005 at 08:24:44AM +1030, Alan Modra wrote:
> > On Thu, Mar 03, 2005 at 08:55:10AM -0800, H. J. Lu wrote:
> > > On Thu, Mar 03, 2005 at 07:55:04AM -0800, H. J. Lu wrote:
> > > > On Thu, Mar 03, 2005 at 11:19:13PM +1030, Alan Modra wrote:
> > > > > On Wed, Mar 02, 2005 at 08:14:59PM -0800, H. J. Lu wrote:
> > > > > > Protected visibility has almost everything, but requires
> > > > > > special handling at run-time.
> > > > > >
> > > > > > I was wondering if we could allow version script to overwrite
> > > > > > hidden symbols. That is if a symbol is global in version script, we
> > > > > > export it even if it is marked hidden. It may improve run-time
> > > > > > performance.
> > > > >
> > > > > How is this going to be different from using protected symbols?
> > > >
> > > > No run-time special handling accociated with protected symbols, which
> > > > may take extra lookup.
> > >
> > > Also compiler/linker can't optimize protected function pointers.
> >
> > Which means that if you export hidden function symbols from shared
> > libraries by means of a version script, you will break function pointer
> > comparisons.
>
> Yes. If you don't do any function pointer comparisons on exported
> functions in DSO, you should be OK.
>
This patch will allow forcing a hidden symbol as global. It can be
used for performance and languange specific features.
H.J.
----
2005-04-21 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): Set the forced_global field
if a forced local symbol is marked as global explicitly.
(elf_link_output_extsym): Handle forced_global.
--- bfd/elf-bfd.h.global 2005-04-04 10:35:34.000000000 -0700
+++ bfd/elf-bfd.h 2005-04-21 10:00:36.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
--- bfd/elflink.c.global 2005-04-19 10:42:57.000000000 -0700
+++ bfd/elflink.c 2005-04-21 13:55:00.000000000 -0700
@@ -377,22 +377,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;
@@ -702,9 +704,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
@@ -726,10 +728,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;
@@ -738,6 +736,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);
@@ -1694,6 +1696,7 @@ _bfd_elf_link_assign_sym_version (struct
struct elf_info_failed eif;
char *p;
bfd_size_type amt;
+ bfd_boolean forced_global;
sinfo = data;
info = sinfo->info;
@@ -1716,6 +1719,10 @@ _bfd_elf_link_assign_sym_version (struct
if (!h->def_regular)
return TRUE;
+ /* Check if a forced local symbol is marked as global explicitly in
+ version script. */
+ forced_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)
@@ -1778,6 +1785,8 @@ _bfd_elf_link_assign_sym_version (struct
&& ! info->export_dynamic)
(*bed->elf_backend_hide_symbol) (info, h, TRUE);
}
+ else if (d)
+ forced_global = TRUE;
free (alc);
break;
@@ -1868,6 +1877,7 @@ _bfd_elf_link_assign_sym_version (struct
h->verinfo.vertree = t;
local_ver = NULL;
d->script = 1;
+ forced_global = TRUE;
break;
}
if (d != NULL)
@@ -1904,11 +1914,20 @@ _bfd_elf_link_assign_sym_version (struct
&& info->shared
&& ! info->export_dynamic)
{
+ forced_global = FALSE;
(*bed->elf_backend_hide_symbol) (info, h, TRUE);
}
}
}
+ if (h->forced_local && forced_global)
+ {
+ h->forced_global = 1;
+
+ if (! bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+ }
+
return TRUE;
}
@@ -6316,12 +6335,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;
}
@@ -6351,6 +6370,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
@@ -6404,7 +6424,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)