我有一块调用在组件中定义的函数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调用约定,并应作为错位这样的功能? 任何其他的想法?
一种选择,虽然危险,是说服GCC省略ABI要求的前导下划线。
另外,更安全的选择,是明确地告诉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功能”。
您可以使用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__)
你可以声明它两次?
.global bar
.global _bar
我没有编写汇编一段时间,但在全球的互动圈标识只是行为有点像一个标签吗?
为ELF目标编译器默认不添加前导下划线。 您可以添加-fleading-underscore
编译成ELF格式(在Linux下)时。 使用条件在makefile。
参考: http://opencores.org/openrisc,gnu_toolchain (做一个对网页搜索“离开的全局名称不变”)