0%

[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 補數的運算,將一個數取 2 補數之後放回原本的目的地,等同於一個數被 0 減掉再放回暫存器(即 eax = 0 - eax),目的地可以是暫存器也可以是記憶體位址。它原文下面還有說明,但到這就能夠來說明想要表達的程式碼了。再來看看它的流程 Pseudo code

1
2
3
4
5
6
Operation
IF DEST = 0
 THEN CF ← 0;
 ELSE CF ← 1;
FI;
DEST ← [– (DEST)]

短短幾行 Pseudo code,代表了無數的文字,相信一看就懂它想說甚麼。在簡短的 NEG 描述與操作流程可以知道若 DEST 不為 0,進位旗標 (CF) 會被設置為 1,這是因為 0 減非 0 的數需要補位。

應用方式

這時候假設你的程式中有個副程式如下

1
2
3
4
5
6
BOOL NEGtest(TCHAR *str1, TCHAR *str2) {
if(lstrcmp(str1, str2) == 0)
return true;
else
return false;
}

不論是組合語言或高階語言,有很多不同編寫方式來完成相同的事情,然而這個函數內的 if else 所對應到的組合語言可能為

1
2
3
4
5
6
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

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 = 0return false

結論

這個執行結果,與高階語言的效果是一樣的。當然,也可以用 cmpjmp等指令來完成同一件事,但不覺得程式拐個彎寫得簡單優雅,會有更有成就感嗎?呵呵!

很高興能在這裡幫助到您,歡迎登入 Liker 為我鼓掌 5 次,或者成為我的讚賞公民,鼓勵我繼續創造優質文章。
以最優質的內容回應您的鼓勵