那些熟悉x86汇编程序设计的人都非常习惯典型的函数前奏/后奏:
push ebp ; Save old frame pointer.
mov ebp, esp ; Point frame pointer to top-of-stack.
sub esp, [size of local variables]
...
mov esp, ebp ; Restore frame pointer and remove stack space for locals.
pop ebp
ret
这段代码序列也可以使用 ENTER
和 LEAVE
指令实现:
enter [size of local variables], 0
...
leave
ret
ENTER
指令的第二个操作数是“嵌套级别(nesting level)”,它允许从被调用函数中访问多个父级帧(parent frames)。
C语言中没有嵌套函数,因此不使用该功能;局部变量只具有它们声明所在的函数的作用域。这种构造在C中不存在(尽管有时我希望存在):
void func_a(void)
{
int a1 = 7;
void func_b(void)
{
printf("a1 = %d\n", a1); /* a1 inherited from func_a() */
}
func_b();
}
然而Python确实有嵌套函数,其行为方式如下:
def func_a():
a1 = 7
def func_b():
print 'a1 = %d' % a1 # a1 inherited from func_a()
func_b()
当然,Python代码并没有直接翻译为x86机器码,因此可能无法利用该指令(不太可能?)。
是否有任何编译成x86并提供嵌套函数的语言?是否有编译器将使用非零第二操作数的ENTER
指令?
英特尔在那个嵌套级别操作数中投入了一定的时间/金钱,基本上我只是好奇是否有人在使用它 :-)
参考资料:
grep
查找gcc-4.8.2/gcc/config/i386/i386.c:10339
可知GCC现在根本不发出ENTER
指令。而该行代码的注释十分明确:“注意:AT&T格式的enter指令没有反转的参数顺序。在所有目标上,使用Enter可能会更慢。而且sdb也不喜欢它。” - Iwillnotexist Idonotexistgit log -p
命令可以看到,这个功能已经在1992年的首次提交中存在了。 - user743382llvm/lib/Target/X86/X86FrameLowering.cpp:355
处有一个关于emitPrologue()
方法的注释,其中部分内容为; Spill general-purpose registers [for all callee-saved GPRs] pushq %<reg> [if not needs FP] .cfi_def_cfa_offset (offset from RETADDR) .seh_pushreg %<reg>
。没有提到ENTER
,只有推送;而x86的枚举常量ENTER
在整个LLVM中仅出现了3次;甚至看起来他们没有为此编写测试用例。 - Iwillnotexist Idonotexist