[asm]NEG的運作與應用

NEG的在程式中不常用到,但在高階語言寫完,用Debug介面的時候有機會看到。
它的運作影響了旗標,進而用來當作實現BOOL function回傳的一個選項。
就來看看NEG是如何運作,以及對應到的高階語言是如何寫的。


想知道一個程式碼如何運作,不外乎就是兩種方法:
  1. 直接編譯/組譯然後執行,觀察結果(暫存器輸出、旗標設置等等),在此不強調
  2. 最基本的就是看技術文件,若參數很多或者回傳複雜無法直接觀察結果推斷的時候,相關文件最有用了。例如Windows的API可以去MSDN上找函數介紹,而組合語言的語法能夠找所使用CPU的廠商要文檔,AMD與Intel的組合語言可能有差異,所以若是使用Intel的就請找Intel的指令手冊來參考。
我的電腦為Intel CPU,因此上網找了一下指令手冊(Intel® 64 and IA-32 Architectures Software Developer’s Manual),內文對neg指令的描述摘要如下
NEG—Two's Complement Negation  
Description
Replaces the value of operand (the destination operand) with its two's complement. (This operation is equivalent to subtracting the operand from 0.) The destination operand is located in a general-purpose register or a memory location.
簡單說明一下,NEG是一個2補數的運算,將一個數取二補數之後放回原本的目的,等同於一個數被0減掉再放回暫存器(作者注:eax = 0 - eax ),目的可以是暫存器也可以是記憶體位址。它接下去還有說明,但到這就能夠來說明想要表達的程式碼了。再來看看它的簡易流程
Operation
IF DEST = 0
Operation
 THEN CF ← 0;
 ELSE CF ← 1;
FI;
DEST ← [– (DEST)]
這短短幾行指令,代表了無數的文字,相信了解程式的一看就懂它想說甚麼。在這NEG的簡短描述之中與操作流程可以知道DEST若不為0,進位旗標(CF)會被設置為1,這是因為0減非0的數需要補位。
這時候假設你的程式中有個副程式如下
BOOL NEGtest(TCHAR *str1, TCHAR *str2) {
  if(lstrcmp(str1, str2) == 0)
    return true;
  else
    return false;
}
不論是組合語言或高階語言,有很多不同編寫方式來完成相同的事情,然而這個函數內的if else所對應到的組合語言可能為
push ebp        //str2的位址
push eax        //str1的位址
call [00404004] //呼叫 lstrcmp 函數
neg eax      //API函數回傳值都放在eax暫存器裡,因此對比較後的結果作NEG運算
sbb eax, eax //eax = eax - eax - CY
inc eax      //eax = eax + 1
  1. push ebp //str2的位址
  2. push eax //str1的位址
  3. call [00404004] //呼叫 lstrcmp 函數
  4. neg eax //API函數回傳值都放在eax暫存器裡,因此對比較後的結果作NEG運算
  5. sbb eax, eax    //eax = eax - eax - CY
  6. inc eax            //eax = eax + 1
lstrcmp需要兩個參數,因此先壓入棧再調用(call)其函數,因為它的回傳值放在eax裡面,若兩個字串相同,則eax = 0;反之eax = 非0。此時分為兩個情況來討論:
  1. str1 == str2
    • 在第三行指令執行完時 eax 值為 0,neg eax 之後 eax 還是 0 且 CY 為 0,因此到程式結束時 eax 為 1,即 return true
  2. str1 !=  str2
    • 在第三行指令執行完時eax值為非0,neg eax之後eax還是非0且CY為1,因此第五行的執行結果為 eax = eax - eax -CY = 0xFFFFFFFF (32位元的話),eax = eax + 1 = 0 即 return false
這個執行結果,與高階語言的效果是一樣的。當然,也可以用 cmp, jmp等指令來完成同一件事,但不覺得程式拐個彎寫得簡單優雅,會有更有成就感嗎?呵呵!

留言

這個網誌中的熱門文章

[Hyper-V] 讓 Windows 可以吃到超過 16TB 的硬碟!