尝试使用 AVX 汇编文件编译 x86

Trying to compile x86 with AVX assembly file

我正在尝试使用命令编译以下汇编代码:

nasm -f elf AvxScalarFloatingPointArithmetic_.asm

汇编代码:

    .model flat,c
        .const
AbsMask qword 7fffffffffffffffh, 7fffffffffffffffh
        .code

; extern "C" void AvxSfpArithmetic_(double a, double b, double results[8]);
;
; Description:  The following function demonstrates how to use basic
;               scalar DPFP arithmetic instructions.
;
; Requires:     AVX

AvxSfpArithmetic_ proc
        push ebp
        mov ebp,esp

; Load argument values
        mov eax,[ebp+24]                    ;eax = ptr to results array
        vmovsd xmm0,real8 ptr [ebp+8]       ;xmm0 = a
        vmovsd xmm1,real8 ptr [ebp+16]      ;xmm1 = b

; Perform basic arithmetic using AVX scalar DPFP instructions
        vaddsd xmm2,xmm0,xmm1               ;xmm2 = a + b
        vsubsd xmm3,xmm0,xmm1               ;xmm3 = a - b
        vmulsd xmm4,xmm0,xmm1               ;xmm4 = a * b
        vdivsd xmm5,xmm0,xmm1               ;xmm5 = a / b
        vmovsd real8 ptr [eax+0],xmm2       ;save a + b
        vmovsd real8 ptr [eax+8],xmm3       ;save a - b
        vmovsd real8 ptr [eax+16],xmm4      ;save a * b
        vmovsd real8 ptr [eax+24],xmm5      ;save a / b

; Compute min(a, b), max(a, b), sqrt(a) and fabs(b)
        vminsd xmm2,xmm0,xmm1               ;xmm2 = min(a, b)
        vmaxsd xmm3,xmm0,xmm1               ;xmm3 = max(a, b)
        vsqrtsd xmm4,xmm0,xmm0              ;xmm4 = sqrt(a)
        vandpd xmm5,xmm1,xmmword ptr [AbsMask]  ;xmm5 = fabs(b)
        vmovsd real8 ptr [eax+32],xmm2      ;save min(a, b)
        vmovsd real8 ptr [eax+40],xmm3      ;save max(a, b)
        vmovsd real8 ptr [eax+48],xmm4      ;save sqrt(a)
        vmovsd real8 ptr [eax+56],xmm5      ;save trunc(sqrt(a))

        pop ebp
        ret
AvxSfpArithmetic_ endp
        end

不幸的是有一些错误:

AvxScalarFloatingPointArithmetic_.asm:1: error: attempt to define a local label before any non-local labels
AvxScalarFloatingPointArithmetic_.asm: error: parser: instruction expected
AvxScalarFloatingPointArithmetic_.asm:2: error: attempt to define a local label before any non-local labels
AvxScalarFloatingPointArithmetic_.asm:3: error: parser: instruction expected
AvxScalarFloatingPointArithmetic_.asm:13: error: parser: instruction expected

我该如何编译这个文件? 代码应该是正确的。摘自书本:"Modern X86 Assembly Language Programming: 32-bit, 64-bit, SSE, and AVX".

它看起来像 MASM 语法,而不是 NASM 语法。如果您知道 NASM 语法,那么移植到 NASM 就足够简单了,但是教您的内容超出了 SO 答案的范围。请参阅 the manual, and the 标签 wiki。

JWasm 是一个可移植的 MASM 语法汇编器,但要注意 ABI 差异。这样可以省去移植到NASM语法的麻烦,但是不能省去移植WindowsAPI/库调用到Linux系统调用/库调用的麻烦。

如果您从 C 执行所有 I/O 和其他系统调用,并在您的 asm 函数中进行数据处理,您会没事的(除了 Windows 和 Windows 之间的调用约定差异SystemV ABI)。

然而,如果你有直接使用 Windows API/library 函数的 asm 函数,那就更复杂了。那些 API 在 Linux 上不存在(除非我们谈论的是像 printf 这样的 C99 标准库函数)。

理论上你可以 运行 你的 Windows 代码在 wine 下,但你会更容易调试正常的 Linux 可执行文件,因为 stracegdb 将可以直接使用。


在这种情况下,您可以这样做:

default rel

section .rodata
AbsMask dq 7fffffffffffffffh, 7fffffffffffffffh

section .text
; extern "C" void AvxSfpArithmetic_(double a, double b, double results[8]);
global AvxSfpArithmetic
AvxSfpArithmetic:
       push ebp
       mov ebp,esp       ; you don't need to waste instructions on this stack frame crap, as you will soon learn.

; Load argument values
        ;mov eax,[esp+20]                    ;eax = ptr to results array
        vmovsd xmm0,  [ebp+8]       ;xmm0 = a
        vmovsd xmm1,  [ebp+16]      ;xmm1 = b
        ...

我刚刚删除了 real8 ptr,因为该指令暗示操作数大小很好。 qword [ebp+8] 可以。

如果您只想将该 AND 掩码加载到寄存器中(在循环之前)而不是直接从内存中使用它,您应该考虑使用 pcmpeqw xmm7,xmm7 / psrlq xmm7, 1.


在 64 位代码中,SystemV ABI(在 Linux 上使用)不同于 Windows,因此如果您书中的 64 位示例使用 Windows 调用约定,您将必须处理那个。您可以在 C 原型上使用 __attribute__((ms_abi))

32 位 SysV ABI 使用与 Window 基本兼容的调用,所有参数都在堆栈上。 IDK,如果它完全不同,例如对于结构 returns.