简体   繁体   English

内联汇编代码无法在Visual C ++ 2010 Express中编译

[英]Inline Assembly Code Does Not Compile in Visual C++ 2010 Express

I have some assembly merge sort code that I obtained from Github and I am trying to embed it into Inline Assembly in C++, but it won't compile and keeps returning these errors: 我有一些我从Github获得的汇编合并排序代码,我试图将它嵌入到C ++的Inline Assembly中,但它不会编译并继续返回这些错误:

1>c:\\users\\mayank\\desktop\\assembly\\assembly\\main.cpp(147): error C2415: improper operand type 1> c:\\ users \\ mayank \\ desktop \\ assembly \\ assembly \\ main.cpp(147):错误C2415:操作数类型不正确

The code that I am attempting to run is this: 我试图运行的代码是这样的:

#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;
}

( Update: In the original code posted in the question there were attempts to address memory as DWORD [address] , which is incompatible with the syntax used by Visual C++'s inline assembler as I point out in my answer below.) 更新:在问题中发布的原始代码中,尝试将内存作为DWORD [address] ,这与Visual C ++的内联汇编程序使用的语法不兼容,正如我在下面的答案中指出的那样。)

Visual C++ uses MASM syntax for its inline assembly, so you need to use DWORD PTR instead of just DWORD . Visual C ++使用MASM语法进行内联汇编,因此您需要使用DWORD PTR而不仅仅是DWORD That's what's causing these compilation errors. 这就是造成这些编译错误的原因。

See eg this table from The Art of Assembly. 参见例如The Art of Assembly的这张表

This looks like the code is from this github repository . 这看起来像是来自这个github存储库的代码。

In that code, GetLInt is actually a NASM macro which is included in an external macro definition file and calls a function proc_GetLInt , which in turn is provided in an object file io.o , the source code is not there. 在该代码中, GetLInt实际上是一个NASM宏,它包含在外部宏定义文件中并调用一个函数proc_GetLInt ,而函数proc_GetLInt又在目标文件io.o ,源代码不存在。 The problem is therefore simply that 因此问题就在于此

  • you didn't realize that GetLint is external code that you're missing 你没有意识到GetLint是你缺少的外部代码

  • even if you took all files from that repository, it would work because NASM macros don't work directly in VC++ inline assembly 即使您从该存储库中获取了所有文件,它也可以工作,因为NASM宏不能直接在VC ++内联汇编中工作

  • even if you fixed the macro problem, you still don't have the GetLInt function because it is provided as a linux object file only, you'd have to write it yourself 即使您修复了宏问题,您仍然没有GetLInt函数,因为它仅作为linux对象文件提供,您必须自己编写


How do you fix this? 你是如何解决这个问题的?

That code was meant to provide a self-contained assembler program that handles all input/output on its own. 该代码旨在提供一个独立的汇编程序,它自己处理所有输入/输出。 Since you're inlining it in VC++, you have much more powerful I/O handling at your hands already. 由于您使用VC ++进行内联,因此您已经掌握了更强大的I / O处理能力。 Use those instead, ie make sure that the values you want to sort are already in arr before the inline assembly starts. 请改用它们,即确保arr联汇编开始之前,您要排序的值已经在arr

Then, looking at the code: Merge_Sort expects the start of your array in EAX , and its length in ECX . 然后,查看代码: Merge_Sort期望在EAX启动数组,并在ECX它的长度。 You can get both from your C++ code. 您可以从C ++代码中获取这两者。 When you do that, you no longer need the READ_ARR_LEN and GET_ARRAY blocks from the assembler code. 执行此操作时,不再需要汇编程序代码中的READ_ARR_LENGET_ARRAY块。

I am rather reluctant to reproduce parts of the code with modifications as I cannot find a licence file on github that would say I may do so. 我不太愿意通过修改来重现代码的一部分,因为我在github上找不到一个许可文件,可能会说我可能会这样做。 Let me try to describe: You need to manually move the pointer to arr into EAX and the content of ARRAYSIZE into EBX at the very start of the assembler routine. 让我试着描述一下:在汇编程序例程的最开始,你需要手动将指向arr的指针移动到EAX ,并将ARRAYSIZE的内容移动到EBX中。 (*) As I can see, you have already taken care of filling the array with numbers, so there's nothing you need to do there. (*)正如我所看到的,你已经注意用数字填充数组,所以你不需要做任何事情。

Then you need to remove all unnecessary assembler functions and calls to them. 然后,您需要删除所有不必要的汇编程序函数并调用它们。 You also should either condense all your separate __asm blocks into one or use external variables to conserve and restore registers between blocks ( or read the tutorial here , but just using one block works and is less hassle). 您还应该将所有单独的__asm块压缩为一个或使用外部变量来保存和恢复块之间的寄存器( 或者在此处阅读教程 ,但只使用一个块工作并且不那么麻烦)。

Finally, you have to be careful with the stack frames: every call has to have a matching ret . 最后,您必须小心堆栈帧:每个call必须具有匹配的ret This is easy to stumble over as the merge sort procedure is recursive. 由于合并排序过程是递归的,因此很容易发生这种情况。

(*) Careful with VC++'s way of treating variables in inside asm blocks, be sure to actually use pointers when you need them. (*)小心VC ++处理内部asm块中的变量的方法,确保在需要时实际使用指针。

So all in all, porting this to VC++ is not a trivial task. 总而言之,将其移植到VC ++并不是一项简单的任务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM