gpt4 book ai didi

c - 在 Win32 上使用 GCC 向程序集符号添加前导下划线?

转载 作者:太空狗 更新时间:2023-10-29 16:23:03 24 4
gpt4 key购买 nike

我有一段 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’ 的 undefined reference ”。事实证明,这是因为在 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 调用约定的函数并且应该被这样处理?还有其他想法吗?

最佳答案

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

  • -fleading-underscore

    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.

    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 要使用的名称。

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;

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

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.

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.

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

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 函数”。

关于c - 在 Win32 上使用 GCC 向程序集符号添加前导下划线?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1034852/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com