x86 32位Linux汇编矩阵乘法程序出现无限循环,求排查
32位Linux下x86汇编矩阵乘法无限循环问题修复
在32位Linux环境中用x86汇编实现矩阵乘法时,三层for循环陷入无限循环,核心问题出在栈帧局部变量分配错误和循环条件逻辑颠倒,以下是具体分析与修复方案:
原代码
.data段
m1: .long 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0 m2: .long 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0 mres: .long 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 n: .long 4 fs: .asciz "%ld"
.text段(matrix_mult函数)
matrix_mult: pushl %ebp mov %esp, %ebp pushl %edi pushl %esi pushl %ebx subl $12, %ebp // -16(ebp) = i // -20(ebp) = j // -24(ebp) = k subl $8, %ebp // -28(ebp) = x // -32(ebp) = y locul unde stocam elem din cele 2 matrici movl $0, -16(%ebp) movl $0, -20(%ebp) movl $0, -24(%ebp) et_for1: mov -16(%ebp), %eax mov 20(%ebp), %ecx cmp %eax, %ecx jge final movl $0, -20(%ebp) et_for2: mov -20(%ebp), %eax mov 20(%ebp), %ecx cmp %eax, %ecx jge cont_for2 movl $0, -24(%ebp) et_for3: mov -24(%ebp), %eax mov 20(%ebp), %ecx cmp %eax, %ecx jge cont_for3 //mres[i][j]=m1[i][k]*m2[k][j] lea 8(%ebp), %edi lea 12(%ebp), %esi //ecx=i*n+k, ecx= indicele pt m1 mov -16(%ebp), %eax xorl %edx, %edx mull 20(%ebp) addl -24(%ebp), %eax mov %eax, %ecx //eax=k*n+j, eax= indicele pt m2 mov -24(%ebp) , %eax xorl %edx, %edx mull 20(%ebp) addl -20(%ebp), %eax //ecx = produsul termenilor mov (%edi, %ecx, 4), %ebx mov %ebx, -28(%ebp) mov (%esi, %eax, 4), %ebx mov %ebx, -32(%ebp) mov -28(%ebp), %eax xorl %edx, %edx mull -32(%ebp) mov %eax, %ecx //eax=i*n+j movl -16(%ebp), %eax xorl %edx, %edx mull 20(%ebp) movl -20(%ebp), %ebx addl %ebx, %eax //ecx= prod term + mres[i][j] lea 16(%ebp), %edi movl (%edi, %eax, 4), %ebx movl %ebx, -28(%ebp) addl -28(%ebp), %ecx movl %ecx, (%edi, %eax, 4) mov -24(%ebp), %ebx incl %ebx mov %ebx, -24(%ebp) //k++ jmp et_for3 cont_for3: mov -20(%ebp), %ebx incl %ebx mov %ebx, -20(%ebp) mov $0, -24(%ebp) //j++ si k=0 jmp et_for2 cont_for2: mov -16(%ebp), %ebx incl %ebx mov %ebx, -16(%ebp) //i++ jmp et_for1 final: addl $20, %esp popl %ebx popl %esi popl %edi popl %ebp ret
main函数
.global main main: pushl n pushl mres pushl m2 pushl m1 call matrix_mult addl $16, %esp lea mres, %edi mov $0, %ecx mov n, %eax xorl %edx, %edx mull %eax //eax=n*n et_for: cmp %eax, %ecx je et_exit mov (%edi, %ecx, 4), %ebx pushl %eax pushl %ecx //afisare ebx push %ebx push $fs call printf addl $8, %esp push $0 call fflush addl $4, %esp popl %ecx popl %eax incl %ecx jmp et_for et_exit: mov $1, %eax xorl %ebx, %ebx int $0x80
问题分析
栈帧局部变量分配错误:
分配局部变量时错误修改了%ebp寄存器(subl $12, %ebp、subl $8, %ebp),%ebp作为栈帧基址应保持固定,局部变量空间需通过修改%esp来分配。错误修改%ebp会导致所有基于%ebp的参数、局部变量偏移计算完全错误,循环条件中读取的n值变成栈内垃圾数据,引发无限循环。循环条件逻辑颠倒:
三层循环的退出条件判断逻辑错误,原代码用cmp %eax, %ecx(比较n和循环变量)配合jge跳转,导致循环未执行或退出条件永远不满足。正确逻辑应为当循环变量>=n时退出,需将cmp操作数顺序颠倒。
修复后的代码
.text段(matrix_mult函数)
matrix_mult: pushl %ebp mov %esp, %ebp pushl %edi pushl %esi pushl %ebx // 修复:用%esp分配局部变量空间,而非修改%ebp subl $12, %esp // -16(ebp) = i // -20(ebp) = j // -24(ebp) = k subl $8, %esp // -28(ebp) = x // -32(ebp) = y locul unde stocam elem din cele 2 matrici movl $0, -16(%ebp) movl $0, -20(%ebp) movl $0, -24(%ebp) et_for1: mov -16(%ebp), %eax // 取循环变量i mov 20(%ebp), %ecx // 取n的值 cmp %ecx, %eax // 比较i和n,判断i >=n jge final // 若i >=n,退出外层循环 movl $0, -20(%ebp) et_for2: mov -20(%ebp), %eax // 取循环变量j mov 20(%ebp), %ecx // 取n的值 cmp %ecx, %eax // 比较j和n,判断j >=n jge cont_for2 // 若j >=n,退出中层循环 movl $0, -24(%ebp) et_for3: mov -24(%ebp), %eax // 取循环变量k mov 20(%ebp), %ecx // 取n的值 cmp %ecx, %eax // 比较k和n,判断k >=n jge cont_for3 // 若k >=n,退出内层循环 //mres[i][j]=m1[i][k]*m2[k][j] lea 8(%ebp), %edi lea 12(%ebp), %esi //ecx=i*n+k, ecx= indicele pt m1 mov -16(%ebp), %eax xorl %edx, %edx mull 20(%ebp) addl -24(%ebp), %eax mov %eax, %ecx //eax=k*n+j, eax= indicele pt m2 mov -24(%ebp) , %eax xorl %edx, %edx mull 20(%ebp) addl -20(%ebp), %eax //ecx = produsul termenilor mov (%edi, %ecx, 4), %ebx mov %ebx, -28(%ebp) mov (%esi, %eax, 4), %ebx mov %ebx, -32(%ebp) mov -28(%ebp), %eax xorl %edx, %edx mull -32(%ebp) mov %eax, %ecx //eax=i*n+j movl -16(%ebp), %eax xorl %edx, %edx mull 20(%ebp) movl -20(%ebp), %ebx addl %ebx, %eax //ecx= prod term + mres[i][j] lea 16(%ebp), %edi movl (%edi, %eax, 4), %ebx movl %ebx, -28(%ebp) addl -28(%ebp), %ecx movl %ecx, (%edi, %eax, 4) mov -24(%ebp), %ebx incl %ebx mov %ebx, -24(%ebp) //k++ jmp et_for3 cont_for3: mov -20(%ebp), %ebx incl %ebx mov %ebx, -20(%ebp) mov $0, -24(%ebp) //j++ si k=0 jmp et_for2 cont_for2: mov -16(%ebp), %ebx incl %ebx mov %ebx, -16(%ebp) //i++ jmp et_for1 final: addl $20, %esp popl %ebx popl %esi popl %edi popl %ebp ret
修复说明
- 把局部变量分配的
subl $12, %ebp和subl $8, %ebp改为subl $12, %esp和subl $8, %esp,恢复正确的栈帧结构,确保参数和局部变量的偏移计算准确。 - 修正三层循环的
cmp操作数顺序,将cmp %eax, %ecx改为cmp %ecx, %eax,配合jge实现“循环变量 >=n 时退出”的正确逻辑。
内容的提问来源于stack exchange,提问作者David Berbece
相关产品推荐
相关产品推荐

