【发布时间】:2021-04-29 20:40:41
【问题描述】:
在 Igor Zhirkov 的书中Low-Level Programming 中有这个悬而未决的问题:
"尝试在不调用 print_char 或复制其代码的情况下重写 print_newline。提示:阅读 关于尾调用优化。”。
我花了一些时间阅读关于尾调用优化的文章,但我不知道什么是正确的做法。
原始代码(无尾调用):print_newline => print_char => print_string=>string_length=>print_string
string_length:
xor rax, rax
.loop:
cmp byte [rdi+rax], 0 ; if rdi = 0 (not an address), then seg fault
je .end
inc rax
jmp .loop
.end:
ret
print_string:
push rdi
call string_length
pop rsi
mov rdx, rax
mov rax, 1
mov rdi, 1
syscall
ret
print_char:
push rdi
mov rdi, rsp
call print_string
pop rdi
ret
print_newline:
mov rdi, 10
jmp print_char
什么是尾调用优化?
【问题讨论】:
-
print_newline应用了尾调用优化。注意它是如何使用jmp而不是ret。所以,控制流将是print_newline,print_char,print_string,回到print_char,回到print_newline的调用者(而不是回到print_newline)。如果没有尾调用优化,print_newline将变为mov rdi, 10; call print_char; ret。 -
感谢埃里克!所以没有什么可以“重写”的,这个问题没有意义?
-
(注意它是如何使用
jmp而不是call+ret。) -
是的,TCO 已在您发布的代码中应用于
print_newline。 -
并不是真正的 TCO 示例,但您也可以将
print_newline: mov rdi, 10放在紧挨在print_char:之前的行上,这样print_newline将直接进入print_char而无需跳转全部。当然这个技巧只适用一次,例如你也不能这样print_space。
标签: assembly nasm tail-call-optimization