Tag: callstack

分配新的调用堆栈

(我认为这个问题很可能已经重复或者已经在这里回答了,但是由于“堆栈分配”和相关术语的干扰,寻找答案很难。) 我有一个玩具编译器,我一直在研究脚本语言。 为了能够在脚本正在进行时暂停执行并返回到主机程序,它有自己的堆栈:带有“堆栈指针”变量的简单内存块,使用正常的C代码操作递增对于那种事情等等。 到目前为止没有意思。 目前我编译为C.但我也有兴趣调查编译机器代码 – 同时保持二级堆栈和在预定义控制点返回主机程序的能力。 所以…我认为在我自己的代码中使用传统的堆栈寄存器不太可能是一个问题,我假设寄存器会发生什么,只要一切都在我完成时就恢复了(如果我做的话,请纠正我)在这一点上我错了。 但是 ……如果我希望脚本代码调用其他库代码,使用这个“虚拟堆栈”离开程序是否安全,或者是否必须为此目的返回原始堆栈? 像这一个和这一个的答案表明堆栈不是传统的内存块,但它依赖于特殊的,系统特定的行为来处理页面错误和诸如此类的东西。 所以: 将堆栈指针移动到其他内存区域是否安全? 堆栈内存不是“特殊”? 我认为线程库必须做这样的事情,因为它们会创建更多的堆栈…… 假设使用堆栈寄存器和指令操作任何内存区域都是安全的,我可以认为没有理由调用任何具有已知调用深度的函数(即没有递归,没有函数指针)是一个问题,只要这样做金额在虚拟堆栈上可用。 对? 无论如何,堆栈溢出在普通代码中显然是一个问题,但是对于这样的系统中的溢出会有任何额外的灾难性后果吗? 这显然不是必需的,因为简单地将指针返回到实际堆栈将是完全可用的,或者就此而言,首先不要滥用它们并且只是放置更少的寄存器,我可能不应该尝试这样做完全(尤其是因为显然不在我的深处)。 但无论如何我仍然很好奇。 想知道这些事情是如何运作的。 编辑:对不起,当然应该说。 我正在研究x86(我自己的机器为32位),Windows和Ubuntu。 没有异国情调。

如何更好地打印C / C ++中的调用堆栈?

我想打印调用堆栈与更多信息,如在gdb中。 这就是我到目前为止所拥有的。 void to_print_callstack() { void *buffer[100]; int n = backtrace(buffer,10); char **str = backtrace_symbols(buffer, n); for (int i = 0; i < n; i++) { printf("%d: %s\n", i, str[i]); } } 当它运行时,我得到如下的东西。 0: ./test-prog() [0x4466bf] 1: ./test-prog() [0x445e1d] 2: ./test-prog() [0x443fd5] 3: ./test-prog() [0x439a99] 4: ./test-prog() [0x43302f] 5: ./test-prog() [0x4322c9] 6: ./test-prog() [0x4320cd] 7: […]

关于函数调用堆栈的混淆

根据维基: 调用者将返回地址压入堆栈,被调用的子例程一旦完成,就会从调用堆栈中弹出返回地址并将控制转移到该地址。 来自Wiki的图片: 我不太明白这一点。 说我有一个C程序如下: #include int foo(int x) { return x+1; } void spam() { int a = 1; //local variable int b = foo(a); //subroutine called int c = b; //local variable } int main() { spam(); return 0; } 我认为调用堆栈应该类似于绘图,如下所示: means none local variables or params _| parameters for foo() |_ top […]

-fno-stack-protector有什么用?

我用C编写了一个应用程序,我试图在编译时理解-fno-stack-protector命令的用途是什么。 对于我的特定应用程序,如果我在防止缓冲区溢出方面使用此命令,则没有任何区别。 我在网上看到-fstack-protector和-fno-stack-protector命令分别启用和禁用堆栈粉碎保护器,但如果我自己编译应用程序,如何预先启用保护器? 命令的使用是否可能取决于运行应用程序的系统?

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

我曾经在嵌入式系统的项目上工作,我们重新安排了堆栈变量声明的顺序,以减少生成的可执行文件的大小。 例如,如果我们有: void func() { char c; int i; short s; … } 我们会将此重新排序为: void func() { int i; short s; char c; … } 由于对齐问题,第一个导致使用12个字节的堆栈空间,第二个导致仅8个字节。 这是C编译器的标准行为,还是我们使用的编译器的缺点? 在我看来,编译器应该能够重新排序堆栈变量,以便在需要时支持更小的可执行文件大小。 有人向我建议,C标准的某些方面可以防止这种情况,但我无法以任何方式找到信誉良好的来源。 作为一个额外的问题,这也适用于C ++编译器吗? 编辑 如果答案是肯定的,那么C / C ++编译器可以重新排列堆栈变量,你能给出一个肯定会这样做的编译器的例子吗? 我想看看编译器文档或类似的东西支持这一点。 再次编辑 谢谢大家的帮助。 对于文档,我能够找到的最好的东西是GCC (pdf)中的最佳堆栈槽分配 ,由Naveen Sharma和Sanjiv Kumar Gupta撰写,于2003年在海湾合作委员会峰会会议上提交。 这里讨论的项目是使用ADS编译器进行ARM开发。 在该编译器的文档中提到,像我所示的排序声明可以提高性能以及堆栈大小,因为ARM-Thumb架构如何计算本地堆栈帧中的地址。 该编译器没有自动重新排列本地人以利用这一点。 这里链接的文章说,截至2003年,GCC也没有重新安排堆栈帧以改善ARM-Thumb处理器的参考局部性,但它暗示你可以。 我找不到任何明确说明在GCC中实施的内容,但我认为这篇论文可以certificate你是正确的。 再次感谢。

如何使用Windows x64记录堆栈帧

我正在使用带有Win32的Stackdumps,将所有返回地址写入我的日志文件。 我稍后将这些与mapfile匹配(参见我的文章[Post Mortem Debugging] [1])。 编辑::问题解决了 – 请参阅下面我自己的答案。 对于Windows x64,我找不到将返回地址写入日志文件的可靠方法。 我尝试了几种方法: 试验1:指针算术: CONTEXT Context; RtlCaptureContext(&Context); char *eNextBP = (char *)Context.Rdi; for(ULONG Frame = 0; eNextBP ; Frame++) { char *pBP = eNextBP; eNextBP = *(char **)pBP; // Next BP in Stack fprintf(LogFile, “*** %2d called from %016LX (pBP at %016LX)\n”, Frame, (ULONG64)*(char **)(pBP + 8), […]