Skip site navigation (1)Skip section navigation (2)
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>