我有一段 C 代码调用程序集中定义的函数。例如,假设 foo.c 包含:
int bar(int x); /* returns 2x */
int main(int argc, char *argv[]) { return bar(7); }
bar.s 包含了 bar() 在 x86 程序集中的实现:
.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,而不是 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
选项,但似乎都没有做任何事情(至少在 Windows 上)。
我现在看到的唯一选择是通过 C 预处理器传递程序集文件,如果定义了 WIN32,则手动重新定义所有声明的符号,但这也不是很漂亮。
有没有人有一个干净的解决方案?也许是我监督的编译器选项?也许 GNU 汇编器支持一种方法来指定这个特定的符号是指使用 C 调用约定的函数并且应该像这样被修改?还有其他想法吗?