问题标签 [callstack]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
11 回答
5261 浏览

c++ - C 编译器可以重新排列堆栈变量吗?

过去我从事过嵌入式系统的项目,我们重新安排了堆栈变量的声明顺序以减小生成的可执行文件的大小。例如,如果我们有:

我们将其重新排序为:

由于对齐问题,第一个导致使用了 12 个字节的堆栈空间,而第二个导致仅使用了 8 个字节。

这是 C 编译器的标准行为还是我们使用的编译器的一个缺点?

在我看来,如果编译器愿意,它应该能够重新排序堆栈变量以支持更小的可执行文件大小。有人向我建议 C 标准的某些方面阻止了这种情况,但无论哪种方式我都无法找到有信誉的来源。

作为一个额外的问题,这是否也适用于 C++ 编译器?

编辑

如果答案是肯定的,C/C++ 编译器可以重新排列堆栈变量,你能举一个绝对做到这一点的编译器的例子吗?我想查看编译器文档或类似的东西来支持这一点。

再次编辑

谢谢大家的帮助。对于文档,我能找到的最好的东西是 Naveen Sharma 和 Sanjiv Kumar Gupta 的论文GCC 中的 Optimal Stack Slot Assignment (pdf),它在 2003 年的 GCC 峰会上发表。

这里讨论的项目是使用 ADS 编译器进行 ARM 开发。在该编译器的文档中提到,像我展示的排序声明可以提高性能以及堆栈大小,因为 ARM-Thumb 体系结构如何计算本地堆栈帧中的地址。该编译器不会自动重新排列本地变量以利用这一点。此处链接的论文说,截至 2003 年,GCC 也没有重新排列堆栈帧以改善 ARM-Thumb 处理器的参考位置,但这意味着您可以。

我找不到任何可以肯定地说这曾经在 GCC 中实现过的东西,但我认为这篇论文可以证明你都是正确的。再次感谢。

0 投票
14 回答
2083 浏览

c++ - 什么可以修改帧指针?

我现在在一个相当庞大的 C++ 应用程序中出现了一个非常奇怪的错误(在 CPU 和 RAM 使用以及代码长度方面非常大 - 超过 100,000 行)。这是在双核 Sun Solaris 10 机器上运行的。该程序订阅股票价格馈送并将它们显示在用户配置的“页面”上(页面是用户自定义的窗口结构 - 该程序允许用户配置此类页面)。在其中一个底层库变为多线程之前,该程序一直可以正常工作。受此影响的程序部分已相应更改。关于我的问题。

大约在每三次执行中,程序将在启动时出现段错误。这不一定是硬性规则——有时它会连续崩溃 3 次,然后连续工作 5 次。有趣的是段错误(阅读:痛苦)。它可能以多种方式表现出来,但最常见的情况是函数 A 调用函数 B,进入函数 B 时,帧指针会突然设置为 0x000002。功能一:

这是一个简单的信号实现。impl_ 和 _A_a1 在崩溃时的框架内定义良好。在实际执行该指令时,我们最终到达程序计数器 0x000002。

这并不总是发生在该功能上。事实上,它发生在很多地方,但这是最简单的情况之一,不会留下太大的错误空间。有时会发生的情况是堆栈分配的变量会突然无缘无故地坐在垃圾内存上(总是在 0x000002 上)。其他时候,相同的代码会运行得很好。所以,我的问题是,什么可以如此严重地破坏堆栈?什么实际上可以改变帧指针的值?我当然从来没有听说过这样的事情。我能想到的唯一一件事就是在数组上越界写入,但我已经使用堆栈保护器构建了它,它应该会出现这种情况的任何实例。我在这里的堆栈范围内也很好。我也不 看不到另一个线程如何覆盖第一个线程的堆栈上的变量,因为每个线程都有自己的堆栈(这都是 pthreads)。我已经尝试在 linux 机器上构建它,虽然我没有在那里遇到段错误,但大约有三分之一的时间它会冻结在我身上。

0 投票
35 回答
526752 浏览

javascript - 如何在 JavaScript 中找出调用者函数?

有没有办法找出调用堆栈?

0 投票
2 回答
12170 浏览

c# - 你如何找到调用者函数?

关闭为“如何找到调用当前方法的方法?”的完全相同的副本

可以用c#吗?

0 投票
1 回答
1321 浏览

winforms - 帮我分析这个调用堆栈,看看是什么调用了我的方法

好的,所以我有一个非常简单的表单,其中几乎没有逻辑,由演示者控制。有一个方法 public void Reset() 将表单重置为其初始状态。这应该只由演示者调用,并且在非常特殊的情况下(例如活动超时)。我遇到了一个问题,尽管在一些边缘情况下(例如,当我模拟我的应用程序失去数据库连接时) Reset() 方法在不应该被调用的时候被调用,我无法弄清楚是什么.

所以我在 Reset() 方法中设置了一个跟踪点并让它打印调用堆栈。奇怪的是,这引发了更多的问题。谁能帮我弄清楚对 Reset() 的调用来自哪里?我的调用堆栈在下面。

我应该解释的一件事是 DriverInterface2.UI.WinForms.NonInheritingForms.CheckInForm 您可以在调用堆栈中看到。这是 ICheckInForm(相关接口)的一个非常简单的实现,只需创建 CheckInForm 并将其委托给它。它存在只是因为我使用的是城堡温莎,并且连接从 Form 继承的类变得非常混乱。无论如何,该方法的全部内容是这样的:

这是调用堆栈:

0 投票
2 回答
465 浏览

execution - 调用堆栈中更高的东西进行调用

当调用者在堆栈中较高时,这意味着什么?例如,假设我启动一个程序,加载一个表单(我们称之为 a),然后这个表单调用另一个表单 (b)。被调用的表单将在堆栈的顶部,所以如果这个表单调用了表单 a,这会是堆栈中更高的调用者调用下面的东西吗?

谢谢

0 投票
17 回答
141566 浏览

assembly - 堆栈在汇编语言中是如何工作的?

我目前正在尝试了解堆栈是如何工作的,所以我决定自学一些汇编语言,我正在使用这本书:

http://savannah.nongnu.org/projects/pgubook/

我正在使用Gas并在Linux Mint上进行开发。

我有点困惑:

据我所知,堆栈只是一种数据结构。所以我假设如果我在汇编中编码,我必须自己实现堆栈。然而,情况似乎并非如此,因为有类似的命令

因此,在为x86架构编写汇编代码并使用 Gas 语法时:堆栈只是已经实现的数据结构吗?或者它实际上是在硬件级别实现的?或者是别的什么?其他芯片组的大多数汇编语言也是否已经实现了堆栈?

我知道这是一个有点愚蠢的问题,但我实际上对此感到很困惑。

0 投票
12 回答
29659 浏览

c++ - 如何使用 Windows x64 记录堆栈帧

我正在使用带有 Win32 的 Stackdumps,将所有返回地址写入我的日志文件。我稍后将这些与映射文件进行匹配(请参阅我的文章 [Post Mortem Debugging][1])。

编辑:: 问题已解决 - 请参阅下面我自己的答案。

在 Windows x64 中,我找不到仅将返回地址写入日志文件的可靠方法。我尝试了几种方法:

试验一:指针算术:

这在调试版本中工作正常 - 但它在发布版本中崩溃。Context.Rdi 的值在那里没有可用的值。我确实检查了编译器设置的差异(visual Studio 2005)。我没有发现任何可疑之处。

试用 2:使用 StackWalk64

这不仅会转储返回地址,还会转储整个堆栈。我使用这种方法在我的日志文件中收到了大约 1000 行。我可以使用它,但是我必须通过行搜索,并且堆栈的一些数据恰好是有效的代码地址。

试验 3:使用回溯

导致没有可用的信息。

有没有人在 x64 中实现了这样的堆栈遍历,它只写出堆栈中的返回地址?我见过 [StackTrace64][2]、[StackWalker][3] 和其他方法。它们要么不编译,要么过于复杂。这基本上是一个简单的任务!

示例 StackDump64.cpp

运行此示例会产生以下日志文​​件内容:

0 投票
10 回答
7397 浏览

macos - 为什么 Mac ABI 要求 x86-32 的 16 字节堆栈对齐?

我可以理解旧 PPC RISC 系统甚至 x86-64 的这一要求,但对于久经考验的旧 x86?在这种情况下,堆栈只需要在 4 字节边界上对齐。是的,一些 MMX/SSE 指令需要 16 字节对齐,但如果这是被调用者的要求,那么它应该确保对齐正确。为什么要让每个调用者都负担这个额外的要求?这实际上会导致性能下降,因为每个呼叫站点都必须管理此要求。我错过了什么吗?

更新:在对此进行了更多调查并咨询了一些内部同事之后,我对此有一些理论:

  1. 操作系统的 PPC、x86 和 x64 版本之间的一致性
  2. 似乎 GCC 代码生成器现在始终执行 sub esp,xxx 然后将数据“移动”到堆栈上,而不是简单地执行“推送”指令。这实际上在某些硬件上可能更快。
  3. 虽然这确实使调用站点有点复杂,但在使用调用者清理堆栈的默认“cdecl”约定时几乎没有额外的开销。

我对最后一项的问题是,对于依赖于被调用方清理堆栈的调用约定,上述要求确实“丑化”了代码生成。例如,某些编译器决定实现更快的基于寄存器的调用样式以供其内部使用(即任何不打算从其他语言或源调用的代码)?这种堆栈对齐的事情可能会抵消通过在寄存器中传递一些参数所获得的一些性能提升。

更新:到目前为止,唯一真正的答案是一致性,但对我来说,这有点太容易了。我在 x86 架构方面拥有超过 20 年的经验,如果一致性,而不是性能或其他具体的东西,真的是原因,那么我恭敬地建议开发人员要求它有点天真。他们忽略了近三年的工具和支持。特别是如果他们希望工具供应商能够快速轻松地为他们的平台调整他们的工具(也许不是......它苹果......),而不必跳过几个看似不必要的障碍。

我会在另一天左右给出这个话题然后关闭它......

有关的

0 投票
4 回答
2045 浏览

c++ - 你可以在 C++ 中设置调用堆栈的大小吗?(vs2008)

我正在使用分配相对较大的本地数组的示例代码。(准确地说是 32768)当我尝试相同的操作时,我得到的行为似乎是堆栈溢出。现在我想知道我的示例是否可能将堆栈设置为比我的应用程序更大。这可能吗?如果是这样怎么办?