在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;
这指定在汇编代码中用于variables
foo
的名称应该是“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“保持全球名称不变”)