更改ARM上的本机代码调用约定(VS2012)

时间:2014-01-24 10:36:15

标签: assembly windows-phone-8 arm

我正在使用Windows Phone 8上的一个项目,我正在通过指针调用静态函数,但没有参数的类型(我有参数的数量和一个以int或float作为参数的函数类型)

我已经检查了这个帖子What is the Windows RT on ARM native code calling convention?

我也查看了程序集,它似乎从int处理不同的浮点数(在S0中传递的浮点数)。

我的问题是,有没有办法强迫某些功能(甚至所有功能)被称为旧时尚?

1 个答案:

答案 0 :(得分:0)

好的,我打算通过假装你问底层的问题来澄清事情:

  

当我只有一个通用的(void *)(float)指针时,如何调用(void *)(int)函数?

直接跳到询问如何更改调用约定听起来如下:

  

如何让一个实现的未定义行为表现得像另一个实现的未定义行为,因为我编写了大量依赖于此并且不想修复它的代码?


首先,让我们看看C标准说的是什么......

  

如果转换的指针用于调用类型与指向类型不兼容的函数,则行为未定义。

是的,有问题。悲伤的脸:(

但是等一下,上一句话说的是什么?

  

指向一种类型的函数的指针可以转换为指向另一种函数的指针   打字再回来;结果应该等于原始指针

万岁,我们可以用一种定义明确的方式来做,而不需要求助于垫片和装配黑客,只需在我们打电话时转换回正确的功能签名即可!

总之; 强制转换函数指针,而不是参数,并且它不仅会起作用,而且正确 。由于你必须知道你正在调用的函数的真实签名(否则你无法传递适当的参数),你总是可以进行正确的强制转换,并且中间指针类型变为非问题。

这是一个演示:

#include <stdio.h>

void fn(float x){
    printf("%.1f\n", x);
}

int main(void) {
    float f = 27.3;
    void (*fptr)(float) = fn;
    void (*iptr)(int) = fn;     /* LA LA COMPILER WARNING I CAN'T HEAR YOU */

    printf("expected:\t");
    fptr(f);
    printf("casting arg:\t");
    iptr(*(int *)&f);           /* double-undefined behaviour */
    printf("casting iptr:\t");
    ((void(*)(float))iptr)(f);
}

请注意,*(int *)&f本身是未定义的,但在这种情况下(VS2013),“预期”代码(在没有转换的情况下用作int的float)确实会在两个版本中生成。嘿,这是一种有效的未定义行为形式(就像其他任何东西 ......)

输出:

expected:       27.3
casting arg:    27.3
casting iptr:   27.3
Press any key to continue . . .

咦?何必?这两种方法都“有效”。我们来试试x64构建......

expected:       27.3
casting arg:    0.0
casting iptr:   27.3
Press any key to continue . . .

阿。它就是。事实上,如果你在其他3个当前支持的Windows平台上编写原始代码,你就不会遇到这个问题,因为它不会起作用 - x86-64,IA-64和ARM都使用基于寄存器的调用约定,浮点数和整数分别处理,而x86是基于堆栈的不合时宜。

或者,如果你真的真的想要一个可移植的尝试来利用未定义的行为,请尝试重写所有函数以在真实参数之前加载虚拟整数和浮点数,并且之后类似的负荷和浮子负荷,以确保中间的那些在不考虑评估顺序的情况下溢出到堆中。是的,那将是疯狂 ......