调用函数后如何正确返回main函数?

时间:2015-07-21 17:21:42

标签: function assembly return nasm

我正在尝试让以下内容跳回到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 

1 个答案:

答案 0 :(得分:3)

要返回功能,需要使用RET指令。要使RET指令处理返回地址,指令应跳转到的位置需要位于堆栈的顶部。通常,这个返回地址由CALL指令压入堆栈,但是你没有使用CALL指令来调用该函数。相反,您使用了JE read_int。这意味着你的函数不知道从哪里调用它,因此RET指令不能继续执行它停止的前一个函数。

解决方案是将调用read_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函数的第一条指令。这会导致您的主要功能从一开始就再次执行。

除非设置堆栈帧,否则不想使用LEAVE指令。您的read_int函数未设置堆栈帧,因此使用它可能会导致代码崩溃。