【发布时间】:2014-12-07 00:40:04
【问题描述】:
熟悉 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 指令的第二个操作数是嵌套层,它允许从被调用函数访问多个父帧。
这在 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 指令?
英特尔在嵌套级别操作数上投入了非零的时间/金钱,基本上我只是好奇是否有人使用它:-)
参考资料:
【问题讨论】:
-
+1,今天最有趣的问题。对于 1),GCC 完全使用您的语法支持 nested functions in C。但明确不在 C++ 中。
-
@IwillnotexistIdonotexist 巧合的是,我刚好碰到了同一个页面。有趣的是,它使用默认选项在 gcc 4.7.2 上编译。期待拆解。有趣的东西!
-
对于它的价值,我从
grep-inggcc-4.8.2/gcc/config/i386/i386.c:10339了解到,现在 GCC 根本不会发出ENTER。那行的评论很清楚:/* Note: AT&T enter does NOT have reversed args. Enter is probably slower on all targets. Also sdb doesn't like it. */ -
@IwillnotexistIdonotexist FWIW,这是 GCC 的第一个版本的一部分。
git log -p在他们的 cvs->svn->git 转换存储库中显示它在 1992 年的初始签入中已经存在。 -
我对 LLVM 3.5 的私人 svn 结帐在
llvm/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,只有推送; x86ENTER的枚举常量在所有 LLVM 中仅出现 3 次;它甚至看起来都没有测试用例。