• 关于尾部调用,我的一点贡献


    下文摘自我翻译《Expert .NET 2.0 IL Assembler》第13章中的一节,这本书是IL的权威之作,作者就是IL开发Team的:
    尾部调用

    尾部调用类似于方法调用(jmp),二者都是放弃当前方法,并将参数传递到尾部调用(跳转)的方法上。然而,由于尾部调用的参数必须在计算堆栈上被显式加载(与跳转不同,尾部调用丢弃了当前方法的堆栈帧[1]stack frame),它保护了栈的框架并可以使用已经被加载的参数),与跳转不同,尾部调用不需要被调用方法的全部签名匹配调用方法的签名;而只要求返回类型是相同的或兼容的。尾部调用在大规模的递归方法实现中是非常有用的;调用方的栈帧在尾部调用的过程中会被丢弃,因此,不管递归有多么的深,栈的溢出都是没有风险的。对于功能性语言来说这是很重要的,它们会使用递归来代替循环。

    尾部调用是通过在callcallvirtcalli指令前加上前缀tail.指令来识别的:

    l         tail. (0xFE 0x14) 将随后的调用指令标注为尾部调用。该指令不使用参数和栈。和其他前缀指令unaligned.volatite.一样,ILAsm要求该指令与其后随的指令之间至少有一个空格符分隔。

    跳转方法和尾部调用的区别在于尾部调用指令对(tail call pair)原则上是可验证的,只要该指令后面紧跟着ret指令(这取决于调用参数的可验证性)。和其他前缀指令一样,跳过前缀并直接转移到前缀指令(如callcallvirtcalli)是非法的。



    [1] 译注:stack frame,即堆栈帧,是堆栈中的一块区域,它保存着一个函数的返回地址,和该函数内部使用的局部数据(Local Data),它是由函数入口处的SUB ESP48h之类的语句来建立的。

    详细内容参见http://www.zaoxue.com/article/tech-32942.htm




    此外,给出尾部调用的几个异常:

    0x80131899

    Can not pass byref to a tail call.

    0x8013189A

    Missing ret.

    0x8013189B

    Void ret type expected for tail call.

    0x8013189C

    Tail call return type not compatible.

    0x8013189D

    Stack not empty after tail call.

  • 相关阅读:
    sprintf函数%u输入long long int型数值异常
    关于smarty模板display函数的$compile_id 参数的意义
    打log的时候如果少写一个%d,cgi会core掉
    c++标准库的源码和SIG实现是什么关系
    2010
    jquery 中jsonp原理最简说明
    1月17日stl string阅读笔记
    Moss母版页制作详解(一)
    Moss中的权限操作
    动态添加和删除表格行
  • 原文地址:https://www.cnblogs.com/Jax/p/1426653.html
Copyright © 2020-2023  润新知