C 使用MinGW使用浮点值调用约定时出错
我试图使用汇编函数处理C代码,发现MinGw不遵循浮点值的调用约定,这与MinGw的版本不同 带有单函数Test.c的测试文件C 使用MinGW使用浮点值调用约定时出错,c,gcc,assembly,mingw,gnu-assembler,C,Gcc,Assembly,Mingw,Gnu Assembler,我试图使用汇编函数处理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; }; 浮点结果
#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;
};
浮点结果存储到ST0寄存器,而不是像在linux上那样存储到xmm0
但在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"
正如预期的那样,只有两条指令,xmm0中的args、xmm1和xmm0的结果
但是,使用这个mingw,来自C代码的函数调用在rax和rdx寄存器中有错误的参数
我的集会
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寄存器,导致程序崩溃
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)
0x401614 0f 28 45 e0 movaps-0x20(%rbp),%xmm0
0x401618 0f 29 85 40 ff ff ff movaps%xmm0,-0xc0(%rbp)
0x40161f 0f 28 45 d0 movaps-0x30(%rbp),%xmm0
0x401623 0f 29 85 30 ff ff ff movaps%xmm0,-0xd0(%rbp)
0x40162a 48 8d 95 30 ff ff ff lea-0xd0(%rbp),%rdx
0x401631 48 8d 85 40 ff ff ff lea-0xc0(%rbp),%rax
0x401638 48 89 c1移动%rax,%rcx
0x40163b e8 d4 29 00 00呼叫0x404014
0x40164066 0f 7e c0移动%xmm0,%eax
0x401644 89 45 cc mov%eax,-0x34(%rbp)
我的代码出了什么问题,是MinGW编译器的错误吗?比较MinGW 32位和MinGW 64位二进制是错误的,因此当使用最新的MinGW-w64编译时,所有调用约定都如预期的那样。第一个代码是32位。惯例是使用
st0
返回浮点数。第二个代码是64位的windows惯例(这并不奇怪,因为mingw是windows的)。谢谢,为什么第二个错误@开玩笑没错。你怎么认为这是错的?您知道windows使用的约定与linux/sysv不同,对吧?它会在movd%xmm0,%eax行上使我的程序崩溃。但是float args去xmm寄存器并从xmm返回,或者不去?这不是我要说的代码。你的函数(我算是第三个代码)被破坏了,因为它没有遵循调用约定。此外,故障不能出现在+224
,因为该指令不能出现故障。
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);
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)