【发布时间】:2013-08-10 21:50:31
【问题描述】:
我有一个汇编例程,它以通用方式调用已知使用stdcall 约定并返回float 的函数。编组框架正在使用此函数将 stdcall 函数公开给脚本语言。
背景
这是在 MinGW 4.3、Win32 上编译的使用 GNU 内联汇编的函数:
inline uint64_t stdcall_invoke_return_float(int args_size_bytes,
const char * args_ptr,
void * func_ptr)
{
uint64_t result;
assert(
0 == args_size_bytes % 4
|| !"argument size must be a multiple of 4 bytes");
#if defined(__GNUC__)
asm
(
/* INPUT PARAMS: %0 is the address where top of FP stack to be stored
* %1 is the number of BYTES to push onto the stack, */
/* and during the copy loop it is the address of */
/* the next word to push */
/* %2 is the base address of the array */
/* %3 is the address of the function to call */
"testl %1, %1 # If zero argument bytes given, skip \n\t"
"je 2f # right to the function call. \n\t"
"addl %2, %1\n"
"1:\n\t"
"subl $4, %1 # Push arguments onto the stack in \n\t"
"pushl (%1) # reverse order. Keep looping while \n\t"
"cmp %2, %1 # addr to push (%1) > base addr (%2) \n\t"
"jg 1b # Callee cleans up b/c __stdcall. \n"
"2:\n\t"
"call * %3 # Callee will leave result in ST0 \n\t"
"fsts %0 # Copy 32-bit float from ST0->result"
: "=m" (result)
: "r" (args_size_bytes), "r" (args_ptr), "mr" (func_ptr)
: "%eax", "%edx", "%ecx" /* eax, ecx, edx are caller-save */, "cc"
);
#else
#pragma error "Replacement for inline assembler required"
#endif
return result;
}
这只是让编写测试用例更容易的一点胶水:
template<typename FuncPtr, typename ArgType>
float float_invoke(FuncPtr f, int nargs, ArgType * args)
{
uint64_t result = stdcall_invoke_return_float(
nargs * sizeof(ArgType),
reinterpret_cast<const char *>(args),
reinterpret_cast<void *>(f)
);
return *reinterpret_cast<float *>(&result);
}
现在我有一些调用这个函数的测试用例:
__stdcall float TestReturn1_0Float()
{ return 1.0f; }
__stdcall float TestFloat(float a)
{ return a; }
__stdcall float TestSum2Floats(float a, float b)
{ return a + b; }
static const float args[2] = { 10.0f, -1.0f };
assert_equals(1.0f, float_invoke(TestReturn1_0Float, 0, args)); // test 1
assert_equals(10.0f, float_invoke(TestFloat, 1, args)); // test 2
assert_equals(-1.0f, float_invoke(TestFloat, 1, args + 1)); // test 3
assert_equals(9.0f, float_invoke(TestSumTwoFloats, 2, args)); // test 4
问题
随机地,测试 3 给了我垃圾输出而不是返回 -1.0。
我想知道我是不是
- 未能保留
call指令之前的某些状态? - 用
fsts指令弄乱了某些状态? - 从根本上误解了如何从返回
float的stdcall函数中获取float值????
非常感谢所有帮助。
【问题讨论】:
标签: c++ windows x86 inline-assembly stdcall