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

MSVC 內嵌組合語言完整指南:語法、資料存取、函數實作與優化技巧

     編輯:組合語言

Visual C++ 6.0/7.x 內建的內嵌組譯器(__asm)支援 Intel 486 指令集與 MMX,允許在 C/C++ 函數內直接編寫組語指令,無需獨立組譯/連結步驟,且能無縫存取 C/C++ 變數。本文系統整理官方文件精華,涵蓋語法規則、資料操作、流程控制、函數呼叫與實戰範例。

一、 基礎語法與限制

關鍵字

VC 不支援 asm,必須使用 __asm(雙底線)。

兩種寫法

; 區塊寫法(推薦,可視化範圍、避免重複關鍵字)
__asm {
    mov al, 2
    mov dx, 0xD007
    out al, dx
}

; 單行寫法
__asm mov al, 2
__asm mov dx, 0xD007
__asm out al, dx

不支援的 MASM 功能

  • 資料定義指令:DB, DW, DD, DQ, DT, DF, DUP, THIS
  • 結構/記錄指令:STRUC, RECORD, WIDTH, MASK
  • 巨集指令:MACRO, REPT, IRC, IRP, ENDM 等
  • 段名稱直接引用(需用暫存器如 ES:[BX])

支援的特殊功能

  • _emit 偽指令:相當於 DB,每次定義一 Byte,可構建字串。
  • EVEN / ALIGN:指令對齊優化。
  • C/C++ 前置處理器巨集定義組語巨集。
  • /Zi 編譯選項支援原始碼級除錯;/FAs 輸出混合原始碼列表。

二、 在 __asm 區塊中使用 C/C++ 元素

可用元素說明
符號標號、變數名、函數名(需在作用域內)
常數包含 const、enum 成員
巨集/前置處理器#define 等
註解//, /* */, ;
型別名稱含 typedef 別名

三、 關鍵操作符差異:陣列索引與 TYPE

C 中 array[6] 會自動乘上元素大小;組語中 [bx+6] 僅為位元組偏移。

int array[10];
__asm mov array[6], 0          ; 錯誤!寫入 array+6 bytes
__asm mov array[6 * TYPE int], 0 ; 正確!等同 C 的 array[6]=0

TYPE、SIZE、LENGTH 操作符可查詢 C/C++ 變數/型別大小資訊。

四、 存取結構/類別成員

struct first_type { char *weasel; int same_name; } hal;
__asm {
    mov ebx, OFFSET hal
    mov ecx, [ebx]hal.same_name  ; 必須加變數名限定(非唯一成員)
    mov esi, [ebx].weasel        ; 唯一成員可省略變數名
}

五、 實作組語函數與呼叫慣例

範例:冪次計算

int power2(int num, int power) {
    __asm {
        mov eax, num   ; 參數 1
        mov ecx, power ; 參數 2
        shl eax, cl    ; eax *= 2^cl
    }
    ; 無需 RET,編譯器自動生成結尾碼;返回值於 EAX
}
  • 參數直接以名稱引用,編譯器自動解析堆疊/暫存器位置。
  • 返回值慣例:整數/指標於 EAX;float 於 EAX,double 於 EDX:EAX。

呼叫 C 函數(Caller Cleanup)

__asm {
    push offset szWorld
    push offset szHello
    push offset szFormat
    call printf
    add esp, 12        ; 必須手動清理堆疊(C 呼叫慣例)
}

呼叫 Windows API(Callee Cleanup)

__asm {
    push MB_OK
    push offset szTitle
    lea eax, szText
    push eax
    push 0
    call DWORD PTR [MessageBoxA]  ; 間接呼叫,API 為 stdcall 自動清堆疊
}

六、 流程控制與標號互跳

  • C goto label 可跳往 __asm { label: };組語 jmp label 可跳往 C 標號。
  • 組語標號不分大小寫;C 標號分大小寫。
  • 避免使用函數名作標號(會跳往函數入口而非標號)。
  • $ 符號代表當前位置,常用於短跳轉:JNE $+5。

七、 實戰範例:CRC32 校驗碼計算

完整 Win32 視窗程式,內嵌兩段組語:

  1. 建立 CRC32 查表(256 entries,多項式 0xEDB88320)。
  2. 逐位元組計算 CRC32,充分利用暫存器(EAX, EBX, ECX, EDX, ESI, EDI),速度遠超 C 版本。

關鍵指令片段:

_NextByte:
    mov dl, [ebx]       ; 取資料位元組
    xor dl, al          ; 與 CRC 低位異或
    movzx edx, dl       ; 零擴展至 32 位
    shr eax, 8          ; CRC 右移 8 位
    xor eax, [dwCRC32Table + edx*4] ; 查表異或
    inc ebx
    loop _NextByte
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved