使用 MinGW 的浮点值调用约定错误
Wrong calling conventions with float values with MinGW
我正在尝试使用我的汇编函数处理 C 代码,发现 MinGw 不遵循浮点值的调用约定,这与 mingw 的版本不同。
单函数测试文件test.c
#include <xmmintrin.h>
float vector_dot(__m128 v1, __m128 v2)
{
__m128 resp = _mm_mul_ps(v1, v2);
float res;
_mm_store_ss(&res, resp);
return res;
};
编译成程序集
gcc -O -S test.c -msse4.1
.file "test.c"
.text
.globl _vector_dot
.def _vector_dot; .scl 2; .type 32; .endef
_vector_dot:
LFB503:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl , %esp
mulps %xmm1, %xmm0
movss %xmm0, 12(%esp)
flds 12(%esp)
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE503:
.ident "GCC: (MinGW.org GCC-6.3.0-1) 6.3.0"
float 结果存储到 ST0 寄存器,而不是 xmm0,就像在 linux
上一样
但在不同版本的 MinGW 中:
.file "test.c"
.text
.globl vector_dot
.def vector_dot; .scl 2; .type 32; .endef
.seh_proc vector_dot
vector_dot:
.seh_endprologue
movaps (%rdx), %xmm0
mulps (%rcx), %xmm0
ret
.seh_endproc
.ident "GCC: (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 7.3.0"
只有 2 条指令,参数在 xmm0、xmm1 中,结果在 xmm0 中,正如预期的那样。
但是,对于这个 mingw,来自 C 代码的函数调用在 rax 和 rdx 寄存器中有错误的参数
我的assemble
vector_dot: /* vector xmm0, vector xmm1 -> float xmm0 */
mulps %xmm1,%xmm0
vector_horizontal_sum: /* vector xmm0 -> float xmm0 (0 + 1 + 2 + 3) */
movshdup %xmm0, %xmm1
addps %xmm1, %xmm0
movhlps %xmm0, %xmm1
addss %xmm1, %xmm0
ret
C 中的函数头文件
extern float vector_dot(__m128 vector_1, __m128 vector_2) asm("vector_dot");
正在调用我的函数
float values1[] __attribute__((aligned(16))) = { 1.3f, 5.4f, -4.f, 5. } ;
__m128 vec1 = _mm_load_ps(values1);
float values2[] __attribute__((aligned(16))) = {0.5f, -43.5f, 0, 0 };
__m128 vec2 = _mm_load_ps(values2);
float dot = vector_dot(vec1, vec2);
函数调用程序集,编译器未将 xmm 寄存器用于 args,导致我的程序崩溃
0x401614 <+ 180> 0f 28 45 e0 movaps -0x20(%rbp),%xmm0
0x401618 <+ 184> 0f 29 85 40 ff ff ff movaps %xmm0,-0xc0(%rbp)
0x40161f <+ 191> 0f 28 45 d0 movaps -0x30(%rbp),%xmm0
0x401623 <+ 195> 0f 29 85 30 ff ff ff movaps %xmm0,-0xd0(%rbp)
0x40162a <+ 202> 48 8d 95 30 ff ff ff lea -0xd0(%rbp),%rdx
0x401631 <+ 209> 48 8d 85 40 ff ff ff lea -0xc0(%rbp),%rax
0x401638 <+ 216> 48 89 c1 mov %rax,%rcx
0x40163b <+ 219> e8 d4 29 00 00 callq 0x404014 <vector_dot>
0x401640 <+ 224> 66 0f 7e c0 movd %xmm0,%eax
0x401644 <+ 228> 89 45 cc mov %eax,-0x34(%rbp)
我的代码有什么问题,是 MinGW 编译器错误吗?
比较 mingw 32 位和 mingw 64 位二进制文件是错误的,因此当使用最新的 mingw-w64 编译时,所有调用约定都符合预期。
我正在尝试使用我的汇编函数处理 C 代码,发现 MinGw 不遵循浮点值的调用约定,这与 mingw 的版本不同。
单函数测试文件test.c
#include <xmmintrin.h>
float vector_dot(__m128 v1, __m128 v2)
{
__m128 resp = _mm_mul_ps(v1, v2);
float res;
_mm_store_ss(&res, resp);
return res;
};
编译成程序集
gcc -O -S test.c -msse4.1
.file "test.c"
.text
.globl _vector_dot
.def _vector_dot; .scl 2; .type 32; .endef
_vector_dot:
LFB503:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl , %esp
mulps %xmm1, %xmm0
movss %xmm0, 12(%esp)
flds 12(%esp)
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE503:
.ident "GCC: (MinGW.org GCC-6.3.0-1) 6.3.0"
float 结果存储到 ST0 寄存器,而不是 xmm0,就像在 linux
上一样但在不同版本的 MinGW 中:
.file "test.c"
.text
.globl vector_dot
.def vector_dot; .scl 2; .type 32; .endef
.seh_proc vector_dot
vector_dot:
.seh_endprologue
movaps (%rdx), %xmm0
mulps (%rcx), %xmm0
ret
.seh_endproc
.ident "GCC: (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 7.3.0"
只有 2 条指令,参数在 xmm0、xmm1 中,结果在 xmm0 中,正如预期的那样。
但是,对于这个 mingw,来自 C 代码的函数调用在 rax 和 rdx 寄存器中有错误的参数
我的assemble
vector_dot: /* vector xmm0, vector xmm1 -> float xmm0 */
mulps %xmm1,%xmm0
vector_horizontal_sum: /* vector xmm0 -> float xmm0 (0 + 1 + 2 + 3) */
movshdup %xmm0, %xmm1
addps %xmm1, %xmm0
movhlps %xmm0, %xmm1
addss %xmm1, %xmm0
ret
C 中的函数头文件
extern float vector_dot(__m128 vector_1, __m128 vector_2) asm("vector_dot");
正在调用我的函数
float values1[] __attribute__((aligned(16))) = { 1.3f, 5.4f, -4.f, 5. } ;
__m128 vec1 = _mm_load_ps(values1);
float values2[] __attribute__((aligned(16))) = {0.5f, -43.5f, 0, 0 };
__m128 vec2 = _mm_load_ps(values2);
float dot = vector_dot(vec1, vec2);
函数调用程序集,编译器未将 xmm 寄存器用于 args,导致我的程序崩溃
0x401614 <+ 180> 0f 28 45 e0 movaps -0x20(%rbp),%xmm0
0x401618 <+ 184> 0f 29 85 40 ff ff ff movaps %xmm0,-0xc0(%rbp)
0x40161f <+ 191> 0f 28 45 d0 movaps -0x30(%rbp),%xmm0
0x401623 <+ 195> 0f 29 85 30 ff ff ff movaps %xmm0,-0xd0(%rbp)
0x40162a <+ 202> 48 8d 95 30 ff ff ff lea -0xd0(%rbp),%rdx
0x401631 <+ 209> 48 8d 85 40 ff ff ff lea -0xc0(%rbp),%rax
0x401638 <+ 216> 48 89 c1 mov %rax,%rcx
0x40163b <+ 219> e8 d4 29 00 00 callq 0x404014 <vector_dot>
0x401640 <+ 224> 66 0f 7e c0 movd %xmm0,%eax
0x401644 <+ 228> 89 45 cc mov %eax,-0x34(%rbp)
我的代码有什么问题,是 MinGW 编译器错误吗?
比较 mingw 32 位和 mingw 64 位二进制文件是错误的,因此当使用最新的 mingw-w64 编译时,所有调用约定都符合预期。