3

ネクロマンシーの試みをお許しください。ただし、実際には 16 ビット DOS 用のコードを書く必要があります (!)。ソフトウェアの一部が 16 ビット プラットフォーム用にビルドされたときに正しく実行されることを確認する必要があり、XP ワークステーションが実際に 16 ビット DOS アプリを実行できることを発見しました。これにより、既存のバッチ テスト システムを使用できるようになります。

いずれの場合も、ソフトウェアは 1 つのライブラリと 1 つのデータベースで構成されます。小規模なデータベース (最大 150kB) は、静的グローバル配列として定義するか、または で割り当てられたバッファーにファイルから読み取ることができるhalloc()ため、ライブラリとテスト ツールが正しく構築されていることはかなり確信しています。

ただし、最大 1.8Mb までのより大きなデータベースをテストすることもできます。これは大きすぎて正常に割り当てることができないため、XMS メモリを割り当てるための小さなサポート ライブラリを作成しました。これにより、小さなおもちゃのプログラムで最大 16Mb のデータを正常に割り当て、使用 (つまり、データの書き込みと読み取り)、および解放することができます。ただし、「実際の」アプリケーションで XMS 機能を使用すると、次のエラーが発生します。

The NTVDM CPU has encountered an illegal instruction.
CS:0000 IP:00ba OP:0f 04 10 0e 51

このエラーをグーグルで調べても、関連する結果はほとんど得られませんでした。このタイプのエラーは通常、さまざまなマルウェアのせいにされているようです。

コードベースは厳密な C90 であり、DOS ビルドに現在使用されているコンパイラは、「ラージ」メモリ モデルを使用する OpenWatcom 1.9 です。ビルド中に警告やエラーは発生しません。

XMS サポート ライブラリは次のとおりです。xmsmalloc() の呼び出し後にエラーが発生するようです。

/* This file implements rudimentary XMS memory handling.
 * Documentation on the XMS API was found on http://www.qzx.com/pc-gpe/xms30.txt
 */

#include <stddef.h> /* Definition of NULL */
#include <limits.h> /* Definition of UINT_MAX */
#include <stdio.h>  /* fprintf and (FILE *) */

/* Allow external configuration of maximum concurrent XMS allocations */
#ifndef MAX_XMS_ALLOCATIONS
#define MAX_XMS_ALLOCATIONS 4
#endif

/* Address of the XMS driver */
static long XMSControl;

/* Mapping of XMS handle <-> normal pointer */
typedef struct {
    unsigned int XMSHandle;
    void huge * XMSPointer; 
} XMSHandleMap;

static XMSHandleMap allocMap[MAX_XMS_ALLOCATIONS];

/* Set up the XMS driver, returns 0 on success and non-zero on failure */
static int initxms(void)
{
    char XMSStatus = 0;

    if ( XMSControl == 0 )
    {
        __asm {
        ; Is an XMS driver installed?
            mov ax,4300h
            int 2Fh
            mov [XMSStatus], al
        }

        if ( XMSStatus == 0x80 )
        {
            __asm {
            ; Get the address of the driver control function
                mov ax,4310h
                int 2Fh
                mov word ptr [XMSControl]  ,bx
                mov word ptr [XMSControl+2],es
            }
        }
    }

    return ( XMSControl == 0 );
}

/* Allocate a slab of memory from XMS */
void huge * xmsmalloc(long unsigned int size)
{
    unsigned int kB;
    unsigned int XMSStatus = 0;
    unsigned int XMSHandle = 0;
    void huge * XMSPointer = NULL;
    int n;

    /* If we can not initialize XMS, the allocation fails */
    if ( initxms() )
        return NULL;

    /* It is not possible to allocate more kilobytes than a 16-bit register can hold :-) */
    if ( size / 1024 > UINT_MAX )
        return NULL;

    /* Get the next free entry in the handle <-> pointer mapping */
    for ( n = 0; n < MAX_XMS_ALLOCATIONS; n++ )
    {
        if ( allocMap[n].XMSPointer == NULL )
            break;
    }

    if ( n == MAX_XMS_ALLOCATIONS )
        return NULL;

    kB = size / 1024 + (size % 1024 > 0);

    __asm {
    ; Allocate [kB] kilobytes of XMS memory
        mov ah, 09h
        mov dx, [kB]
        call [XMSControl]
        mov [XMSStatus], ax
        mov [XMSHandle], dx
    }

    /* Check if XMS allocation failed */
    if ( XMSStatus == 0)
        return NULL;

    __asm {
    ; Convert XMS handle to normal pointer
        mov ah, 0Ch
        mov dx, [XMSHandle]
        call [XMSControl]
        mov [XMSStatus], ax

        mov word ptr [XMSPointer],  bx 
        mov word ptr [XMSPointer+2],dx
    }

    if ( XMSStatus == 0 )
    {
        /* Lock failed, deallocate the handle */
        __asm {
        ; Free XMS handle
            mov ah, 0Ah
            mov dx, [XMSHandle]
            call [XMSControl]

        ; Return value is not really interesting 
        ;   mov [XMSStatus], ax
        }
        return NULL;
    }

    /* Create an entry in the handle <-> pointer mapping */
    allocMap[n].XMSHandle = XMSHandle;
    allocMap[n].XMSPointer = XMSPointer;

    return XMSPointer;
}

/* Free a pointer allocated with xmsalloc */
void xmsfree(void huge * XMSPointer)
{
    int n;

    if ( XMSPointer == NULL )
        return;

    if ( initxms() ) 
        return;

    for ( n = 0; n < MAX_XMS_ALLOCATIONS; n++ )
    {
        if ( allocMap[n].XMSPointer == XMSPointer )
        {
            int XMSHandle = allocMap[n].XMSHandle;

            __asm {
            ; Unlock handle so we can free the memory block
                mov ah, 0Dh
                mov dx, [XMSHandle]
                call [XMSControl]

            ; Free XMS memory
                mov ah, 0Ah
                mov dx, [XMSHandle]
                call [XMSControl]

            ; Return value ignored
            }

            /* Clear handle <-> pointer map entry so it can be reused */
            allocMap[n].XMSHandle = 0;
            allocMap[n].XMSPointer = NULL;

            return;
        }
    }
}

/* Write a memory report for debugging purposes */
void xmsreport(FILE * stream)
{
    int XMSVersionNumber = 0;
    int XMSLargestBlock = 0;
    int XMSTotal = 0;

    if ( initxms() ) 
    {
        puts("Could not initialize XMS Driver!");
        return;
    }

    __asm {
    ; Get the driver version number
        mov ah,00h
        call [XMSControl] ; Get XMS Version Number
        mov [XMSVersionNumber], ax

    ; Get the amount of free XMS memory
        mov ah, 08h
        call [XMSControl]
        mov [XMSLargestBlock], ax
        mov [XMSTotal], dx
    }

    fprintf(stream, "XMS Version number: %d\n", XMSVersionNumber);
    fprintf(stream, "Largest available block: %d kB (%d kB total)\n", XMSLargestBlock, XMSTotal);
}

いくつかの具体的な質問:

  1. エラー メッセージに関する詳細情報はどこで入手できますか (OP はオペコードを意味すると思いますが、他のフィールドはどうでしょうか?)
  2. 私が見つけた XMS API リファレンスは、Windows XP で実行している場合でも適用できますか?それとも、参照すべき新しいバージョンはありますか?
  3. インライン アセンブラでシステム状態を台無しにすることはできますか? どうすれば解決できますか?
  4. これを解決する方法について何か良いアイデアはありますか? :-) DOS エクステンダには 32 ビット モードが必要なようですが、この演習の要点は 16 ビット モードを使用することです。
4

3 に答える 3

2

2 つの問題があります。

1st: コンパイラが near 呼び出しの代わりに far 呼び出しを使用していることを確認してください。そうしないと、間違ったセグメントにジャンプして不明なコードを実行し、無効なオペコードを生成する可能性があります...これが起こっているようです。コンパイラのデフォルトがニアコールである場合は、コードで「call far [XMSControl]」を試してください。

2 番目: NTVDM.EXE は、真のリアル モードではなく、仮想 86 モードでコードを実行します。Windows XP が 16 ビット アプリをサポートしているのは事実ですが、サポートは限定的です。そのため、データベースで他の問題が発生する可能性があります。たとえば、USB にアクセスできないため、USB プリンターで印刷できず、古いパラレル ポート スタイルのプリンターを使用する必要があります。ガレージ セールで使用されているものの 1 つを見つけてください...

于 2010-12-16T09:27:24.017 に答える
2

ああ、私は自分の質問に答えなければなりません。

XMS ルーチンを使用して比較的大量のメモリを割り当てることはできますが、16 ビット命令でアドレス指定することはできません。戻り値は 32 ビットの線形アドレスです。これを正しく理解していれば、16 ビット環境からそれを使用することはできません。

そのメモリ ブロックの一部を 1Mb のアドレス指定可能な制限より下のローカル メモリ バッファにマップすることでそのメモリ ブロックを使用し、EMS の動作と同じようにウィンドウを移動することは可能ですが、それは単に面倒なことではありません

于 2011-02-08T08:49:24.670 に答える
0

'0f 04 10 0e 51' は、実行しようとしている命令自体が無効です。

確認しましたが、このコード 0F 04 の x86 命令は見当たりません

http://ref.x86asm.net/geek.html#x0F04

したがって、そのような無効な命令を生成するコードを見つけて修正する必要があります。

メモリに関しては、XMSよりEMSの方が使いやすいとずっと思っていましたが、間違っているかもしれません。

于 2010-12-01T11:09:01.690 に答える