2011-04-04 86 views
3

我正在嘗試學習彙編。我使用NASM而不是AT & T語法。彙編中的尾遞歸

這是我的第一個程序,它比較兩個命令行參數並輸出哪一個是最小的(有利於第一個以防它們相等)。

我想我做錯了。我注意到堆棧隨着比較的每次「調用」而增長,所以我可以使用尾遞歸優化使其更好。但是,我不知道如何正確做到這一點。我是否應該用其他的東西替換所有出現的'call',比如jmp? 我讀過,跳躍的方式也取決於你如何與Linux內核和/或libc有關'函數'對象(我不與libc鏈接,因此沒有主'功能'),這使我很困惑我以爲我會來這裏尋求簡單的建議。另外,我的另一個問題是,如果「jl」跳轉實際上改變了標誌內容,所以「jg」也會跳轉,那麼「jl」立即跟着「jg」會引起不希望的行爲是多麼愚蠢。是否有雙向的「原子」跳躍?

section .data 
    usage: db 'Please provide two strings',10 
    usageLen: equ $-usage 
    bigger:  db 'It is bigger!',10 
    biggerLen: equ $-bigger 
    smaller: db 'It is smaller!',10 
    smallerLen: equ $-smaller 

section .text 
    global _start 

_start: 
    pop ebx ; argc 
    cmp ebx, 3 
    jne usage_exit 

    pop eax ; argv[0] 
    pop eax 
    pop ebx 
    call compare ; 

usage_exit: 
    mov eax, 4 ; sys_write 
    mov ebx, 1 ; int fd = stdout 
    mov ecx, usage 
    mov edx, usageLen 
    int 80h ; call kernel 

    mov eax, 1 ; sys_exit 
    mov ebx, 0 ; int status = 0 
    int 80h ; call kernel 

report: 
    mov ecx, eax 
    mov edx, ebx 
    mov eax, 4 ; sys_write 
    mov ebx, 1 ; int fd = stdout 
    int 80h ; call kernel 

    mov eax, 1 ; sys_exit 
    mov ebx, 0 ; int status = 0 
    int 80h ; call kernel (exit) 

compare: 
    push eax 
    push ebx 
    mov eax, [eax] 
    mov ebx, [ebx] 

    test ax, ax 
    jz is_smaller 
    test bx, bx 
    jz is_bigger 

    cmp ax, bx 
    jl is_smaller 
    jg is_bigger 
    ; if the same, try next positions 
    pop ebx 
    pop eax 
    inc eax 
    inc ebx 
    call compare 

is_smaller: 
    mov eax, smaller 
    mov ebx, smallerLen 
    call report 

is_bigger: 
    mov eax, bigger 
    mov ebx, biggerLen 
    call report 

回答

5

是的,你應該jmp小號取代call秒。一般來說,如果您希望執行在呼叫返回時在下一行繼續,則應使用call。在你的代碼中,執行永遠不會返回,因爲compare只是一個循環,因此jmp是進入下一次迭代的正確方法。對於call report這兩個實例也是如此。

至於你的第二個問題,jl不會改變標誌,所以在它後面調用jg沒有問題。