我正在使用MASM和Irvine32编写一个基本的ASM代码。该代码采用输入字符方式,用户输入他想输入的字符数,循环运行该次数。该过程只接受字母表。如果按num或其他键,则显示拒绝的消息。返回Main(调用函数)如果ecx == 0(用户输入的数字)。现在我的问题是ret关键字将控制权交还给同一过程(被调用过程)的开始,而不是返回到main(调用者)。
include Irvine32.inc
.data
Input_Prompt BYTE "Enter String:", 0
Max_Length_input BYTE "Enter max length to read:", 0
Rejected_mess BYTE "Rejected !", 0
ret_mess BYTE "returing mess !", 0
USER_STR BYTE ?
.code
main PROC
mov edx, offset Max_Length_input ;ask for max length
call WriteString
call Readint
mov ecx, eax
mov esi, offset USER_STR ;passing offset of storage
call String_Input
main endp
String_Input PROC
mov ebx, 0
mov edx, offset Input_Prompt ;ask for input
l1:
call WriteString
call Readchar
call writechar
call crlf
cmp al, 'a'
JA L2
cmp al, 'z'
JB L2
L2:
cmp al, 'A'
JA break
JB Reject
cmp al, 'Z'
JB break
JA Reject
break:
mov [esi+ebx], al ;filling chars in the storage
inc ebx
loop l1
mov edx, offset USER_STR ;displaying final data in storage
call writestring
mov edx, offset ret_mess
call crlf
call writestring
call crlf
ret
reject:
mov edx, offset Rejected_mess
call crlf
call writestring
String_Input endp
exit
end main
堆栈溢出RET function returning to beginning of code instead of CALL point有一个类似的问题,但是有推和弹出,而我还没有接触堆栈。我错过了什么。谢谢你的帮助
1条答案
按热度按时间ut6juiuv1#
汇编语言的控制流很像BASIC语言,在某种意义上说,一旦程序开始,除非被重定向,否则它将继续前进到下一“行”。这是
eip
寄存器的硬编码行为;它被设置为一个起始地址,并读取该地址的字节以确定要运行的指令,然后将该指令的大小添加到它自己的内部值并重复。如果您的代码没有jmp
、call
和ret
等控制流指令,CPU只会按照程序编写的顺序运行程序中的所有代码,标签和proc
不会被CPU看到;它们的存在仅仅是为了方便你,汇编器将它们翻译成一个相对于起始位置的内存地址(即.code
标签)。代码到达
call String_Input
后,eip
寄存器将被重定向到指令mov ebx, 0
(因为它是String_Input PROC
下面的指令,并从那里继续向前。在String_Input PROC
中有一个ret
,当执行ret
时,eip
寄存器被设置为紧跟在call String_Input
之后的指令。这就是问题所在,因为main endp
不是指令,它只是为了方便您而存在。下一条指令是mov ebx,0
,这是String_Input
例程的第一条指令。这就是为什么ret
看起来只是再次给予控制流返回给同一个函数-因为它直接出现在调用之后!主要的结论是标签和
proc
声明 * 不 * 改变控制流,这与C和其他高级语言中的花括号不同。解决这个问题最简单的方法是在
proc
的末尾加上一个ret
。main
是一个值得注意的例外,因为正确退出main
的方式是特定于平台的。在您的情况下,它很可能不是ret
,但我不知道确切的方法。也许它是ret
。也许不是。你必须阅读你的操作系统和环境的文档。