[cfe-dev] Creating an alias to a static function in C++

Richard Smith via cfe-dev cfe-dev at lists.llvm.org
Thu May 3 19:32:39 PDT 2018


On 1 May 2018 at 21:56, Evan Driscoll via cfe-dev <cfe-dev at lists.llvm.org>
wrote:

> On Tue, May 1, 2018 at 11:43 PM, Evan Driscoll <evaned at gmail.com> wrote:
>
>>   $ cat huh.cc
>>   extern "C" {
>>     static __attribute__((used)) void dummy1(int x) { }
>>   }
>>   $ clang -c huh.cc && nm huh.o
>>   0000000000000000 t f
>>   0000000000000000 t _ZL1fi
>>   $ clang -c huh.cc && nm huh.o | c++filt
>>   0000000000000000 t f
>>   0000000000000000 t f(int)
>>
>
> In the interest of hopefully eliminating confusion -- sorry for the output
> not exactly matching up with the examples in terms of function names. I was
> working half in Compiler Explorer and half with a file on a local file
> system. I noticed as I was finishing the email, and thought I'd try to
> align the names by editing the command output to match... but of course
> that is always a bad idea. :-)
>
> Anyway, of course that code doesn't produce an object file with a symbol
> 'f' in it, it'd be 'dummy1'. The presence of both the unmangled and mangled
> symbols is the same though.
>

In C++, extern "C" means two different things:

1) All[*] function types within the region are given C language linkage
(which means they use the C calling convention). In GCC and Clang, the C
calling convention is the same as the C++ calling convention, so this
doesn't really matter (and actually isn't implemented at all, which is
slightly non-conforming).
2) All[*] function and variable declarations *with external linkage* within
the region are given C language linkage (which means they use the C symbol
names).

Point 2 is the relevant one here, and the key fact is that it only applies
to functions with external linkage. In particular, this is valid:

extern "C" {
  static void f(int) {}
  static void f(double) {}
}

... and the two functions do not collide per the standard C++ rules.

However, GCC historically did not implement this rule that way (and as far
as I know, still doesn't), and applies the C language linkage rules even to
internal linkage functions.

Clang chooses to try to satisfy both the goal of C++ standard conformance
and GCC compatibility, and the way it does that is to use two different
mangled names for such internal-linkage-in-extern-C blocks: a C++ one
(allowing overloading), and a C alias; the latter is omitted in the case
where it would collide with another symbol (which effectively means we try
to emit it only after we emit everything else).

I would guess the problem is that we check that the referent of
__attribute__((alias(...))) exists before we register the static extern "C"
aliases, which is why the lookup is failing.


 [*]: Irrelevant exceptions elided

Evan
>
>
>
>
>>
>>
>> So I tried using the mangled name in the alias, and that works:
>>
>>   extern "C" {
>>     static __attribute__((used)) void f1 () {}
>>     void f () __attribute__ ((weak, alias("_ZL2f1v"))); // OK
>>   }
>>
>> and of course then so does this
>>
>>   static __attribute__((used)) void f1 () {}
>>   extern "C" {
>>     void f () __attribute__ ((weak, alias("_ZL2f1v")));
>>   }
>>
>>
>> Furthermore, if I browse the Itanium ABI page, I can't even figure out
>> how you get a "_ZL..." mangled symbol, but I'm sure I'm missing something
>> (e.g. c++filt demangles it fine...)
>>
>
_ZL is a GCC mangling extension used to mangle the names of
internal-linkage symbols. Because it's only used for internal-linkage
symbols, it's not part of the ABI per se, but it's still useful for us to
use the same scheme so that demanglers can produce proper output for our
names. (Historically, C++ allowed some weird constructs where you could
have two distinct symbols, one with internal linkage and one with external
linkage, that would mangle the same, named in the same translation unit, so
a disambiguator was needed. Such cases are now ill-formed, but the legacy
of that remains in our mangling scheme.)


> Anyway, I can easily work around this is my actual code, but how much of
>> this is expected behavior?
>>
>
Everything except the actual error is expected behavior. For GCC
compatibility, I think we should try to accept examples such as yours.
Interested in putting together a patch?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20180503/36706316/attachment.html>


More information about the cfe-dev mailing list