獻給初學者的DJGPP教程
發表于:2007-07-04來源:作者:點擊數:
標簽:
自從用上 LINUX 后就用夠了 WINDOWS ,但是好多 開發 還脫離不開DOS,真是沒辦法!早就聽說FREEDOS和MSDOS完全兼容,而且遵循的是GPL協議,所以下定決心脫離 WINDOWS ,裝了個FREEDOS!開發工具當然不能再用TURBO C啊等等原先商業化的東西了,用就用個純GNU
自從用上LINUX后就用夠了WINDOWS,但是好多開發還脫離不開DOS,真是沒辦法!早就聽說FREEDOS和MSDOS完全兼容,而且遵循的是GPL協議,所以下定決心脫離WINDOWS,裝了個FREEDOS!開發工具當然不能再用TURBO C啊等等原先商業化的東西了,用就用個純GNU的平臺!好,就把TURBO C換成DJGPP吧,還有MASM和TASM,全部給我扔掉 ,換成NASM!編輯器呢?用著EDIT根本就不爽,換成了DOS版的VIM,也是GNU工具!不好意思,中文平臺還是得用UCDOS,因為似乎還沒有GPL協議的中文化DOS平臺呢,還好UCDOS是免費的了,不會讓我的系統中存在D版軟件了,我也沒有做賊的感覺了!^-^
OK,這一切都搞定了,可是面對DJGPP和NASM突然發覺自己什么都不會了,以前用TURBO C和MASM寫代碼的時候調用中斷啊,交互編程啊,現在都不知道怎么做了,靠,和當初剛剛接觸LINUX怎么一樣??!只好到http://delorie.com/djgpp去看了,全他媽的E文的,硬著頭皮看吧!總算找到了一些用戶指南,讀懂了,基本上可以解決以上問題了!想一想,那么多和自己一樣的家伙們肯定也是一樣的頭疼,所以寫出來和大家一起分享,并非是翻譯的,因為我沒有耐心去翻譯那些洋話連篇的東西,還是根據我的理解來寫一份教程吧,不過大牛們就不必看了! 另外,本教程假設您對turbo c或者DOS下的其他C/C++有一定了解并且作過一些中斷調用,中斷駐留,顯存映射操作以及C/C++和ASM混合編程!
OK,廢話少說,本教程分為如下四個部分:
1 如何調用中斷;
2 如何往VIDEO RAM中寫入數據;
3 如何寫中斷駐留程序;
4 如何調用NASM寫的匯編函數;
5 相關協議以及免責聲明及其他
_____________________________________________________________________________________
1 如何調用中斷: 在DJGPP中調用實模式中斷和在TURBO C中使用INT86調用中斷在形式上是很類似的,看下面的例子(來自http://delorie.com/djgpp): #include void main(void){ __dpmi_regs r; r.x.ax = 0x13; r.d.ebx = 0x10000; r.h.cl = 4; r.h.dh = 5; __dpmi_int(0x10, &r); } __dpmi_regs是一個結構,其中包含所有的80386用到的寄存器,如果你要使用8位寄存器可以這樣 __dpmi_regs.h.xx可以是ah, al, bh, bl等寄存器),如果你要使用16位寄存器可以這樣__dpmi_regs.x.即用x替換掉h即可),如果要使用32位寄存器,把h用d替 換就可以了! 上面的代碼就是調用int10中斷,把顯示模式設置為0x13(320*200 256)。 當中斷執行完畢時,傳給__dpmi_int的__dpmi_regs類型參數中將包含寄存器的新值,你可以通過檢測這些新值來分析中斷的執行情況!注意,這些中斷調用都是實模式下的!_____________________________________________________________________________________
2 如何往VIDEO RAM中寫入數據: 往VIDEO RAM中寫入數據有兩種方法,這兩種方法個有優缺點,您需要根據情況選擇使用! 第一種方法: 下面是代碼: #include void main(void){ char *screen; __dpmi_regs r; r.x.ax = 0x13; r.d.ebx = 0x10000; r.h.cl = 4; r.h.dh = 5; __dpmi_int(0x10, &r);/*設置為0x13顯示模式*/ if (__djgpp_nearptr_enable() == 0) return 0; /* 有可能發生 */ screen = 0xa0000 + __djgpp_conventional_base; screen[0] = 4;/*將屏幕左上角的一個點設置為紅色*/ __djgpp_nearptr_disable(); } 這個例子在屏幕的左上角畫一個紅色的點。這種方法有下面兩種缺點: <1>在調用一些特定的DPMI過程后,你必須重新計算video ram的近指針值! <2>在windows NT下不能用(至少在XP下是不能用的,但是在純DOS下沒問題)! 因此,一般并不推薦使用這種方法! 下面是第二種方法: #include #include int main(){ int x=0,y=0; char * screen; __dpmi_regs r; r.x.ax = 0x13; __dpmi_int(0x10, &r); _farsetsel(_dos_ds); _farnspokeb(0xA0000, 4); return 1; } 這個例子在屏幕的左上角畫一個紅色的點。它也有一個缺點,那就是比第一種方法要稍微慢一點。但是它比較安全,據說能夠在NT下使用(但是我在XP上驗證的效果很糟糕),而且不必重新計算VIDEO RAM的指針,在Allegro庫中就是使用的這種方法,所以它的速度也是比較不錯的,所以推薦使用這種方法!_____________________________________________________________________________________
3 如何寫中斷駐留程序:這兒有個程序,漢化自DJGPP的用戶指南,不多說了,看程序,里面的注釋已經很清楚了!
#include
#include
#include
#include
#define LOCK_VARIABLE(x) _go32_dpmi_lock_data((void *)&x,(long)sizeof(x));#define LOCK_FUNCTION(x) _go32_dpmi_lock_code(x,(long)sizeof(x));
#define TIMER 8/*時鐘中斷8每18.2 ms產生一次*/
int counter = 0;/*計數器初始值*/
void TickHandler(void){/*新的時鐘中斷處理程序*/ counter++;}
int main(void)
{ /*含有中斷地址(selector:offset)信息的結構體*/
_go32_dpmi_seginfo OldISR, NewISR; printf("將要把新的中斷處理程序連結到舊的中斷處理程序上..n"); getkey(); /*鎖住函數和變量*/ LOCK_FUNCTION(TickHandler); LOCK_VARIABLE(counter); /*把舊的中斷地址寫入OldISR結構變量中*/ _go32_dpmi_get_protected_mode_interrupt_vector(TIMER, &OldISR); /*把NewISR指向函數TickHandler的地址*/ NewISR.pm_offset = (int)TickHandler; NewISR.pm_selector = _go32_my_cs();/*把NewISR指向的地址連接到中斷8的地址上*/ _go32_dpmi_chain_protected_mode_interrupt_vector(TIMER,&NewISR); while (!kbhit()) printf("%dn",counter); printf("正在恢復原有的時鐘中斷。。。。。。n"); /*恢復原有的時鐘中斷*/ _go32_dpmi_set_protected_mode_interrupt_vector(TIMER, &OldISR); return 0;}_____________________________________________________________________________________
4 如何調用NASM寫的匯編函數:下面這個例子是我自己寫的,共有三個文件:將下面的代碼存為asm.asm:
[BITS 32][GLOBAL _AddFour__FUi][SECTION .text]; ---------------------------------------------------------------------------; 原型聲明: unsigned int
AddFour(unsigned int x);; Returns: x + 4; ---------------------------------------------------------------------------
x_AddFour equ 8_AddFour__FUi:
push ebpmov ebp, esp
mov eax, [ebp + x_AddFour]
add eax, 4
mov esp, ebp
pop ebp
ret
將下面的代碼存為c.c:
#include extern unsigned int AddFour(unsigned int);
int main(void)
{
printf("AddFour(4) = %in", AddFour(4));
return 0;
}
將下面的代碼存為maker.bat:
@echo offnasm -f coff asm.asmgclearcase/" target="_blank" >cc -o c.exe c.c asm.oc.exe
最后輸入maker,如果成功將輸出:AddFour(4) =8不成功的原因可能是你的NASM也許版本太老,也或者不是32位的NASM(非32位NASM不認識coff目標文件格式),也或者是其他不可想象的原因。
_____________________________________________________________________________________
5 相關協議以及免責聲明及其他
本文擋是本人參考http://delorie.com/djgpp上的某些文擋寫成的,相當一部分直接來自于那些文擋,所以本人只保留漢化的版權,但是您可以任意轉載而且可以任意修改!
由于本人真正使用DJGPP的時間并不長,也沒有時間仔細研究,所以并不能保證本 文相關內容絕對正確,如果給您帶來某些災難性后果,本人概不負責! 如果您有問題,請通過郵
件和我聯系,
我的郵箱是:xy_god@163.com 也可以到我的主頁留言,我的主頁是:http://www.xygod.mycool.net
最后,祝您愉快!^-^
原文轉自:http://www.kjueaiud.com