how do i properly link asm files to c++?

2019-02-14 18:50发布

问题:

this is a hw problem, ive done all the coding but im having trouble linking the asm with c++, im using windows visual studio 2010, i put the main in source files, and my asm files in the resources files, when i try to compiling it just gives me a linking error

1>------ Build started: Project: clearArray, Configuration: Debug Win32 ------ 
1>clearArray.cpp 
1>clearArray.obj : error LNK2019: unresolved external symbol _clearPointerOp referenced in function _main 
1>clearArray.obj : error LNK2019: unresolved external symbol _clearIndexOp referenced in function _main 
1>C:\Users\Joe Chen\documents\visual studio 2010\Projects\clearArray\Debug\clearArray.exe : fatal error LNK1120: 2 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

the objective of this hw was to clear an array using index method and pointer method, then optimize the generated asm code

please help!!!

heres my codes: main.cpp

// clear array using unoptimized code with index and pointers
#include<iostream>
#include<fstream>
#include"timer.h"

using namespace std;

extern "C" {void clearIndexOp(int A[], int size);}
extern "C" {void clearPointerOp(int *A, int size);}

const int size = 100000;
int A[size] = {0};

void clearIndex(int A[], int size)
{
    for(int i=0; i<size; i++)
        A[i]=0;
}

void clearPointer(int *A, int size)
{
    int *p;
    for(p=&A[0]; p<&A[size]; p++)
        *p=0;
}

int main()
{   
    double timeIndex = 0;
    double timeIndexOp = 0;
    double timePointer = 0;
    double timePointerOp = 0;
    StopWatch time;
    ofstream myfile;
    myfile.open("results.txt");

    for(int n=2000; n<1000000; n=n*2)
    {
        // put values into the array
        for(int i=0; i<size; i++)
            A[i]=i+rand()%10+1;

        time.startTimer();
        clearIndex(A, size);
        time.stopTimer();
        timeIndex =  time.getElapsedTime();

        // put values into the array
        for(int i=0; i<size; i++)
            A[i]=i+rand()%10+1;

        time.startTimer();
        clearPointer(A, size);
        time.stopTimer();
        timePointer = time.getElapsedTime();

        // put values into the array
        for(int i=0; i<size; i++)
            A[i]=i+rand()%10+1;

        time.startTimer();
        clearIndexOp(A, size);
        time.stopTimer();
        timeIndexOp =  time.getElapsedTime();

        // put values into the array
        for(int i=0; i<size; i++)
            A[i]=i+rand()%10+1;

        time.startTimer();
        clearPointerOp(A, size);
        time.stopTimer();
        timePointerOp = time.getElapsedTime();

        myfile << "n is now: " << n << "\n";
        myfile << "timeIndex is: " << timeIndex << "\n";
        myfile << "timePointer is: " << timePointer << "\n";
        myfile << "timeIndexOp is: " << timeIndexOp << "\n";
        myfile << "timePointerOp is: " << timePointerOp << "\n";        
    }
    myfile.close();
}

clearIndexOp.asm

.386
.model flat
.stack
.code

global _clearIndexOp proc
_i$ = -8                            ; size = 4
_A$ = 8                                 ; size = 4
_size$ = 12                             ; size = 4

; {
    push    ebp
    mov ebp, esp
    sub esp, 204                        ; 000000ccH
    push    ebx
    push    esi
    push    edi
    lea edi, DWORD PTR [ebp-204]
    mov ecx, 51                         ; 00000033H
    mov eax, -858993460                 ; ccccccccH
    rep stosd

; for(int i=0; i<size; i++)
; initialize the variables
    mov eax, 0                          ; init i=0 to eax
    mov ebx, DWORD PTR _size$[ebp]      ; size stored in ebx for faster access than memory
    mov ecx, DWORD PTR _A$[ebp]         ; get base addr of array
    jmp SHORT $LN3@clearIndex           ; jump into the loop
$LN2@clearIndex:
    add eax, 1                          ; increase eax since eax=i
$LN3@clearIndex:
    cmp eax, ebx                        ; check that i < size
    jge SHORT $LN4@clearIndex           ; exits if i >= size

; A[i]=0;
    mov DWORD PTR [ecx+eax*4], 0        ; A[i]=0
    jmp SHORT $LN2@clearIndex           ; go back to loop body

; after removing useless/repetitive codes 
; we shrunk this code from 10 instructions to only 5 instructions

$LN4@clearIndex:

; }
    pop edi
    pop esi
    pop ebx
    mov esp, ebp
    pop ebp
    ret 0
_clearIndexOp ENDP              

clearPointerOp.asm

.386
.model flat
.stack
.code

global _clearPointerOp proc 
_p$ = -8                                    ; size = 4
_A$ = 8                                     ; size = 4
_size$ = 12                                 ; size = 4

; {
    push ebp
    mov ebp, esp
    sub esp, 204                            ; 000000ccH
    push ebx
    push esi
    push edi
    lea edi, DWORD PTR [ebp-204]
    mov ecx, 51                             ; 00000033H
    mov eax, -858993460                     ; ccccccccH
    rep stosd

; int *p;
; for(p=&A[0]; p<&A[size]; p
; initialize the variables
    mov eax, DWORD PTR _A$[ebp]             ; base addr of the array
    mov DWORD PTR _p$[ebp], eax             ; init p = A[0]
    mov ebx, DWORD PTR _p$[ebp]             ; move p to ebx
    mov ecx, DWORD PTR _size$[ebp]          ; size stored in ecx for faster access from register
    lea edx, DWORD PTR [ecx+eax*4]          ; last index of array, A[size-1]
    jmp SHORT $LN3@clearPoint               ; jump into loop
$LN2@clearPoint:
    add eax, 4                              ; since it is pointer we increase eax by 4 to move to next element
$LN3@clearPoint:
    cmp ebx, edx                            ; check that p < size
    jae SHORT $LN4@clearPoint               ; exit if p >= size

; *p=0;
    mov DWORD PTR [ebx], 0
    jmp SHORT $LN2@clearPoint

; after removing useless/repetitive codes
; we shrunk this code from 11 instructions to only 5 instructions

$LN4@clearPoint:

; }
    pop edi
    pop esi
    pop ebx
    mov esp, ebp
    pop ebp
    ret 0
_clearPointerOp ENDP            

回答1:

The problem is your asm is not being treated as a source file.

To fix:

1) Right-click your project and choose Build Customizations, then check the box next to masm

2) Right-click your .asm files, choose Properties, then change the Item Type to Microsoft Macro Assembler.

Edit #2: I see now that you're using a modified version of the asm code generated by VS and it's almost okay.

Just remove "global" from the PROC declarations, and then add an END to the end of the asm files.

That should get the asm to assemble and link correctly. But it looks like you probably messed something up in clearPointerOp because it goes into an infinite loop at the end. You should be able to figure it out from there once your code is compiling and linking.



回答2:

I think I'm seeing a number of errors and inefficiencies in the asm code, but first, why not use the memset() standard C function?



回答3:

Been a long time since I had too - but you seem to have imported function names using C calling convention which is good (remove C++ name mangling).

Some questions:

  1. Did you compile the asm file and are linking them as object files
  2. Did you check the calling conventions used by the c++ compiler you are using and match them in you asm function