https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91307
--- Comment #8 from Richard Biener <rguenth at gcc dot gnu.org> --- I wonder why we can't simply use .init_array and thus get away with a local symbol on targets that support this. Uh, so the symbol is already local but we're keeping it in our stripping process it seems. And the name is fancy "for debugging purposes". Not sure if gdb has special breakpoints for ctors/dtors or if the user is expected to know the mangling. Btw, for !targetm.have_ctors_dtors we're appending "some randomness" anyways so I wonder if we shouldn't simply pass down appropriate deterministic randomness by producing it from the symbols of the individual ctors/dtors we call here: /* Find the next batch of constructors/destructors with the same initialization priority. */ for (;i < j; i++) { tree call; fn = cdtors[i]; call = build_call_expr (fn, 0); if (ctor_p) DECL_STATIC_CONSTRUCTOR (fn) = 0; else DECL_STATIC_DESTRUCTOR (fn) = 0; /* We do not want to optimize away pure/const calls here. When optimizing, these should be already removed, when not optimizing, we want user to be able to breakpoint in them. */ TREE_SIDE_EFFECTS (call) = 1; append_to_statement_list (call, &body); } like Index: gcc/ipa.c =================================================================== --- gcc/ipa.c (revision 274527) +++ gcc/ipa.c (working copy) @@ -827,7 +827,7 @@ ipa_discover_variable_flags (void) static void cgraph_build_static_cdtor_1 (char which, tree body, int priority, bool final, tree optimization, - tree target) + tree target, hashval_t hstate) { static int counter = 0; char which_buf[16]; @@ -842,7 +842,7 @@ cgraph_build_static_cdtor_1 (char which, /* Proudce sane name but one not recognizable by collect2, just for the case we fail to inline the function. */ sprintf (which_buf, "sub_%c_%.5d_%d", which, priority, counter++); - name = get_file_function_name (which_buf); + name = get_file_function_name (which_buf, hstate); decl = build_decl (input_location, FUNCTION_DECL, name, build_function_type_list (void_type_node, NULL_TREE)); @@ -973,6 +973,7 @@ build_cdtor (bool ctor_p, const vec<tree } /* Find the next batch of constructors/destructors with the same initialization priority. */ + inchash::hash hstate; for (;i < j; i++) { tree call; @@ -987,13 +988,15 @@ build_cdtor (bool ctor_p, const vec<tree optimizing, we want user to be able to breakpoint in them. */ TREE_SIDE_EFFECTS (call) = 1; append_to_statement_list (call, &body); + hstate.merge_hash (IDENTIFIER_HASH_VALUE (DECL_NAME (fn))); } gcc_assert (body != NULL_TREE); /* Generate a function to call all the function of like priority. */ cgraph_build_static_cdtor_1 (ctor_p ? 'I' : 'D', body, priority, true, DECL_FUNCTION_SPECIFIC_OPTIMIZATION (cdtors[0]), - DECL_FUNCTION_SPECIFIC_TARGET (cdtors[0])); + DECL_FUNCTION_SPECIFIC_TARGET (cdtors[0]), + hstate.end); } } plus appropriate changes to get_file_function_name. It also seems to me we may not need to produce a unique symbol here so Martins original idea of using "wpa" for LTO might work fine (but I'd change the signature of get_file_function_name to pass in the actual "file name" then, keeping the original use of main_input_filename via an overload). Note with !targetm.have_ctors_dtors we are going to produce either symbol clashes or random symbols (with and without -flto, "conveniently" IPA CDTOR merging is only run for -flto or !targetm.have_ctors_dtors for whathever reasons).