Function 调用函数后如何正确返回到主函数?

Function 调用函数后如何正确返回到主函数?,function,assembly,return,nasm,Function,Assembly,Return,Nasm,我试图让下面的内容跳回main,它会打印菜单。 在另一个函数(正常工作)中,我使用了jmp main命令。但是,该函数只打印一条消息,指示它在再次打印菜单之前到达了该函数 如果只使用最后三条线路中的一条,则会出现seg故障错误。如果我一起使用“离开”和“返回”,则相同。我想这和给scanf打电话有关 read_int: mov edi, enterintmsg mov eax,0 call printf lea rdi,

我试图让下面的内容跳回main,它会打印菜单。 在另一个函数(正常工作)中,我使用了jmp main命令。但是,该函数只打印一条消息,指示它在再次打印菜单之前到达了该函数

如果只使用最后三条线路中的一条,则会出现seg故障错误。如果我一起使用“离开”和“返回”,则相同。我想这和给scanf打电话有关

read_int:
    mov    edi, enterintmsg
    mov    eax,0
    call   printf           
    lea    rdi, [LC5]
    lea    rsi, [value]
    xor    eax,eax
    call   scanf
    mov    cl, [value]
    jmp    main
    ;leave
    ;ret    
当前代码:

bits 64
global  main
    extern  puts
extern  printf
extern  scanf   
extern  get_kb



section.data
 ;LC0
errormsg:   db  'Invalid Input. Enter N,F, or X',0x0D,0x0a,0

;LC1
numequalsmsg:   db  'Number equals: '

LC2:    db  "%d",0


menuprompt: db  0x0D,0x0a,'Enter N to enter an integer from 0 to 20',0x0D,0x0a,'Enter F to display the first N+1 numbers (beginning with zero) on the console',0x0D,0x0a,'Enter X to quit the program',0x0D,0x0a,0


choicemsg:  db  "Your Choice: ",0

LC5:    db  "%d",0

;LC6
enterintmsg:    db  "Enter and integer 0-20: ",0

;LC7
enternummsg:    db  'Enter a valid number between 0 and 20',0x0D,0x0a,0


LC8:    db  " , ",0
LC9:    db  'Success!',0x0D,0x0a,0
LC10:   db  'In L10!',0x0D,0x0a,0       
LC11:   db  'In L12!',0x0D,0x0a,0 
LC13:   db  'In compare to zero section',0x0D, 
value:  db  0
choice: db  1


.code
main:
    ;function setup 
    push    rbp
    mov rbp, rsp
    sub rsp, 16

menu:
    ;print menu 
    mov edi, menuprompt
    call    puts            ;display menu
    mov edi,choicemsg
    ;mov    eax, 0
    ;call   printf          ;display "Your choice:" 
    call puts
    ;call   getn    
    ;push choice
    ;push LC5       ;string format
    ;call scanf     ;stores input in choice
    ;GetLInt     [choice]
    ;mov    ebx, choice
    ;lea    rdi, [LC5]
    ;lea    rsi, [choice]
    ;xor    eax,eax
    ;call scanf
    ;mov    bl, [choice]
    call    get_kb
    mov bl, al
    cmp bl, 'N' ;N
    je  entered_n
    cmp bl, 'F' ;F
    je  correct
    cmp bl, 'X' ;X
    je  correct
    ;leave
    ;ret

    jmp menu
    ;ret

correct:
    mov edi, LC9
    mov eax,0
    call    printf
    jmp     menu
    ;leave  
    ;ret 

entered_n:
    call    read_int
    ;jmp    menu
    ;leave
    jmp menu

read_int:
    mov edi, enterintmsg
    mov eax,0
    call    printf          

    lea rdi, [LC5]
    lea rsi, [value]
    xor eax,eax

    ;add    esp,4       ;remove parameters
    push    rsi
    push    rdi 
    call scanf
    mov cl, [value]
    ;jmp    menu
    ;leave
    ret


     ;leave 

要返回函数,需要使用RET指令。要使RET指令处理返回地址,指令应该跳转到的位置需要位于堆栈的顶部。通常,这个返回地址由CALL指令推送到堆栈上,但是您没有使用CALL指令来调用函数。相反,您使用了
JE read\u int
。这意味着您的函数不知道从何处调用它,因此RET指令无法继续执行之前停止的函数

解决方案是将调用
read\u int
的代码更改为如下内容:

     cmp bl, 'N'
     jne not_n

     call read_int
     ; read_int returns here so put whatever code 
     ; that needs to be executed afterwards here

not_n:
     ; code handling the case when BL != 'N'
然后,您可以将
read_int
更改为使用RET,并将仅RET更改为从函数返回

使用
JMP main
返回main函数不起作用,因为它完全按照它所说的那样执行。它跳转到
main
的地址,这是
main
函数中的第一条指令。这将导致从一开始就再次执行主功能


除非设置堆栈帧,否则不希望使用LEVE指令。您的
read\u int
函数没有设置堆栈帧,因此使用它可能会导致代码崩溃。

要返回函数,需要使用RET指令。要使RET指令处理返回地址,指令应该跳转到的位置需要位于堆栈的顶部。通常,这个返回地址由CALL指令推送到堆栈上,但是您没有使用CALL指令来调用函数。相反,您使用了
JE read\u int
。这意味着您的函数不知道从何处调用它,因此RET指令无法继续执行之前停止的函数

解决方案是将调用
read\u int
的代码更改为如下内容:

     cmp bl, 'N'
     jne not_n

     call read_int
     ; read_int returns here so put whatever code 
     ; that needs to be executed afterwards here

not_n:
     ; code handling the case when BL != 'N'
然后,您可以将
read_int
更改为使用RET,并将仅RET更改为从函数返回

使用
JMP main
返回main函数不起作用,因为它完全按照它所说的那样执行。它跳转到
main
的地址,这是
main
函数中的第一条指令。这将导致从一开始就再次执行主功能


除非设置堆栈帧,否则不希望使用LEVE指令。您的
read\u int
函数没有设置堆栈帧,因此使用它可能会导致代码崩溃。

要返回函数,需要使用RET指令。要使RET指令处理返回地址,指令应该跳转到的位置需要位于堆栈的顶部。通常,这个返回地址由CALL指令推送到堆栈上,但是您没有使用CALL指令来调用函数。相反,您使用了
JE read\u int
。这意味着您的函数不知道从何处调用它,因此RET指令无法继续执行之前停止的函数

解决方案是将调用
read\u int
的代码更改为如下内容:

     cmp bl, 'N'
     jne not_n

     call read_int
     ; read_int returns here so put whatever code 
     ; that needs to be executed afterwards here

not_n:
     ; code handling the case when BL != 'N'
然后,您可以将
read_int
更改为使用RET,并将仅RET更改为从函数返回

使用
JMP main
返回main函数不起作用,因为它完全按照它所说的那样执行。它跳转到
main
的地址,这是
main
函数中的第一条指令。这将导致从一开始就再次执行主功能


除非设置堆栈帧,否则不希望使用LEVE指令。您的
read\u int
函数没有设置堆栈帧,因此使用它可能会导致代码崩溃。

要返回函数,需要使用RET指令。要使RET指令处理返回地址,指令应该跳转到的位置需要位于堆栈的顶部。通常,这个返回地址由CALL指令推送到堆栈上,但是您没有使用CALL指令来调用函数。相反,您使用了
JE read\u int
。这意味着您的函数不知道从何处调用它,因此RET指令无法继续执行之前停止的函数

解决方案是将调用
read\u int
的代码更改为如下内容:

     cmp bl, 'N'
     jne not_n

     call read_int
     ; read_int returns here so put whatever code 
     ; that needs to be executed afterwards here

not_n:
     ; code handling the case when BL != 'N'
然后,您可以将
read_int
更改为使用RET,并将仅RET更改为从函数返回

使用
JMP main
返回main函数不起作用,因为它完全按照它所说的那样执行。它跳转到
main
的地址,这是
main
函数中的第一条指令。这将导致从一开始就再次执行主功能


除非设置堆栈帧,否则不希望使用LEVE指令。您的
read\u int
函数没有设置堆栈帧,因此使用它可能会导致代码崩溃。

为什么要跳转到
main
并放弃当前堆栈帧等?
main
是否重置堆栈指针?确实如此。我将其设置为where main仅设置堆栈帧,然后调用了menu,但无法使其离开任一函数返回到menu。将其更改回where main仅设置堆栈。在打印成功函数后调用菜单函数,但是如果我校准上面的read_int函数,仍然会得到seg fault错误。C