我有一个有效的IL代码:
.method public hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 1
ldc.i4.s 10
ldc.i4.s 5
ldc.i4.s 15
ldc.i4.s 5
add
call void [mscorlib]System.Console::WriteLine(int32)
ret
}
我将.maxstack设置为1并在eval堆栈上推送4个值。它为什么有效?
答案 0 :(得分:2)
CLI规范对.maxstack
指令的预期用法相当不透明。有人暗示他们预见到了它的必要性,但没有确定具体规则需要做什么。我们可以从SSCLI20发行版中包含的抖动源中精确地了解它是如何使用的。 clr / src / fjit / fjit.cpp中的相关C ++代码:
/* set up the operand stack */
size = methodInfo->maxStack+1; //+1 since for a new obj intr, +1 for exceptions
#ifdef _DEBUG
size++; //to allow writing TOS marker beyond end;
#endif
if (size > opStack_size) {
if (opStack) delete [] opStack;
opStack_size = size+4; //+4 to cut down on reallocations
New(opStack,OpType[opStack_size]);
}
注意他们离开的肘部空间以避免不得不重复分配操作数堆栈数据结构,size+4
足以解释您的观察结果。这不是唯一的原因,它也很重要,之前有什么方法,如果它有一个很大的.maxstack
,那么也没有什么问题。
Fjit.cpp只是一个示例实现,因此无法保证在您使用的抖动中它的工作方式相同。但是否则足以提供洞察力,该指令可以帮助抖动避免解决鸡与蛋的问题,不得不在点击代码之前分配数据结构。这是一种优化。
它可以炸弹,当然没有必要故意撒谎。
答案 1 :(得分:1)
在阅读你的问题时首先想到的是汇编程序可能正在使用微小的方法标题(Partition II 25.4.2),使.maxstack
无效。
模块中方法的IL紧跟在方法标题之后,方法标题有两种,胖和小。如果方法没有本地,没有异常处理程序,少于64字节的IL和最大堆栈8或更少,那么它可以使用一个小的标头。微小的标题没有指定.maxstack
,而是假设任何带有小标题的方法的.maxstack
为8。
如果确实想要测试溢出评估堆栈时会发生什么,那么你应该确保该方法不会通过添加局部变量或异常处理程序来使用tiny头。