У меня странная ошибка. У меня есть один модуль, скомпилированный одним компилятором (в данном случае 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 (на окнах) определяет одно общее соглашение о вызовах? Что именно здесь происходит, и как я могу применить одну и ту же модель на обеих платформах?
Этот же код работает правильно в 32-битном режиме. Как ни странно, в OSX (где другой код компилируется с помощью llvm) он работает в обоих режимах (32 и 64-битный). Я посмотрю, смогу ли я получить какое-то собрание оттуда позже.
—- редактировать —-
Я создал рабочее решение. Тем не менее, это, без сомнения, самый грязный хак, который я когда-либо делал (панель сомнительной встроенной сборки, к сожалению, она недоступна на 64-битном MSVC :)).
// 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);
}
Задача ещё не решена.
Других решений пока нет …