程序集中的尾递归

时间:2011-04-04 15:29:12

标签: assembly x86 nasm

我正在努力学习装配。我使用NASM而不是AT& T语法。

这是我的第一个程序,它比较两个命令行参数和输出哪个是最小的(如果它们相等则支持第一个)。

我想我做错了。我注意到堆栈随着compare的每次“调用”而增长,所以我可以通过尾递归优化来改善它。但是,我不知道如何正确地做到这一点。我应该用其他东西替换所有出现的'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

1 个答案:

答案 0 :(得分:5)

是的,您应该将call替换为jmp s。通常,当您希望在调用返回时在下一行继续执行时,应使用call。在您的代码中,执行永远不会返回,因为compare只是一个循环,所以jmp是进入下一次迭代的正确方法。对于您拥有的call report的两个实例也是如此。

至于你的第二个问题,jl没有改变标志,所以在它之后调用jg没有问题。