2

Github から取得したいくつかのアセンブリ マージ ソート コードがあり、C++ でインライン アセンブリに埋め込もうとしていますが、コンパイルされず、これらのエラーが返され続けます。

1>c:\users\mayank\desktop\assembly\assembly\main.cpp(147): エラー C2415: 不適切なオペランド型

私が実行しようとしているコードは次のとおりです。

#include <iostream>
#include <cmath>
#include <stdio.h>

using namespace std;
const int ARRAYSIZE = 30;

int main()
{
    int arr[ARRAYSIZE];
    int temp_arr[ARRAYSIZE];
    int number;

    for(int x = 0; x < ARRAYSIZE; x++)
    {
        number = (rand() % 99) + 1;
        arr[x] = number;
    }
/*  
READ_ARR_LEN:
    __asm
    {
        // Read the length of the array
        //GetLInt [30]      // Size of input array
        //PutLInt [30]
    }

GET_ARRAY:
    __asm
    {
         //intel_syntax
         // Get values in arr from the user
         mov   EAX, arr
         mov   ECX, ARR_LEN
         call  Read_Arr

         // Run Merge Sort on the array
         mov   EAX, arr
         mov   EBX, temp_arr
         mov   ECX, ARR_LEN
         call  Merge_Sort

        // EXIT
    };;
*/
Merge_Sort:
    __asm
    {
        // EAX - Array start
        // ECX - array length

        // Arrays of size 0 or 1 are already sorted
        cmp   ARRAYSIZE, 2
        jl    Trivial_Merge_Sort

        // Merge_Sort (first half)
        // Length of the first half
        // ECX /= 2
        push  ARRAYSIZE
        shr   ARRAYSIZE, 1
        call  Merge_Sort
        pop   ARRAYSIZE

        // Merge_Sort (second half)
        push  arr
        push  EBX
        push  ARRAYSIZE

        // Length of the second half
        // ECX = ECX - ECX/2
        mov   EDX, ARRAYSIZE
        shr   EDX, 1
        sub   ARRAYSIZE, EDX
        imul  EDX, 4
        // Start index of the second half
        // EAX = EAX + (ECX/2) * 4
        add   arr, EDX
        push  EDX
        call  Merge_Sort
        pop   EDX

        pop   ARRAYSIZE
        pop   EBX
        pop   arr

        pushad
        // Merge (first half, second half)
        // Length of first half = ECX/2
        // Length of second half = ECX - ECX/2
        mov   EDX, ECX
        shr   ECX, 1
        sub   EDX, ECX

        // Start of second half = EAX + (ECX/2) * 4
        mov   EBX, EAX
        mov   EDI, ECX
        imul  EDI, 4
        add   EBX, EDI
        // Index of temp array = 0
        sub   EDI, EDI
        call  Merge
        popad

        // Copy back the merged array from temp_arr to arr
        call  Merge_Copy_Back_Temp

        ret
    };

Trivial_Merge_Sort:
    __asm
    {
        // In case of arrays of length 0 or 1
        ret
    };
Merge:
    __asm
        {
        // Merge two arrays contents.
        // The final merged array will be in temp_arr
        // Merging is done recursively.

        // Arguments:
        // EAX - First array's start
        // EBX - Second array's start
        // ECX - Length of first array
        // EDX - Length of second array
        // EDI - Index in temp array
        pushad

        // Handle the cases where one array is empty
        cmp   ARRAYSIZE, 0
        jz    First_Array_Over
        cmp   EDX, 0
        jz    Second_Array_Over

        // Compare first elements of both the arrays
        push  ARRAYSIZE
        push  EDI
        mov   ARRAYSIZE, [arr]
        mov   EDI, [ARRAYSIZE]
        cmp   ARRAYSIZE, EDI
        pop   EDI
        pop   ARRAYSIZE

        // Pick which ever is the least and update that array
        jl    Update_First_Array
        jmp   Update_Second_Array
    };

Update_First_Array:
   __asm
   {
        // min_elem = min (first elements of first array and second array)
        // Put min_elem into the temp array
        push  dword ptr [EAX]
        pop   dword ptr [temp_arr + EDI * 4]
        add   EAX, 4
        dec   ECX
        inc   EDI

        // Recursively call Merge on the updated array and the
        // other array
        call  Merge
        popad
        ret
   };

Update_Second_Array:
   __asm
   {
       // min_elem = min (first elements of first array and second array)
        // Put min_elem into the temp array
        push  dword ptr [EBX]
        pop   dword ptr [temp_arr + EDI * 4]
        add   EBX, 4
        dec   EDX
        inc   EDI

        // Recursively call Merge on the updated array and the
        // other array
        call  Merge
        popad
        ret
   };

Merge_Copy_Back_Temp:
   __asm
   {
        // Copy back the temp array into original array
        // Arguments:
        // EAX - original array address
        // ECX - original array length
        pushad

        // For copying back, the destination array is EAX
        mov   EBX, EAX
        // Now, the source array is temp_arr
        mov   EAX, temp_arr
        call  Copy_Array
        popad
        ret
   };

Trivial_Merge:
   __asm
   {
        // Note: One array is empty means no need to merge.
        popad
        ret
   };

First_Array_Over:
   __asm
   {
        // Copy the rest of the second array to the temp arr
        // because the first array is empty
        pushad
        mov   EAX, EBX
        mov   ECX, EDX
        mov   EBX, temp_arr
        imul  EDI, 4
        add   EBX, EDI
        call  Copy_Array
        popad
        popad
        ret
   };

Second_Array_Over:
   __asm
   {
    // Copy the rest of the first array to the temp arr
    // because the second array is empty
    pushad
    mov   EBX, temp_arr
    imul  EDI, 4
    add   EBX, EDI
    call  Copy_Array
    popad
    popad
    ret
   }; 
Copy_Array:
   __asm
   {
    // Copy array to destination array
    // EAX - Array start
    // EBX - Destination array
    // ECX - Array length

    // Trivial case
    cmp   ECX, 0
    jz    Copy_Empty_Array

    push  ECX
    sub   EDI, EDI
   };
copy_loop:
   __asm
   {
    // Copy each element
    push  dword ptr [EAX + EDI * 4]
    pop   dword ptr [EBX + EDI * 4]
    inc   EDI
    loop  copy_loop

    pop   ECX
    ret
   };

Copy_Empty_Array:
   __asm
   {
    ret
   };

Read_Arr:
   __asm
   {
        // EAX - array start
        // ECX - array length
        mov   ESI, EAX
        sub   EDI, EDI
   };
loop1:
   __asm
   {
        // Read each element
        lea eax,[esi+edx*4]
        inc   EDI
        loop  loop1
        ret
   };

    return 0;
}
4

2 に答える 2

3

(更新:質問に投稿された元のコードでは、メモリを としてアドレス指定しようとする試みがありましたDWORD [address]。これは、以下の回答で指摘しているように、Visual C++ のインライン アセンブラーで使用される構文と互換性がありません。)

DWORD PTRVisual C++ はインライン アセンブリに MASM 構文を使用するため、単に の代わりにを使用する必要がありますDWORD。それがこれらのコンパイルエラーの原因です。

たとえば、The Art of Assembly のこの表を参照してください。

于 2013-01-12T18:29:45.477 に答える
1

これは、コードがこの github リポジトリからのもののようです。

そのコードでGetLIntは、実際には外部マクロ定義ファイルに含まれる NASM マクロであり、関数を呼び出します。関数proc_GetLIntはオブジェクト ファイルio.oで提供されますが、ソース コードはありません。したがって、問題は単純に

  • GetLintあなたが見逃している外部コードであることを認識していませんでした

  • そのリポジトリからすべてのファイルを取得したとしても、NASM マクロは VC++ インライン アセンブリで直接動作しないため、動作します。

  • マクロの問題を修正したとしても、GetLInt関数は Linux オブジェクト ファイルとしてのみ提供されているため、自分で作成する必要があります。


これをどのように修正しますか?

このコードは、すべての入出力を単独で処理する自己完結型のアセンブラー プログラムを提供することを目的としていました。VC++ でインライン化しているので、既にはるかに強力な I/O 処理を手に入れることができます。arr代わりにそれらを使用してください。つまり、インライン アセンブリを開始する前に、並べ替えたい値が既に含まれていることを確認してください。

次に、コードを見るとMerge_Sort、配列の開始が でEAX、長さが であることが期待されECXます。C++ コードから両方を取得できます。READ_ARR_LENこれを行うと、アセンブラー コードのandGET_ARRAYブロックは不要になります。

コードの一部を変更して複製するのは気が進まないのですが、github でライセンス ファイルを見つけることができないため、そうしてもよいと言っているのです。説明してみましょう:アセンブラ ルーチンの最初で、へのポインタとarrEAXの内容を手動で移動する必要があります。(*) ご覧のとおり、配列に数値を入力する処理は既に完了しているため、何もする必要はありません。ARRAYSIZEEBX

次に、不要なアセンブラー関数とそれらへの呼び出しをすべて削除する必要があります。__asmまた、すべての個別のブロックを 1 つに凝縮するか、外部変数を使用してブロック間のレジスタを保存および復元する必要があります (または、こちらのチュートリアルを読んでください。ただし、1 つのブロックを使用するだけで機能し、手間がかかりません)。

最後に、スタック フレームに注意する必要がありcallますret。マージソート手順は再帰的であるため、これは簡単につまずきます。

(*) asm ブロック内の変数を扱う VC++ の方法に注意してください。必要な場合は実際にポインターを使用してください。

全体として、これを VC++ に移植するのは簡単な作業ではありません。

于 2013-01-13T18:19:32.057 に答える