分配一个新的调用堆栈 [英] Allocating a new call stack

查看:176
本文介绍了分配一个新的调用堆栈的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(我认为有这个问题的机会很高要么是重复或以其他方式已经在这里回答,但寻找的答案是很难得益于堆栈分配和相关术语的干扰。)

我有一个玩具的编译器,我一直工作在一个脚本语言。为了能够同时它在进步暂停脚本的执行并返回到宿主程序,它有自己的堆栈:内存是简单的块与被使用正常的C $ C加一个堆栈指针变量对于诸如此类的事情等等等等$ C这样的操作。不感兴趣为止。

目前,我编译C.但我感兴趣的编译调查机器code,以及 - 同时保持第二堆叠和$ P $返回到宿主程序的能力pdefined控制点。

所以...我想这不太可能是用我自己的code内的常规栈寄存器一个问题,我想会发生什么变化寄存器有我自己的事,只要当它所做的一切将恢复(做纠正我,如果我错了这一点)。的的......如果我想剧本code调出其他一些库code,它是安全的使用这个虚拟堆叠离开程序,或者是有必要这还给原来的堆用于此目的?

答案像<一个href=\"http://stackoverflow.com/questions/6777765/how-does-stack-growing-work-on-windows-and-linux/6777825#6777825\">this 之一和<一个href=\"http://stackoverflow.com/questions/6648059/why-is-there-a-limit-on-the-stack-size/6648119#6648119\">this 之一表明堆栈是不是内存传统的块,但是它依赖于特殊的,系统的具体行为与页面错误和诸如此类的东西做的。

所以:


  • 是安全的堆栈指针移动到内存的其他区域?栈内存是不是特殊?我想,线程库必须这样做,因为他们创造更多的筹码...

  • 假设内存的任何区域是安全的使用栈寄存器和指令来操作,我能想到的任何理由会调用与已知的调用深度的功能(即没有递归,没有函数指针)是一个问题只要该金额可在虚拟堆栈。对吗?

  • 堆栈溢出显然是正常的code的一个问题,无论如何,但会有在这样的系统中溢出的任何额外灾难性的后果?

这显然不是确有必要的,因为简单地返回指针到真正的堆栈将是完全维修,或为此事首先不滥用他们,只是把与较少的寄存器,我可能不应该尝试做它在所有(至少没有因显然被我的深度)。但我还是好奇无论哪种方式。要知道这些事情是如何工作的。

编辑:对不起,当然,应该说。我工作在x86(32位对我自己的机器),Windows和Ubuntu Linux系统。没有什么异国风情。


解决方案

所有这些答案都是基于共同的处理器架构,并且因为它涉及生成汇编code,它是特定目标 - 如果你决定做这个处理器X,它有堆栈的一些怪异的操作,下面显然是不值得的写上[替代皮] screensurface。对于x86在一般情况下,下搁置除非另有说明。


 是安全的堆栈指针移动到内存的其他区域?


  
  

栈内存是不是特殊?我想线程库
  必须这样做,因为他们创造更多的筹码...


这样的内存是不是特别的。但这但认为这不是在x86架构,其中的堆栈段用于限制堆栈使用情况。虽然这是可能的,这是相当罕见的在实现看看。我知道,几年前诺基亚使用了细分32位模式下特殊的操作系统。至于我现在能想到的,这是唯一一个我有任何接触与使用用于为x86的分割模式描述堆栈段。


  

假设存储器中任何区域是安全的使用堆栈来操纵
  寄存器和指令,我能想到的任何理由将是一个
  问题调用与已知调用深度的功能(即不
  递归,没有函数指针),只要该金额可
  上的虚拟堆栈。对吧?


正确的。正如只要你别指望能要回一些其他的功能,而无需切换回原来的堆栈。递归的有限水平也是可以接受的,只要堆栈足够深[有该肯定硬而不递归来解决某些类型的问题 - 二叉树搜索例如]。


  

堆栈溢出显然是正常的code的一个问题,无论如何,
  但会有在溢出任何多余的,灾难性的后果
  这样的系统?


事实上,这将是一个艰难的错误,如果你是一个有点凶开裂。

我会建议你使用 VirtualProtect的()(Windows)或则mprotect()(Linux的一个电话等),以纪念为不可读和不可写叠底,因此如果你的code偶然走开栈,它崩溃正确,而不是其他一些更微妙的未定义行为[因为它不能保证内存的正下方(低地址)不可用,所以你可以覆盖其他一些有用的东西,如果它熄灭堆栈,这将导致一些很难调试的错误。

加一点code那偶尔检查堆栈深度(你知道你的栈开始和结束,因此它不应该是很难检查特定堆栈值范围之外[如果你给自己堆栈的顶部,你保护的我们是死区内的一些额外的缓冲空间 - 一个崩溃区,因为他们将调用它,如果它是在碰撞中汽车]你还可以填补了识别的模式整个堆栈,检查有多少是不变。

(I think there's a high chance of this question either being a duplicate or otherwise answered here already, but searching for the answer is hard thanks to interference from "stack allocation" and related terms.)

I have a toy compiler I've been working on for a scripting language. In order to be able to pause the execution of a script while it's in progress and return to the host program, it has its own stack: a simple block of memory with a "stack pointer" variable that gets incremented using the normal C code operations for that sort of thing and so on and so forth. Not interesting so far.

At the moment I compile to C. But I'm interested in investigating compiling to machine code as well - while keeping the secondary stack and the ability to return to the host program at predefined control points.

So... I figure it's not likely to be a problem to use the conventional stack registers within my own code, I assume what happens to registers there is my own business as long as everything is restored when it's done (do correct me if I'm wrong on this point). But... if I want the script code to call out to some other library code, is it safe to leave the program using this "virtual stack", or is it essential that it be given back the original stack for this purpose?

Answers like this one and this one indicate that the stack isn't a conventional block of memory, but that it relies on special, system specific behaviour to do with page faults and whatnot.

So:

  • is it safe to move the stack pointers into some other area of memory? Stack memory isn't "special"? I figure threading libraries must do something like this, as they create more stacks...
  • assuming any area of memory is safe to manipulate using the stack registers and instructions, I can think of no reason why it would be a problem to call any functions with a known call depth (i.e. no recursion, no function pointers) as long as that amount is available on the virtual stack. Right?
  • stack overflow is obviously a problem in normal code anyway, but would there be any extra-disastrous consequences to an overflow in such a system?

This is obviously not actually necessary, since simply returning the pointers to the real stack would be perfectly serviceable, or for that matter not abusing them in the first place and just putting up with fewer registers, and I probably shouldn't try to do it at all (not least due to being obviously out of my depth). But I'm still curious either way. Want to know how these sorts of things work.

EDIT: Sorry of course, should have said. I'm working on x86 (32-bit for my own machine), Windows and Ubuntu. Nothing exotic.

解决方案

All of these answer are based on "common processor architectures", and since it involves generating assembler code, it has to be "target specific" - if you decide to do this on processor X, which has some weird handling of stack, below is obviously not worth the screensurface it's written on [substitute for paper]. For x86 in general, the below holds unless otherwise stated.

is it safe to move the stack pointers into some other area of memory?

Stack memory isn't "special"? I figure threading libraries must do something like this, as they create more stacks...

The memory as such is not special. This does however assume that it's not on an x86 architecture where the stack segment is used to limit the stack usage. Whilst that is possible, it's rather rare to see in an implementation. I know that some years ago Nokia had a special operating system using segments in 32-bit mode. As far as I can think of right now, that's the only one I've got any contact with that uses the stack segment for as x86-segmentation mode describes.

Assuming any area of memory is safe to manipulate using the stack registers and instructions, I can think of no reason why it would be a problem to call any functions with a known call depth (i.e. no recursion, no function pointers) as long as that amount is available on the virtual stack. Right?

Correct. Just as long as you don't expect to be able to get back to some other function without switching back to the original stack. Limited level of recursion would also be acceptable, as long as the stack is deep enough [there are certain types of problems that are definitely hard to solve without recursion - binary tree search for example].

stack overflow is obviously a problem in normal code anyway, but would there be any extra-disastrous consequences to an overflow in such a system?

Indeed, it would be a tough bug to crack if you are a little unlucky.

I would suggest that you use a call to VirtualProtect() (Windows) or mprotect() (Linux etc) to mark the "end of the stack" as unreadable and unwriteable so that if your code accidentally walks off the stack, it crashes properly rather than some other more subtle undefined behaviour [because it's not guaranteed that the memory just below (lower address) is unavailable, so you could overwrite some other useful things if it does go off the stack, and that would cause some very hard to debug bugs].

Adding a bit of code that occassionally checks the stack depth (you know where your stack starts and ends, so it shouldn't be hard to check if a particular stack value is "outside the range" [if you give yourself some "extra buffer space" between the top of the stack and the "we're dead" zone that you protected - a "crumble zone" as they would call it if it was a car in a crash]. You can also fill the entire stack with a recognisable pattern, and check how much of that is "untouched".

这篇关于分配一个新的调用堆栈的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆