Adding leading underscores to assembly symbols with GCC on Win32?

One option, though dangerous, is to convince GCC to omit the ABI-required leading underscore.

  • -fleading-underscore

    This option and its counterpart, -fno-leading-underscore, forcibly change the way C symbols are represented in the object file. One use is to help link with legacy assembly code.

    Warning: the -fleading-underscore switch causes GCC to generate code that is not binary compatible with code generated without that switch. Use it to conform to a non-default application binary interface. Not all targets provide complete support for this switch.

Another, safer option, is to explicitly tell GCC the name to use.

5.39 Controlling Names Used in Assembler Code

You can specify the name to be used in the assembler code for a C function or variable by writing the asm (or __asm__) keyword after the declarator as follows:

     int foo asm ("myfoo") = 2;

This specifies that the name to be used for the variable foo in the assembler code should be ``myfoo' rather than the usual \``_foo'.

On systems where an underscore is normally prepended to the name of a C function or variable, this feature allows you to define names for the linker that do not start with an underscore.

It does not make sense to use this feature with a non-static local variable since such variables do not have assembler names. If you are trying to put the variable in a particular register, see Explicit Reg Vars. GCC presently accepts such code with a warning, but will probably be changed to issue an error, rather than a warning, in the future.

You cannot use asm in this way in a function definition; but you can get the same effect by writing a declaration for the function before its definition and putting asm there, like this:

 extern func () asm ("FUNC");

 func (x, y)
      int x, y;
 /* ... */

It is up to you to make sure that the assembler names you choose do not conflict with any other assembler symbols. Also, you must not use a register name; that would produce completely invalid assembler code. GCC does not as yet have the ability to store static variables in registers. Perhaps that will be added.

In your case,

extern int bar(int x) asm("bar");

should tell GCC that "bar uses asm name ``bar`', even though it's a ccall function".


You can use the C preprocessor to preprocess your assembly and use a macro to add the missing underscores on Windows. First, you need to rename your assembly file from bar.s to bar.S (capital 'S'). This tells gcc to use cpp to preprocess the file.

To add the missing underscores, you can define a macro "cdecl" like this:

#if defined(__WIN32__)
# define cdecl(s) _##s
#else
# define cdecl(s) s
#endif

Then use it like this:

.global cdecl(bar)
cdecl(bar):
    movl 4(%esp), %eax
    addl %eax, %eax
    ret

Note that Mac OSX also requires leading underscores, so you can update the first line of the macro like this:

#if defined(__WIN32__) || defined(__APPLE__)

can you declare it twice?

.global bar
.global _bar

I haven't written assembly in awhile, but does the .global identifier just act sort of like a label?