调用x64浮点函数的约定不匹配

时间:2014-04-05 23:48:16

标签: c++ assembly 64-bit calling-convention tcc

我有一个奇怪的错误。我有一个由一个编译器编译的模块(在本例中为msvc),它调用从单独编译器(TCC)编译的另一个模块加载的代码。

tcc代码提供了一个回调函数,对于这两个模块定义如下:

typedef float( * ScaleFunc)(float value, float _min, float _max);

MSVC代码调用如下代码:

    finalValue = extScale(val, _min, _max);
000007FEECAFCF52  mov         rax,qword ptr [this]  
000007FEECAFCF5A  movss       xmm2,dword ptr [rax+0D0h]  
000007FEECAFCF62  mov         rax,qword ptr [this]  
000007FEECAFCF6A  movss       xmm1,dword ptr [rax+0CCh]  
000007FEECAFCF72  movss       xmm0,dword ptr [val]  
000007FEECAFCF78  mov         rax,qword ptr [this]  
000007FEECAFCF80  call        qword ptr [rax+0B8h]  
000007FEECAFCF86  movss       dword ptr [finalValue],xmm0 

并且TCC编译的函数如下所示:

    float linear_scale(float value, float _min, float _max) 
    { 
        return value * (_max - _min) + _min;
    }
0000000000503DC4  push        rbp  
0000000000503DC5  mov         rbp,rsp  
0000000000503DC8  sub         rsp,0  
0000000000503DCF  mov         qword ptr [rbp+10h],rcx  
0000000000503DD3  mov         qword ptr [rbp+18h],rdx  
0000000000503DD7  mov         qword ptr [rbp+20h],r8  
0000000000503DDB  movd        xmm0,dword ptr [rbp+20h]  
0000000000503DE0  subss       xmm0,dword ptr [rbp+18h]  
0000000000503DE5  movq        xmm1,xmm0  
0000000000503DE9  movd        xmm0,dword ptr [rbp+10h]  
0000000000503DEE  mulss       xmm0,xmm1  
0000000000503DF2  addss       xmm0,dword ptr [rbp+18h]  
0000000000503DF7  jmp         0000000000503DFC  
0000000000503DFC  leave  
0000000000503DFD  ret  

似乎TCC期望在整数寄存器r6到r8 中的参数,而msvc将它们放在sse寄存器中。我认为x64(在Windows上)定义了一个常见的调用约定?究竟是什么在这里,我如何在两个平台上强制执行相同的模型?

相同的代码在32位模式下正常工作。奇怪的是,在OSX上(其他代码由llvm编译),它可以在两种模式下工作(32位和64位)。我会看看我是否可以从那里取一些装配件。

----编辑----

我创建了一个有效的解决方案。然而,毫无疑问,这是我曾经做过的最脏的黑客攻击(可疑的内联汇编,不幸的是它在msvc 64位上不可用:)。

// passes first three floating point arguments in r6 to r8
template<typename sseType>
    sseType TCCAssemblyHelper(ScaleFunc cb, sseType val, sseType _min, sseType _max)
    {
        sseType xmm0(val), xmm1(_min), xmm2(_max);
        long long rcx, rdx, r8;
        rcx = *(long long*)&xmm0;
        rdx = *(long long*)&xmm1;
        r8 = *(long long*)&xmm2;

        typedef float(*interMedFunc)(long long rcx, long long rdx, long long r8);

        interMedFunc helperFunc = reinterpret_cast<interMedFunc>(cb);
        return helperFunc(rcx, rdx, r8);
    }

0 个答案:

没有答案