首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 組合語言

組語處理 Win32 訊息陷阱:SHR 移位指令與符號位延伸的正確處理

     編輯:組合語言

在處理 WM_MOUSEWHEEL 等將多項資訊打包於 wParam/lParam 的 Win32 訊息時,常需用移位指令擷取高/低字。若不當使用 SHR(邏輯右移)處理帶符號數值,會導致符號位錯誤延伸,造成判斷邏輯失效。

錯誤範例

; WM_MOUSEWHEEL: wParam 高字為滾輪增量 (WHEEL_DELTA = 120)
; 向上滾動為 -120 (FF88h),向下為 +120 (0078h)

mov eax, wParam        ; EAX = 0000FF88h (向上滾動)
shr eax, 16            ; EAX = 000000FFh (錯誤!邏輯右移補 0)
.if eax == -120        ; 永遠不成立,因 EAX 為正數 255
    ; 處理向上滾動
.endif

根本原因

SHR 是無符號邏輯右移,高位補 0。當 16 位有符號數(如 FF88h = -120)放在 32 位暫存器高字時,其第 15 位(原 16 位數的符號位)為 1。SHR EAX, 16 將這 1 移至 AX 的第 15 位,但 EAX 高 16 位被清零,導致結果被視為無符號正數(0x0000FF88 → 0x000000FF),而非預期的有符號 -120 (0xFFFFFF88)。

正確解法

方法一:直接操作 16 位暫存器(最簡潔)

mov ax, word ptr wParam+2   ; 直接取高字到 AX (AX = FF88h)
.if ax == -120              ; 有符號比較,正確判斷為真
    ; 向上滾動處理
.endif

方法二:使用算術右移 SAR(保持符號位)

mov eax, wParam
sar eax, 16                 ; 算術右移,高位補符號位 (EAX = FFFFFF88h)
.if eax == -120             ; 正確
    ; ...
.endif

方法三:MOVSX 符號延伸載入(推薦,語意最清晰)

movsx eax, word ptr wParam+2  ; 從記憶體載入 16 位並符號延伸至 32 位
.if eax == -120
    ; ...
.endif

延伸應用:lParam 坐標解析

lParam 低字為 X 座標,高字為 Y 座標,均為有符號 16 位整數(可為負,如多螢幕負座標)。

; 錯誤做法
mov eax, lParam
shr eax, 16      ; Y 座標若為負,此處變正數
mov ebx, lParam
and ebx, 0FFFFh  ; X 座標若為負,EBX 變大正數

; 正確做法
movsx eax, word ptr lParam+2  ; Y (有符號)
movsx ebx, word ptr lParam    ; X (有符號)

總結原則

  • 提取有符號 16 位值擴展至 32 位:用 MOVSX 或 SAR。
  • 提取無符號 16 位值:用 MOVZX、AND 0FFFFh 或直接操作 AX/DX。
  • 僅做位元操作/無符號邏輯判斷:SHR/SHL 適用。
  • 直接比較 16 位暫存器(AX、DX)可避開擴展問題,代碼更短。

Win32 API 大量使用打包參數,組語處理時務必區分有符號/無符號語意,選擇正確指令,避免隱蔽 Bug。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved