2008年2月15日 星期五

PC Assembly Language 學習筆記(6) - Bit Operations

Shift Operations

bit shift 分為三種,分別是 logical shift(用於 unsigned integer)、arithmetic shift(用於 signed integer) 以及 rotate shift

Logical Shift 所用的指令為 SHR(向右位移) 與 SHL(向左位移),位移的最後一個 bit 會存於 carry flag 中。

Arithmetic Shift 所用的指令為 SALSAR,專門用來處理 signed integer。

【註】Logical Shift 與 Arithmetic Shift 常用於乘二與除二的計算上,速度比 MUL 和 DIV 快上許多!

Rotate Shift 則是將所有 bit 的集合視為一個環狀佇列進行位移,所用的指令為 ROLRORRCL(carry flag 也算佇列中一員)、RCR(carry flag 也算佇列中一員)。

三種 bit shift 的語法都相同,將要位移的資料搬到 register 後,使用類似下方的指令:
# 將 AX register 中的資料向右位移 1 的 bit
shr ax, 1


Boolean Bitwise Operations

最常用的 boolean operation 有 ANDORNOTXOR 四種,在 assembly 中指令也是相同的名稱,使用方式就是將要處理的資料搬入 register 中,再跟另外一個數值或 register 進行 boolean operation。

以下舉個範例:
mov ax, 0x123H or ax, 0E831H
但有幾點必須要注意,NOT 使用後可取得該數值的 1 補數,且不會改變 EFLAGS register 中的值。

另外,AND、OR、XOR 的用途通常在於:
  • AND:關閉某幾個 bit
  • OR:打開某幾個 bit
  • XOR:取得指定 bit 的補數(特殊用法:同樣數值進行 XOR 結果為 0)


Avoiding Conditional Branches

一般在程式中會有許多條件判斷,而 CPU 中有特定的單元可以負責預測程式的走向(不一定每次會準確),若是太多條件判斷,CPU 誤判的機會就越高,執行效率也就越差。

因此,在 assembly 的撰寫中可以避免 conditional branch 的情況發生,可以用 SETxx 指令,以下用個範例來說明:
;檔案: max.asm
;描述:求兩數之間較大的數

%include "asm_io.inc"

segment .data
message1 db "Enter a number: ", 0
message2 db "Enter another number: ", 0
message3 db "The larger number is ", 0

segment .bss
input1 resd 1 ;第一個輸入的數字

segment .text
global asm_main
asm_main:
enter 0, 0
pusha

mov eax, message1 ;取得使用者第一個輸入的整數值
call print_string
call read_int
mov [input1], eax

mov eax, message2 ;取得使用者第二個輸入的整數值
call print_string
call read_int

;一連串為了取得兩數之間的較大值所必須要作的處理
xor ebx, ebx ;EBX=0
cmp eax, [input1] ;比較的結果會影響後續程式的進行
setg bl ;EBX = (input2 > input1) ? 1 : 0 (set 1 if greater)
neg ebx ;EBX = (input2 > input1) ? -1(0xFFFFFFFF) : 0
mov ecx, ebx ;ECX = (input2 > input1) ? -1(0xFFFFFFFF) : 0
and ecx, eax ;ECX = (input2 > input1) ? [intpu2] : 0
not ebx ;EBX = (input2 > input1) ? 0 : -1(0xFFFFFFFF)
and ebx, [input1] ;EBX = (input2 > input1) ? 0 : [input1]
or ecx, ebx ;ECX = (input2 > input1) ? input2 : input1

mov eax, message3
call print_string
mov eax, ecx
call print_int
call print_nl

popa
mov eax, 0 ;回到 C 程式
leave
ret


Big and Little Endian Representations

假設要表示 double word - 0x12345678,兩種表示法分別如下:
  • Big Endian:0x 12 34 56 78
  • Little Endian:0x 78 56 34 12

通常會需要注意到 big/little endian 問題是在寫 TCP/IP 相關程式的時候,在 C 語言中,提供了 htonl()ntohl() 兩個 function 作為 network byte order 與 host byte order 之間的轉換。

而在 486 的 CPU 中提供了兩個指令用來可以反轉 32-bit register 與 16-bit register 的 byte order 之用,以下為使用範例:
#用於 32-bit register
bswap edx

#用於 16-bit register(將 AH 與 AL 對調)
xchg ah, al

沒有留言:

張貼留言