奇怪的 IDA/反编译器浮点输出

逆向工程 艾达 x86 六线谱 漂浮
2021-06-17 21:14:46

我偶然发现了这个(为了可读性而减少)功能。它做了我以前从未遇到过的奇怪的事情。

// a2 is always 60.0
void some_function(struct_123 *this, float a1, float a2)
{
  float v5; // ST10_4
  float v6; // ST14_4

  this->field_34 = a1;
  v5 = a2 / (0.011 * 1000.0); // 60.0 / 11.0
  v6 = v5 - (double)(signed int)v5;
  this->field_38 = (SLODWORD(v6) >> 31) + (signed int)v5;
}

我对 IEEE 754 小数有一点了解,所以我认为(SLODWORD(v6) >> 31)产生了 v6 的符号位。我怀疑这是某种内联地板/天花板舍入操作,但我对此毫无把握。

编辑:我偶然发现了实际的非内联方法。这里是:

int __cdecl float_sub_466560(float a1)
{
  float v1; // ST04_4

  v1 = (double)(signed int)a1 - a1;
  return (signed int)a1 - (SLODWORD(v1) >> 31);
}

编辑 2:似乎我给出的第一个函数在最后一行添加了 1。那是函数的一部分,而不是浮点运算。我删除了它。

编辑 3:根据要求,这是第二个功能的程序集。我可以提供第一个函数的程序集,但是它非常大,如果没有必要,我真的不想提取它的正确部分。

float_sub_466560 proc near

var_8           = dword ptr -8
var_4           = dword ptr -4
arg_0           = dword ptr  4

                sub     esp, 8          ; stack frame
                fld     [esp+8+arg_0]   ; Load Real
                fist    [esp+8+var_8]   ; Store Integer
                fisubr  [esp+8+var_8]   ; Subtract Integer Reversed
                fstp    [esp+8+var_4]   ; Store Real and Pop
                mov     eax, [esp+8+var_4]
                mov     ecx, [esp+8+var_8]
                sar     eax, 1Fh        ; Shift Arithmetic Right
                sub     ecx, eax        ; Integer Subtraction
                mov     eax, ecx        ; move result to correct return register
                add     esp, 8          ; stack frame
                retn                    ; Return Near from Procedure
float_sub_466560 endp
1个回答

我在你贴的反汇编中添加了一些注释,这样更容易理解。

sub     esp, 8          ; stack frame
fld     [esp+8+arg_0]   ; load value of arg0 to st
fist    [esp+8+var_8]   ; store round(arg0) in var8
fisubr  [esp+8+var_8]   ; subtract arg0 from var8
fstp    [esp+8+var_4]   ; store result in var4
;now var4 = round(arg0) - arg0
mov     eax, [esp+8+var_4] ; eax = round(arg0) - arg0
mov     ecx, [esp+8+var_8] ; ecx = round(arg0)
sar     eax, 1Fh        ; shift eax right by 31; eax contains just a sign bit
sub     ecx, eax        ; if eax was negative, subtract 1, do nothing otherwise
mov     eax, ecx        ; eax = round(arg0) - signbit(round(arg0) - arg0)
add     esp, 8          ; stack frame
retn                    ; Return Near from Procedure

whereround(n)可以是一个函数:

  • 四舍五入到最接近的整数
  • 四舍五入(地板)
  • 四舍五入(ceil)
  • 四舍五入0从而返回 的整数部分n

取决于舍入模式。