Assembly 是否有任何语言/编译器使用嵌套级别为非零的x86 ENTER指令?
熟悉x86汇编编程的人非常习惯于典型的函数序言/尾声:Assembly 是否有任何语言/编译器使用嵌套级别为非零的x86 ENTER指令?,assembly,x86,Assembly,X86,熟悉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 同样的代码序列
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函数a(void)
{
int a1=7;
无效函数b(无效)
{
printf(“a1=%d\n”,a1);/*a1继承自func_a()*/
}
func_b();
}
但是Python确实有嵌套函数,其行为如下:
def func_a():
a1=7
def func_b():
打印'a1=%d'%a1#a1继承自func_a()
func_b()
当然,Python代码不会直接转换为x86机器代码,因此无法(不太可能?)利用此指令
是否有编译成x86并提供嵌套函数的语言?是否有编译器会发出带有非零秒操作数的ENTER
指令?
英特尔在嵌套级操作数上投入了非零的时间/金钱,基本上我只是好奇是否有人使用它:-)
参考资料:
ENTER
指令。相反,嵌套函数中使用的变量在局部变量区域中分组在一起,并将指向该组的指针传递给嵌套函数。有趣的是,这个“指向父变量的指针”是通过非标准机制传递的:在x64中,它被传递在#包括
无效函数a(无效)
{
int a1=0x1001;
INTA2=2,a3=3,a4=4;
int a5=0x1005;
无效函数b(int p1,int p2)
{
/*使用func_a()中的变量*/
printf(“a1=%d a5=%d\n”,a1,a5);
}
func_b(1,2);
}
内部主(空)
{
func_a();
返回0;
}
为64位编译时生成以下(代码段):
00000000004004dc <func_b.2172>:
4004dc: push rbp
4004dd: mov rbp,rsp
4004e0: sub rsp,0x10
4004e4: mov DWORD PTR [rbp-0x4],edi
4004e7: mov DWORD PTR [rbp-0x8],esi
4004ea: mov rax,r10 ; ptr to calling function "shared" vars
4004ed: mov ecx,DWORD PTR [rax+0x4]
4004f0: mov eax,DWORD PTR [rax]
4004f2: mov edx,eax
4004f4: mov esi,ecx
4004f6: mov edi,0x400610
4004fb: mov eax,0x0
400500: call 4003b0 <printf@plt>
400505: leave
400506: ret
0000000000400507 <func_a>:
400507: push rbp
400508: mov rbp,rsp
40050b: sub rsp,0x20
40050f: mov DWORD PTR [rbp-0x1c],0x1001
400516: mov DWORD PTR [rbp-0x4],0x2
40051d: mov DWORD PTR [rbp-0x8],0x3
400524: mov DWORD PTR [rbp-0xc],0x4
40052b: mov DWORD PTR [rbp-0x20],0x1005
400532: lea rax,[rbp-0x20] ; Pass a, b to the nested function
400536: mov r10,rax ; in r10 !
400539: mov esi,0x2
40053e: mov edi,0x1
400543: call 4004dc <func_b.2172>
400548: leave
400549: ret
enter
在实践中被避免,因为它的性能相当差-请参阅中的答案。有许多x86指令已经过时,但由于向后兼容的原因仍然受支持-enter
就是其中之一。(leave
是可以的,编译器很乐意发出它。)
在Python中实现完全通用的嵌套函数实际上比简单地选择几个框架管理指令要有趣得多——搜索“闭包转换”和“向上/向下funarg问题”,您会发现许多有趣的讨论
请注意,x86最初设计为Pascal机器,这就是为什么有指令支持嵌套函数(enter
,leave
)、被调用方从堆栈中弹出已知数量的参数的Pascal
调用约定(retk
)、边界检查(bound
)以及,等等这些操作中的许多现在已经过时。我们的编译器(用于SMP x86上的细粒度并行程序)具有词法作用域
PARLANSE尝试生成许多、许多小的并行计算粒度,然后在线程上多路复用它们(每个CPU 1个)。实际上,堆栈帧是堆分配的;我们不想为每一粒粮食付出“大堆码”的代价,因为我们有很多,我们也不想限制任何东西能重复出现的深度。因为有平行的叉子,所以这个堆栈实际上是一个仙人掌堆栈
每个过程在输入时都构建一个词法显示,以允许访问周围的词法范围。我们考虑使用ENTER指令,但出于两个原因决定不使用它:
- 正如其他人所指出的,它并不是特别快。MOV指令也同样适用
- 我们观察到,显示通常是稀疏的,而且在词汇更深的一侧往往更密集。大多数内部助手函数只对其直接词法父函数进行访问;你并不总是需要接触你所有的父母。有时没有
顺便说一句,ENTER现在是传统的CISC指令之一,在它被定义时似乎是一个好主意,但由于RISC指令序列甚至Intel x86都进行了优化,所以性能优于它。我使用Simics虚拟平台在Linux引导上做了一些指令计数统计,发现从未使用过ENTER。然而,混合中有相当多的请假指示。打电话和离开之间几乎有1:1的相关性。这似乎证实了这样一种观点,即进入只是缓慢而昂贵,而离开则相当方便。这是在2.6系列内核上测量的
在4.4系列和3.14系列内核上进行的相同实验表明,leve或ENTER的使用率为零。据推测,用于编译这些内核的较新gcc的gcc代码生成已经停止(或者机器选项设置不同) +1,今天最有趣的问题。对于1),GCC支持