整数与浮点数比较-汇编码分析
(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)
參考:https://stackoverflow.com/questions/32685576/whats-so-difficult-about-uint64-t-conversion-assembly-from-float
參考:https://www.felixcloutier.com/x86/cvtsi2sd
參考:https://www.felixcloutier.com/x86/cvtsi2ss
參考:https://www.felixcloutier.com/x86/addss
參考:https://www.felixcloutier.com/x86/addsd
整數之間比較我們通常比較好理解,按照4字節比較或8字節比較,無符號與有符號基于比較結果跳轉命令差異,基本就涵蓋了整數之間比較的規律。
但對于整數與浮點數之間呢?是什么樣的情況?
整數要轉成浮點數嗎,還是整數和整數部分比較嗎?還是浮點和浮點比較?
8字節整數呢?和浮點比較時有沒有差異?
當時浮點浮點之間比較又是什么樣子呢?
下面希望進行相關的涉獵解惑。
1. 變量定義
依然先進行變量定義,下面分析時直接使用變量進行分析;
int8_t ch1 = 1, ch2 = -1; uint8_t uch1 = 1, uch2 = -1;int32_t n1 = 1, n2 = -1; uint32_t un1 = 1, un2 = -1;int64_t l1 = 1, l2 = -1; uint64_t ul1 = 1, ul2 = -1;float f1 = 1, f2 = -1; double d1 = 1, d2 = -1;bool b1 = true, b2 = false;2.浮點數之間比較
先來看看浮點數之間的比較,浮點數之間的比較能夠支撐分析與整形類型的比較差異。
float與float比較:
if (f1 > f2){b1 = true; }匯編編碼: movss xmm0,dword ptr [f1] comiss xmm0,dword ptr [f2] jbe main+0AEh (07FF710D7135Eh) mov byte ptr [rsp],1把一個float加載到xmm0;
然后使用comiss來比較xmm與另一個變量;
使用jbe來判定標志位。jump below or equal, 和無符號使用的比較都使用的同一組狀態位跳轉函數。
無符號判斷跳轉
JBE: Jump short if below or equal (CF=1 or ZF=1)
JAE: Jump short if above or equal (CF=0)
// 有符號判斷跳轉
JLE: Jump short if less or equal (ZF=1 or SF<>OF)
JGE: Jump short if greater or equal (SF=OF)
double與double比較
if (d1 > d2){b1 = true; }匯編編碼: movsd xmm0,mmword ptr [d1] comisd xmm0,mmword ptr [d2] jbe main+0C0h (07FF710D71370h) mov byte ptr [rsp],1同float比較類似,先把一個double加載到xmm0,然后同另一個變量比較,同樣使用無符號時的狀態比較jbe。不同的是,加載到xmm0使用movsd,比較使用comisd.
float與double比較
if (f1 > d1){b1 = true; }匯編編碼: cvtss2sd xmm0,dword ptr [f1] comisd xmm0,mmword ptr [d1] jbe main+0D2h (07FF710D71382h) mov byte ptr [rsp],1使用cvtss2sd把float值轉換成double加載到xmm0中;
下來同double比較double一致;
3. 整數與浮點數比較
挑選典型的1字節,4字節,8字節整數,再分別選取有符號與無符號整數,與float和double分別進行比較;
排列組合有 322 = 12中組合關系;
有符號整數與浮點比較
1字節與float比較
注意到ch1首先使用movsx移動到eax,使用cvtsi2ss命令,把eax值轉換到xmm0上;
f1讀取使用dword ptr;
比較命令外comiss;
跳轉函數和無符號一樣,使用的jbe;
4字節與float比較
注意到n1也使用dword ptr加載到xmm0
8字節與float比較
注意到仍然使用的cvtsi2ss命令加載l1數據;
也同樣適用xmm0保存8字節整數轉出數據;
使用qword ptr加載l1到xmm0;
1字節與double比較
注意到使用的cvtsi2d命令加載eax到xmm0;
注意到d1加載適用mmword ptr;
注意到比較函數適用comisd;
4字節與double比較
與1字節差別點在n1直接轉換加載到xmm0
8字節與double比較
與1字節差別點在l1直接轉換加載到xmm0
無符號整數與浮點比較
1字節無符號與float比較
往eax放byte值使用movza;
使用cvtsi2ss放eax值;
比較依然使用comiss進行比較,未使用comisd比較;
4字節無符號與float比較
注意,un1需要放到eax上,使用mov命令放置;
注意,往xmm0上轉換放值使用rax;
8字節無符號與float比較
注意:8字節無符號與float比較很不一樣,里面的命令多了兩個不符合一般規律的 test, jge, addss操作,
test進行邏輯與運算,test rax, rax把與的結果放入比較結果中,其中把符號位設在sf標志位上,后面的jge有符號判斷sf=of;
而當前rax存的關聯值ul1是無符號的,使用jge有符號判斷,相當于判斷 rax最高位是0時,不進行addss操作;rax最高位是1時,進行addss操作;
addss的值經過內存值分析,所加的值float表達的2^64。
整體符合推斷,不過比較好奇的點時,為什么要把8字節的最高位單獨處理這個在最后有探討。
1字節無符號與double比較
使用dword
4字節無符號與double比較
if (un1 > d1){b1 = true; } 匯編代碼: mov eax, dword ptr [un1] cvtsi2sd xmm0, rax comisd xmm0, mmword ptr [d1] mov byte ptr [rsp], 18字節無符號與double比較
與8字節無符號與float比較時一樣,也有一個特殊處理,對于最高位為1時,需要使用addsd把2^64往xmm0上加一下。
unit64_t向float/double轉換研究
關于為什么對于uint64_t向float/double查詢時,需要額外的處理?需要檢查檢查最高位是1時增加2^64?
最重要的一點:在cvtsi2ss/cvtsi2sd的說明中可以看到,這兩個命令所支持的均是有符號數signed。
對于cvtsi2ss/cvtsi2d來說,它把rax上的值當成有符號數,認為符號位在最高位上,剩余63位是值;
所以對于無符號來說,當成有符號數時,如果最高為0,值不變;最高位為1時,成為了負數,需要額外把gap-2^64加上才能得到正確的值。
例如:
一個數最高位是1,設除最高位外值位x,則該數字值=2^63 + x;
作為有符號數時,因為負數是補碼形式,有符號數實際表達的值為:-(2^63-x);
兩者的gap恰好就是2^64。
參考指令說明:
cvtsi2ss:
Converts a signed doubleword integer (or signed quadword integer if operand size is 64 bits) in the “convert-from” source operand to a single-precision floating-point value in the destination operand (first operand).
cvtsi2sd:
Converts a signed doubleword integer (or signed quadword integer if operand size is 64 bits) in the “convert-from” source operand to a double-precision floating-point value in the destination operand.
addss:
Adds the low single-precision floating-point values from the second source operand and the first source operand, and stores the double-precision floating-point result in the destination operand.
addsd:
Adds the low double-precision floating-point values from the second source operand and the first source operand and stores the double-precision floating-point result in the destination operand.
在addss/addsd命令說明中可以看到,兩者中間結果是double-precision雙精度浮點,并把結果存到第一個操作數上。
cvtsi2ss邏輯說明:
IF 64-Bit Mode And OperandSize = 64
THEN
DEST[31:0] ←Convert_Integer_To_Single_Precision_Floating_Point(SRC[63:0]);
ELSE
DEST[31:0] ←Convert_Integer_To_Single_Precision_Floating_Point(SRC[31:0]);
FI;
cvtsi2sd邏輯說明:
IF 64-Bit Mode And OperandSize = 64
THEN
DEST[63:0] ←Convert_Integer_To_Double_Precision_Floating_Point(SRC[63:0]);
ELSE
DEST[63:0] ←Convert_Integer_To_Double_Precision_Floating_Point(SRC[31:0]);
FI;
mov:
Copies the second operand (source operand) to the first operand (destination operand). The source operand can be an immediate value, general-purpose register, segment register, or memory location; the destination register can be a general-purpose register, segment register, or memory location. Both operands must be the same size, which can be a byte, a word, a doubleword, or a quadword.
movzx:
Copies the contents of the source operand (register or memory location) to the destination operand (register) and zero extends the value. The size of the converted value depends on the operand-size attribute.
movsx:
movsxd: Copies the contents of the source operand (register or memory location) to the destination operand (register) and sign extends the value to 16 or 32 bits. The size of the converted value depends on the operand-size attribute.
cmp:
Compares the first source operand with the second source operand and sets the status flags in the EFLAGS register according to the results. The comparison is performed by subtracting the second operand from the first operand and then setting the status flags in the same manner as the SUB instruction. When an immediate value is used as an operand, it is sign-extended to the length of the first operand.
(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)
總結
以上是生活随笔為你收集整理的整数与浮点数比较-汇编码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mse python_python3 M
- 下一篇: 麦比乌斯圈