assembly Ret(fr a Procedure)将控制权收回到该过程的开始位置,而不是Main

31moq8wy  于 2022-12-23  发布在  其他
关注(0)|答案(1)|浏览(104)

我正在使用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有一个类似的问题,但是有推和弹出,而我还没有接触堆栈。我错过了什么。谢谢你的帮助

ut6juiuv

ut6juiuv1#

汇编语言的控制流很像BASIC语言,在某种意义上说,一旦程序开始,除非被重定向,否则它将继续前进到下一“行”。这是eip寄存器的硬编码行为;它被设置为一个起始地址,并读取该地址的字节以确定要运行的指令,然后将该指令的大小添加到它自己的内部值并重复。如果您的代码没有jmpcallret等控制流指令,CPU只会按照程序编写的顺序运行程序中的所有代码,标签和proc不会被CPU看到;它们的存在仅仅是为了方便你,汇编器将它们翻译成一个相对于起始位置的内存地址(即.code标签)。

.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

代码到达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的末尾加上一个retmain是一个值得注意的例外,因为正确退出main的方式是特定于平台的。在您的情况下,它很可能不是ret,但我不知道确切的方法。也许它是ret。也许不是。你必须阅读你的操作系统和环境的文档。

相关问题