中国DOS联盟论坛

中国DOS联盟

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

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

游客:  注册 | 登录 | 命令行 | 搜索 | 上传 | 帮助 »
English/Chinese Fix Translation
作者:
标题: 怎么访问BP寄存器啊? 上一主题 | 下一主题
yysn
初级用户





积分 65
发帖 26
注册 2010-7-29
状态 离线
『楼 主』:  怎么访问BP寄存器啊? 使用 LLM 解释/回答一下

// struct REGPACK reg;

reg.r_ax=0x1130;
reg.r_bx=reg_bx;
intr(0x10,&reg);

return MK_FP(reg.r_es,reg.r_bp);


上面的一段代码是获取16X8字符集的首地址,使用intr
我现在不想用intr这个函数,而想换成int86函数,不知道该怎么写啊?
BP寄存器不用intr还能怎么访问啊?或者有别的计算地址的方法?


2010-11-8 05:43
查看资料  发送邮件  发短消息  网志  OICQ (50987013)  编辑帖子  回复  引用回复
firstsail
高级用户





积分 668
发帖 295
注册 2005-7-26
来自 广东深圳
状态 离线
『第 2 楼』:   [已使用 LLM 解释]

//获取8X8字符集的首地址
unsigned char* GetCharacterPoint()
{

unsigned short wSeg = 0;
unsigned short wOff = 0;

asm push es
asm push bp

asm mov ax, 1130H
asm mov bh, 03H //获问8*8字库首地址
asm int 10h

asm mov ax, bp
asm pop bp //非常重要,否则程序会崩溃
asm mov wOff, ax

asm mov ax, es
asm mov wSeg, ax
asm pop es

return ((unsigned char *)(unsigned long)MK_FP(wSeg, wOff));
}

Last edited by firstsail on 2010-11-8 at 10:02 ]
LLM 解释

代码整体功能及背景信息

这段代码是用于在x86环境下获取8x8字符集的首地址,它使用了x86汇编指令与BIOS中断(int 10h)相结合的方式。在x86体系中,BIOS中断提供了很多底层的系统功能调用,这里通过int 10h的特定功能来获取字符库相关信息。

代码逐部分解释

1. 初始化局部变量

unsigned short wSeg = 0;
unsigned short wOff = 0;

这里定义了两个16位的无符号短整型变量wSegwOff,分别用于存储段地址和偏移地址,初始值都为0,后续会被赋值为获取到的字符集首地址的段地址和偏移地址。

2. 汇编指令部分

asm push es
asm push bp
  • push eses是x86中的附加段寄存器,这里将es的值压入栈中,是为了保存原来es的值,以便后续恢复。
  • push bpbp是基址指针寄存器,同样将bp的值压入栈中,保存原来bp的值,后续要恢复。
asm mov ax, 1130H
asm mov bh, 03H //获问8*8字库首地址
asm int 10h
  • mov ax, 1130H:将立即数1130H送入ax寄存器。在BIOS int 10h中断调用中,不同的功能号存放在ax寄存器中,这里1130H应该是用于获取8x8字符库首地址的功能号相关设置。
  • mov bh, 03H:将立即数03H送入bh寄存器,这可能是与获取8x8字符库首地址相关的参数设置。
  • int 10h:这是调用BIOS的视频中断,通过前面对axbh等寄存器的设置,BIOS会执行相应的功能来获取8x8字符集的首地址相关信息,此时首地址的段地址会存放在es寄存器中,偏移地址会存放在bp寄存器中。
asm mov ax, bp
asm pop bp //非常重要,否则程序会崩溃
asm mov wOff, ax
  • mov ax, bp:将bp寄存器中的值(即获取到的偏移地址)送入ax寄存器。
  • pop bp:将之前压入栈中的bp的值弹出,恢复bp原来的值,这一步很关键,如果不恢复bp的值,会导致栈的状态不正确,进而可能使程序崩溃。
  • mov wOff, ax:将ax中的偏移地址值存入前面定义的wOff变量中。
asm mov ax, es
asm mov wSeg, ax
asm pop es
  • mov ax, es:将es寄存器中的值(即获取到的段地址)送入ax寄存器。
  • mov wSeg, ax:将ax中的段地址值存入前面定义的wSeg变量中。
  • pop es:将之前压入栈中的es的值弹出,恢复es原来的值。

3. 返回字符集首地址

return ((unsigned char *)(unsigned long)MK_FP(wSeg, wOff));
  • MK_FP是一个宏(在DOS环境下常见),用于将段地址和偏移地址组合成一个线性地址,这里将wSeg(段地址)和wOff(偏移地址)组合后,再强制转换为unsigned char*类型的指针,返回8x8字符集的首地址。

多种实现获取字符集首地址的思路(扩展)

思路一:使用C语言结合BIOS中断的标准方式

可以直接调用BIOS中断int 10h,根据中断的功能规范来获取相关信息。例如:

#include <dos.h>

unsigned char* GetCharacterPoint() {
    union REGS regs;
    regs.h.ah = 0x13; // 这里只是示例,实际根据正确功能号设置
    regs.h.bh = 0x03;
    int86(0x10, &regs, &regs);
    // 这里需要根据int 10h中断返回的结果来获取段和偏移地址,然后组合返回
    return (unsigned char*)MK_FP(regs.x.es, regs.x.bp);
}

这里使用了dos.h头文件中的int86函数来调用BIOS中断,通过union REGS来传递和获取寄存器的值。

思路二:使用内联汇编的更简洁方式

unsigned char* GetCharacterPoint() {
    unsigned short wSeg, wOff;
    __asm {
        push es
        push bp
        mov ax, 0x1130
        mov bh, 0x03
        int 0x10
        mov ax, bp
        pop bp
        mov wOff, ax
        mov ax, es
        mov wSeg, ax
        pop es
    }
    return (unsigned char*)MK_FP(wSeg, wOff);
}

这种方式和原始代码类似,只是在C语言中使用了__asm关键字来嵌入汇编代码,逻辑基本一致,只是写法上更符合C语言中内联汇编的语法形式。



2010-11-8 10:00
查看资料  访问主页  发短消息  网志   编辑帖子  回复  引用回复
yysn
初级用户





积分 65
发帖 26
注册 2010-7-29
状态 离线
『第 3 楼』:   使用 LLM 解释/回答一下

额,楼上的老大,我是需要C语言的,不要内嵌汇编。。。


2010-11-8 15:23
查看资料  发送邮件  发短消息  网志  OICQ (50987013)  编辑帖子  回复  引用回复
netwinxp
高级用户





积分 741
发帖 366
注册 2007-7-25
状态 离线
『第 4 楼』:   使用 LLM 解释/回答一下

c语言虽然可以通过声明register变量来尽可能使用寄存器做变量,但bp一般用来传递参数,所以即使用嵌入汇编方式使用bp,也要小心翼翼,否则程序很容易崩溃。


2010-11-26 08:21
查看资料  发短消息  网志   编辑帖子  回复  引用回复

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


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



论坛跳转: