GCC内联汇编 - 在调用之前将float移动到XMM0

时间:2011-05-02 17:21:36

标签: c gcc assembly sse

我目前正试图从GCC内联汇编中调用一个通用的C函数(糟糕的是,我知道,但我今天很无聊......)。

我的操作系统是Mac OS X,64位,因此调用约定是System V,这意味着参数0-6通过rdirsirdx,{{ 1}},rcxr8个寄存器。其他参数被推送到堆栈。

我知道函数签名,所以我可以猜测返回类型和参数的类型。 有了这些信息,我可以将参数放在正确的寄存器中。

使用整数类型一切都很好,但我遇到浮点值问题。

浮点值需要通过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;

1 个答案:

答案 0 :(得分:7)

我花了一段时间,但我想出来了。在使用内联汇编的输出中,gcc使用rbp的负偏移量来存储值。但是,由于它不知道内联汇编中的函数调用,因此它并不认为它调用任何函数。因此,它将变量放在红色区域中,并且不会更改rsp以为变量腾出空间。当你调用foo时,返回地址被推送到堆栈,覆盖你存储的变量并给你一个不正确的变量。

如果在程序集外部的main函数中的任何一点调用了一个函数,那么gcc会更改堆栈以保留变量。例如,如果您将foo(-1);添加到main的顶部,则可以正常工作。