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("").