x64 - 为什么仍然使用 'call'?
x64 - Why still use 'call'?
在最近的 windows 二进制文件中,例如 (win 8.1 x64) 和使用 VC++ 'call' 指令编译的程序仍然存在。将 return 地址存储到寄存器中是不是更快更好的方法,与大多数参数相同而不是仍然使用堆栈?
我的意思是:
函数:
func:
; do something
jmp r8
它的实例:
lea r8, [rip + tmp_1 - tmp_0] ; or rip + 'jmp func' size
tmp_0:
jmp func
tmp_1:
; rest of code
现代 x86 微架构有多种通过堆栈进行调用的方法,实际上是免费的:
1. 一个专用的堆栈引擎,在OoO执行期间保持堆栈指针与堆栈操作同步。
2. 一个硬件 return 堆栈,保留 return 个地址以便快速访问。
此外,整个体系结构不同于 MIPS。 MIPS 和大多数其他 RISC 是加载存储,这意味着它们 必须 将 return 地址存储在寄存器中,否则 call/return
必须 load/store 操作,搞乱了指令集的正交性。
x86 是一种寄存器-内存架构,并针对这些访问进行了优化,尤其是具有微操作等现代微架构功能融合,弥补了相对较少的寄存器数量。
最后,这只会加速只在寄存器上运行的叶函数。这种工作量大部分可以内联,将函数调用成本降低到零。
底线:不值得。
在最近的 windows 二进制文件中,例如 (win 8.1 x64) 和使用 VC++ 'call' 指令编译的程序仍然存在。将 return 地址存储到寄存器中是不是更快更好的方法,与大多数参数相同而不是仍然使用堆栈?
我的意思是:
函数:
func:
; do something
jmp r8
它的实例:
lea r8, [rip + tmp_1 - tmp_0] ; or rip + 'jmp func' size
tmp_0:
jmp func
tmp_1:
; rest of code
现代 x86 微架构有多种通过堆栈进行调用的方法,实际上是免费的:
1. 一个专用的堆栈引擎,在OoO执行期间保持堆栈指针与堆栈操作同步。
2. 一个硬件 return 堆栈,保留 return 个地址以便快速访问。
此外,整个体系结构不同于 MIPS。 MIPS 和大多数其他 RISC 是加载存储,这意味着它们 必须 将 return 地址存储在寄存器中,否则 call/return
必须 load/store 操作,搞乱了指令集的正交性。
x86 是一种寄存器-内存架构,并针对这些访问进行了优化,尤其是具有微操作等现代微架构功能融合,弥补了相对较少的寄存器数量。
最后,这只会加速只在寄存器上运行的叶函数。这种工作量大部分可以内联,将函数调用成本降低到零。
底线:不值得。