我在编译汇编代码(nasm)时遇到麻烦。

在Linux(elf32)上,使用g++编译后它不会失败,但是当我尝试使用i686-w64-mingw32-g++(对于Win32)进行构建时,它失败了。

我的build.sh脚本:

#!/bin/bash

nasm -fwin32 wct.asm
i686-w64-mingw32-g++ -m32 -O2 -Wall -fno-exceptions -ffloat-store -ffast-math -fno-rounding-math -fno-signaling-nans -fcx-limited-range -fno-math-errno -funsafe-math-optimizations -fassociative-math -freciprocal-math -ffinite-math-only -fno-signed-zeros -fno-trapping-math -frounding-math -fsingle-precision-constant -fcx-fortran-rules -fno-rtti -mfpmath=387 -mfancy-math-387 -fno-ident -fmerge-all-constants -mpreferred-stack-boundary=2 -falign-functions=1 -falign-jumps=1 -falign-loops=1 -fno-unroll-loops -fno-math-errno -s main.cpp wct.obj -o wct.exe
strip --strip-unneeded wct.exe

有汇编代码:
   [bits 32]
   section .text
   global wct

   wct:

    mov esi, [esp+4]
    mov edi, esi
    mov ecx, [esp+8]

    @L:
            lodsw
            sub ax, 04141h

            cmp al,0Fh
            jne @F
            dec al
            jmp @E
            @F:
            cmp al,0Eh
            jne @E
            inc al
            @E:

            mov bx, ax
            shr bx, 8

            cmp bl,0Fh
            jne @@F
            dec bl
            jmp @@E
            @@F:
            cmp bl,0Eh
            jne @@E
            inc bl
            @@E:

            shl al, 4
            add ax, bx
            stosb
    loop @L
    ret

main.cpp:
#include <fstream>

using namespace std;

extern "C" int wct(char* buff, int N);

#define N 1024*1024

char buff[N];
ifstream in;
ofstream out;
int size;

int main(int argc, char* argv[]) {

    if ( argc == 1 ) return 0;

    in.open(argv[1], ios_base::in | ios_base::binary);

    if ( argc >= 3 )
        out.open(argv[2], ios_base::out | ios_base::binary);

    if( in.is_open())
    {
        while(!in.eof())
        {
            in.read((char *)&buff, sizeof buff);
            size = in.gcount()/2;
            wct((char *)&buff, size);

            if ( out.is_open())
                out.write((char *)&buff, size);
            else
            {
                out.close();
            }
        }
    }

    in.close();
    out.close();

    return 0;
}

我显然做错了,因为使用build.sh脚本时总是遇到相同的错误:
/tmp/cc3SD7dA.o:main.cpp:(.text.startup+0x90): undefined reference to `wct'
collect2: error: ld returned 1 exit status

我该如何解决?

最佳答案

在Windows上,GCC编译器期望外部符号中使用下划线。因此,将asm文件中的所有wct更改为_wct

如果要在Windows和Linux中测试程序,则可以“全局化”两个连续的标签:wct_wct:

...
global wct
global _wct
...
wct:
_wct:
...

Linux获取不带下划线的wct,Windows附带它。

顺便说一句:汇编过程是C函数,必须遵循CDECL calling convention。该函数可以自由更改寄存器EAXECXEDX(保存了调用者)。其他寄存器(EBXESIEDIEBP)必须保持不变。如果该功能需要使用它们,则必须保存并还原它们(已保存被调用者):
wct:
_wct:

 push esi                ; sp+= 4
 push edi                ; sp+= 4
 push ebx                ; sp+= 4
                        ; ======
                        ; sp+= 12
 mov esi, [esp+16]
 mov edi, esi
 mov ecx, [esp+20]

 ...

 pop ebx
 pop edi
 pop esi
 ret

08-28 05:37