2011-04-04 88 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没有问题。