2015-07-21 636 views
0

我試圖得到以下回到主打印菜單。 在另一個函數(工作正常)中,我使用了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 
+0

你爲什麼要跳到'main'並放棄當前的堆棧幀? 'main'是否重置堆棧指針? –

+0

它的確如此。我把它設置爲main,只設置堆棧幀然後調用菜單,但不能讓它離開任何一個函數返回到菜單。 – user3866044

+0

將其更改回主設置堆棧的位置。打印成功函數後調用菜單函數,但如果我調用上面的read_int函數,仍然會出現seg錯誤。將jmp main更改爲jmp菜單。 – user3866044

回答

2

要返回您需要使用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函數不會設置堆棧幀,因此使用它可能會導致您的代碼崩潰。

+0

由於我有三個選項,N,F和X,我可以將它轉換爲N,跳轉到「等於n」,這會調用read_int? – user3866044

+0

@ user3866044是的,那也可以。 –

+0

我準備好將我的頭髮撕掉!將我當前的代碼添加到主要問題中。這很容易從C轉換而來,但如果沒有它,很難寫出來。仍然陷入seg故障。嘗試了幾件事情。 – user3866044