Date: Sat, 29 Jun 2002 22:40:23 -0700 From: Bakul Shah <bakul@bitblocks.com> To: Terry Lambert <tlambert2@mindspring.com> Cc: arch@FreeBSD.ORG Subject: Re: Time to make the stack non-executable? Message-ID: <200206300540.BAA20480@leviathan.cnchost.com> In-Reply-To: Your message of "Sat, 29 Jun 2002 15:13:58 PDT." <3D1E3126.C96FFAA5@mindspring.com>
next in thread | previous in thread | raw e-mail | index | archive | help
GCC uses trampolines to handle addresses of nested functions. This is a method that allows you to avoid passing a static link of a nested function as a separate (but hidden) arg. (For the benefit of people who don't know this technique) Consider: int f(int(*p)(int), int x) { return p(2*x); } int g(int a) { int b; int h(int c) { return b + c; } b = a*a; return f(&h, 2); } int i(int d) { return f(&g, 2); } Here h is a function nested within g. When g is called, it calls h and passes it the address of h. When h is called from f, it must have access to locals in the containing g's frame. Normally you'd passed a hidden static link (address of g's frame). Alternately you can construct a trampoline function on the stack and pass its address (compile the above example and see for yourself). Since this function is created at runtime, it has the necessary information to provide the right static link before calling g. By putting it on the stack it is removed upon return from g (i.e. no need to garbage collect it). For details please see gcc.info and http://master.debian.org/~karlheg/Usenix88-lexic.pdf I don't know if other compilers use this technique. You should ask on comp.lang.{lisp,scheme,functional,ada,pascal,misc,...} before going ahead with this change. In any case, IMHO you are patching the wrong thing. Any time you have more user mode threads than the kernel supplied ones, you can't say anything about where the actual stack is (since the stack switching must be done in user mode and the kernel can't play any stack segment switching games). Also, with threads there is not much point in having a stack segment that grows downward since threads may die in any order. As an example I have a simulation core where I can create as many threads as I want subject to memory limits (100K+ is no problem). I simply malloc() the stack for each thread. The point being, if you don't want an executable stack you must also not allow executable data segment since for a threaded program that is where a stack may be. This *will* contrain LISP + functional languages which create function closures on the fly or increase the cost of such function closure a lot. -- bakul To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-arch" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200206300540.BAA20480>