在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而不是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调用约定来引用一个函数,并且应这样处理?还有其他想法吗?


撒科打诨
浏览 512回答 3
3回答

跃然一笑

您可以使用C预处理器对程序集进行预处理,并使用宏在Windows上添加缺少的下划线。首先,您需要将程序集文件从bar.s重命名为bar.S(大写“ S”)。这告诉gcc使用cpp预处理文件。要添加缺少的下划线,您可以定义一个宏“ 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还需要前划线,因此您可以像这样更新宏的第一行:#if defined(__WIN32__) || defined(__APPLE__)
打开App,查看更多内容
随时随地看视频慕课网APP