http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46055
--- Comment #10 from Jan Hubicka <hubicka at ucw dot cz> 2010-10-18 15:11:52 UTC --- Hi, I found what is causing the problem. I accidentally comitted also the following cleanup of visibility code. The difference is that we now trust linker's LDPR_PREVAILING_DEF_IRONLY and bring symbols local when they are declared so even without default visibility. Linker should not declare symbols that can be bound by dynamic linker as LDPR_PREVAILING_DEF_IRONLY (according to my earlier conversation about COMDATs). I am looking into it and will either revert the patch today or add missing changelog (and post to ML). Sorry for that. Honza Index: ipa.c =================================================================== *** ipa.c (revision 165562) --- ipa.c (working copy) *************** cgraph_externally_visible_p (struct cgra *** 595,600 **** --- 608,630 ---- /* If linker counts on us, we must preserve the function. */ if (cgraph_used_from_object_file_p (node)) return true; + if (DECL_PRESERVE_P (node->decl)) + return true; + if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node->decl))) + return true; + + /* See if we have linker information about symbol not being used or + if we need to make guess based on the declaration. + + Even if the linker clams the symbol is unused, never bring internal + symbols that are declared by user as used or externally visible. + This is needed for i.e. references from asm statements. */ + for (alias = node->same_body; alias; alias = alias->next) + if (alias->resolution != LDPR_PREVAILING_DEF_IRONLY) + break; + if (!alias && node->resolution == LDPR_PREVAILING_DEF_IRONLY) + return false; + /* When doing link time optimizations, hidden symbols become local. */ if (in_lto_p && (DECL_VISIBILITY (node->decl) == VISIBILITY_HIDDEN *************** cgraph_externally_visible_p (struct cgra *** 626,636 **** return true; } } ! if (DECL_PRESERVE_P (node->decl)) ! return true; if (MAIN_NAME_P (DECL_NAME (node->decl))) return true; ! if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node->decl))) return true; return false; } --- 656,725 ---- return true; } } ! if (MAIN_NAME_P (DECL_NAME (node->decl))) return true; ! ! return false; ! } ! ! /* Return true when variable VNODE should be considered externally visible. */ ! ! static bool ! varpool_externally_visible_p (struct varpool_node *vnode, bool aliased) ! { ! struct varpool_node *alias; ! if (!DECL_COMDAT (vnode->decl) && !TREE_PUBLIC (vnode->decl)) ! return false; ! ! /* Do not even try to be smart about aliased nodes. Until we properly ! represent everything by same body alias, these are just evil. */ ! if (aliased) ! return true; ! ! /* If linker counts on us, we must preserve the function. */ ! if (varpool_used_from_object_file_p (vnode)) ! return true; ! ! if (DECL_PRESERVE_P (vnode->decl)) ! return true; ! if (lookup_attribute ("externally_visible", ! DECL_ATTRIBUTES (vnode->decl))) ! return true; ! ! /* See if we have linker information about symbol not being used or ! if we need to make guess based on the declaration. ! ! Even if the linker clams the symbol is unused, never bring internal ! symbols that are declared by user as used or externally visible. ! This is needed for i.e. references from asm statements. */ ! if (varpool_used_from_object_file_p (vnode)) ! return true; ! for (alias = vnode->extra_name; alias; alias = alias->next) ! if (alias->resolution != LDPR_PREVAILING_DEF_IRONLY) ! break; ! if (!alias && vnode->resolution == LDPR_PREVAILING_DEF_IRONLY) ! return false; ! ! /* When doing link time optimizations, hidden symbols become local. */ ! if (in_lto_p ! && (DECL_VISIBILITY (vnode->decl) == VISIBILITY_HIDDEN ! || DECL_VISIBILITY (vnode->decl) == VISIBILITY_INTERNAL) ! /* Be sure that node is defined in IR file, not in other object ! file. In that case we don't set used_from_other_object_file. */ ! && vnode->finalized) ! ; ! else if (!flag_whole_program) ! return true; ! ! /* Do not attempt to privatize COMDATS by default. ! This would break linking with C++ libraries sharing ! inline definitions. ! ! FIXME: We can do so for readonly vars with no address taken and ! possibly also for vtables since no direct pointer comparsion is done. ! It might be interesting to do so to reduce linking overhead. */ ! if (DECL_COMDAT (vnode->decl) || DECL_WEAK (vnode->decl)) return true; return false; } *************** function_and_variable_visibility (bool w *** 786,812 **** if (!vnode->finalized) continue; if (vnode->needed ! && (DECL_COMDAT (vnode->decl) || TREE_PUBLIC (vnode->decl)) ! && (((!whole_program ! /* We can privatize comdat readonly variables whose address is ! not taken, but doing so is not going to bring us ! optimization oppurtunities until we start reordering ! datastructures. */ ! || DECL_COMDAT (vnode->decl) ! || DECL_WEAK (vnode->decl)) ! /* When doing linktime optimizations, all hidden symbols will ! become local. */ ! && (!in_lto_p ! || (DECL_VISIBILITY (vnode->decl) != VISIBILITY_HIDDEN ! && DECL_VISIBILITY (vnode->decl) != VISIBILITY_INTERNAL) ! /* We can get prevailing decision in other object file. ! In this case we do not sed used_from_object_file. */ ! || !vnode->finalized)) ! || DECL_PRESERVE_P (vnode->decl) ! || varpool_used_from_object_file_p (vnode) ! || pointer_set_contains (aliased_vnodes, vnode) ! || lookup_attribute ("externally_visible", ! DECL_ATTRIBUTES (vnode->decl)))) vnode->externally_visible = true; else vnode->externally_visible = false; --- 875,883 ---- if (!vnode->finalized) continue; if (vnode->needed ! && varpool_externally_visible_p ! (vnode, ! pointer_set_contains (aliased_vnodes, vnode))) vnode->externally_visible = true; else vnode->externally_visible = false;