在 Win32 上使用 GCC 向程序集符号添加前导下划线? [英] Adding leading underscores to assembly symbols with GCC on Win32?

查看:31
本文介绍了在 Win32 上使用 GCC 向程序集符号添加前导下划线?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一段 C 代码,它调用在汇编中定义的函数.例如,假设 foo.c 包含:

I have a piece of C code that calls a function defined in assembly. By way of example, let's say foo.c contains:

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

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

And bar.s contains the implementation of bar() in x86 assembly:

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

在 Linux 上,我可以使用 GCC 轻松编译和链接这些源代码,如下所示:

On Linux I can easily compile and link these sources with GCC as follows:

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

在带有 MinGW 的 Windows 上,这会失败并显示未定义对‘bar’的引用"的错误.事实证明,这是因为在 Windows 上,所有具有 C 调用约定的函数标识符都带有下划线前缀,但由于bar"是在程序集中定义的,因此它没有获得此前缀并且链接失败.(因此错误消息实际上是在抱怨缺少符号 _bar,而不是 bar.)

On Windows with MinGW this fails with an error of "undefined reference to `bar'". It turns out the cause for this is that on Windows all identifiers of functions with C calling convention are prefixed with an underscore, but since "bar" is defined in assembly, it doesn't get this prefix and linking fails. (So the error message is actually complaining about missing the symbol _bar, not 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 上).

The question now is: how can I resolve this nicely? If I were writing for Windows only, I could just add the underscore to the identifier in bar.s, but then the code breaks on Linux. I have looked at gcc's -fleading-underscore and -fno-leading-underscore options but neither appears to do anything (at least on Windows).

我现在看到的唯一替代方法是将汇编文件通过 C 预处理器并在定义了 WIN32 的情况下手动重新定义所有声明的符号,但这也不是很漂亮.

The only alternative I see now is passing the assembly file through the C preprocessor and redefining all the declared symbols manually if WIN32 is defined, but that's not very pretty either.

有没有人有一个干净的解决方案?也许是我监督的编译器选项?也许 GNU 汇编器支持一种方法来具体说明这个特定符号是指使用 C 调用约定的函数,并且应该像这样修改?还有其他想法吗?

Does anyone have a clean solution for this? Perhaps a compiler option I oversaw? Maybe the GNU assembler supports a way to specific that this particular symbol refers to a function using C calling convention and should be mangled as such? Any other ideas?

推荐答案

一种选择,虽然危险,但说服 GCC 省略 ABI 要求的前导下划线.

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

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

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.

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

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.

另一个更安全的选择是明确告诉 GCC 要使用的名称.

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

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

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;

这指定在汇编代码中用于变量 foo 的名称应该是``myfoo' 而不是通常的 ``_foo'.

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

在通常在 C 函数或变量的名称前面加上下划线的系统上,此功能允许您为不以下划线开头的链接器定义名称.

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.

将此功能与非静态局部变量一起使用是没有意义的,因为此类变量没有汇编程序名称.如果您尝试将变量放在特定寄存器中,请参阅 显式 Reg Vars.GCC 目前接受带有警告的此类代码,但将来可能会更改为发出错误而不是警告.

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.

你不能在函数定义中以这种方式使用asm;但是您可以通过在函数定义之前为函数编写声明并将 asm 放在那里来获得相同的效果,如下所示:

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;
 /* ... */

确保您选择的汇编程序名称不与任何其他汇编程序符号冲突取决于您.此外,您不得使用注册名称;这将产生完全无效的汇编代码.GCC 尚不具备在寄存器中存储静态变量的能力.也许会添加.

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.

就你而言,

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

应该告诉 GCC bar 使用 asm 名称 ``bar`',即使它是一个 ccall 函数".

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

这篇关于在 Win32 上使用 GCC 向程序集符号添加前导下划线?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆