Adriaan van Os wrote:
Peter N Lewis wrote:
Adriaan van Os wrote:
I now read that Apple has gone completely mad http://lists.apple.com/archives/Xcode-users/2005/Nov/msg00402.html. Bad news.
I agree entirely with their reasoning (the stack should not be executable, it makes far too many exploits possible),
I don't, they have apparently problems with CFM code, so instead of fixing those problems they choose the easy way. Why don't they forbid the execution of *any* code on the Macintosh ? That would be the ultimate safety precaution.
but their solution does indeed sound like madness. Surely it cannot be all that hard to support nested functions without stack based execution?
You can put the trampolining code in a stack-like array (see the last section of http://people.debian.org/~aaronl/Usenix88-lexic.pdf) but that part of memory then still must be made executable. The Darwin kernel forbidding to make any memory executable would be the end of interfacing with CFM code - but you never know what they decide in Cupertino. I will be glad when at some point in the future we all work with free open-source operating systems where the decisions are taken by sane people on sane grounds, after thorough and open discussion. At present, we are entirely dependent on what some empty headed manager in Cupertino or Redmond decides.
I think they do not dare to disable `mprotect': after all dynamic linker have to modify jump tables for correct execution. And Java it too important to forbid executing freshly generated code.
Note that trampolines are not needed for nested procedures as such - only when you pass them as actual procedural parameter.
Also note that trampolines are far from optimal, e.g. for the PowerPC the data and execution cache must be flushed. Trampolines are only there for compatibility with C (http://gcc.gnu.org/onlinedocs/gccint/Trampolines.html). A more elegant and efficient solution is given by Niklaus Wirth in his book on compiler architecture [1] by passing the static link pointer along with the address of the nested procedure. I proposed that solution for FPC.
Do not know about PPC, but on most processors it is enough to flush a single cache line, which is moderate cost. In fact the `mprotect' syscall is likely to cost much more. However, if the trampoline stack is separate from normal stack then you can save most of the `mprotect' calls.
IIRC on AIX you do not need trampolines because all funtions are called via a descriptor which contains static link pointer. Wirth solution probably only considers procedure parameters. If you want also function pointers then there is a choice between thick pointers (which contain both the address and static link) and pointers to descriptors.
But what is more efficient depends very much on expected usage: if you have many function pointer but only limited number of functions then thick pointers require much more space then either trampolines or pointers to descriptors. Similarly when you pass function pointers/parameters: thick pointers are more expensive. Calling functions via trampolines is probably the most expensive way, but if you use trampolines than the const of calling normal functions is the lowest one.
If you assume that most functions are ordinary functions, and that trampolines are created infrequently and used slightly more frequently then created, then trampolines look like an optimal solution. And I think that such assumptions are in fact quite realistic.