简体   繁体   English

GCC 内联汇编 - 调用前将浮点数移动到 XMM0

[英]GCC inline assembly - Move float to XMM0 before call

I'm currently trying to call a generic C function from GCC inline assembly (bad idea, I know, but I'm bored today...).我目前正在尝试从 GCC 内联程序集调用通用 C function (坏主意,我知道,但我今天很无聊)。

My operating system is Mac OS X, 64bits, so the calling convention is System V, meaning arguments 0-6 are passed through the rdi , rsi , rdx , rcx , r8 and r9 registers.我的操作系统是 64 位的 Mac OS X,所以调用约定是 System V,这意味着 arguments 0-6 通过rdirsirdxrcxr8r9寄存器传递。 Other arguments are pushed to the stack.其他 arguments 被推入堆栈。

I know the function signature, so I can guess the return type, and the type of the arguments.我知道 function 签名,所以我可以猜测返回类型,以及 arguments 的类型。 With that information, I can place the arguments in the correct registers.有了这些信息,我可以将 arguments 放在正确的寄存器中。

Everything is working great with integer types, but I got a problem with floating point values. integer 类型一切正常,但浮点值有问题。

Floating point values need to be passed through the xmm0 - xmm7 registers.浮点值需要通过xmm0 - xmm7寄存器传递。

So the problem is basically the following.所以问题基本上如下。 I've got a C variable of type float .我有一个float类型的 C 变量。 I need to move that variable in, let's say, the xmm0 register, using GCC's inline assembly.我需要使用 GCC 的内联汇编将该变量移动到xmm0寄存器中。

Imagine the following code:想象一下下面的代码:

#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;
}

The function foo is called, with 42 as parameter.调用 function foo ,参数为 42。 It works...有用...

Now I try the same with a float argument.现在我尝试使用浮点参数进行相同的操作。 I only have to use movss instead of mov , and it works.我只需要使用movss而不是mov ,它就可以工作。

The problem comes when I try to call both functions:当我尝试调用这两个函数时,问题就来了:

#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;
}

The function taking the float argument receive 0. I don't understand why.采用 float 参数的 function 接收 0。我不明白为什么。 I don't touch the stack, so there's no cleanup to do...我不碰堆栈,所以没有清理工作要做......

If I call the functions directly from C, GCC produces the following:如果我直接从 C 调用函数,GCC 会产生以下结果:

movl    $42, -4(%rbp)
movl    $0x42280000, %eax
movl    %eax, -8(%rbp)
movl    -4(%rbp), %edi
call    _foo
movss   -8(%rbp), %xmm0
call    _bar

I don't get the difference... Any help will be greatly appreciated: )我不明白...任何帮助将不胜感激:)

Have a nice day, all祝大家有个愉快的一天

EDIT编辑

As requested, here's the ASM output when using inline assembly:根据要求,这是使用内联汇编时的 ASM output:

 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;

EDIT2编辑2

As requested, here's the GDB output:根据要求,这是 GDB output:

0x100000e9e <main+4>:   movl   $0x2a,-0x4(%rbp)
0x100000ea5 <main+11>:  mov    $0x42280000,%eax
0x100000eaa <main+16>:  mov    %eax,-0x8(%rbp)
0x100000ead <main+19>:  mov    -0x4(%rbp),%rdi
0x100000eb1 <main+23>:  callq  0x100000e54 <foo>
0x100000eb6 <main+28>:  movss  -0x8(%rbp),%xmm0
0x100000ebb <main+33>:  callq  0x100000e75 <bar>

It took me a while, but I figured this out.我花了一段时间,但我想通了。 In the output using inline assembly, gcc uses negative offsets of rbp to store the values.在使用内联汇编的 output 中,gcc 使用rbp的负偏移量来存储值。 However, since it doesn't know about the function calls in the inline assembly, it doesn't think it calls any functions.但是,由于它不知道内联汇编中的 function 调用,因此它认为它不会调用任何函数。 Therefore, it puts the variables in the red zone and doesn't change rsp to make room for the variables.因此,它将变量放在红色区域中,并且不会更改rsp以为变量腾出空间。 When you call foo, the return address is pushed to the stack, overwriting your stored variables and giving you an incorrect variable.当你调用 foo 时,返回地址被压入堆栈,覆盖你存储的变量并给你一个不正确的变量。

If, at any point in the main function outside of the assembly, you called a function, then gcc would change the stack to preserve the variables.如果在程序集外部的主 function 中的任何一点,您调用了 function,那么 gcc 将更改堆栈以保留变量。 For example, if you add foo(-1);例如,如果您添加foo(-1); to the top of main, it would work.到主要的顶部,它会起作用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM