从文档文件在 Turbo C++ 3.0 中创建内联汇编代码 (TASM)

Creating Inline Assembly code(TASM) in Turbo C++ 3.0 from a documentation file

我正在尝试在 Turbo C++ 3.0 中创建一个 C 程序,该程序将在 MS-DOS 6.22 上运行,并且需要使用 MSCDEX 和中断访问 CD-ROM,以在其上播放曲目。

Turbo C 对我来说不是问题,我已经做到了并且效果很好,但现在我正在尝试使用 this 文档来获取 CD-ROM 设备驱动程序的名称.

这是我的代码:

#include <stdio.h>
#include <dos.h>

void main(){
    clrscr();
    CDname();

    printf("\nPress a button to exit the program.");
    getch();
}

void CDname(){
    char myArray[15];
    int i;

    asm{
        mov AX,1501H
        les BX,DWORD PTR[myArray]
        int 2FH
    }

    for(i=0; i < 15; i++){
        printf("\nArray = %c", myArray[i]);
    }
}

这里是我试图遵循的文档的一小部分:

How do I get the name of the CD-ROM device driver?

      First, you need to know how many CD-ROMs you have (see question
      2.01, How many CD-ROMs are present?). You need a block of memory
      whose size, in bytes, is 5 times the number of CD-ROMs present.
      This code will fill that array:

      mov  AX,1501H
      les  BX,DriverArray
      int  2FH

      Each 5-byte element in the array consists of the drive's subunit
      number (a CD-ROM device driver may support several drives as
      subunits), followed by the address of the drive's device driver.
      The filename is 10 bytes into the device driver. The filename is
      at most 8 bytes long, and if less than 8 bytes, is terminated by
      a space (20H).

问题是我需要将 CD-ROM 名称放在 myArray 中,但这样我就不太确定我在做什么。有人可以帮我做吗?

提前致谢!

如果您首先使用 memset() 将 myarray 归零,您会发现内联程序集不会向该位置写入任何信息。这是因为 LES 指令正在将远指针从 ES:BX 未初始化的内存中加载,而不是将 ES:BX 的地址设置为您想要的内存.

这些示例说明假设您在 DriverArray 中有一个远指针。中断函数真正期望的是 ES:BX 指向您的数组。由于 ES 已经指向数据段(DS 和 SS 也是如此),只需 使用 "lea bx,[myarray]".

将数组在堆栈上的偏移量加载到 BX

当 "int 2Fh" 执行时(至少在我的虚拟机上),它会将以下字节写入 myarray 缓冲区:

00 00 00 EF 04

我假设第一个字节必须是子单元,其余 4 个字节对应于远指针 04EF:0000。在 Turbo Debugger 中,我机器上的这个位置有以下字节:

04EF:0000 00 00 A8 03 00 C8 DC 00 E7 00 4D 53 43 44 30 30  ..........MSCD00
04EF:0010 30 20 00 00 04 01 00 4F 41 $B 20 41 54 41 50 49  0 .....OAK ATAPI
04EF:0020 20 49 44 45 20 43 44 2D 52 4F 4D 98 00 3F 15 3B   IDE CD-ROM.....

您可以看到驱动程序文件名为 MSCD000,偏移量为 10,正如说明中所说。

因此,我们只需要制作一个结构,您可以从中取消引用指向 CD-ROM 信息的远指针并添加 10 偏移量。然后您可以使用 far 字符串格式说明符使用 printf 指定您的字符串:

struct CDINFO
{
    unsigned char subunit;
    unsigned char far* pData;
};

...

printf("CDROM filename = \"%Fs\"\n",
    ((CDINFO*)myarray)->pData + 10
);

这里是完整的修改代码:

注意:我懒得显示没有终止符 space 的 CD-ROM 文件名。我将把它作为练习留给您删除它或显示任何其他 CD-Rom 驱动程序字符串。 我还将您的数组类型从 char 更改为 unsigned char 因为它是将任何字节 >127 扩展为 15 字节调试中的完整字的符号-转储

#include <stdio.h>
#include <conio.h>
#include <dos.h>
#include <string.h>

//we'll superimpose this upon myarray
struct CDINFO
{
    unsigned char      subunit;
    unsigned char far* pData;
};

void CDname()
{
    unsigned char myarray[15];
    int i;

    //for debugging, ensure this buffer is initially clear
    memset(myarray,0,sizeof(myarray));

    asm {
        mov ax,1501h
        lea bx,[myarray]
        int 2Fh
    }

    //notice the %Fs format specified specifies a "far" string
    printf("CDROM filename = \"%Fs\"\n",
        ((CDINFO*)myarray)->pData + 10
    );

    //this is useful for debugging
    for(i=0; i<sizeof(myarray); i++)
    {
        printf("Array = %02X\n",myarray[i]);
    }
}

void main()
{
    clrscr();
    CDname();
    printf("\nPress a button to exit the program.");
    getch();
}

输出:

CDROM filename = "MSCD000 "
Array = 00
Array = 00
Array = 00
Array = EF
Array = 04
Array = 00
Array = 00
Array = 00
Array = 00
Array = 00
Array = 00
Array = 00
Array = 00
Array = 00
Array = 00

Press a button to exit the program.

更新:在排除故障时,我最初将 myarray 设为全局变量,使用 "mov bx,OFFSET myarray" 访问它。但是我没有意识到 SS 也指向数据段,所以我将源代码更改回更接近原始版本的版本,其中 myarray 作为本地基于堆栈的缓冲区进行访问。