HLA汇编程序内存访问违例修复及字符串长度计算问题求助
HLA汇编程序内存访问违例修复及字符串长度计算问题求助
我现在卡在一段HLA汇编代码上了,想做的功能很简单——计算用户输入字符串的长度,预期运行效果是这样的:
Feed Me: asdf
The String You Entered: asdf Has Length = 4
但折腾了好半天程序要么跑不对,还时不时报内存访问违例。HLA的资料实在太少了,我怀疑是栈操作哪里出问题了,有没有懂的大佬帮我看看啊?
我的代码是这样的:
program strlenDemo; #include("stdlib.hhf"); static length: byte; inputString: string; procedure strlen( baseStringAddress: dword ); @nodisplay; @noframe; begin strlen; mov( baseStringAddress, esi ); // Load the base address of the string into ESI mov( 0, ecx ); // Clear ECX, it will be used as the character counter strlen_loop: mov( [esi], al ); // Load the current byte of the string into AL test( al, al ); // Test if AL is zero (null character) jz strlen_done; // If zero, jump to strlen_done // 这里漏了递增指针和计数器的步骤! jmp strlen_loop; strlen_done: // 也没处理返回值和寄存器恢复 end strlen; // 主程序里也没正确调用这个过程和输出结果 begin strlenDemo; // 缺少获取输入和调用逻辑 end strlenDemo;
问题分析
- 字符串遍历逻辑缺失:循环里只读取了第一个字符,没有递增ESI指针移动到下一个字符,也没给计数器ECX加1,要么死循环要么读越界内存导致违例。
- 栈帧与寄存器管理问题:用了
@noframe就意味着要手动处理寄存器保存恢复、参数传递和返回操作,原代码完全没做这些,会破坏主程序的寄存器状态,甚至导致返回地址错误。 - 返回值未传递:原
strlen过程没把计算好的长度返回给主程序,主程序也没调用过程的逻辑。 - 输入输出与内存管理缺失:主程序里没写获取用户输入、输出结果的代码,也没处理
stdin.gets分配的内存。
修复后的完整代码
program strlenDemo; #include("stdlib.hhf"); static inputString: string; procedure strlen( baseStringAddress: dword ); @nodisplay; @noframe; begin strlen; // 保存非易失性寄存器ESI(HLA调用约定里ESI需要保留) push( esi ); // 虽然ECX是易失性的,但这里保存一下更稳妥 push( ecx ); mov( baseStringAddress, esi ); // 把字符串基地址载入ESI mov( 0, ecx ); // 计数器ECX初始化为0 strlen_loop: mov( [esi], al ); // 读取当前字节到AL test( al, al ); // 检查是否是字符串结束符(0) jz strlen_done; // 是结束符就跳转到结束逻辑 inc( ecx ); // 计数器加1 inc( esi ); // 指针移动到下一个字符 jmp strlen_loop; // 继续循环 strlen_done: mov( ecx, eax ); // 把计算好的长度放到EAX里返回(HLA默认用EAX返回整数) // 恢复之前保存的寄存器 pop( ecx ); pop( esi ); ret(); // 手动返回(@noframe需要自己调用ret) end strlen; begin strlenDemo; stdout.put("Feed Me: "); stdin.gets( inputString ); // 获取用户输入的字符串 push( inputString ); // 把字符串地址压栈作为参数 call strlen; // 调用strlen,结果存在EAX里 add( 4, esp ); // 清理栈上的参数(因为传了一个dword,占4字节) // 输出结果 stdout.put( "The String You Entered: ", inputString, " Has Length = ", eax, nl ); free( inputString ); // 释放stdin.gets分配的内存,避免泄漏 end strlenDemo;
关键修复点说明
- 寄存器保护:因为用了
@noframe,必须手动保存ESI这类非易失性寄存器,否则会干扰主程序的寄存器状态。 - 遍历逻辑补全:每次循环后递增ESI和ECX,确保逐个字符遍历直到结束符。
- 返回值处理:用EAX传递返回值,这是HLA里整数返回的常规方式。
- 栈操作规范:调用过程前压入参数,调用后手动清理栈(符合cdecl风格的调用约定)。
- 内存管理:记得释放
stdin.gets分配的动态内存,避免内存泄漏。
这样修改后程序应该就能正常运行,准确计算字符串长度啦~
备注:内容来源于stack exchange,提问作者Tiburcio
相关产品推荐
相关产品推荐

