我正在嘗試對一些最初用 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])
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/408732.html
標籤:
上一篇:在64位masm中列印hello
下一篇:浮點數的乘法和加法
