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

C++Builder 與組合語言混合編程:繞過 Ring 0 保護直接操作 8254 晶片發聲

     編輯:關於C++

Windows 保護模式下,應用程式運行於 Ring 3 (用戶態),無法直接存取硬體 I/O 埠。但 PC Speaker 控制埠 (0x42/0x43/0x61) 屬於「無傷大雅」類別,Windows 未加保護,允許用戶態直接操作。本文展示如何在 C++Builder 中結合獨立組合語言模組,實現精準頻率蜂鳴器控制。

硬體背景:8253/8254 可程式化間隔計時器

  • 0x43:控制字暫存器,寫入 0xB6 設定通道 2、模式 3 (方波產生器)、二進位計數
  • 0x42:通道 2 計數值低/高位元組 (頻率 = 1,193,181 Hz / 計數值)
  • 0x61:喇叭控制埠,Bit 0/1 控制通道 2 輸出閘門與喇叭開關

C++ 介面層聲明


extern "C" {
    unsigned char InPortB(int port);      // 讀取埠位元組
    void OutPortB(int port, unsigned char val); // 寫入埠位元組
}

void __fastcall Sound(int freq) {
    if (freq < 20 || freq > 20000) return;
    int count = 1193181 / freq;
    unsigned char b = InPortB(0x61);
    if ((b & 3) == 0) {          // 喇叭未開啟
        OutPortB(0x61, b | 3);   // 開啟閘門 + 喇叭
        OutPortB(0x43, 0xB6);    // 設定 8254 模式
    }
    OutPortB(0x42, (unsigned char)count);        // 低位元組
    OutPortB(0x42, (unsigned char)(count >> 8)); // 高位元組
}

void __fastcall NoSound() {
    OutPortB(0x61, InPortB(0x61) & 0xFC); // 關閉 Bit 0/1
}

組合語言模組 (IOPortB.asm)


.386p
.model flat
_TEXT segment dword public use32 'CODE'

_InPortB proc near
    push ebp
    mov  ebp, esp
    mov  dx, word ptr [ebp + 8]  ; 參數: port
    in   al, dx                  ; 讀取埠
    pop  ebp
    ret
_InPortB endp

_OutPortB proc near
    push ebp
    mov  ebp, esp
    mov  dx, word ptr [ebp + 8]   ; 參數: port
    mov  al, byte ptr [ebp + 12]  ; 參數: value
    out  dx, al                   ; 寫入埠
    pop  ebp
    ret
_OutPortB endp

public _InPortB
public _OutPortB
_TEXT ends
end

關鍵技術細節解析

專案整合步驟

  1. 建立 IOPortB.asm 加入專案
  2. 專案選項 → 匯編器 → 開啟「區分大小寫」
  3. C++ 端以 extern "C" 宣告外部函數
  4. 編譯連結生成可執行檔

平台相容性警示

  • Windows 95/98/Me:可正常運作
  • Windows NT/2000/XP/後續版本:完全失效,HAL 嚴格保護所有 I/O 埠,需撰寫核心模式驅動 (WDM/KMDF) 才能存取

現代替代方案

  • Beep(freq, duration) (WinAPI,需 XP+ 支援)
  • MessageBeep(MB_ICONASTERISK) 系統提示音
  • DirectSound/XAudio2 播放合成波形
  • 跨平台庫 (SDL2, PortAudio) 控制音訊輸出

此技術雖屬經典,但完美展示了「用戶態繞過硬體保護」的邊界條件、C/C++ 與組合語言混合編程的呼叫慣例、以及作業系統演進對硬體存取權限的收緊歷程。理解這些底層機制,對系統程式設計師極具啟發價值。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
項目說明
.386p指示 32 位元保護模式指令集
.model flat平坦記憶體模型 (32 位元線性位址空間)
參數存取32 位元呼叫慣例:參數在堆疊 [ebp+8]、[ebp+12]...,非 16 位元 [bp+6]
前綴底線C 建構器預期 _InPortB 符號,區分大小寫
public 宣告匯出符號供連結器解析