我正在准备C中的一些培训材料,我希望我的示例适合典型的堆栈模型.
C堆栈在Linux,Windows,Mac OSX(PPC和x86),Solaris和最新的Unix中的发展方向是什么?
如果有人能用一个简单的例子说明这一点会有所帮助吗?
此外,在哪里使用parent.frame()而不是parent.env()反之亦然.
我最近一直在研究Java虚拟机规范(JVMS),试图更好地理解我的程序是如何工作的,但我找到了一个我不太了解的部分......
第4.7.4节描述了StackMapTable属性,在该部分中,文档详细介绍了堆栈映射帧.问题在于它有点罗嗦,我通过榜样学得最好; 不是通过阅读.
我知道第一个堆栈映射帧是从方法描述符派生的,但我不明白如何(这应该在这里解释.)另外,我不完全理解堆栈映射帧的作用.我认为它们与Java中的块类似,但看起来好像你不能在彼此内部堆栈映射帧.
无论如何,我有两个具体问题:
还有一个普遍的问题:
Assembly.GetEntryAssembly()不适用于Web应用程序.
但是......我真的需要这样的东西.我使用了一些在Web和非Web应用程序中使用的深层嵌套代码.
我目前的解决方案是浏览StackTrace以找到第一个被调用的程序集.
/// <summary>
/// Version of 'GetEntryAssembly' that works with web applications
/// </summary>
/// <returns>The entry assembly, or the first called assembly in a web application</returns>
public static Assembly GetEntyAssembly()
{
// get the entry assembly
var result = Assembly.GetEntryAssembly();
// if none (ex: web application)
if (result == null)
{
// current method
MethodBase methodCurrent = null;
// number of frames to skip
int framestoSkip = 1;
// loop until we cannot got further in …Run Code Online (Sandbox Code Playgroud) 我试图弄清楚alloca()在记忆层面上实际上是如何工作的。来自Linux 手册页:
alloca() 函数在调用者的堆栈帧中分配 size 字节的空间。当调用 alloca() 的函数返回到其调用者时,该临时空间会自动释放。
这是否意味着将按字节alloca()转发堆栈指针n?或者说新创建的内存到底分配在哪里?
这不是与可变长度数组完全相同吗?
我知道实现细节可能留给操作系统之类的东西。但我想知道一般来说这是如何实现的。
我发现ESP寄存器是当前的堆栈指针,而EBP是当前堆栈帧的基本指针.但是,我不明白这些定义(我刚开始学习如何在汇编程序中编写代码).
据我所知,ESP指向堆栈本身,EBP指向堆栈顶部的任何东西.但这些只是我的猜测而且很可能是不正确的.否则,如下所述的声明是什么意思?
MOV EBP, ESP
Run Code Online (Sandbox Code Playgroud)
编辑:我认为上面的陈述是我书的错字.我认为它应该是EBX而不是EBP
正如很久以前建议的那样,我总是在没有帧指针的情况下构建我的发布可执行文件(如果用/ Ox编译,这是默认的).
但是,现在我在http://research.microsoft.com/apps/pubs/default.aspx?id=81176这篇论文中读到,帧指针对性能没有太大影响.因此,完全优化它(使用/ Ox)或使用帧指针(使用/ Ox/Oy-)完全优化它并不会对性能产生重大影响.
微软似乎表示添加帧指针(/ Oy-)使调试变得更容易,但事实确实如此吗?
我做了一些实验并注意到:
关于帧指针的一般建议是什么?
使用Visual Studio 2010.
我有一个不寻常的情况,我有一个非常简单的异常被抛出并被相同的方法捕获. 它不会被重新抛出(天真的程序员常常遇到的问题).然而它的StackFrame只包含一个当前方法.这是它的样子:
at (my class).MyMethod() in C:\(my file path and line)
Run Code Online (Sandbox Code Playgroud)
实际上,在VS2010调试器的调用堆栈中,可能有30种方法可以实现这一点,它涉及六个不同的程序集.似乎不可能对所有人进行优化.此外,对于.NET 4 ,此代码是在调试模式下构建的,没有优化.我甚至(基于http://msdn.microsoft.com/en-us/library/9dd8z24x.aspx).ini文件(包括一个)命名为[app] .vshost.ini)在同一文件夹中包含:
[.NET Framework Debugging Control]
GenerateTrackingInfo=1
AllowOptimize=0
Run Code Online (Sandbox Code Playgroud)
此外,方法调用不在方法的末尾,因此尾递归优化似乎更不可能.
至于如何调用它:在调用堆栈上没有反射的使用,没有任何类型的Invoke()或BeginInvoke().这只是一个按钮点击的长链调用.点击处理程序大约是调用堆栈的10次调用.在它之下你有通常的WndProc,NativeWindow.Callback,本机/托管转换和消息循环.这最终是在一个从C#EXE程序集运行的ShowDialog()调用中.
现在,我发现我可以在catch处理程序中构造StackTrace类的实例,如果我传递Exception对象,则调用堆栈也很短.相反,如果我只调用没有参数的新StackTrace(),它会产生一个完整的调用堆栈.
我已经使用Reflector试图调试Exception类的内部被抛出并构造它的调用堆栈,但是我无法在Exception或StackTrace中设置断点.我可以在Environment.GetStackTrace()中设置它们,并且这个方法(Exception调用)似乎在构造和抛出过程中不会被调用,但我不知道调试器是否真的正常工作.(虽然这个方法确实被其他一些东西触发了,所以我不知道该怎么做.)
以下是该方法的摘录:
private void MyMethod()
{
...
try
{
throw new ApplicationException("Test failure");
}
catch (Exception e)
{
StackTrace stackTrace1 = new StackTrace(e);
StackTrace stackTrace2 = new StackTrace(e, false);
StackTrace stackTrace3 = new StackTrace(e, true);
StackTrace stackTrace4 = new StackTrace();
string STs = stackTrace1.ToString() + "\n---\n"
+ stackTrace2.ToString() + …Run Code Online (Sandbox Code Playgroud) 默认情况下,将帧指针放在64位体系结构上的理由是什么?我很清楚它可以启用但是为什么GCC在启用32位时首先禁用它?毕竟,64位的寄存器多于32位CPU.
编辑: 当使用更新的GCC版本时,看起来也会为x86删除帧指针.从手册:
"从GCC版本4.6开始,32位Linux x86和32位Darwin x86目标的默认设置(不优化大小时)已更改为-fomit-frame-pointer.默认设置可以恢复为-fno-通过使用--enable-frame-pointer配置选项配置GCC来省略帧指针."
但为什么?
我正在研究两个代码的输出,使用-fomit-frame-pointer和without(gcc at"-O3"默认启用该选项).
pushq %rbp
movq %rsp, %rbp
...
popq %rbp
Run Code Online (Sandbox Code Playgroud)
如果我全局禁用该选项,即使是在极端情况下编译操作系统,是否有一个问题?
我知道中断使用该信息,那么该选项仅适用于用户空间吗?
stack-frame ×10
assembly ×4
c ×2
c# ×2
callstack ×2
gcc ×2
x86 ×2
.net ×1
64-bit ×1
abi ×1
alloca ×1
assemblies ×1
bytecode ×1
environment ×1
exception ×1
java ×1
jvm ×1
performance ×1
r ×1
reflection ×1
stack ×1
stack-trace ×1
x86-64 ×1