From owner-freebsd-arch Sat Jun 29 22:40:34 2002 Delivered-To: freebsd-arch@freebsd.org Received: from mx1.FreeBSD.org (mx1.FreeBSD.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 6108937B400 for ; Sat, 29 Jun 2002 22:40:29 -0700 (PDT) Received: from leviathan.cnchost.com (leviathan.cnchost.com [207.155.252.18]) by mx1.FreeBSD.org (Postfix) with ESMTP id 1EE0543E13 for ; Sat, 29 Jun 2002 22:40:29 -0700 (PDT) (envelope-from bakul@bitblocks.com) Received: from bitblocks.com (adsl-209-204-185-216.sonic.net [209.204.185.216]) by leviathan.cnchost.com id BAA20480; Sun, 30 Jun 2002 01:40:27 -0400 (EDT) [ConcentricHost SMTP Relay 1.14] Message-ID: <200206300540.BAA20480@leviathan.cnchost.com> To: Terry Lambert Cc: arch@FreeBSD.ORG Subject: Re: Time to make the stack non-executable? In-reply-to: Your message of "Sat, 29 Jun 2002 15:13:58 PDT." <3D1E3126.C96FFAA5@mindspring.com> Date: Sat, 29 Jun 2002 22:40:23 -0700 From: Bakul Shah Sender: owner-freebsd-arch@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG 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