2013-01-12 2 views
1

Github에서 가져온 일부 어셈블리 병합 정렬 코드가 있는데이 코드를 C++의 인라인 어셈블리에 포함하려고 시도하지만 컴파일하지 않고 이러한 오류를 계속 반환합니다. :Visual C++ 2010 Express에서 인라인 어셈블리 코드가 컴파일되지 않음

1> C : \ 사용자 \ mayank 바탕 화면 \ 어셈블리 \ 조립 \의 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

왜 그렇게 많은 인라인 어셈블리가 필요합니까? 컴파일러가 코드를 적절하게 최적화 할 것이라고 믿지 않습니까? 유지 보수 할 수없는 코드에 대한 주물이 있습니까? –

+1

나는 두 가지 편집을했습니다 : 1) 동일한 오류가 N 번 반복되는 것을 걱정하지 않습니다. 2) 제목 : 문제는 코드가 실행되지 않는 것이 아니라 ** 컴파일되지 않는 것입니다 **. * 거대한 차이가 있으며 차이점을 이해하는 것이 중요합니다. –

+0

64 비트 컴파일러를 사용하고 있습니까? 그렇다면이 문제를 해결할 다른 방법을 찾아야합니다. 컴파일러가 생성하는 것보다 손으로 조립 된 병합 정렬을하는 것이 의미가 있다고 확신합니까? 그렇다면 pushad/popad를 사용하지 않으면 성능이 약간 향상 될 것입니다. –

답변

2

(업데이트 :. 나는 내 대답은 아래에 지적으로 비주얼 C++의 인라인 어셈블러에서 사용하는 구문과 호환되지 DWORD [address]로 메모리를 해결하기위한 시도가 있었다 질문에 게시 원래 코드에서)

Visual C++는 인라인 어셈블리에 MASM 구문을 사용하므로 DWORD 대신 DWORD PTR을 사용해야합니다. 이것이 컴파일 오류의 원인입니다.

this table에서 The Art of Assembly.

+0

정말 고맙습니다. 코드를 다시 컴파일하고 오류가 하나뿐입니다! 오류 : 1> c : \ users \ mayank \ desktop \ assembly \ assembly \ main.cpp (289) : 오류 C2400 : 'opcode'의 인라인 어셈블러 구문 오류; '[' – Mayankmmmx

+0

'GetLInt [ESI + EDI * 4]'줄을 발견했습니다. 나는'GetLInt'이 무엇이되어야한다고 확신하지 못합니다 (당신이 선언하고 다른 곳에 정의한 함수입니까?). 이 경우 x86 어셈블리에서 함수 호출을 수행하는 방법이 아닙니다. 'lea eax, [esi + edx * 4]/push eax/GetLInt'와 같은 함수를 호출해야하고, 그 함수가 표준 호출 규칙을 따른다면 반환 값은'eax'에 있어야합니다. READ_ARR_LEN : – Michael

+0

그것은이 코드 깜빡 밝혀 \t __asm ​​ \t { \t \t를 // 배열의 길이를 읽으 \t \t GetLInt 입력 배열 \t \t PutLInt의 // 크기 [30] \t [30 ] \t} 하지만 이제 코드를 실행하면 1> c : \ users \ mayank \ desktop \ assembly \ assembly \ main 오류가 발생합니다.cpp (31) : 오류 C2400 : 'opcode'의 인라인 어셈블러 구문 오류. 발견 '[' (선상에서 반복 32) I 개 코드 라인을 추가하기 때문에 (31, 32)은 : \t GetLInt [30] 입력 배열의 \t // 크기 \t PutLInt [30] 그리고 사람 내가 위의 편집을 만들었습니다. 297 줄은 : lea eax, [esi + edx * 4] call GetLInt – Mayankmmmx

1

코드가 this github repository 인 것처럼 보입니다. 그 코드에

, GetLInt 실제로 차례로 오브젝트 파일 io.o에서 제공되는 함수 proc_GetLInt를 외부 매크로 정의 파일에 포함 된 호출 된 NASM 매크로 인, 소스 코드는 없다. 문제는 단순히

  • 당신이 GetLint 당신이 NASM이 돈을 매크로로 때문에, 그것이 작동 것이라고 저장소에서 모든 파일을했다하더라도

  • 을 놓치고있어 외부 코드는 몰랐어요 그러므로 매크로 문제를 해결하는 경우 't는 당신이 자신에게 그것을

    를 작성해야 것, 그것은 단지 리눅스 오브젝트 파일로 제공되기 때문에 여전히 GetLInt 기능이없는,

  • 도 VC++ 인라인 어셈블리에서 직접 작업


어떻게 수정합니까?

그 코드는 모든 입력/출력을 자체적으로 처리하는 자체 포함 된 어셈블러 프로그램을 제공하기위한 것입니다. VC++로 인라이닝하고 있기 때문에 이미 훨씬 더 강력한 I/O 처리가 가능합니다. 대신 인라인 어셈블리를 시작하기 전에 정렬 할 값이 이미 arr에 있는지 확인하십시오.

코드를 보면 다음과 같습니다. Merge_Sort은 배열의 시작이 EAX이고 길이가 ECX이라고 가정합니다. 둘 다 C++ 코드에서 얻을 수 있습니다. 그렇게하면 더 이상 어셈블러 코드에서 READ_ARR_LENGET_ARRAY 블록이 필요하지 않습니다.

github에서 라이센스 파일을 찾을 수 없어 수정 된 코드의 일부를 재생하는 것이 다소 바람직하지 않습니다.먼저 포인터를 arr으로 수동으로 이동하여 EAX으로, ARRAYSIZEEBX으로 어셈블러 루틴의 맨 처음에 이동해야합니다. (*) 알 수 있듯이 이미 배열에 숫자를 채우는 일을 처리 했으므로 거기에서 수행 할 작업이 없습니다.

그런 다음 불필요한 어셈블러 함수와 호출을 모두 제거해야합니다. 또한 별도의 모든 __asm 블록을 하나로 압축하거나 블록간에 레지스터를 보존하고 복원하기 위해 외부 변수를 사용해야합니다 (or read the tutorial here,하지만 블록 하나만 사용하면 번거롭지 않음).

마지막으로 스택 프레임에주의해야합니다. call에는 일치 항목 ret이 있어야합니다. 병합 정렬 절차가 재귀 적이므로 쉽게 뒤죽박죽입니다.

(*) 내부 asm 블록에서 변수를 처리하는 VC++의 방법에주의를 기울여야 할 때 실제로 포인터를 사용해야합니다.

이렇게 모두 VC++로 이식하는 것은 쉬운 일이 아닙니다.

+0

예 Github 저장소의 코드를 소스로 사용하여 인라인 어셈블리를 테스트했습니다. 그리고 그것이 작동하지 않는 이유에 대해 훨씬 더 이해가됩니다. 나는 GetLInt 함수를 무엇으로 대체해야하는지에 대해서 당신이 무엇을 의미하는지 완전히 이해하지 못합니다. – Mayankmmmx

+0

@mayankmmmx : 와우, 와우. 귀하의 질문에, 당신은 주장 :'... 내가 C에서 인라인 어셈블리에서 쓴 + +. '. 나는 그 점에서 나는 조금 화가났다. 너는 그것을 분명하게 * 쓰지 않았다. – us2012

+0

나는 내가 그렇게 말한 것을 몰랐다. 내가 말하고자하는 것은 그것을 인라인 어셈블리로 번역한다는 것입니다. 사과 드리며 그 진술을 수정했습니다. 내 문제를 해결할 수 있도록 도와 주시겠습니까? – Mayankmmmx

관련 문제