Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Recursion 递归函数上的程序集早期返回_Recursion_Assembly_X86_X86 64_Setjmp - Fatal编程技术网

Recursion 递归函数上的程序集早期返回

Recursion 递归函数上的程序集早期返回,recursion,assembly,x86,x86-64,setjmp,Recursion,Assembly,X86,X86 64,Setjmp,这更像是一个学术练习,但我想在汇编中编写一个递归函数,如果它接收到并“中断信号”,它将返回到主函数,而不仅仅是调用它的函数(通常是同一个递归函数) 对于这个测试,我正在做一个基本的倒计时并打印一个字符的数字(8…7…6…等等)。为了模拟一个“中断”,我使用的是数字7,因此当函数点击7时(如果它在上面启动),它将返回一个1,表示它被中断,如果它没有被中断,它将倒计时到零。以下是我迄今为止所做的: .globl _start _start: # countdown(9); mov

这更像是一个学术练习,但我想在汇编中编写一个递归函数,如果它接收到并“中断信号”,它将返回到主函数,而不仅仅是调用它的函数(通常是同一个递归函数)

对于这个测试,我正在做一个基本的倒计时并打印一个字符的数字(8…7…6…等等)。为了模拟一个“中断”,我使用的是数字
7
,因此当函数点击7时(如果它在上面启动),它将返回一个
1
,表示它被中断,如果它没有被中断,它将倒计时到零。以下是我迄今为止所做的:

.globl _start
_start:

    # countdown(9);
    mov $8, %rdi
    call countdown

    # return 0;
    mov %eax, %edi
    mov $60, %eax
    syscall

print:
    push %rbp
    mov %rsp, %rbp

    # write the value to a memory location
    pushq %rdi # now 16-byte aligned
    add $'0', -8(%rbp)
    movb $'\n', -7(%rbp)

    # do a write syscall
    mov $1, %rax        # linux syscall write
    mov $1, %rdi        # file descriptor: stdout=1
    lea -8(%rbp), %rsi  # memory location of string goes in rsi
    mov $2, %rdx        # length: 1 char + newline
    syscall

    # restore the stack
    pop %rdi
    pop %rbp
    ret;

countdown:
    # this is the handler to call the recursive function so it can
    # pass the address to jump back to in an interrupt as one of the
    # function parameters
    # (%rsp) currntly holds the return address, and let's pass that as the second argument
    mov %rdi, %rdi      # redundant, but for clarity
    mov (%rsp), %rsi    # return address to jump
    call countdown_recursive


countdown_recursive:

    # bool countdown(int n: n<10, return_address)

    # ...{
    push %rbp
    mov %rsp, %rbp

    # if (num<0) ... return
    cmp $0, %rdi
    jz end

    # imaginary interrupt on num=7
    cmp $7, %rdi
    jz fast_ret

    # else...printf("%d\n", num);
    push %rsi
    push %rdi
    call print
    pop %rdi
    pop %rsi

    # --num
    dec %rdi

    # countdown(num)
    call countdown_recursive

end:
    # ...}
    mov $0, %eax
    mov %rbp, %rsp
    pop %rbp
    ret

fast_ret:
    mov $1, %eax
    jmp *%rsi
.globl\u开始
_开始:
#倒计时(9);
mov$8,%rdi
呼叫倒计时
#返回0;
mov%eax,%edi
mov$60,%eax
系统调用
打印:
推送%rbp
mov%rsp,%rbp
#将该值写入内存位置
pushq%rdi#现在16字节对齐
添加$'0',-8(%rbp)
movb$'\n',-7(%rbp)
#执行写系统调用
mov$1,%rax#linux系统调用写入
mov$1,%rdi#文件描述符:stdout=1
lea-8(%rbp),%rsi#字符串的内存位置位于rsi中
mov$2,%rdx#长度:1个字符+换行符
系统调用
#恢复堆栈
pop%rdi
弹出%rbp
ret;
倒计时:
#这是调用递归函数的处理程序,因此它可以
#将中断中要跳回的地址作为
#功能参数
#(%rsp)当前保存返回地址,我们将其作为第二个参数传递
mov%rdi,%rdi冗余,但为清晰起见
mov(%rsp),%rsi#要跳转的返回地址
调用倒计时
倒计时\u递归:

#bool倒计时(int n:n除了返回此备用返回地址外,您还需要恢复呼叫者(保留呼叫)的寄存器,而不仅仅是您最近的父母的寄存器。这包括RSP

您基本上是在尝试重新发明C的
setjmp
/
longjmp
,它正是这样做的,包括将堆栈指针重置回调用
setjmp
的范围。我认为SO标签中的一些问题是关于在asm中实现您自己的setjmp/longjmp

此外,为了提高效率,您可能希望使用一种自定义调用约定,其中返回地址指针(或实现上述操作后的jmpbuf指针)位于调用保留寄存器(如R15)中,因此您不必在递归函数体中的打印调用周围保存/恢复它