c – 汇编中的float数组
我在程序集x86中实现一个函数,从C程序调用,添加一个float数组.函数的第一个参数是指向数组的指针,第二个参数是元素的数量.当我在
linux中运行代码时,我遇到了分段错误.我做错了什么?
.text .globl floatsum floatsum: push %ebp movl %esp,%ebp movl 8(%ebp),%eax movl 12(%ebp),%edx shrl $2,%edx xorps %xmm0,%xmm0 loop: testl %edx,%edx je end movaps (%eax),%xmm1 addps %xmm1,%xmm0 addl $16,%eax decl %edx jmp loop end: # 3 2 1 0 movaps %xmm0,%xmm1 # xmm0: w z y x # xmm1: z w x y shufps $0xb1,%xmm1,%xmm1 # 10 11 00 01 = 0xb1 addps %xmm1,%xmm0 # xmm0: w+z z+w y+x x+y movaps %xmm0,%xmm1 # xmm1: w+z z+w y+x x+y # xmm1: x+y y+x z+w w+z shufps $0x1b,%xmm1 # 00 01 10 11 = 0x1b addps %xmm1,%xmm0 # xmm0: w+z+x+y z+w+y+x y+x+z+w x+y+w+z # #movd %xmm0,%eax #pushl %eax finst: flds (%esp) popl %eax movl %ebp,%esp popl %ebp ret // C代码 #include <stdio.h> #include <stdlib.h> float floatsum(float *array,size_t number_of_items); float floatsum_c(float *array,size_t number_of_items){ float sum; size_t i; sum=0.0; for(i=0; i<number_of_items;i++){ sum+=array[i]; } return sum; } float * create_array(size_t number_of_items){ float *array; size_t i; array=calloc(number_of_items,sizeof(float)); if(array){ for(i=0; i<number_of_items; i++){ array[i]=1.0+(float)i; } } return array; } int main(int argc,char **argv){ float *a; float result; size_t number_of_items,i; number_of_items=8; a=create_array(number_of_items); if(a){ result=floatsum_c(a,number_of_items); printf("Sum (c version): %fn",result); result=floatsum(a,number_of_items); printf("Sum (asm version): %fn",result); free(a); } return 0; } 解决方法
正如保罗所说,这可能是一个对齐问题.从C代码可以清楚地看出,您的浮点数组不能保证在16字节边界上对齐.失败就是这一行:
movaps (%eax),%xmm1 原因是MOVAPS有这个要求:
由于您使用的是128位向量寄存器,因此需要16字节对齐.你有两个选择: >将MOVAPS更改为MOVUPS,以便可以完成未对齐的内存访问 第一个解决方案需要: movaps (%eax),%xmm1 被改为 movups (%eax),%xmm1 第二种解决方案是避免使用calloc并使用允许您创建16字节对齐对象的函数.如果使用C11,则可以使用功能aligned_alloc和memset将阵列归零.您的create_array可能如下所示: float * create_array(size_t number_of_items) { float *array = NULL; size_t i; array=(float *)aligned_alloc(16,number_of_items * sizeof(*array)); if(array){ memset (array,0x00,number_of_items * sizeof(*array)); for(i=0; i<number_of_items; i++){ array[i]=1.0+(float)i; } } return array; } 如果您不使用C11,可以在Linux上使用POSIX功能posix_memalign和memset.代码看起来像: float * create_array(size_t number_of_items) { float *array = NULL; size_t i; if (!posix_memalign((void **)&array,16,number_of_items * sizeof(*array))){ memset (array,number_of_items * sizeof(*array)); for(i=0; i<number_of_items; i++){ array[i]=1.0+(float)i; } } return array; } 您还必须取消注释这些行: #movd %xmm0,%eax #pushl %eax 这样它们就会出现: movd %xmm0,%eax pushl %eax 注意:尽管我使用memset将float数组归零,但是在代码中实际上并不需要它,因为之后将所有元素初始化为特定值.在您的情况下,可以删除对memset的调用. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |