如何正确地将汇编文件与C++链接?

4

这是一个作业问题,我已经完成了所有的编码,但我在将汇编与C++链接时遇到了问题。我的操作系统是Windows Visual Studio 2010,我将主文件放在源文件中,将汇编文件放在资源文件中。当我尝试编译时,出现了链接错误。

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 ==========

这个作业的目标是使用索引方法和指针方法清除数组,然后优化生成的汇编代码。
请帮忙!!!
以下是我的代码: 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>------开始构建: 项目: clearArray, 配置: Debug Win32 ------ 1> clearArray.cpp 1>clearArray.obj : error LNK2019: 未解析的外部符号 _clearPointerOp,该符号在函数 _main 中被引用 1>clearArray.obj : error LNK2019: 未解析的外部符号 _clearIndexOp,该符号在函数 _main 中被引用 1>C:\Users\Joe Chen\documents\visual studio 2010\Projects\clearArray\Debug\clearArray.exe : 致命错误 LNK1120: 2 个无法解析的外部命令 ========== 构建: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ========== - iCodeLikeImDrunk
3个回答

9
问题是你的asm文件没有被视为源文件。
修复方法:
1)右键单击项目,选择“生成自定义”,然后勾选masm旁边的框。
2)右键单击.asm文件,选择属性,然后将项目类型更改为Microsoft Macro Assembler。
编辑#2:我现在看到你正在使用VS生成的修改过的asm代码,它几乎可以正常运行。
只需从PROC声明中删除“global”,然后在asm文件末尾添加END即可。
这应该能够正确地组装和链接asm。但是,看起来你可能在clearPointerOp中搞糊涂了,因为它最终会进入一个无限循环。一旦你的代码编译和链接成功,你应该能够从那里找到解决问题的方法。

你尝试过修复和运行它吗?以下是我逐步完成的过程,请告诉我是否有遗漏...
  1. 编写clearArray.cpp
  2. 生成clearIndex和clearPointer的汇编代码
  3. 拷贝clearIndex和clearPointer代码,为每个函数创建asm文件,并将它们重命名为clearIndexOp和clearPointerOp
  4. 将我创建的asm文件移动到项目的源代码文件夹里
  5. 使用生成自定义设置,检查masm(.targets, .props)
  6. 使用extern "C" functionName()调用它们的asm函数
  7. 运行它...
- iCodeLikeImDrunk
这是我修改后的代码,你能帮我检查一下吗?它仍然出现链接错误:( - iCodeLikeImDrunk
是的,正如我之前提到的,你修改后的clearPointerOp过程有问题。它进入了一个无限循环,因此它永远不会退出,因此你的C++代码永远不会达到写入文件的部分。我从Visual Studio中转储了clearPointer函数到汇编,并使用生成的代码,它可以正常工作。 - Gerald
非常感谢,我意识到我在寄存器方面做了一些愚蠢的事情...现在一切都正常了,非常感谢!!! - iCodeLikeImDrunk
我按照你说的做了,但还是出现了同样的错误。可能哪里出了问题? - David G

2

我认为汇编代码存在许多错误和低效之处,但首先,为什么不使用memset()标准的C函数呢?


我不是C++程序员,我的主要语言是Java/Perl,所以对此非常陌生,请问memset()是什么? - iCodeLikeImDrunk
1
我完全同意Mike的观点 - 如果你不懂C++或者C,那就别想着使用汇编代码。除非你有特定的性能需求需要使用汇编器 - 基本上最好别用! :-) - memset是标准的C/C++库中的实用函数 - 例如,你可以在这里了解它 http://www.cplusplus.com/reference/clibrary/cstring/memset/ - Adrian Cornish
2
哦,用有趣的方式来说 - Java不会让你弯下腰去咬自己的屁股,Perl - 如果你知道怎么做,你可以轻轻地咬一口,C++会让你咬上一口 - 可能致命,C会让你很容易地从你的屁股上咬下一个威胁生命的大块。但是汇编语言 - 你花费大部分时间试图阻止自己每次呼吸时都咬下致命的一块屁股。希望这有所帮助;-) - Adrian Cornish
哈哈..问题是我没有写汇编代码,它是从VS 2010生成的,我只是删除了一些/添加了一些行来“优化”它,因为它有一些无用的重复/通用行... - iCodeLikeImDrunk
1
如果你看了他的问题,他提到这是一个优化编译器生成的汇编代码的家庭作业。很可能不是他选择使用哪种语言 ;) - Gerald
为了消除错误...全局_clearPointerOp过程对我来说有点久远了,但必须有前导下划线吗?尝试将其删除。此外,clearPointerOp:末尾是否应该有冒号?global使其导出,但可能两者都需要。真的太久远了,无法从头脑中知道这一点... - Mike

1

好久没做了 - 但你似乎使用了 C 调用约定导入函数名称,这很好(去掉 C++ 名称修饰)。

一些问题:

  1. 你是否编译了 asm 文件并将它们链接为目标文件?
  2. 你是否检查了你正在使用的 c++ 编译器所使用的调用约定,并在你的汇编函数中匹配它们?

抱歉,我不知道,C++ 不是我的主要语言,所以我对如何链接它们等方面了解不多... =/ - iCodeLikeImDrunk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接