添加下划线开头组装符号与在Win32 GCC?添加下划线开头组装符号与在Win32 GCC?(Add

2019-05-13 16:25发布

我有一块调用在组件中定义的函数C代码。 举例来说,假设foo.c的包含:

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

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

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

在Linux上,我可以很容易地编译和如下与GCC链接这些来源:

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

在Windows上使用MinGW这个失败的“未定义的参考`栏'”错误。 事实证明,这样做的原因是,在Windows与C调用约定函数的所有标识符以下划线前缀,但由于“栏中的”组装的定义,它并没有得到这个前缀和连接失败。 (因此,该错误信息实际上是在抱怨缺少符号_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调用约定,并应作为错位这样的功能? 任何其他的想法?

Answer 1:

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

  • -fleading-underscore

    此选项及其对应, -fno-leading-underscore ,强行变动c符号对象文件中的表示方式。 一个用途是帮助传统的汇编代码的链接。

    警告: -fleading-underscore开关使GCC来生成代码为不与没有这种开关生成的代码二进制兼容的。 用它符合非默认应用程序二进制接口。 并非所有的目标提供了该交换机全面支持。

另外,更安全的选择,是明确地告诉GCC使用的名称。

5.39控制名称中使用的汇编代码

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

  int foo asm ("myfoo") = 2; 

这指定了要使用的名称为变量foo在汇编代码应该``myfoo ' rather than the usual \``_foo ”。

在其中一个下划线通常是预先考虑C函数或变量的名称系统,该功能允许你为不以下划线开头的链接定义名称。

它没有意义的,使用此功能与非静态局部变量,因为这些变量没有汇编程序的名字。 如果你试图把变量在一个特定的寄存器,见显式注册瓦尔 。 GCC目前接受这样的代码有警告,但可能会被改为发出一个错误,而不是警告,在未来的。

不能使用asm以这种方式在一个函数的定义 ; 但你可以通过它的定义之前写的函数的声明,并把得到相同的效果asm那里,就像这样:

  extern func () asm ("FUNC"); func (x, y) int x, y; /* ... */ 

它是由你来确保你选择的汇编程序名称不与任何其他汇编符号冲突。 此外,您不能使用寄存器名; 那会产生完全无效的汇编代码。 GCC不作为尚未有在寄存器中存储静态变量的能力。 也许这将被添加。

根据你的情况,

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

应该告诉GCC说:“ bar使用ASM名``bar`”,即使它是一个ccall功能”。



Answer 2:

您可以使用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__)


Answer 3:

你可以声明它两次?

.global bar
.global _bar

我没有编写汇编一段时间,但在全球的互动圈标识只是行为有点像一个标签吗?



Answer 4:

为ELF目标编译器默认不添加前导下划线。 您可以添加-fleading-underscore编译成ELF格式(在Linux下)时。 使用条件在makefile。

参考: http://opencores.org/openrisc,gnu_toolchain (做一个对网页搜索“离开的全局名称不变”)



文章来源: Adding leading underscores to assembly symbols with GCC on Win32?