方阵乘法汇编程序出现Segmentation fault错误,求助定位修复
方阵乘法汇编程序段错误分析与修复
错误原因分析
栈帧基址寄存器ebp被非法修改
程序初始化时通过movl %esp, %ebp建立栈帧,后续在matrix_loop中执行movl $0, %ebp将ebp清零。原本20(%ebp)用于获取参数N,此时ebp为0,[ebp+0x14]指向0x14这个非法内存地址,直接触发段错误。矩阵乘法逻辑完全错误
当前内循环仅遍历A和B的同一偏移元素相乘,不符合矩阵乘法的规则——矩阵C的元素C[i][j]应该是A的第i行与B的第j列对应元素相乘后的累加和。循环计数器冲突
外层循环使用eax作为计数器,但eax在内循环中被用来存储A的元素值,执行incl %eax会破坏外层循环的计数逻辑。
修复方案
修正后的汇编代码
matrix_mult: pushl %ebp # 保存ebp到栈,建立栈帧前的准备 movl %esp, %ebp # 初始化栈帧基址 pushl %ebx # 遵循cdecl调用约定,保存被调用者保存寄存器 pushl %esi pushl %edi movl 8(%ebp), %ebx # 获取矩阵A的基地址 movl 12(%ebp), %ecx # 获取矩阵B的基地址 movl 16(%ebp), %edx # 获取矩阵C的基地址 movl 20(%ebp), %edi # 获取方阵大小N xorl %eax, %eax # 外层循环计数器i(行号)初始化为0 matrix_loop: cmpl %edi, %eax jge end_matrix_loop # i >= N时退出外层循环 xorl %esi, %esi # 内层循环计数器j(列号)初始化为0 inner_loop: cmpl %edi, %esi jge end_inner_loop # j >= N时退出内层循环 # 准备计算C[i][j]:保存i、j到栈,初始化累加和sum=0 pushl %eax pushl %esi pushl $0 xorl %ecx, %ecx # sum循环计数器k初始化为0 sum_loop: cmpl %edi, %ecx jge end_sum_loop # 读取A[i][k]:地址 = A + (i*N + k)*4 movl 8(%esp), %edx # 取出i leal (%edx,%edi,1), %edx # 计算i*N addl %ecx, %edx # i*N + k movl (%ebx,%edx,4), %edx # 读取A[i][k] # 读取B[k][j]:地址 = B + (k*N + j)*4 movl 4(%esp), %eax # 取出j leal (%ecx,%edi,1), %eax # 计算k*N addl 4(%esp), %eax # k*N + j movl (%ecx,%eax,4), %eax # 读取B[k][j] mull %edx # 计算A[i][k] * B[k][j],结果低32位在eax addl %eax, (%esp) # 累加到sum incl %ecx jmp sum_loop end_sum_loop: # 将sum写入C[i][j]:地址 = C + (i*N + j)*4 movl (%esp), %eax # 取出sum movl 8(%esp), %ecx # 取出i leal (%ecx,%edi,1), %ecx # i*N addl 4(%esp), %ecx # i*N + j movl %eax, (%edx,%ecx,4) # 写入C[i][j] # 恢复寄存器,继续循环 addl $4, %esp # 弹出sum popl %esi popl %eax incl %esi # j++ jmp inner_loop end_inner_loop: incl %eax # i++ jmp matrix_loop end_matrix_loop: # 恢复被调用者保存寄存器,销毁栈帧 popl %edi popl %esi popl %ebx popl %ebp ret
关键修改说明
保护栈帧基址ebp
全程不再修改ebp,所有参数访问(如12(%ebp)获取B的指针)都基于原始栈帧,彻底避免非法内存访问导致的段错误。实现正确的矩阵乘法逻辑
新增sum_loop循环,遍历k从0到N-1,计算A的第i行与B的第j列对应元素的乘积并累加,符合矩阵乘法的数学定义。规范寄存器管理
- 遵循cdecl调用约定,保存并恢复ebx、esi、edi这些被调用者保存寄存器,避免破坏调用者的寄存器状态。
- 为不同循环分配独立的计数器寄存器:外层用eax(i)、内层用esi(j)、sum循环用ecx(k),避免寄存器冲突覆盖。
修正内存寻址
正确计算矩阵元素的内存地址:对于N阶方阵,元素M[x][y]的地址为基地址 + (x*N + y)*4(假设每个元素是4字节的32位整数)。
内容的提问来源于stack exchange,提问作者dra_solo
相关产品推荐
相关产品推荐

