中国DOS联盟论坛

中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net  论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

游客:  注册 | 登录 | 命令行 | 会员 | 搜索 | 上传 | 帮助 »
中国DOS联盟论坛 » DOS开发编程 & 发展交流 (开发室) » 我写的djgpp的简单教程![原创]
作者:
标题: 我写的djgpp的简单教程![原创] 上一主题 | 下一主题
xy_god
中级用户

疯狂的流浪者


积分 276
发帖 56
注册 2003-9-25
状态 离线
『楼 主』:  我写的djgpp的简单教程![原创]

献给初学者的DJGPP教程
                                by xy_god
                      homepage:http://www.xygod.pc5.org
_____________________________________________________________________________________
    自从用上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(xx可以是ah, al, bh, bl等寄存器),如果你要使用16位寄存器
可以这样__dpmi_regs.x.xx(即用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();
         }
    这个例子在屏幕的左上角画一个红色的点。这种方法有下面两种缺点:
    在调用一些特定的DPMI过程后,你必须重新计算video ram的近指针值!
    在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)
{
/*含有中断地址(selectorffset)信息的结构体*/
_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("%d\n",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 ebp
        mov 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) = %i\n", AddFour(4));
  return 0;
}
将下面的代码存为maker.bat:
@echo off

nasm -f coff asm.asm

gcc -o c.exe c.c asm.o

c.exe

最后输入maker,如果成功将输出:AddFour(4) =8
不成功的原因可能是你的NASM也许版本太老,也或者不是32位的NASM(非32位NASM
不认识coff目标文件格式),也或者是其他不可想象的原因。
_____________________________________________________________________________________
5 相关协议以及免责声明及其他
    本文挡是本人参考http://delorie.com/djgpp上的某些文挡写成的,相当一部分直接来自
于那些文挡,所以本人只保留汉化的版权,但是您可以任意转载而且可以任意修改!
    由于本人真正使用DJGPP的时间并不长,也没有时间仔细研究,所以并不能保证本 文相关
内容绝对正确,如果给您带来某些灾难性后果,本人概不负责!
    如果您有问题,请通过邮件和我联系,我的邮箱是:xy_god@163.com
    也可以到我的主页留言,我的主页是:http://www.xygod.pc5.org
    最后,祝您愉快!^-^


   此帖被 +2 点积分    点击查看详情   




临河居士
http://www.xygod.pc5.org
2004-5-19 00:00
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
o2y
中级用户




积分 226
发帖 51
注册 2004-4-16
状态 离线
『第 2 楼』:  

奉献伟大,顶一下!

2004-5-20 00:00
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
fsblm
初级用户





积分 28
发帖 10
注册 2006-2-13
状态 离线
『第 3 楼』:  

好样的,顶!!!1

2006-2-17 16:57
查看资料  发送邮件  发短消息 网志  OICQ (369165123)  编辑帖子  回复  引用回复

请注意:您目前尚未注册或登录,请您注册登录以使用论坛的各项功能,例如发表和回复帖子等。


可打印版本 | 推荐给朋友 | 订阅主题 | 收藏主题



论坛跳转: