汇编实现C语言strstr()模拟函数遇无输出问题求助
汇编实现strstr无输出问题排查
核心错误点
1. 栈参数访问完全错误
- 在
start流程中,你先压入string1的偏移,再压入string2的偏移,调用strstr时栈结构为:返回地址 → string2偏移 → string1偏移。原代码错误地将[bp+4](返回地址)当作string1的指针,导致后续所有地址访问失效。 - 调用
search前压入了di和si,但原代码用[bp+10]、[bp+12]访问参数,属于无意义的越界操作;且返回时错误执行pop bx、pop dx(未提前push过这些寄存器),直接破坏栈平衡,导致程序执行混乱。
2. 字符串结束判断错误
int 21h的0Ah号输入功能,不会自动在字符串末尾添加'$',有效字符范围由缓冲区第二个字节(实际输入长度)决定。原代码用cmp al, '$'判断结束,会导致遍历到无关内存,触发未知错误。
3. 函数返回栈操作混乱
strstr和search的返回逻辑中,错误地弹出未入栈的bx、dx寄存器,导致栈指针错乱,函数返回后程序无法正常执行。
4. 结果打印逻辑错误
原print_result的循环逻辑错误,test ax, ax后直接跳转到除法步骤,无法正确将地址偏移转换为十进制输出。
修正后的代码
assume cs:code, ds:data data segment newline db 0Dh, 0Ah, '$' string1 db 100, 99 dup (0) ; 0Ah输入缓冲区:[0]最大长度, [1]实际长度, [2...]字符 string2 db 100, 99 dup (0) not_found_message db 'Not found', '$' data ends code segment ; strstr参数:(主串指针, 子串指针) ; 返回ax=子串在主串有效字符中的偏移,未找到则返回-1 strstr proc push bp mov bp, sp ; 栈结构:bp+4=返回地址, bp+6=子串指针, bp+8=主串指针 mov di, [bp+8] ; 主串缓冲区起始 mov cl, [di+1] ; 主串实际字符数 add di, 2 ; 主串有效字符起始位置 mov di_end, di add di_end, cx ; 主串结束位置(下一个字节) mov si, [bp+6] ; 子串缓冲区起始 mov cl, [si+1] ; 子串实际字符数 mov si_len, cx add si, 2 ; 子串有效字符起始位置 cmp si_len, 0 je success1 ; 子串为空,直接返回主串起始偏移 inner_loop: cmp di, di_end jge failed1 ; 遍历完主串未找到,返回失败 ; 调用search匹配当前位置 push di push si push si_len call search add sp, 6 ; 清理栈上3个参数(各2字节) cmp ax, 1 je success1 ; 匹配成功,计算偏移返回 inc di jmp inner_loop success1: sub di, [bp+8] ; 计算相对于主串缓冲区的偏移 sub di, 2 ; 转换为相对于有效字符的偏移 mov ax, di pop bp ret 4 ; 自动清理栈上的主串、子串参数(各2字节) failed1: mov ax, -1 pop bp ret 4 strstr endp ; search参数:(主串当前位置, 子串起始, 子串长度) ; 返回ax=1匹配成功,ax=0失败 search proc push bp mov bp, sp mov di, [bp+10] ; 主串当前位置 mov si, [bp+8] ; 子串起始 mov cx, [bp+6] ; 子串长度 jcxz success2 ; 子串长度为0,直接判定成功 custom_loop: mov al, [di] mov bl, [si] cmp al, bl jne failed2 ; 字符不匹配,返回失败 inc di inc si loop custom_loop ; 遍历完子串所有字符 success2: mov ax, 1 pop bp ret failed2: mov ax, 0 pop bp ret search endp start: mov ax, data mov ds, ax ; 输入主串 mov dx, offset string1 mov ah, 0Ah int 21h ; 换行 mov dx, offset newline mov ah, 09h int 21h ; 输入子串 mov dx, offset string2 mov ah, 0Ah int 21h ; 换行 mov dx, offset newline mov ah, 09h int 21h ; 压入参数:先主串,再子串(栈后进先出) push offset string1 push offset string2 call strstr ; 处理返回值 cmp ax, -1 je not_found ; 打印找到的偏移量(十进制) mov bx, ax cmp bx, 0 je print_zero print_loop: xor dx, dx mov ax, bx mov cx, 10 div cx ; ax=商,dx=余数 push dx ; 余数入栈(逆序存储) mov bx, ax test bx, bx jnz print_loop print_digits: pop dx add dl, '0' mov ah, 02h int 21h jmp print_done print_zero: mov dl, '0' mov ah, 02h int 21h print_done: mov dx, offset newline mov ah, 09h int 21h mov ah, 4ch int 21h not_found: mov ah, 09h mov dx, offset not_found_message int 21h mov dx, offset newline mov ah, 09h int 21h mov ah, 4ch int 21h ; 全局变量存储主串结束位置和子串长度 di_end dw ? si_len dw ? code ends end start
修正说明
- 栈参数规范:明确每个函数的栈结构,使用
ret n自动清理栈参数,避免手动操作栈导致的错误。 - 字符串遍历逻辑:根据0Ah输入缓冲区的实际长度确定有效字符范围,不再依赖
'$'判断结束。 - 函数返回逻辑:简化返回流程,确保栈平衡,避免非法寄存器弹出操作。
- 结果打印:修复十进制转换逻辑,正确将偏移量转换为字符输出。
内容的提问来源于stack exchange,提问作者Andi
相关产品推荐
相关产品推荐

