Intel 64汇编集合差集循环打印异常:仅输出首个元素
Intel 64汇编集合差集打印问题:仅输出第一个元素后退出循环
我用Intel 64汇编实现集合差集打印功能时遇到问题,预期循环打印出差集的所有元素,但实际仅输出第一个元素后就退出循环。相关代码如下:
msjFinal db "}",10,0 msjElemento db "%c ,",0 msjDiferencia db "Diferencia entre conjuntos: { ",0 conjuntos_0 dw '' conjuntos_1 dw '2', '8', '6', '7', '5', '3', '8', 'A', 'B', 'D', 'G', 'H', 'U', 'Y', 'Q', 'R', 'Q', '0', 'W', 'L' conjuntos_2 dw '1', '2', '3', '4', '5', '6', '7', '8', '1', '9', 'P', 'P', 'Q', 'R', 'Z', 'W', 'A', 'B', 'C', 'D' conjuntos_3 dw '6', '7', '1', '9', '8', '9', 'L', 'A', 'D', 'F', 'P', 'R', 'X', 'S', '0', 'M', 'N', 'Q', 'Z', '5' conjuntos_4 dw '1', '2', '5', '6', '7', '8', 'A', 'B', 'P', 'O', 'L', 'I', 'S', 'O', '0', 'E', '3', 'N', 'M', 'Z' conjuntos_5 dw '3', '4', '7', '8', '1', '9', 'N', 'E', 'R', 'O', 'K', 'M', 'V', 'F', 'I', 'A', 'C', 'P', 'D', 'W' conjuntos_6 dw '5', '3', 'J', '2', 'T', '1', '7', '8', 'X', 'S', 'U', 'Z', 'E', 'B', 'A', 'L', 'P', 'V', 'W', 'Q' conjuntos dq conjuntos_0, conjuntos_1, conjuntos_2, conjuntos_3, conjuntos_4, conjuntos_5, conjuntos_6 diferenciaDeConjuntos: mov rdi,msjDiferencia sub rsp,8 call printf add rsp,8 mov rcx,[nConjunto1] mov rdi,[conjuntos + rcx * 8] ; cargo a rdi el 1er conjunto mov rcx,[nConjunto2] mov rsi,[conjuntos + rcx * 8] ; cargo a rsi el 2do conjunto mov r11,0 ; indice para pasar de elemento conjunto1 mov r8,0 ; indice para pasar de elemento conjunto2 diferenciaLoop: mov dx, word[rsi + r8 ] ; elemento del segundo conjunto sub rsp,8 call compararElementosPertenencia ; salta a funcion de pertenencia add rsp,8 cmp byte[elementoPertenece],0 ; si es 1 no lo necesito paso de elemento, si no lo agrego je agregarElementoDiferencia add r8,2 ; siguiente elemento cmp r8,40 je terminarPrint jmp diferenciaLoop agregarElementoDiferencia: mov word[resultadoElemento],dx ; agrego el elemento mov rdi,msjElemento mov rsi, [resultadoElemento] sub rsp,8 call printf add rsp,8 add r8,2 cmp r8,40 jb diferenciaLoop sub rsp,8 call terminarPrint add rsp,8 terminarPrint: mov rdi,msjFinal sub rsp,8 call puts add rsp,8 sub rsp,8 call quiereSeguirOSalir add rsp,8 ret
问题分析
差集逻辑完全颠倒
集合差集A-B的定义是「属于集合A但不属于集合B的元素」,但当前代码是遍历集合B的元素,判断是否不在集合A中,实际计算的是B-A,和预期功能不符。循环退出逻辑错误
在agregarElementoDiferencia中,当遍历到集合B的最后一个元素时,执行call terminarPrint,而terminarPrint末尾的ret会直接返回至diferenciaDeConjuntos的调用者,导致程序直接退出,无法继续循环。寄存器未妥善保存
调用printf等C标准库函数时,System V AMD64调用约定会破坏r8等易失性寄存器的值,而r8是你的循环计数器,这会导致循环索引异常,提前终止循环。
修复方案
1. 修正差集逻辑
改为遍历集合A的元素,逐个判断是否存在于集合B中,不存在则打印该元素。
2. 修复循环退出逻辑
将call terminarPrint改为跳转(jmp terminarPrint),避免ret导致提前返回。
3. 保存易失性寄存器
调用C函数前,将循环计数器等需要保留的寄存器压入栈中,调用后恢复。
修改后的代码示例
diferenciaDeConjuntos: mov rdi,msjDiferencia sub rsp,8 call printf add rsp,8 mov rcx,[nConjunto1] mov rdi,[conjuntos + rcx * 8] ; 集合A:差集A-B的左集合 mov rcx,[nConjunto2] mov rsi,[conjuntos + rcx * 8] ; 集合B:差集A-B的右集合 mov r11,0 ; 集合A的遍历索引 mov r8,0 ; 集合B的遍历索引(用于元素存在性判断) diferenciaLoop: cmp r11,40 ; 检查是否遍历完集合A的所有元素 je terminarPrint mov dx, word[rdi + r11 ] ; 取集合A的当前元素 mov r8,0 ; 重置集合B的索引,准备查找 buscarEnB: cmp r8,40 je agregarElementoDiferencia ; 遍历完B未找到,说明元素属于A-B,需要打印 mov cx, word[rsi + r8 ] cmp dx,cx je siguienteElementoA ; 在B中找到元素,跳过当前A元素 add r8,2 jmp buscarEnB siguienteElementoA: add r11,2 jmp diferenciaLoop agregarElementoDiferencia: mov word[resultadoElemento],dx push r11 ; 保存集合A的索引,避免printf破坏 mov rdi,msjElemento mov rsi, [resultadoElemento] sub rsp,8 call printf add rsp,8 pop r11 ; 恢复索引寄存器 add r11,2 jmp diferenciaLoop terminarPrint: mov rdi,msjFinal sub rsp,8 call puts add rsp,8 sub rsp,8 call quiereSeguirOSalir add rsp,8 ret
内容的提问来源于stack exchange,提问作者delfipani
相关产品推荐
相关产品推荐

