[英]Assembly early return on a recursive function
This is more an academic exercise than anything else, but I'm looking to write a recursive function in assembly, that, if it receives and "interrupt signal" it returns to the main function, and not just the function that invoked it (which通常是相同的遞歸函數)。
對於這個測試,我正在做一個基本的倒計時並打印一個字符的數字(8...7...6...等)。 為了模擬“中斷”,我使用數字7
,所以當 function 達到 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
以上看起來像一個有效的方法,將 memory 地址傳遞給 go 回到rsi
嗎? function 對我來說寫起來非常棘手,但我認為主要是因為我對組裝非常陌生/原始。
除了返回到這個備用返回地址之外,您還需要恢復調用者的(保留調用的)寄存器,而不僅僅是您最近的父母的寄存器。 這包括RSP。
您基本上是在嘗試重新發明 C 的setjmp
/ longjmp
,它正是這樣做的,包括將堆棧指針重置回您調用setjmp
的 scope 。 我認為 SO 的setjmp標簽中的一些問題是關於在 asm 中實現你自己的 setjmp / longjmp。
此外,為了提高效率,您可能希望使用自定義調用約定,其中返回地址指針(或實現上述內容后的 jmpbuf 指針)位於像 R15 這樣的調用保留寄存器中,因此您不必保存/在遞歸 function 的主體內圍繞打印調用恢復它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.