gpt4 book ai didi

masm - 将 __m128d 从 MASM 过程返回给 C 调用者

转载 作者:行者123 更新时间:2023-12-04 04:30:20 24 4
gpt4 key购买 nike

我正在将一个函数从内联汇编移植到 Visual Studio 2013 中的 MASM,并且无法从中获取返回值。

这是 C 调用者和汇编函数原型(prototype):

extern "C" void AbsMax(__m128d* samples, int len, __m128d* pResult);

__m128d AbsMax(__m128d* samples, int len)
{
__m128d absMax = { 0, 0 };
AbsMax(samples, len, &absMax);
return absMax;
}

以及组装功能:
.686              ;Target processor.  Use instructions for Pentium class machines
.xmm

.model flat, c ;Use the flat memory model. Use C calling conventions
.code ;Indicates the start of a code segment.

AbsMax proc samples:PTR DWORD, len:DWORD, result:PTR XMMWORD
;; Load up registers. xmm0 is min, xmm1 is max. L is Ch0, H is Ch1.
mov ecx, [len]
shl ecx, 4
mov esi, [samples]
lea esi, [esi+ecx]
neg ecx
pxor xmm0, xmm0
pxor xmm1, xmm1

ALIGN 16
_loop:
movaps xmm2, [esi+ecx]
add ecx, 16
minpd xmm0, xmm2
maxpd xmm1, xmm2
jne _loop

;; Store larger of -min and max for each channel. xmm2 is -min.
pxor xmm2, xmm2
subpd xmm2, xmm0
maxpd xmm1, xmm2
movaps [result], xmm1 ; <=== access violation here

xor eax, eax
xor ebx, ebx
ret
AbsMax ENDP
END

据我了解 MASM 的约定,返回值通常通过 EAX 寄存器返回。但是,由于我试图返回一个 128 位的值,所以我假设 out 参数是可行的方法。正如您在程序集 list 中所见,分配 out 参数 ( movaps [result]) 会导致访问冲突(访问冲突读取位置 0x00000000)。我已经在调试器中验证了结果的地址,它看起来很好。

我究竟做错了什么?

最佳答案

出于教育目的,我编写了一个使用内在函数的函数版本:

#include <immintrin.h>

extern "C" void AbsMax(__m128d* samples, int len, __m128d* pResult)
{
__m128d min = _mm_setzero_pd();
__m128d max = _mm_setzero_pd();
while (len--)
{
min = _mm_min_pd(min, *samples);
max = _mm_max_pd(max, *samples);
++samples;
}
*pResult = _mm_max_pd(max, _mm_sub_pd(_mm_setzero_pd(), min));
}

然后我使用 VC++ x64 编译器使用 cl /c /O2 /FA absmax.cpp 进行编译。生成汇编列表(编辑以删除行注释):
; Listing generated by Microsoft (R) Optimizing Compiler Version 18.00.31101.0 
include listing.inc

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

PUBLIC AbsMax
_TEXT SEGMENT
samples$ = 8
len$ = 16
pResult$ = 24
AbsMax PROC ; COMDAT
xorps xmm3, xmm3
movaps xmm2, xmm3
movaps xmm1, xmm3
test edx, edx
je SHORT $LN6@AbsMax
npad 3
$LL2@AbsMax:
minpd xmm2, XMMWORD PTR [rcx]
maxpd xmm1, XMMWORD PTR [rcx]
lea rcx, QWORD PTR [rcx+16]
dec edx
jne SHORT $LL2@AbsMax
$LN6@AbsMax:
subpd xmm3, xmm2
maxpd xmm1, xmm3
movaps XMMWORD PTR [r8], xmm1
ret 0
AbsMax ENDP
_TEXT ENDS
END

注意 x64 使用 __fastcall默认约定,并在堆栈上隐藏参数,我看到 out 参数实际上是通过 r8 间接写入的,这是 x64 代码的第三个整数参数,根据 MSDN .我认为如果您的汇编代码采用此参数约定,它将起作用。

阴影堆栈空间未使用实际参数值进行初始化;它适用于被调用者,如果他们在使用寄存器时需要一个地方来存储值。这就是您的代码中出现零值取消引用错误的原因。调用约定不匹配。调试器知道调用约定,因此它可以向您显示参数的注册值。

关于masm - 将 __m128d 从 MASM 过程返回给 C 调用者,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27387055/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com