拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 这个反编译的f2xm1/fscale序列是什么意思?

这个反编译的f2xm1/fscale序列是什么意思?

白鹭 - 2022-02-10 2023 0 0

我正在尝试对一些最初用 C/C 撰写的反编译代码进行逆向工程,即我怀疑下面与 FPU 相关的代码序列可能源自一些简单的 C 代码“双重”处理,在生成时看起来更复杂汇编代码。在此之前,已经执行了一些浮点乘法,结果在 ST0 中(对应于 d1)。我已经阅读了有关底层 FPU 操作在技术上做什么的档案,但相应代码序列的意图对我来说仍然不是很明显。

  d1 = (float10)1.442695040888963 *(float10)0.6931471805599453 * (float10)DOUBLE_00430088 * (float10)param_1[0x58];
  d2 = ROUND(d1);
  d1 = (float10)f2xm1(d1 - d2);
  d1 = (float10)fscale((float10)1   d1,d2);

对原始 d1 结果执行的预期更改是什么,即 C 代码对原始 d1 “double”做了什么?

PS:在实际的 x86 代码下方(以防 Ghidra 在反编译时误解了某些内容):


                     * Push ST(i) onto the FPU register stack, i.e.               *
                     * duplicate ST0                                              *
                     **************************************************************
0040aeef d9 c0           FLD        ST0
                     **************************************************************
                     * Rounds the source value in the ST(0) register              *
                     * to the nearest integral value, depending on                *
                     * the current rounding mode (lets suppose some               *
                     * "floor" mode was used?)                                    *
                     **************************************************************
0040aef1 d9 fc           FRNDINT
                     **************************************************************
                     * Exchange the contents of ST(0) and ST(1).                  *
                     **************************************************************
0040aef3 d9 c9           FXCH
                     **************************************************************
                     * get fractional part?                                       *
                     **************************************************************
0040aef5 d8 e1           FSUB       d2[0],d1[0]
                     **************************************************************
                     * Computes the exponential value of 2 to the power           *
                     * of the source operand minus 1.                             *
                     **************************************************************
0040aef7 d9 f0           F2XM1
                     **************************************************************
                     * Push  1.0 onto the FPU register stack.                     *
                     **************************************************************
0040aef9 d9 e8           FLD1
                     **************************************************************
                     * Add ST(0) to ST(1), store result in ST(1),                 *
                     * and pop the register stack.                                *
                     **************************************************************
0040aefb de c1           FADDP
                     **************************************************************
                     * Scale ST(0) by ST(1).  This instruction provides           *
                     * rapid multiplication or division by integral               *
                     * powers of 2.                                               *
                     **************************************************************
0040aefd d9 fd           FSCALE
                     **************************************************************
                     * The FSTP instruction copies the value in the ST(0)         *
                     * register to the destination operand and then pops          *
                     * the register stack.                                        *
                     **************************************************************
0040aeff dd d9           FSTP       d1[0]

uj5u.com热心网友回复:

如果没有完整的背景关系,很难完全确定,但这里的计算似乎是对exp(x)via的幼稚计算F2XM1请注意,F2XM1在早期的 x87 实作中,自变量 to被限制为 [-0.5, 0.5],在后来的实作中被限制为 [-1, 1]。计算自变量的整数部分FRNDINT并从自变量中减去它会产生一个适合于使用的小数部分F2XM1该代码可能假定默认舍入模式,舍入到最近或偶数是有效的。

下面是一个简单exp(x)计算的整个带注释的指令序列,被编程为尽可能接近地匹配反汇编代码。我使用了英特尔 C/C 编译器的行内汇编工具,因此它使用英特尔语法。在评论中,插入符号^表示幂。这个程序的输出是:

x=2.5000000000000000e 000 exp(x)=1.2182493960703475e 001 lib=1.2182493960703473e 001
#include <stdio.h>
#include <math.h>

int main (void)
{
    double r, x = 2.5; 

    __asm fld qword ptr[x]; // x
    __asm fldl2e;           // log2(e)=1.442695040888963, x
    __asm fmulp st(1), st;  // x*log2(e)
    __asm fld st(0);        // x*log2(e), x*log2(e)
    __asm frndint;          // rint(x*log2(e)), x*log2(e)
    __asm fxch st(1);       // x*log2(e), rint(x*log2(e))
    __asm fsub st, st(1);   // frac(x*log2(e)), rint(x*log2(e))
    __asm f2xm1;            // 2^frac(x*log2(e))-1, rint(x*log2(e))
    __asm fld1;             // 1, 2^frac(x*log2(e))-1, rint(x*log2(e))
    __asm faddp st(1),st;   // 2^frac(x*log2(e)), rint(x*log2(e))
    __asm fscale;           // exp(x)=2^frac(x*log2(e))*2^rint(x*log2(e)), rint(x*log2(e)
    __asm fstp qword ptr[r];// rint(x*log2(e)
    __asm fstp st(0);       // <empty>
    
    printf ("x=#.16e exp(x)=#.16e lib=#.16e\n", x, r, exp(x));
    return 0;
}

uj5u.com热心网友回复:

似乎它是 pow(x,y) 实作的一些变体(请参阅我自己如何撰写幂函式?)。Ghidra 只是在反编译的代码视图中把它弄得一团糟。

在除错器中跟踪结果,执行的功能确实是:

pow((float10)DOUBLE_00430088, (float10)param_1[0x58])

标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *