2003-04-27  H.J. Lu <hjl@gnu.org>

	* elf-bfd.h (ELF_LINK_DYNAMIC_DEF): New.
	(ELF_LINK_DYNAMIC_WEAK): New.

	* elflink.h (elf_merge_symbol): Add one argument to indicate if
	a symbol should be skipped. Ignore definitions in dynamic
	objects for symbols with non-default visibility.
	(elf_add_default_symbol): Adjusted.
	(elf_link_add_object_symbols): Check if a symbol should be
	skipped. Don't merge the visibility field with the one from
	a dynamic object.
	(elf_link_check_versioned_symbol): Use undef_bfd.
	(elf_link_output_extsym): Warn if a forced local symbol is
	referenced from dynamic objects. Make non-weak undefined symbol
	with non-default visibility a fatal error.

ld/testsuite/

2003-04-27  H.J. Lu <hjl@gnu.org>

	* ld-elfvsb/elfvsb.dat: Updated.
	* ld-elfvsb/elfvsb.exp: Likewise.
	* ld-elfvsb/main.c: Likewise.
	* ld-elfvsb/sh1.c: Likewise.
	* ld-elfvsb/sh2.c: Likewise.
This commit is contained in:
H.J. Lu 2003-04-28 03:31:36 +00:00
parent e4c4d240a3
commit 1b1fe8feb3
9 changed files with 316 additions and 14 deletions

View file

@ -1,3 +1,20 @@
2003-04-27 H.J. Lu <hjl@gnu.org>
* elf-bfd.h (ELF_LINK_DYNAMIC_DEF): New.
(ELF_LINK_DYNAMIC_WEAK): New.
* elflink.h (elf_merge_symbol): Add one argument to indicate if
a symbol should be skipped. Ignore definitions in dynamic
objects for symbols with non-default visibility.
(elf_add_default_symbol): Adjusted.
(elf_link_add_object_symbols): Check if a symbol should be
skipped. Don't merge the visibility field with the one from
a dynamic object.
(elf_link_check_versioned_symbol): Use undef_bfd.
(elf_link_output_extsym): Warn if a forced local symbol is
referenced from dynamic objects. Make non-weak undefined symbol
with non-default visibility a fatal error.
2003-04-27 Daniel Jacobowitz <drow@mvista.com> 2003-04-27 Daniel Jacobowitz <drow@mvista.com>
* configure.in: Bump version on HEAD to 2.14.90. * configure.in: Bump version on HEAD to 2.14.90.

View file

@ -204,6 +204,10 @@ struct elf_link_hash_entry
/* Symbol is referenced by a non-GOT/non-PLT relocation. This is /* Symbol is referenced by a non-GOT/non-PLT relocation. This is
not currently set by all the backends. */ not currently set by all the backends. */
#define ELF_LINK_NON_GOT_REF 010000 #define ELF_LINK_NON_GOT_REF 010000
/* Symbol has a definition in a shared object. */
#define ELF_LINK_DYNAMIC_DEF 020000
/* Symbol is weak in all shared objects. */
#define ELF_LINK_DYNAMIC_WEAK 040000
}; };
/* Records local symbols to be emitted in the dynamic symbol table. */ /* Records local symbols to be emitted in the dynamic symbol table. */

View file

@ -42,7 +42,7 @@ static bfd_boolean elf_merge_symbol
PARAMS ((bfd *, struct bfd_link_info *, const char *, PARAMS ((bfd *, struct bfd_link_info *, const char *,
Elf_Internal_Sym *, asection **, bfd_vma *, Elf_Internal_Sym *, asection **, bfd_vma *,
struct elf_link_hash_entry **, bfd_boolean *, bfd_boolean *, struct elf_link_hash_entry **, bfd_boolean *, bfd_boolean *,
bfd_boolean *, bfd_boolean)); bfd_boolean *, bfd_boolean *, bfd_boolean));
static bfd_boolean elf_add_default_symbol static bfd_boolean elf_add_default_symbol
PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
const char *, Elf_Internal_Sym *, asection **, bfd_vma *, const char *, Elf_Internal_Sym *, asection **, bfd_vma *,
@ -463,7 +463,7 @@ elf_link_add_archive_symbols (abfd, info)
a shared object. */ a shared object. */
static bfd_boolean static bfd_boolean
elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash, elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash, skip,
override, type_change_ok, size_change_ok, dt_needed) override, type_change_ok, size_change_ok, dt_needed)
bfd *abfd; bfd *abfd;
struct bfd_link_info *info; struct bfd_link_info *info;
@ -472,6 +472,7 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
asection **psec; asection **psec;
bfd_vma *pvalue; bfd_vma *pvalue;
struct elf_link_hash_entry **sym_hash; struct elf_link_hash_entry **sym_hash;
bfd_boolean *skip;
bfd_boolean *override; bfd_boolean *override;
bfd_boolean *type_change_ok; bfd_boolean *type_change_ok;
bfd_boolean *size_change_ok; bfd_boolean *size_change_ok;
@ -484,6 +485,7 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
bfd *oldbfd; bfd *oldbfd;
bfd_boolean newdyn, olddyn, olddef, newdef, newdyncommon, olddyncommon; bfd_boolean newdyn, olddyn, olddef, newdef, newdyncommon, olddyncommon;
*skip = FALSE;
*override = FALSE; *override = FALSE;
sec = *psec; sec = *psec;
@ -606,6 +608,57 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
else else
olddef = TRUE; olddef = TRUE;
/* We need to rememeber if a symbol has a definition in a dynamic
object or is weak in all dynamic objects. Internal and hidden
visibility will make it unavailable to dynamic objects. */
if (newdyn && (h->elf_link_hash_flags & ELF_LINK_DYNAMIC_DEF) == 0)
{
if (!bfd_is_und_section (sec))
h->elf_link_hash_flags |= ELF_LINK_DYNAMIC_DEF;
else
{
/* Check if this symbol is weak in all dynamic objects. If it
is the first time we see it in a dynamic object, we mark
if it is weak. Otherwise, we clear it. */
if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0)
{
if (bind == STB_WEAK)
h->elf_link_hash_flags |= ELF_LINK_DYNAMIC_WEAK;
}
else if (bind != STB_WEAK)
h->elf_link_hash_flags &= ~ELF_LINK_DYNAMIC_WEAK;
}
}
/* If the old symbol has non-default visibility, we ignore the new
definition from a dynamic object. */
if (newdyn
&& ELF_ST_VISIBILITY (h->other)
&& !bfd_is_und_section (sec))
{
*skip = TRUE;
/* Make sure this symbol is dynamic. */
h->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC;
/* FIXME: Should we check type and size for protected symbol? */
return _bfd_elf_link_record_dynamic_symbol (info, h);
}
else if (!newdyn
&& ELF_ST_VISIBILITY (sym->st_other)
&& (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0)
{
/* If the new symbol with non-default visibility comes from a
relocatable file and the old definition comes from a dynamic
object, we remove the old definition. */
h->root.type = bfd_link_hash_new;
h->root.u.undef.abfd = NULL;
h->elf_link_hash_flags &= ~ELF_LINK_HASH_DEF_DYNAMIC;
h->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC;
/* FIXME: Should we check type and size for protected symbol? */
h->size = 0;
h->type = 0;
return TRUE;
}
/* NEWDYNCOMMON and OLDDYNCOMMON indicate whether the new or old /* NEWDYNCOMMON and OLDDYNCOMMON indicate whether the new or old
symbol, respectively, appears to be a common symbol in a dynamic symbol, respectively, appears to be a common symbol in a dynamic
object. If a symbol appears in an uninitialized section, and is object. If a symbol appears in an uninitialized section, and is
@ -934,6 +987,7 @@ elf_add_default_symbol (abfd, info, h, name, sym, psec, value,
{ {
bfd_boolean type_change_ok; bfd_boolean type_change_ok;
bfd_boolean size_change_ok; bfd_boolean size_change_ok;
bfd_boolean skip;
char *shortname; char *shortname;
struct elf_link_hash_entry *hi; struct elf_link_hash_entry *hi;
struct bfd_link_hash_entry *bh; struct bfd_link_hash_entry *bh;
@ -989,7 +1043,7 @@ elf_add_default_symbol (abfd, info, h, name, sym, psec, value,
size_change_ok = FALSE; size_change_ok = FALSE;
sec = *psec; sec = *psec;
if (! elf_merge_symbol (abfd, info, shortname, sym, &sec, value, if (! elf_merge_symbol (abfd, info, shortname, sym, &sec, value,
&hi, &override, &type_change_ok, &hi, &skip, &override, &type_change_ok,
&size_change_ok, dt_needed)) &size_change_ok, dt_needed))
return FALSE; return FALSE;
@ -1098,7 +1152,7 @@ elf_add_default_symbol (abfd, info, h, name, sym, psec, value,
size_change_ok = FALSE; size_change_ok = FALSE;
sec = *psec; sec = *psec;
if (! elf_merge_symbol (abfd, info, shortname, sym, &sec, value, if (! elf_merge_symbol (abfd, info, shortname, sym, &sec, value,
&hi, &override, &type_change_ok, &hi, &skip, &override, &type_change_ok,
&size_change_ok, dt_needed)) &size_change_ok, dt_needed))
return FALSE; return FALSE;
@ -1740,6 +1794,7 @@ elf_link_add_object_symbols (abfd, info)
{ {
Elf_Internal_Versym iver; Elf_Internal_Versym iver;
unsigned int vernum = 0; unsigned int vernum = 0;
bfd_boolean skip;
if (ever != NULL) if (ever != NULL)
{ {
@ -1837,10 +1892,14 @@ elf_link_add_object_symbols (abfd, info)
} }
if (! elf_merge_symbol (abfd, info, name, isym, &sec, &value, if (! elf_merge_symbol (abfd, info, name, isym, &sec, &value,
sym_hash, &override, &type_change_ok, sym_hash, &skip, &override,
&size_change_ok, dt_needed)) &type_change_ok, &size_change_ok,
dt_needed))
goto error_free_vers; goto error_free_vers;
if (skip)
continue;
if (override) if (override)
definition = FALSE; definition = FALSE;
@ -2020,9 +2079,10 @@ elf_link_add_object_symbols (abfd, info)
h->type = ELF_ST_TYPE (isym->st_info); h->type = ELF_ST_TYPE (isym->st_info);
} }
/* If st_other has a processor-specific meaning, specific code /* If st_other has a processor-specific meaning, specific
might be needed here. */ code might be needed here. We never merge the visibility
if (isym->st_other != 0) attribute with the one from a dynamic object. */
if (isym->st_other != 0 && !dynamic)
{ {
unsigned char hvis, symvis, other, nvis; unsigned char hvis, symvis, other, nvis;
@ -2089,7 +2149,7 @@ elf_link_add_object_symbols (abfd, info)
override, dt_needed)) override, dt_needed))
goto error_free_vers; goto error_free_vers;
if (definition && (abfd->flags & DYNAMIC) == 0) if (definition && !dynamic)
{ {
char *p = strchr (name, ELF_VER_CHR); char *p = strchr (name, ELF_VER_CHR);
if (p != NULL && p[1] != ELF_VER_CHR) if (p != NULL && p[1] != ELF_VER_CHR)
@ -6106,7 +6166,7 @@ elf_link_check_versioned_symbol (info, h)
if ((undef_bfd->flags & DYNAMIC) == 0 if ((undef_bfd->flags & DYNAMIC) == 0
|| info->hash->creator->flavour != bfd_target_elf_flavour || info->hash->creator->flavour != bfd_target_elf_flavour
|| elf_dt_soname (h->root.u.undef.abfd) == NULL) || elf_dt_soname (undef_bfd) == NULL)
return FALSE; return FALSE;
for (loaded = elf_hash_table (info)->loaded; for (loaded = elf_hash_table (info)->loaded;
@ -6273,6 +6333,28 @@ elf_link_output_extsym (h, data)
} }
} }
/* We should also warn if a forced local symbol is referenced from
shared libraries. */
if (! finfo->info->relocateable
&& (! finfo->info->shared || ! finfo->info->allow_shlib_undefined)
&& (h->elf_link_hash_flags
& (ELF_LINK_FORCED_LOCAL | ELF_LINK_HASH_REF_DYNAMIC
| ELF_LINK_DYNAMIC_DEF | ELF_LINK_DYNAMIC_WEAK))
== (ELF_LINK_FORCED_LOCAL | ELF_LINK_HASH_REF_DYNAMIC))
{
(*_bfd_error_handler)
(_("%s: %s symbol `%s' in %s is referenced by DSO"),
bfd_get_filename (finfo->output_bfd),
ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
? "internal"
: ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
? "hidden" : "local",
h->root.root.string,
bfd_archive_filename (h->root.u.def.section->owner));
eoinfo->failed = TRUE;
return FALSE;
}
/* We don't want to output symbols that have never been mentioned by /* We don't want to output symbols that have never been mentioned by
a regular file, or that we have been told to strip. However, if a regular file, or that we have been told to strip. However, if
h->indx is set to -2, the symbol is used by a reloc and we must h->indx is set to -2, the symbol is used by a reloc and we must
@ -6433,10 +6515,25 @@ elf_link_output_extsym (h, data)
sym.st_info = ELF_ST_INFO (bindtype, ELF_ST_TYPE (sym.st_info)); sym.st_info = ELF_ST_INFO (bindtype, ELF_ST_TYPE (sym.st_info));
} }
/* If a symbol is not defined locally, we clear the visibility field. */ /* If a non-weak symbol with non-default visibility is not defined
locally, it is a fatal error. */
if (! finfo->info->relocateable if (! finfo->info->relocateable
&& ELF_ST_VISIBILITY (sym.st_other)
&& ELF_ST_BIND (sym.st_info) != STB_WEAK
&& h->root.type != bfd_link_hash_undefweak
&& (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
sym.st_other &= ~ ELF_ST_VISIBILITY (-1); {
(*_bfd_error_handler)
(_("%s: %s symbol `%s' isn't defined"),
bfd_get_filename (finfo->output_bfd),
ELF_ST_VISIBILITY (sym.st_other) == STV_PROTECTED
? "protected"
: ELF_ST_VISIBILITY (sym.st_other) == STV_INTERNAL
? "internal" : "hidden",
h->root.root.string);
eoinfo->failed = TRUE;
return FALSE;
}
/* If this symbol should be put in the .dynsym section, then put it /* If this symbol should be put in the .dynsym section, then put it
there now. We already know the symbol index. We also fill in there now. We already know the symbol index. We also fill in

View file

@ -1,3 +1,11 @@
2003-04-27 H.J. Lu <hjl@gnu.org>
* ld-elfvsb/elfvsb.dat: Updated.
* ld-elfvsb/elfvsb.exp: Likewise.
* ld-elfvsb/main.c: Likewise.
* ld-elfvsb/sh1.c: Likewise.
* ld-elfvsb/sh2.c: Likewise.
2003-04-26 Stephane Carrez <stcarrez@nerim.fr> 2003-04-26 Stephane Carrez <stcarrez@nerim.fr>
* ld-m68hc11/bug-3331.d: New test. * ld-m68hc11/bug-3331.d: New test.

View file

@ -20,3 +20,7 @@ main_visibility_check () == 1
visibility_checkvar () == 1 visibility_checkvar () == 1
visibility_checkvarptr () == 1 visibility_checkvarptr () == 1
main_visibility_checkvar () == 1 main_visibility_checkvar () == 1
main_visibility_checkcom () == 1
shlib_visibility_checkcom () == 1
main_visibility_checkweak () == 1
shlib_visibility_checkweak () == 1

View file

@ -144,6 +144,8 @@ proc visibility_test { visibility progname testname main sh1 sh2 dat args } {
pass "$testname" pass "$testname"
} else { if { [ string match $visibility "hidden_undef_def" ] } else { if { [ string match $visibility "hidden_undef_def" ]
&& [regexp ".*/main.c.*: undefined reference to \`visibility\'" $link_output] && [regexp ".*/main.c.*: undefined reference to \`visibility\'" $link_output]
&& [regexp ".*/main.c.*: undefined reference to \`visibility_def\'" $link_output]
&& [regexp ".*/main.c.*: undefined reference to \`visibility_func\'" $link_output]
&& [regexp ".*/main.c.*: undefined reference to \`visibility_var\'" $link_output] } { && [regexp ".*/main.c.*: undefined reference to \`visibility_var\'" $link_output] } {
pass "$testname" pass "$testname"
} else { } else {

View file

@ -42,6 +42,18 @@ extern int visibility_checkvar ();
extern int visibility_checkvarptr (); extern int visibility_checkvarptr ();
extern int visibility_varval (); extern int visibility_varval ();
extern void *visibility_varptr (); extern void *visibility_varptr ();
extern int shlib_visibility_checkcom ();
extern int shlib_visibility_checkweak ();
int shlib_visibility_com = 1;
int shlib_visibility_var_weak = 1;
int
shlib_visibility_func_weak ()
{
return 1;
}
#ifdef HIDDEN_WEAK_TEST #ifdef HIDDEN_WEAK_TEST
#define WEAK_TEST #define WEAK_TEST
@ -81,6 +93,23 @@ main_visibility_checkvar ()
return visibility_varval () != visibility_var return visibility_varval () != visibility_var
&& visibility_varptr () != &visibility_var; && visibility_varptr () != &visibility_var;
} }
#ifndef PROTECTED_UNDEF_TEST
int shared_data = 1;
asm (".protected shared_data");
int
shared_func ()
{
return 1;
}
asm (".protected shared_func");
extern int * shared_data_p ();
typedef int (*func) ();
extern func shared_func_p ();
#endif
#else #else
static int static int
main_visibility_check () main_visibility_check ()
@ -121,10 +150,57 @@ shlib_overriddencall2 ()
return 8; return 8;
} }
#ifdef HIDDEN_NORMAL_TEST
int visibility_com;
asm (".hidden visibility_com");
int
main_visibility_checkcom ()
{
return visibility_com == 0;
}
int
main_visibility_checkweak ()
{
return 1;
}
#elif defined (HIDDEN_UNDEF_TEST)
extern int visibility_def;
asm (".hidden visibility_def");
extern int visibility_func ();
asm (".hidden visibility_func");
int
main_visibility_checkcom ()
{
return &visibility_def != NULL;
}
int
main_visibility_checkweak ()
{
return &visibility_func != NULL;
}
#else
int
main_visibility_checkcom ()
{
return 1;
}
int
main_visibility_checkweak ()
{
return 1;
}
#endif
int int
main () main ()
{ {
int (*p) (); int (*p) ();
int ret = 0;
printf ("mainvar == %d\n", mainvar); printf ("mainvar == %d\n", mainvar);
printf ("overriddenvar == %d\n", overriddenvar); printf ("overriddenvar == %d\n", overriddenvar);
@ -173,6 +249,27 @@ main ()
visibility_checkvarptr ()); visibility_checkvarptr ());
printf ("main_visibility_checkvar () == %d\n", printf ("main_visibility_checkvar () == %d\n",
main_visibility_checkvar ()); main_visibility_checkvar ());
return 0; printf ("main_visibility_checkcom () == %d\n",
main_visibility_checkcom ());
printf ("shlib_visibility_checkcom () == %d\n",
shlib_visibility_checkcom ());
printf ("main_visibility_checkweak () == %d\n",
main_visibility_checkweak ());
printf ("shlib_visibility_checkweak () == %d\n",
shlib_visibility_checkweak ());
#if !defined (PROTECTED_UNDEF_TEST) && defined (PROTECTED_TEST)
if (&shared_data != shared_data_p ())
ret = 1;
p = shared_func_p ();
if (shared_func != p)
ret = 1;
if (shared_data != *shared_data_p ())
ret = 1;
if (shared_func () != (*p) () )
ret = 1;
#endif
return ret;
} }
#endif #endif

View file

@ -323,3 +323,54 @@ asm (".protected visibility");
asm (".protected visibility_var"); asm (".protected visibility_var");
#endif #endif
#endif #endif
#ifdef HIDDEN_NORMAL_TEST
int shlib_visibility_com;
asm (".hidden shlib_visibility_com");
int
shlib_visibility_checkcom ()
{
return shlib_visibility_com == 0;
}
int
shlib_visibility_checkweak ()
{
return 1;
}
#else
int
shlib_visibility_checkcom ()
{
return 1;
}
int
shlib_visibility_checkweak ()
{
return 1;
}
#endif
#ifdef PROTECTED_TEST
int shared_data = 100;
int *
shared_data_p ()
{
return &shared_data;
}
int
shared_func ()
{
return 100;
}
void *
shared_func_p ()
{
return shared_func;
}
#endif

View file

@ -5,6 +5,10 @@
the shared library. */ the shared library. */
int shlibvar2 = 4; int shlibvar2 = 4;
/* This variable is defined here, and shouldn't be used to resolve a
reference with non-default visibility in another shared library. */
int visibility_com = 2;
/* This function is called by another file in the shared library. */ /* This function is called by another file in the shared library. */
int int
@ -21,4 +25,22 @@ visibility ()
} }
int visibility_var = 2; int visibility_var = 2;
int visibility_def = 2;
int
visibility_func ()
{
return 2;
}
#endif
#ifdef HIDDEN_WEAK_TEST
int visibility_var_weak = 2;
int
visibility_func_weak ()
{
return 2;
}
#endif #endif