diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 3833e05f68..2bd268c9c1 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,20 @@ +2003-04-27 H.J. Lu + + * 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 * configure.in: Bump version on HEAD to 2.14.90. diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 2e5587cf79..f15353ce2d 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 505bfb1215..5889e1c70f 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 a0ae7fdf8b..8334e587d8 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2003-04-27 H.J. Lu + + * 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 * ld-m68hc11/bug-3331.d: New test. diff --git a/ld/testsuite/ld-elfvsb/elfvsb.dat b/ld/testsuite/ld-elfvsb/elfvsb.dat index e94a178e14..bad3b1ec14 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 c4f82f45c0..220e28251a 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 26542b8a1f..6ce97bf4b2 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 41bc4934d2..2b9b9eeb52 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 6ed30bc52e..ef6b2f16f6 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