https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114984

            Bug ID: 114984
           Summary: asm() renaming of symbols inconsistent with dllimport
           Product: gcc
           Version: 13.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: martin at martin dot st
  Target Milestone: ---

A function declaration can use asm("") to point out that the function actually
exists under a different symbol name. E.g. like this:

$ cat call-bar.c
extern void foo (void) asm("bar");
void call_bar(void)
{ foo(); }

$ x86_64-w64-mingw32-gcc -S -O2 -o - call-bar.c 
call_bar:
        jmp     bar

On i686, where symbols normally have an extra underscore prefix (signaled via
__USER_LABEL_PREFIX__), the symbol name in asm() is taken literally, so one has
to include the underscore prefix manually:

$ cat call-bar.c
extern void foo (void) asm("_bar");
void call_bar(void)
{ foo(); }
$ i686-w64-mingw32-gcc -S -O2 -o - call-bar.c
_call_bar:
        jmp     _bar


If the renamed function is declared with dllimport, however, GCC suddenly
treats the symbol name given with asm("") as an undecorated one, that gets the
extra implicit underscore added.

$ cat call-bar2.c 
extern __declspec(dllimport) void foo1 (void) asm("_bar");
extern __declspec(dllimport) void foo2 (void);
void call_bar(void)
{ foo1(); foo2(); }
$ /usr/bin/i686-w64-mingw32-gcc -S -O2 -o - call-bar2.c -O2
_call_bar:
        subl    $12, %esp
        call    *__imp___bar
        addl    $12, %esp
        jmp     *__imp__foo2

Regularly, when adding dllimport, it references a symbol named "__imp_"
followed by the symbol name used without dllimport, i.e. a non-dllimport call
to "foo2" would reference "_foo2", while a dllimport call references
"__imp__foo2".

Therefore, it is surprising and inconsistent that dllimport together with asm()
implicitly includes __USER_LABEL_PREFIX__, while asm() without dllimport
doesn't.

This issue was reported already in 2007 in
https://sourceware.org/pipermail/cygwin/2007-February/154845.html, with an
intent to send a patch, but I find no traces of such a patch.

To fully show off all combinations in one example, consider:

$ cat sym-asm.c 
void regular(void);
void __declspec(dllimport) imported(void);
void renamed(void) asm("newname");
void __declspec(dllimport) renamedimported(void) asm("newimportedname");

void call(void) {
  regular();
  imported();
  renamed();
  renamedimported();
}
$ i686-w64-mingw32-gcc -S -O2 -o - sym-asm.c 
_call:
        subl    $12, %esp
        call    _regular
        call    *__imp__imported
        call    newname
        addl    $12, %esp
        jmp     *__imp__newimportedname

Contrary, Clang does seem to handle this consistently:
$ clang -target i686-w64-mingw32 -S -O2 -o - sym-asm.c 
_call:
        calll   _regular
        calll   *__imp__imported
        calll   newname
        jmpl    *__imp_newimportedname

I.e., when naming the symbol asm("newimportedname"), this singifies the literal
string that would be included after "__imp_", i.e. the user need to include
__USER_LABEL_PREFIX__ within asm("").

Reply via email to