关于LEA指令操作SI寄存器与数据段变量的代码逻辑疑问
8086汇编子串检测代码执行逻辑解析
问题背景
现有一段8086汇编代码,功能是检查用户输入字符串中是否存在子串ktmt。存在几个疑问:
- main过程中
lea si, inputstring是让SI持有inputstring的偏移地址,但经过getstring后,SI的值却等于输入字符数,这是怎么回事? findstringktmt子程序中把SI的值移入CX后,CX为何能表示输入字符串的字符数?- 整段代码的完整执行逻辑是怎样的?
完整汇编代码
.model small .data inputstring db 100 dup('?') findstring db 'ktmt' result db 0 crlf db 13, 10, '$' ;回车换行符 .code ;读取单个字符的子函数 getchar: mov ah, 1 int 21h ret ;从屏幕读取字符串的子函数 getstring: call getchar inc si mov [inputstring + si], al cmp al, '#' jne getstring ret ;检查输入字符串中是否存在'ktmt'的子函数 findstringktmt: mov cx, si lea si, inputstring + 1 lea di, findstring mov bh, 0 find: mov al, [si] mov bl, [di] cmp bl, al je if_equal lea di, findstring - 1 mov bh, -1 if_equal: inc di inc bh cmp bh, 4 je found inc si loop find ret found: mov [result], 1 ret ;输出结果到屏幕的子函数 printresult: mov ah, 9 lea dx, crlf int 21h mov dl, [result] add dx, 48 mov ah, 2 int 21h ret main proc mov ax, @data mov ds, ax lea si, inputstring call getstring call findstringktmt call printresult int 20h main endp end main
逐阶段执行逻辑解析
1. 程序初始化与字符串输入阶段
- 初始化:main过程中
mov ax, @data; mov ds, ax把数据段的段地址加载到DS寄存器,确保后续访问.data段的变量时地址正确。lea si, inputstring将inputstring在数据段的偏移地址(通常为0x0000)加载到SI。 - 字符串输入(getstring):
- 每次调用
getchar,通过int 21h AH=1读取用户输入的字符(字符存在AL中,同时自动回显到屏幕)。 - 执行
inc si:SI从初始的偏移地址开始,每输入一个字符就自增1。比如输入第一个字符后,SI从0x0000变成0x0001;输入第二个字符后变成0x0002,以此类推。 mov [inputstring + si], al:把输入的字符存储到inputstring对应的偏移位置(比如SI=0x0001时,存储到inputstring+1的位置)。- 检查输入字符是否为
#,如果不是就循环继续读取;输入#时停止,此时SI的数值恰好等于输入的总字符数(包括#)。
- 每次调用
2. 子串检测阶段(findstringktmt)
- 初始化检测参数:
mov cx, si:把SI中存储的输入字符总数赋值给CX,作为后续loop指令的循环次数(遍历所有输入字符)。lea si, inputstring + 1:让SI指向输入字符串的第一个有效字符(因为inputstring的初始位置存的是默认值?,第一个输入字符存在inputstring+1的位置)。lea di, findstring:让DI指向待匹配子串ktmt的第一个字符。mov bh, 0:用BH寄存器记录当前匹配成功的子串字符数,初始为0。
- 遍历匹配逻辑:
- 进入
find循环,每次取出SI指向的输入字符(AL)和DI指向的子串字符(BL)进行比较:- 如果字符相等,直接进入
if_equal;如果不相等,把DI重置到findstring - 1(后续inc di会回到子串起始位置),同时把BH设为-1(后续inc bh会回到0,重置匹配计数)。 if_equal中:DI自增指向下一个待匹配的子串字符,BH自增1(匹配计数+1)。- 检查BH是否等于4:因为子串
ktmt共4个字符,等于4说明完全匹配,跳转到found标签,把result设为1(表示找到子串)。
- 如果字符相等,直接进入
- SI自增指向下一个输入字符,执行
loop find:CX自减1,若CX不为0则继续循环。
- 进入
- 循环结束:如果遍历完所有字符都没匹配成功,直接执行
ret返回,result保持初始值0。
3. 结果输出阶段(printresult)
- 先通过
int 21h AH=9输出回车换行符(crlf)。 - 把
result的值(0或1)加上48,转换成ASCII字符(0→'0',1→'1'),然后通过int 21h AH=2输出到屏幕,展示检测结果。
关键疑问解答
- 为何SI的值等于输入字符数?:因为
getstring中SI从inputstring的偏移地址(通常为0)开始,每输入一个字符就自增1,输入结束时SI的数值刚好等于输入的总字符数,这是这段代码的特殊逻辑设计,并非SI寄存器本身的属性。 - 教材说SI持有实际地址?:这里的“实际地址”指的是逻辑地址——段地址存在DS寄存器中,SI是偏移地址,两者结合可计算出物理地址。而SI的数值恰好等于字符数,是代码执行后的结果,和它作为偏移地址的功能不冲突。
内容的提问来源于stack exchange,提问作者Dương Nguyễn
相关产品推荐
相关产品推荐

