我目前正试图从GCC内联汇编中调用一个通用的C函数(糟糕的是,我知道,但我今天很无聊......)。
我的操作系统是Mac OS X,64位,因此调用约定是System V,这意味着参数0-6通过rdi
,rsi
,rdx
,{{ 1}},rcx
和r8
个寄存器。其他参数被推送到堆栈。
我知道函数签名,所以我可以猜测返回类型和参数的类型。 有了这些信息,我可以将参数放在正确的寄存器中。
使用整数类型一切都很好,但我遇到浮点值问题。
浮点值需要通过r9
- xmm0
寄存器传递。
所以问题基本上如下。我有一个xmm7
类型的C变量。我需要使用GCC的内联汇编将该变量移入float
寄存器。
想象一下以下代码:
xmm0
调用函数#include <stdio.h>
void foo( int x )
{
printf( "X: %i\n", x );
}
int main( void )
{
int x = 42;
__asm__
(
"mov %[x], %%rdi;"
"call _foo;"
:
: [ x ] "m" ( x )
);
return 0;
}
,参数为42。它有效......
现在我尝试使用float参数。我只需使用foo
代替movss
,它就可以了。
当我尝试调用这两个函数时出现问题:
mov
使用float参数的函数接收0.我不明白为什么。 我没有碰到堆栈,所以没有清理工作......
如果我直接从C调用函数,GCC会生成以下内容:
#include <stdio.h>
void foo( int a )
{
printf( "A: %i\n", a );
}
void bar( float b )
{
printf( "B: %f\n", b );
}
int main( void )
{
int a = 42;
float b = 42;
__asm__
(
"mov %[a], %%rdi;"
"call _foo;"
"movss %[b], %%xmm0;"
"call _bar;"
:
: [ a ] "m" ( a ),
[ b ] "m" ( b )
);
return 0;
}
我没有区别......任何帮助将不胜感激:)
祝你有个愉快的一天
修改
根据要求,这是使用内联汇编时的ASM输出:
movl $42, -4(%rbp)
movl $0x42280000, %eax
movl %eax, -8(%rbp)
movl -4(%rbp), %edi
call _foo
movss -8(%rbp), %xmm0
call _bar
EDIT2
根据要求,这是GDB输出:
movl $42, -4(%rbp)
movl $0x42280000, %eax
movl %eax, -8(%rbp)
mov -4(%rbp), %rdi;
call _foo;
movl -8(%rbp), %eax;
movl %eax, -4(%rbp);
movss -4(%rbp), %xmm0;
call _bar;
答案 0 :(得分:7)
我花了一段时间,但我想出来了。在使用内联汇编的输出中,gcc使用rbp
的负偏移量来存储值。但是,由于它不知道内联汇编中的函数调用,因此它并不认为它调用任何函数。因此,它将变量放在红色区域中,并且不会更改rsp
以为变量腾出空间。当你调用foo时,返回地址被推送到堆栈,覆盖你存储的变量并给你一个不正确的变量。
如果在程序集外部的main函数中的任何一点调用了一个函数,那么gcc会更改堆栈以保留变量。例如,如果您将foo(-1);
添加到main的顶部,则可以正常工作。