[英]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_LEN
和GET_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.