aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog17
-rw-r--r--bfd/elf-bfd.h4
-rw-r--r--bfd/elflink.h123
-rw-r--r--ld/testsuite/ChangeLog8
-rw-r--r--ld/testsuite/ld-elfvsb/elfvsb.dat4
-rw-r--r--ld/testsuite/ld-elfvsb/elfvsb.exp2
-rw-r--r--ld/testsuite/ld-elfvsb/main.c99
-rw-r--r--ld/testsuite/ld-elfvsb/sh1.c51
-rw-r--r--ld/testsuite/ld-elfvsb/sh2.c22
9 files changed, 316 insertions, 14 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 3833e05..2bd268c 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -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>
* configure.in: Bump version on HEAD to 2.14.90.
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 2e5587c..f15353c 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -204,6 +204,10 @@ struct elf_link_hash_entry
/* Symbol is referenced by a non-GOT/non-PLT relocation. This is
not currently set by all the backends. */
#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. */
diff --git a/bfd/elflink.h b/bfd/elflink.h
index 505bfb1..5889e1c 100644
--- a/bfd/elflink.h
+++ b/bfd/elflink.h
@@ -42,7 +42,7 @@ static bfd_boolean elf_merge_symbol
PARAMS ((bfd *, struct bfd_link_info *, const char *,
Elf_Internal_Sym *, asection **, bfd_vma *,
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
PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
const char *, Elf_Internal_Sym *, asection **, bfd_vma *,
@@ -463,7 +463,7 @@ elf_link_add_archive_symbols (abfd, info)
a shared object. */
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)
bfd *abfd;
struct bfd_link_info *info;
@@ -472,6 +472,7 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
asection **psec;
bfd_vma *pvalue;
struct elf_link_hash_entry **sym_hash;
+ bfd_boolean *skip;
bfd_boolean *override;
bfd_boolean *type_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_boolean newdyn, olddyn, olddef, newdef, newdyncommon, olddyncommon;
+ *skip = FALSE;
*override = FALSE;
sec = *psec;
@@ -606,6 +608,57 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
else
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
symbol, respectively, appears to be a common symbol in a dynamic
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 size_change_ok;
+ bfd_boolean skip;
char *shortname;
struct elf_link_hash_entry *hi;
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;
sec = *psec;
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))
return FALSE;
@@ -1098,7 +1152,7 @@ elf_add_default_symbol (abfd, info, h, name, sym, psec, value,
size_change_ok = FALSE;
sec = *psec;
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))
return FALSE;
@@ -1740,6 +1794,7 @@ elf_link_add_object_symbols (abfd, info)
{
Elf_Internal_Versym iver;
unsigned int vernum = 0;
+ bfd_boolean skip;
if (ever != NULL)
{
@@ -1837,10 +1892,14 @@ elf_link_add_object_symbols (abfd, info)
}
if (! elf_merge_symbol (abfd, info, name, isym, &sec, &value,
- sym_hash, &override, &type_change_ok,
- &size_change_ok, dt_needed))
+ sym_hash, &skip, &override,
+ &type_change_ok, &size_change_ok,
+ dt_needed))
goto error_free_vers;
+ if (skip)
+ continue;
+
if (override)
definition = FALSE;
@@ -2020,9 +2079,10 @@ elf_link_add_object_symbols (abfd, info)
h->type = ELF_ST_TYPE (isym->st_info);
}
- /* If st_other has a processor-specific meaning, specific code
- might be needed here. */
- if (isym->st_other != 0)
+ /* If st_other has a processor-specific meaning, specific
+ code might be needed here. We never merge the visibility
+ attribute with the one from a dynamic object. */
+ if (isym->st_other != 0 && !dynamic)
{
unsigned char hvis, symvis, other, nvis;
@@ -2089,7 +2149,7 @@ elf_link_add_object_symbols (abfd, info)
override, dt_needed))
goto error_free_vers;
- if (definition && (abfd->flags & DYNAMIC) == 0)
+ if (definition && !dynamic)
{
char *p = strchr (name, 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
|| 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;
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
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
@@ -6433,10 +6515,25 @@ elf_link_output_extsym (h, data)
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
+ && 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)
- 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
there now. We already know the symbol index. We also fill in
diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog
index a0ae7fd..8334e58 100644
--- a/ld/testsuite/ChangeLog
+++ b/ld/testsuite/ChangeLog
@@ -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>
* ld-m68hc11/bug-3331.d: New test.
diff --git a/ld/testsuite/ld-elfvsb/elfvsb.dat b/ld/testsuite/ld-elfvsb/elfvsb.dat
index e94a178..bad3b1e 100644
--- a/ld/testsuite/ld-elfvsb/elfvsb.dat
+++ b/ld/testsuite/ld-elfvsb/elfvsb.dat
@@ -20,3 +20,7 @@ main_visibility_check () == 1
visibility_checkvar () == 1
visibility_checkvarptr () == 1
main_visibility_checkvar () == 1
+main_visibility_checkcom () == 1
+shlib_visibility_checkcom () == 1
+main_visibility_checkweak () == 1
+shlib_visibility_checkweak () == 1
diff --git a/ld/testsuite/ld-elfvsb/elfvsb.exp b/ld/testsuite/ld-elfvsb/elfvsb.exp
index c4f82f4..220e282 100644
--- a/ld/testsuite/ld-elfvsb/elfvsb.exp
+++ b/ld/testsuite/ld-elfvsb/elfvsb.exp
@@ -144,6 +144,8 @@ proc visibility_test { visibility progname testname main sh1 sh2 dat args } {
pass "$testname"
} else { if { [ string match $visibility "hidden_undef_def" ]
&& [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] } {
pass "$testname"
} else {
diff --git a/ld/testsuite/ld-elfvsb/main.c b/ld/testsuite/ld-elfvsb/main.c
index 26542b8..6ce97bf 100644
--- a/ld/testsuite/ld-elfvsb/main.c
+++ b/ld/testsuite/ld-elfvsb/main.c
@@ -42,6 +42,18 @@ extern int visibility_checkvar ();
extern int visibility_checkvarptr ();
extern int visibility_varval ();
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
#define WEAK_TEST
@@ -81,6 +93,23 @@ main_visibility_checkvar ()
return visibility_varval () != 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
static int
main_visibility_check ()
@@ -121,10 +150,57 @@ shlib_overriddencall2 ()
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
main ()
{
int (*p) ();
+ int ret = 0;
printf ("mainvar == %d\n", mainvar);
printf ("overriddenvar == %d\n", overriddenvar);
@@ -173,6 +249,27 @@ main ()
visibility_checkvarptr ());
printf ("main_visibility_checkvar () == %d\n",
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
diff --git a/ld/testsuite/ld-elfvsb/sh1.c b/ld/testsuite/ld-elfvsb/sh1.c
index 41bc493..2b9b9ee 100644
--- a/ld/testsuite/ld-elfvsb/sh1.c
+++ b/ld/testsuite/ld-elfvsb/sh1.c
@@ -323,3 +323,54 @@ asm (".protected visibility");
asm (".protected visibility_var");
#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
diff --git a/ld/testsuite/ld-elfvsb/sh2.c b/ld/testsuite/ld-elfvsb/sh2.c
index 6ed30bc..ef6b2f1 100644
--- a/ld/testsuite/ld-elfvsb/sh2.c
+++ b/ld/testsuite/ld-elfvsb/sh2.c
@@ -5,6 +5,10 @@
the shared library. */
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. */
int
@@ -21,4 +25,22 @@ visibility ()
}
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