簡體   English   中英

這兩種形式的內聯匯編程序在C中有什么區別?

[英]What is the difference between these two forms of inline assembler in C?

背景:我的任務是為Unitech HT630編寫一個數據收集程序,它運行一個專有的DOS操作系統,可以運行為16位MS DOS編譯的可執行文件,盡管有一些限制。 我正在使用Digital Mars C / C ++編譯器,它似乎運行得很好。

對於某些我可以使用標准C庫的東西,但是在單元的屏幕上繪制等其他東西需要匯編代碼。 設備文檔中給出的匯編示例與我在C / C ++中使用內聯匯編代碼的方式不同。 作為參考,以下示例中的BYTEunsigned char類型。

給出了示例代碼的示例:

#include <dos.h>

/* Set the state of a pixel */
void LCD_setpixel(BYTE x, BYTE y, BYTE status) {
  if(status > 1 || x > 63 || y > 127) {
    /* out of range, return */
    return;
  }
  /* good data, set the pixel */
  union REGS regs;
  regs.h.ah = 0x41;
  regs.h.al = status;
  regs.h.dh = x;
  regs.h.dl = y;
  int86(0x10, &regs, &regs);
}

我如何被教導使用內聯匯編:

/* Set the state of a pixel */
void LCD_setpixel(BYTE x, BYTE y, BYTE status) {
  if(status > 1 || x > 63 || y > 127) {
    /* out of range, return */
    return;
  }
  /* good data, set the pixel */
  asm {
    mov AH, 41H
    mov AL, status
    mov DH, x
    mov DL, y
    int 10H
  }
}

這兩種形式似乎都有效,到目前為止我還沒有遇到過這兩種方法的問題。 對於DOS編程,一種形式被認為比另一種更好嗎? 在第二個例子中, int86函數是否為我處理我自己的匯編代碼中沒有處理的東西?

預先感謝您的任何幫助。

當您使用int86函數調用時,這是一個C運行時庫調用,它設置寄存器並發出DOS int errupt函數。 兩種方法都是相同的,只有一個例外,當您使用內聯匯編程序時,代碼實際上是在編譯和鏈接時嵌入到目標代碼中。

內聯匯編會被認為更快,因為您沒有調用C運行時庫為您調用DOS中斷所涉及的開銷。 在使用內聯匯編時,有責任確保有足夠的堆棧空間,而C Runtime庫在調用int86函數之前設置寄存器時負責分配堆棧空間。

int86是一種使調用DOS中斷更容易的方法。 這在舊的Borland Turbo C編譯器套件和微軟中非常受歡迎,我在談論Win 3.1出現之前的舊編譯器。

說到負責視頻輸出的中斷0x10,如果我沒記錯的話,當時有些BIOS破壞了bp寄存器,解決方法就是這樣做:

__asm{
   push bp;
}
/* set up the registers */
int86(0x10, &regs, &regs);
__asm{
   pop bp;
}

您可以在此處找到Ralph Brown中斷列表中的大量BIOS功能。 此外HelpPC V2.1可能也有幫助,找到這里

第一種形式更具可讀性,也適用於某些事物;-)

如果你想知道int86是否在你背后做了什么,只需編譯你的程序並檢查生成的匯編代碼

通過調用int86,您的代碼保留在C中。無論哪種方式,它都是通過執行系統中斷來寫入像素。

如果您要編寫大量像素,並且開始嚴重影響速度問題,則可能會有更直接(並且更不安全但可能有價值)的方式直接寫入像素存儲器。

兩個代碼片段都完成了同樣的事情。 第一個的一大優點是,當您切換編譯器時,您仍有可能仍然可以使用它。 而且你沒有踩到'C'編譯器的代碼生成器用於其他目的的寄存器。 你絕對忘記在你的asm片段中處理的事情。

您應該檢查編譯器手冊,以找出在內聯匯編部分后負責恢復寄存器值的人員。 由於您的變量已分配給寄存器,因此值的意外更改可能會導致難以發現的錯誤。 int86(0x10,&regs,&regs); 執行軟件中斷后保存寄存器並恢復它們。

一些編譯器接受指令來定義一個clobber列表(應該保存和恢復的寄存器)。 通常,匯編程序部分應該保存寄存器和標志,這些寄存器和標志將通過push進行更改,並使用pop通過編譯器或您自己進行恢復。 因此,應首選第一個例子。

那不是內聯匯編,它是C.非常低級別的C,使用函數來引起中斷,但仍然是C.

這個頁面有一些文檔(對於DJGPP編譯器,你的工作可能會有所不同),包括用於表示寄存器的結構。 它還指出:

請注意,與__dpmi_int函數不同,對經過int86和類似函數的請求進行了特殊處理,使其適用於從保護模式程序調用實模式中斷。 例如,如果特定例程在BX中使用指針,則int86期望您在EBX中放置(保護模式)指針。 因此,int86應該對您以這種方式調用的每個中斷和函數都有特定的支持。 目前,它僅支持所有可用中斷和功能的子集[...]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM