diff options
Diffstat (limited to 'gcc/symtab.c')
-rw-r--r-- | gcc/symtab.c | 266 |
1 files changed, 192 insertions, 74 deletions
diff --git a/gcc/symtab.c b/gcc/symtab.c index c188710..06d618b 100644 --- a/gcc/symtab.c +++ b/gcc/symtab.c @@ -52,6 +52,26 @@ const char * const ld_plugin_symbol_resolution_names[]= "prevailing_def_ironly_exp" }; +/* Follow the IDENTIFIER_TRANSPARENT_ALIAS chain starting at ALIAS + until we find an identifier that is not itself a transparent alias. */ + +static inline tree +ultimate_transparent_alias_target (tree alias) +{ + tree target = alias; + + while (IDENTIFIER_TRANSPARENT_ALIAS (target)) + { + gcc_checking_assert (TREE_CHAIN (target)); + target = TREE_CHAIN (target); + } + gcc_checking_assert (! IDENTIFIER_TRANSPARENT_ALIAS (target) + && ! TREE_CHAIN (target)); + + return target; +} + + /* Hash asmnames ignoring the user specified marks. */ hashval_t @@ -73,6 +93,44 @@ symbol_table::decl_assembler_name_hash (const_tree asmname) return htab_hash_string (IDENTIFIER_POINTER (asmname)); } +/* Return true if assembler names NAME1 and NAME2 leads to the same symbol + name. */ + +bool +symbol_table::assembler_names_equal_p (const char *name1, const char *name2) +{ + if (name1 != name2) + { + if (name1[0] == '*') + { + size_t ulp_len = strlen (user_label_prefix); + + name1 ++; + + if (ulp_len == 0) + ; + else if (strncmp (name1, user_label_prefix, ulp_len) == 0) + name1 += ulp_len; + else + return false; + } + if (name2[0] == '*') + { + size_t ulp_len = strlen (user_label_prefix); + + name2 ++; + + if (ulp_len == 0) + ; + else if (strncmp (name2, user_label_prefix, ulp_len) == 0) + name2 += ulp_len; + else + return false; + } + return !strcmp (name1, name2); + } + return true; +} /* Compare ASMNAME with the DECL_ASSEMBLER_NAME of DECL. */ @@ -82,51 +140,13 @@ symbol_table::decl_assembler_name_equal (tree decl, const_tree asmname) tree decl_asmname = DECL_ASSEMBLER_NAME (decl); const char *decl_str; const char *asmname_str; - bool test = false; if (decl_asmname == asmname) return true; decl_str = IDENTIFIER_POINTER (decl_asmname); asmname_str = IDENTIFIER_POINTER (asmname); - - - /* If the target assembler name was set by the user, things are trickier. - We have a leading '*' to begin with. After that, it's arguable what - is the correct thing to do with -fleading-underscore. Arguably, we've - historically been doing the wrong thing in assemble_alias by always - printing the leading underscore. Since we're not changing that, make - sure user_label_prefix follows the '*' before matching. */ - if (decl_str[0] == '*') - { - size_t ulp_len = strlen (user_label_prefix); - - decl_str ++; - - if (ulp_len == 0) - test = true; - else if (strncmp (decl_str, user_label_prefix, ulp_len) == 0) - decl_str += ulp_len, test=true; - else - decl_str --; - } - if (asmname_str[0] == '*') - { - size_t ulp_len = strlen (user_label_prefix); - - asmname_str ++; - - if (ulp_len == 0) - test = true; - else if (strncmp (asmname_str, user_label_prefix, ulp_len) == 0) - asmname_str += ulp_len, test=true; - else - asmname_str --; - } - - if (!test) - return false; - return strcmp (decl_str, asmname_str) == 0; + return assembler_names_equal_p (decl_str, asmname_str); } @@ -273,6 +293,8 @@ symbol_table::change_decl_assembler_name (tree decl, tree name) : NULL); if (node) unlink_from_assembler_name_hash (node, true); + + const char *old_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) && DECL_RTL_SET_P (decl)) warning (0, "%D renamed after being referenced in assembly", decl); @@ -283,8 +305,48 @@ symbol_table::change_decl_assembler_name (tree decl, tree name) IDENTIFIER_TRANSPARENT_ALIAS (name) = 1; TREE_CHAIN (name) = alias; } + /* If we change assembler name, also all transparent aliases must + be updated. There are three kinds - those having same assembler name, + those being renamed in varasm.c and weakref being renamed by the + assembler. */ if (node) - insert_to_assembler_name_hash (node, true); + { + insert_to_assembler_name_hash (node, true); + ipa_ref *ref; + for (unsigned i = 0; node->iterate_direct_aliases (i, ref); i++) + { + struct symtab_node *alias = ref->referring; + if (alias->transparent_alias && !alias->weakref + && symbol_table::assembler_names_equal_p + (old_name, IDENTIFIER_POINTER ( + DECL_ASSEMBLER_NAME (alias->decl)))) + change_decl_assembler_name (alias->decl, name); + else if (alias->transparent_alias + && IDENTIFIER_TRANSPARENT_ALIAS (alias->decl)) + { + gcc_assert (TREE_CHAIN (DECL_ASSEMBLER_NAME (alias->decl)) + && IDENTIFIER_TRANSPARENT_ALIAS + (DECL_ASSEMBLER_NAME (alias->decl))); + + TREE_CHAIN (DECL_ASSEMBLER_NAME (alias->decl)) = + ultimate_transparent_alias_target + (DECL_ASSEMBLER_NAME (node->decl)); + } +#ifdef ASM_OUTPUT_WEAKREF + else gcc_assert (!alias->transparent_alias || alias->weakref); +#else + else gcc_assert (!alias->transparent_alias); +#endif + } + gcc_assert (!node->transparent_alias || !node->definition + || node->weakref + || TREE_CHAIN (DECL_ASSEMBLER_NAME (decl)) + || symbol_table::assembler_names_equal_p + (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), + IDENTIFIER_POINTER + (DECL_ASSEMBLER_NAME + (node->get_alias_target ()->decl)))); + } } } @@ -727,6 +789,8 @@ symtab_node::dump_base (FILE *f) fprintf (f, " analyzed"); if (alias) fprintf (f, " alias"); + if (transparent_alias) + fprintf (f, " transparent_alias"); if (weakref) fprintf (f, " weakref"); if (cpp_implicit_alias) @@ -973,9 +1037,14 @@ symtab_node::verify_base (void) error ("node is alias but not definition"); error_found = true; } - if (weakref && !alias) + if (weakref && !transparent_alias) { - error ("node is weakref but not an alias"); + error ("node is weakref but not an transparent_alias"); + error_found = true; + } + if (transparent_alias && !alias) + { + error ("node is transparent_alias but not an alias"); error_found = true; } if (same_comdat_group) @@ -1061,6 +1130,29 @@ symtab_node::verify_base (void) get_alias_target ()->dump (stderr); error_found = true; } + if (transparent_alias && definition && !weakref) + { + symtab_node *to = get_alias_target (); + const char *name1 + = IDENTIFIER_POINTER ( + ultimate_transparent_alias_target (DECL_ASSEMBLER_NAME (decl))); + const char *name2 + = IDENTIFIER_POINTER ( + ultimate_transparent_alias_target (DECL_ASSEMBLER_NAME (to->decl))); + if (!symbol_table::assembler_names_equal_p (name1, name2)) + { + error ("Transparent alias and target's assembler names differs"); + get_alias_target ()->dump (stderr); + error_found = true; + } + } + if (transparent_alias && definition + && get_alias_target()->transparent_alias && get_alias_target()->analyzed) + { + error ("Chained transparent aliases"); + get_alias_target ()->dump (stderr); + error_found = true; + } return error_found; } @@ -1132,15 +1224,35 @@ symtab_node::make_decl_local (void) { rtx rtl, symbol; + if (weakref) + { + weakref = false; + IDENTIFIER_TRANSPARENT_ALIAS (DECL_ASSEMBLER_NAME (decl)) = 0; + TREE_CHAIN (DECL_ASSEMBLER_NAME (decl)) = NULL_TREE; + symtab->change_decl_assembler_name + (decl, DECL_ASSEMBLER_NAME (get_alias_target ()->decl)); + DECL_ATTRIBUTES (decl) = remove_attribute ("weakref", + DECL_ATTRIBUTES (decl)); + } /* Avoid clearing comdat_groups on comdat-local decls. */ - if (TREE_PUBLIC (decl) == 0) + else if (TREE_PUBLIC (decl) == 0) return; + /* Localizing a symbol also make all its transparent aliases local. */ + ipa_ref *ref; + for (unsigned i = 0; iterate_direct_aliases (i, ref); i++) + { + struct symtab_node *alias = ref->referring; + if (alias->transparent_alias) + alias->make_decl_local (); + } + if (TREE_CODE (decl) == VAR_DECL) { DECL_COMMON (decl) = 0; /* ADDRESSABLE flag is not defined for public symbols. */ TREE_ADDRESSABLE (decl) = 1; + TREE_STATIC (decl) = 1; } else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); @@ -1175,29 +1287,28 @@ symtab_node::make_decl_local (void) symtab_node * symtab_node::ultimate_alias_target_1 (enum availability *availability) { - bool weakref_p = false; + bool transparent_p = false; /* To determine visibility of the target, we follow ELF semantic of aliases. Here alias is an alternative assembler name of a given definition. Its availability prevails the availability of its target (i.e. static alias of weak definition is available. - Weakref is a different animal (and not part of ELF per se). It is just - alternative name of a given symbol used within one complation unit - and is translated prior hitting the object file. It inherits the - visibility of its target (i.e. weakref of non-overwritable definition - is non-overwritable, while weakref of weak definition is weak). + Transaparent alias is just alternative anme of a given symbol used within + one compilation unit and is translated prior hitting the object file. It + inherits the visibility of its target. + Weakref is a different animal (and noweak definition is weak). If we ever get into supporting targets with different semantics, a target hook will be needed here. */ if (availability) { - weakref_p = weakref; - if (!weakref_p) + transparent_p = transparent_alias; + if (!transparent_p) *availability = get_availability (); else - *availability = AVAIL_LOCAL; + *availability = AVAIL_NOT_AVAILABLE; } symtab_node *node = this; @@ -1207,27 +1318,19 @@ symtab_node::ultimate_alias_target_1 (enum availability *availability) node = node->get_alias_target (); else { - if (!availability) + if (!availability || (!transparent_p && node->analyzed)) ; - else if (node->analyzed) - { - if (weakref_p) - { - enum availability a = node->get_availability (); - if (a < *availability) - *availability = a; - } - } + else if (node->analyzed && !node->transparent_alias) + *availability = node->get_availability (); else *availability = AVAIL_NOT_AVAILABLE; return node; } - if (node && availability && weakref_p) + if (node && availability && transparent_p + && node->transparent_alias) { - enum availability a = node->get_availability (); - if (a < *availability) - *availability = a; - weakref_p = node->weakref; + *availability = node->get_availability (); + transparent_p = false; } } if (availability) @@ -1442,7 +1545,7 @@ symtab_node::set_implicit_section (symtab_node *n, it returns false. */ bool -symtab_node::resolve_alias (symtab_node *target) +symtab_node::resolve_alias (symtab_node *target, bool transparent) { symtab_node *n; @@ -1468,6 +1571,11 @@ symtab_node::resolve_alias (symtab_node *target) definition = true; alias = true; analyzed = true; + transparent |= transparent_alias; + transparent_alias = transparent; + if (transparent) + while (target->transparent_alias && target->analyzed) + target = target->get_alias_target (); create_reference (target, IPA_REF_ALIAS, NULL); /* Add alias into the comdat group of its target unless it is already there. */ @@ -1492,19 +1600,29 @@ symtab_node::resolve_alias (symtab_node *target) when renaming symbols. */ alias_target = NULL; - if (cpp_implicit_alias && symtab->state >= CONSTRUCTION) + if (!transparent && cpp_implicit_alias && symtab->state >= CONSTRUCTION) fixup_same_cpp_alias_visibility (target); /* If alias has address taken, so does the target. */ if (address_taken) target->ultimate_alias_target ()->address_taken = true; - /* All non-weakref aliases of THIS are now in fact aliases of TARGET. */ + /* All non-transparent aliases of THIS are now in fact aliases of TARGET. + If alias is transparent, also all transparent aliases of THIS are now + aliases of TARGET. + Also merge same comdat group lists. */ ipa_ref *ref; for (unsigned i = 0; iterate_direct_aliases (i, ref);) { struct symtab_node *alias_alias = ref->referring; - if (!alias_alias->weakref) + if (alias_alias->get_comdat_group ()) + { + alias_alias->remove_from_same_comdat_group (); + alias_alias->set_comdat_group (NULL); + if (target->get_comdat_group ()) + alias_alias->add_to_same_comdat_group (target); + } + if (!alias_alias->transparent_alias || transparent) { alias_alias->remove_all_references (); alias_alias->create_reference (target, IPA_REF_ALIAS, NULL); @@ -1648,9 +1766,9 @@ symtab_node::get_partitioning_class (void) if (cnode && cnode->global.inlined_to) return SYMBOL_DUPLICATE; - /* Weakref aliases are always duplicated. */ - if (weakref) - return SYMBOL_DUPLICATE; + /* Transparent aliases are always duplicated. */ + if (transparent_alias) + return definition ? SYMBOL_DUPLICATE : SYMBOL_EXTERNAL; /* External declarations are external. */ if (DECL_EXTERNAL (decl)) |