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

标签 assembly dos inline-assembly tasm turbo-c++

我正在尝试在 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 偏移量。然后您可以使用远字符串格式说明符使用 printf 指定您的字符串:

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

...

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

这是完整的修改后的代码:

注意:我没有费心去显示没有终止空格的 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 作为本地基于堆栈的缓冲区进行访问。

关于assembly - 从文档文件在 Turbo C++ 3.0 中创建内联汇编代码 (TASM),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39484266/

相关文章:

c - 如何在汇编中遍历矩阵?

c - 目标文件中的函数和参数不正确?

android - 来自 .bat 文件的 ADB shell "run-as"未找到 Unix 命令

linux - 将DOS程序移植到linux上通过usb读写串口

java - 如何在MS-DOS中获取当前正在运行的批处理作业的路径?

C++ 从内存中执行函数

gcc - 使用 SSE2 内在函数和 gcc 内联汇编器

java - JVM 上的汇编编程?

assembly - 汇编中的 16 位乘法?

c++ - 如何将%rax中的double移到%ymm或%zmm上的特定qword位置? (卡比湖或更高版本)