在Win32上用GCC添加前导下划线到汇编符号?

我有一段C代码调用在程序集中定义的函数。 举例来说,假设foo.c包含:

int bar(int x); /* returns 2x */ int main(int argc, char *argv[]) { return bar(7); } 

而bar.s包含x86汇编中bar()的实现:

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

在Linux上,我可以很容易地编译和链接这些来源与GCC如下:

 % gcc -o test foo.c bar.s % ./test; echo $? 14 

在使用MinGW的Windows上,失败的错误是“未定义的引用”bar“”。 原因是这样的,在Windows上所有带有C调用约定的函数的标识符都以下划线作为前缀,但是由于在汇编中定义了“bar”,所以它不会得到这个前缀,并且链接失败。 (所以这个错误信息实际上是抱怨丢失了_bar符号,而不是吧。)

总结:

 % gcc -c foo.c bar.s % nm foo.o bar.o foo.o: 00000000 b .bss 00000000 d .data 00000000 t .text U ___main U _bar 00000000 T _main bar.o: 00000000 b .bss 00000000 d .data 00000000 t .text 00000000 T bar 

现在的问题是:我怎样才能解决这个很好? 如果我只是为Windows编写代码,我可以在bar.s中添加下划线到标识符,但是代码在Linux上会中断。 我曾经看过gcc的-fleading-underscore-fno-leading-underscore选项,但都没有出现任何事情(至less在Windows上)。

我现在看到的唯一select是通过C预处理程序传递程序集文件,如果定义了WIN32,则手动重新定义所有已声明的符号,但这也不是很漂亮。

有没有人有一个干净的解决scheme呢? 也许我监督一个编译器选项? 也许GNU汇编程序支持一种方式来指定这个特定的符号是指一个使用C调用约定的函数,并应该像这样被破坏? 任何其他的想法?

一个选项虽然很危险,但是要说服GCC省略ABI要求的主要下划线。

  • -fleading-underscore

    此选项及其对应-fno-leading-underscore强制更改目标文件中C符号的表示方式。 一个用途是帮助链接旧的汇编代码。

    警告: -fleading-underscore开关会导致GCC生成与未使用该开关生成的代码不是二进制兼容的代码。 使用它来符合非默认的应用程序二进制接口。 并非所有的目标都为这个交换机提供完整的支持

另一个更安全的select是明确告诉GCC使用的名称。

5.39控制汇编代码中使用的名称

您可以通过在声明__asm__之后写入asm (或__asm__ )关键字来指定在C函数或variables的汇编代码中使用的名称,如下所示:

  int foo asm ("myfoo") = 2; 

这指定在汇编代码中用于variablesfoo的名称应该是“myfoo ' rather than the usual \``_foo ”。

在通常将下划线加在C函数或variables的名称上的系统上,该function允许您为链接器定义不以下划线开头的名称。

在非静态局部variables中使用此function是没有意义的,因为这些variables没有汇编名称。 如果您试图将该variables放入特定的寄存器,请参阅显式调节variables。 海湾合作委员会目前接受这样的代码警告,但将来可能会更改为发出错误,而不是警告。

在函数定义中不能像这样使用asm ; 但是可以通过在函数定义之前为函数写一个声明来获得相同的效果,并且可以像这样写入asm

  extern func () asm ("FUNC"); func (x, y) int x, y; /* ... */ 

确保您select的汇编程序名称与任何其他汇编程序符号不冲突,由您决定。 另外,您不能使用注册名称; 那会产生完全无效的汇编代码。 GCC还没有能力将静态variables存储在寄存器中。 也许这将被添加。

在你的情况下,

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

应该告诉GCC:“ bar使用asm name” bar “,即使它是一个ccall函数”。

您可以使用C预处理器预处理程序集,并使用macros在Windows上添加缺less的下划线。 首先,您需要将您的程序集文件从bar.s重命名为bar.S(大写“S”)。 这告诉gcc使用cpp来预处理文件。

要添加缺less的下划线,您可以像这样定义一个macros“cdecl”:

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

然后像这样使用它:

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

请注意,Mac OSX也需要前导下划线,所以你可以像这样更新macros的第一行:

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

你可以申报两次吗?

 .global bar .global _bar 

我有一段时间没有写汇编,但.global标识符的行为有点像标签?

ELF目标的编译器默认不添加前导下划线。 编译为ELF格式(在Linux下)时,可以添加-fleading-underscore 。 在makefile中使用一个条件。

参考: http : //opencores.org/openrisc,gnu_toolchain (做一个页面search“保持全球名称不变”)