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