数组double元素无法加载至FP寄存器?汇编函数结果异常排查
点积函数汇编实现的问题排查与修复
问题描述
实现了C版本的点积函数,同时用x86 FPU汇编编写了同功能函数,但汇编版本始终返回0,调试时寄存器中显示随机数而非预期数组值,需要排查原因并修复,使汇编函数结果与C版本一致。
代码实现
C++点积函数
double fun_w22(double* xx, double* z, int N) { double result= 0.0; for (int i = 0; i < N; i++) { result+= xx[i] * z[i]; } return result; }
有问题的汇编实现
double fun_w22_asm(double* xx, double* z, int N) { double result= 0.0; __asm { mov ecx, N mov esi, xx mov edi, z fld [esi] fld [edi] fmul [esi] dec ecx petla: add esi, 8 add edi, 8 fld[esi] fmul[edi] fadd dec ecx jnz petla fstp result } return result; }
主函数调用
int main() { int N=3; double xx[] = { 1.0, 2.0, 3.0 }; // Sample array x double z[] = { 4.0, 5.0, 6.0 }; // Sample array z // Call the function to calculate the result double result = fun_w22(xx, z, N); double result1 = fun_w22_asm(xx, z, N); // Display the result std::cout << "Result: " << result << std::endl; std::cout << "Result ASM: " << result1 << std::endl; return 0; }
问题原因
- FPU栈操作逻辑错误:初始步骤错误地压入两个数组元素,且后续未清理冗余的栈元素,导致FPU栈不平衡,最终计算结果被异常覆盖或程序状态混乱。
- 累加器初始化缺失:未将累加器初始化为0,反而引入了额外的未参与计算的数值留在栈中,干扰最终结果。
- 乘法与累加逻辑混乱:第一次乘法操作的操作数匹配错误,后续
fadd操作未正确维护累加器的栈结构,导致计算过程中数值叠加错误。
修复后的汇编实现
double fun_w22_asm(double* xx, double* z, int N) { double result = 0.0; __asm { mov ecx, N mov esi, xx mov edi, z fldz ; 初始化FPU栈顶为0.0,作为累加器 test ecx, ecx ; 检查N是否为0,处理边界情况 jz end_loop ; N=0时直接跳至结束 petla: fld [esi] ; 加载当前xx数组元素到FPU栈顶 fmul [edi] ; 栈顶元素 = xx[i] * z[i] faddp st(1), st(0) ; 累加器(ST1) += 乘积(ST0),弹出栈顶,保持栈平衡 add esi, 8 ; 指针移动到下一个double元素(占8字节) add edi, 8 dec ecx jnz petla ; 计数器不为0则继续循环 end_loop: fstp result ; 将累加结果存入result,同时弹出栈顶,平衡FPU栈 } return result; }
修复说明
- 用
fldz直接初始化累加器为0.0,确保从正确的初始值开始计算。 - 统一通过循环处理所有元素,避免初始步骤的冗余错误操作,逻辑更简洁。
- 使用
faddp st(1), st(0)明确完成乘积与累加器的叠加,并维护FPU栈的平衡,避免栈溢出或数值残留。 - 增加边界判断,处理N=0的情况,避免无效循环。
- 确保指针每次移动8字节(对应double类型的长度),计数器递减逻辑正确。
修复后,汇编函数计算结果将与C++版本一致,对于测试用例返回32.0。
内容的提问来源于stack exchange,提问作者Biskopt
相关产品推荐
相关产品推荐

