Why are 'extern "C"' static functions emitted with C++ Mangling?

I have been trying to fix "ifunc must point to a defined function" error for static IFUNC resolver functions in C++ mode · Issue #54549 · llvm/llvm-project · GitHub, which is an issue where an ifunc referring to an extern "C"static function ends up not being valid, since the ‘alias’ doesn’t end up being created.

I’ve been trying to do some work to ‘fixup’ the case we are in to update the ifuncs resolver to refer to the aliasee, however I am wondering why we choose to mangle this? I see that the ‘alias’ emission was from Richard Smith here: When an internal-linkage function or variable is declared within an e… · llvm/llvm-project@df931ce · GitHub.

I also note that in ItaniumMangle, we choose to not mangle ONLY if language-linkage is CLanguageLinkage. I’m wondering if instead we could change that to ALSO skip mangling extern-C ‘static’ functions?

This would allow me to remove most of Richard’s patch above, and also end up fixing the problem I’m having here.

So, is there a reason I cannot?

I’ll note that even in their IR (assuming I’m reading this right), GCC does NOT seem to mangle these: Compiler Explorer

Another bit of info:

GCC emits 2 symbols with the same ‘unmangled’ name here, we do it for neither (since we notice the conflict). We can’t leave them both ‘unmangled’, since LLVM-IR doesn’t support duplicate names.

Also, removing ‘static’, we diagnose those as the same function, and GCC still causes the assembler issue with duplicate names. So this is some level of implementation divergence. I guess we cannot just make ‘static’ functions inside extern-C have unmangled names, or we end up breaking code. So I think I probably have to go back to trying to ‘repair’ ifuncs.

Like the commit message for df931ce notes, we allow inline asm to refer to internal linkage functions marked __attribute((used)). If possible, I’d like to avoid breaking this.

For other internal linkage functions, there isn’t any requirement to use any particular mangling; we can mess with the mangling if we want.

I wasn’t considering breaking that. The question really is whether we can implement that by JUST using the unmangled-name as the name of the symbol, rather than creating the alias.

I believe the answer to that ends up being ‘no’, because that causes the following to have two symbols with the same name (which is a problem that GCC has, but the assembler catches, whereas we’d break during IR generation):

extern "C" {
  __attribute__((used)) static void foo();
  namespace NS {
     __attribute__((used)) static void foo();
  }

Currently clang considers those to be two different functions, and I think that is the correct interpretation of the standard. Doing what I was asking about (just using the C name for them) ends up breaking stuff.

Currently in THAT case, clang actually does NOT emit the alias (since there are duplicates), so those aren’t usable in asm anyway.

I think I’d be okay with rejecting two “used” symbols with C linkage with the same name, with an error like “you asked for two symbols with the same name”. The only practical reason for anyone to mark a function “used” is if they plan to look for the symbol later, and that isn’t possible if we rename it behind the user’s back.

Alternatively, if you want to avoid touching the current behavior, you could probably defer ifunc name lookup? But ifuncs aren’t the only attribute defined using this sort of name lookup scheme; we’d probably end up revisiting this later.

By my reading of the standard, I think treating those two declarations as separate functions is necessary (even if GCC mucks it up). In THAT case however, neither will receive the C mangling, which is at least a little confusing.

I opted against trying to make ‘used’ mean ‘C Mangling’ as I think still following the standard behavior for those ‘foo’ declarations (even if the ‘used’ ends up not doing much), and just fix up the ‘ifunc’ when emitting those. See this review here: ⚙ D122608 Fix behavior of ifuncs with 'used' extern "C" static functions