尝试使用 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 x86 标签 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 可执行文件,因为 strace
和 gdb
将可以直接使用。
在这种情况下,您可以这样做:
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.
我正在尝试使用命令编译以下汇编代码:
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 x86 标签 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 可执行文件,因为 strace
和 gdb
将可以直接使用。
在这种情况下,您可以这样做:
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.