Discussion:
[9fans] assembly syntax in plan 9
(too old to reply)
Alexander Kapshuk
2012-01-16 12:30:02 UTC
Permalink
i have a question about putting things on the stack for x86 arch under plan
9...

under unix/linux, when defining a function, i would:
(1). push the address the base pointer is pointing to prior to this
function being called, onto the stack; e.g. pushl %ebp
(2). then i would have the base pointer point to the current stack pointer;
e.g. movl %esp, %ebp
(3). then i would allocate space on the stack for local variables, if any;
e.g. subl $n, %esp;
(4). then follows the function body;
to return from the function i would:
(1). restore the stack pointer; e.g. movl %ebp, %esp;
(2). restore the base pointer, e.g. popl %ebp;
(3). then return to the calling function;

i searched the 9fans archives for posts on assembly programming under plan
9; found some bits and pieces; e.g. in one of the posts it was mentioned
that BP is a general purpose register, not the base pointer; and that FP is
what ebp is under unix/linux;

in the paper for the plan 9 assembler, it says that there are three
registers available to manipulate the stack, FP, SP, and TOS; would the
following comparison stand true then?
plan9 unix/linux
------- -------------
FP EBP
SP -4(%EBP)...-n(%EBP) /* local variables */
TOS ESP

thanks;

sasha kapshuk
Charles Forsyth
2012-01-16 13:08:01 UTC
Permalink
You should read /sys/doc/asm.pdf first.
careful: TOS is only for 68k. nothing else defines or uses it.

Plan 9 doesn't use a base pointer, because everything can be addressed
relative to the stack pointer,
and the loader keeps track of the SP level. thus FP is a virtual register,
that the loader implements
by replacing offsets relative to it by the current appropriate offset from
the hardware stack pointer register (whatever
that might be on a given platform). That's esp on the x86. the TEXT
directive specifies the space a function
requires for its stack frame, and the loader then adds appropriate code at
start and end to provide it.
0(FP) is the first argument, 4(FP) is the second, and so on. 0(SP) is the
bottom of the current frame,
and 0(SP), 4(SP) etc are referenced to build the arguments for outgoing
calls (but that space must
be accounted for in the TEXT directive).

(it's probably not very different in effect from -fno-frame-pointer or
whatever it is for gcc,
which also doesn't use ebp except that is implemented entirely by the
compiler.)
Post by Alexander Kapshuk
i have a question about putting things on the stack for x86 arch under
plan 9...
(1). push the address the base pointer is pointing to prior to this
function being called, onto the stack; e.g. pushl %ebp
(2). then i would have the base pointer point to the current stack
pointer; e.g. movl %esp, %ebp
(3). then i would allocate space on the stack for local variables, if any;
e.g. subl $n, %esp;
(4). then follows the function body;
(1). restore the stack pointer; e.g. movl %ebp, %esp;
(2). restore the base pointer, e.g. popl %ebp;
(3). then return to the calling function;
i searched the 9fans archives for posts on assembly programming under plan
9; found some bits and pieces; e.g. in one of the posts it was mentioned
that BP is a general purpose register, not the base pointer; and that FP is
what ebp is under unix/linux;
in the paper for the plan 9 assembler, it says that there are three
registers available to manipulate the stack, FP, SP, and TOS; would the
following comparison stand true then?
plan9 unix/linux
------- -------------
FP EBP
SP -4(%EBP)...-n(%EBP) /* local variables */
TOS ESP
thanks;
sasha kapshuk
Alexander Kapshuk
2012-01-16 13:27:27 UTC
Permalink
On Mon, Jan 16, 2012 at 3:08 PM, Charles Forsyth
Post by Charles Forsyth
You should read /sys/doc/asm.pdf first.
careful: TOS is only for 68k. nothing else defines or uses it.
Plan 9 doesn't use a base pointer, because everything can be addressed
relative to the stack pointer,
and the loader keeps track of the SP level. thus FP is a virtual register,
that the loader implements
by replacing offsets relative to it by the current appropriate offset from
the hardware stack pointer register (whatever
that might be on a given platform). That's esp on the x86. the TEXT
directive specifies the space a function
requires for its stack frame, and the loader then adds appropriate code at
start and end to provide it.
0(FP) is the first argument, 4(FP) is the second, and so on. 0(SP) is the
bottom of the current frame,
and 0(SP), 4(SP) etc are referenced to build the arguments for outgoing
calls (but that space must
be accounted for in the TEXT directive).
(it's probably not very different in effect from -fno-frame-pointer or
whatever it is for gcc,
which also doesn't use ebp except that is implemented entirely by the
compiler.)
Post by Alexander Kapshuk
i have a question about putting things on the stack for x86 arch under
plan 9...
(1). push the address the base pointer is pointing to prior to this
function being called, onto the stack; e.g. pushl %ebp
(2). then i would have the base pointer point to the current stack
pointer; e.g. movl %esp, %ebp
(3). then i would allocate space on the stack for local variables, if
any; e.g. subl $n, %esp;
(4). then follows the function body;
(1). restore the stack pointer; e.g. movl %ebp, %esp;
(2). restore the base pointer, e.g. popl %ebp;
(3). then return to the calling function;
i searched the 9fans archives for posts on assembly programming under
plan 9; found some bits and pieces; e.g. in one of the posts it was
mentioned that BP is a general purpose register, not the base pointer; and
that FP is what ebp is under unix/linux;
in the paper for the plan 9 assembler, it says that there are three
registers available to manipulate the stack, FP, SP, and TOS; would the
following comparison stand true then?
plan9 unix/linux
------- -------------
FP EBP
SP -4(%EBP)...-n(%EBP) /* local variables */
TOS ESP
thanks;
sasha kapshuk
thanks;

i'll look into that;
Bakul Shah
2012-01-16 15:41:47 UTC
Permalink
A frame pointer is needed for C99's variable length arrays but not otherwise. Only an issue if ever plan9 C is extended to handle C99 or C1x. gcc has to do the right thing even with -fno-frame-pointer.
Post by Charles Forsyth
You should read /sys/doc/asm.pdf first.
careful: TOS is only for 68k. nothing else defines or uses it.
Plan 9 doesn't use a base pointer, because everything can be addressed relative to the stack pointer,
and the loader keeps track of the SP level. thus FP is a virtual register, that the loader implements
by replacing offsets relative to it by the current appropriate offset from the hardware stack pointer register (whatever
that might be on a given platform). That's esp on the x86. the TEXT directive specifies the space a function
requires for its stack frame, and the loader then adds appropriate code at start and end to provide it.
0(FP) is the first argument, 4(FP) is the second, and so on. 0(SP) is the bottom of the current frame,
and 0(SP), 4(SP) etc are referenced to build the arguments for outgoing calls (but that space must
be accounted for in the TEXT directive).
(it's probably not very different in effect from -fno-frame-pointer or whatever it is for gcc,
which also doesn't use ebp except that is implemented entirely by the compiler.)
i have a question about putting things on the stack for x86 arch under plan 9...
(1). push the address the base pointer is pointing to prior to this function being called, onto the stack; e.g. pushl %ebp
(2). then i would have the base pointer point to the current stack pointer; e.g. movl %esp, %ebp
(3). then i would allocate space on the stack for local variables, if any; e.g. subl $n, %esp;
(4). then follows the function body;
(1). restore the stack pointer; e.g. movl %ebp, %esp;
(2). restore the base pointer, e.g. popl %ebp;
(3). then return to the calling function;
i searched the 9fans archives for posts on assembly programming under plan 9; found some bits and pieces; e.g. in one of the posts it was mentioned that BP is a general purpose register, not the base pointer; and that FP is what ebp is under unix/linux;
in the paper for the plan 9 assembler, it says that there are three registers available to manipulate the stack, FP, SP, and TOS; would the following comparison stand true then?
plan9 unix/linux
------- -------------
FP EBP
SP -4(%EBP)...-n(%EBP) /* local variables */
TOS ESP
thanks;
sasha kapshuk
Comeau At9Fans
2012-01-16 18:51:45 UTC
Permalink
Post by Bakul Shah
A frame pointer is needed for C99's variable length arrays but not
otherwise. Only an issue if ever plan9 C is extended to handle C99 or C1x.
gcc has to do the right thing even with -fno-frame-pointer.
What we do in problematic cases with Comeau is to generate code to arrange
for the allocation of the VLA on the heap. I'm not saying this is perfect,
but at least it gets the feature implementable and up and running as "a
portable implementation" versus perhaps not being able to implement it at
all on some platforms.
Bakul Shah
2012-01-16 19:03:43 UTC
Permalink
How do you deal with longjmp?
Post by Bakul Shah
A frame pointer is needed for C99's variable length arrays but not otherwise. Only an issue if ever plan9 C is extended to handle C99 or C1x. gcc has to do the right thing even with -fno-frame-pointer.
What we do in problematic cases with Comeau is to generate code to arrange for the allocation of the VLA on the heap. I'm not saying this is perfect, but at least it gets the feature implementable and up and running as "a portable implementation" versus perhaps not being able to implement it at all on some platforms.
Charles Forsyth
2012-01-16 19:39:48 UTC
Permalink
They are compiling C++ which has language-visible exception handling
instead.
Post by Bakul Shah
How do you deal with longjmp?
Post by Bakul Shah
A frame pointer is needed for C99's variable length arrays but not
otherwise. Only an issue if ever plan9 C is extended to handle C99 or C1x.
gcc has to do the right thing even with -fno-frame-pointer.
What we do in problematic cases with Comeau is to generate code to arrange
for the allocation of the VLA on the heap. I'm not saying this is perfect,
but at least it gets the feature implementable and up and running as "a
portable implementation" versus perhaps not being able to implement it at
all on some platforms.
Comeau At9Fans
2012-01-17 19:27:07 UTC
Permalink
We do allow VLAs in C++ mode as well, but currently keep them separate from
EH.

On Mon, Jan 16, 2012 at 2:39 PM, Charles Forsyth
Post by Charles Forsyth
They are compiling C++ which has language-visible exception handling
instead.
Post by Bakul Shah
How do you deal with longjmp?
Post by Bakul Shah
A frame pointer is needed for C99's variable length arrays but not
otherwise. Only an issue if ever plan9 C is extended to handle C99 or C1x.
gcc has to do the right thing even with -fno-frame-pointer.
What we do in problematic cases with Comeau is to generate code to
arrange for the allocation of the VLA on the heap. I'm not saying this is
perfect, but at least it gets the feature implementable and up and running
as "a portable implementation" versus perhaps not being able to implement
it at all on some platforms.
--
Greg Comeau / 4.3.10.1 with C++0xisms now in beta!
Comeau C/C++ ONLINE ==> http://www.comeaucomputing.com/tryitout
World Class Compilers: Breathtaking C++, Amazing C99, Fabulous C90.
Comeau C/C++ with Dinkumware's Libraries... Have you tried it?
erik quanstrom
2012-01-16 19:49:08 UTC
Permalink
Post by Charles Forsyth
They are compiling C++ which has language-visible exception handling
instead.
Post by Bakul Shah
How do you deal with longjmp?
i thought this wasn't entirely supported, see the "limitations" section.
http://drdobbs.com/184401468

(i had a better reference, but can't find it anymore.)

- erik
Comeau At9Fans
2012-01-17 19:29:49 UTC
Permalink
Post by erik quanstrom
Post by Charles Forsyth
They are compiling C++ which has language-visible exception handling
instead.
Post by Bakul Shah
How do you deal with longjmp?
i thought this wasn't entirely supported, see the "limitations" section.
http://drdobbs.com/184401468
(i had a better reference, but can't find it anymore.)
My recollection is that that paragraph correctly reflects the situation.
--
Greg Comeau / 4.3.10.1 with C++0xisms now in beta!
Comeau C/C++ ONLINE ==> http://www.comeaucomputing.com/tryitout
World Class Compilers: Breathtaking C++, Amazing C99, Fabulous C90.
Comeau C/C++ with Dinkumware's Libraries... Have you tried it?
Joel C. Salomon
2012-01-16 20:11:24 UTC
Permalink
Post by Bakul Shah
Post by Comeau At9Fans
What we do in problematic cases with Comeau is to generate code to
arrange for the allocation of the VLA on the heap. I'm not saying
this is perfect, but at least it gets the feature implementable and up
and running as "a portable implementation" versus perhaps not being
able to implement it at all on some platforms.
How do you deal with longjmp?
I recall reading the source for a (mostly-) portable alloca() that
checked where on the call-stack is was invoked from and released memory
for any alloca() invocation from lower on the stack. (The allocations
themselves were on the heap.)

--Joel
Bakul Shah
2012-01-16 23:18:58 UTC
Permalink
Post by Joel C. Salomon
Post by Bakul Shah
Post by Comeau At9Fans
What we do in problematic cases with Comeau is to generate code to
arrange for the allocation of the VLA on the heap. I'm not saying
this is perfect, but at least it gets the feature implementable and up
and running as "a portable implementation" versus perhaps not being
able to implement it at all on some platforms.
How do you deal with longjmp?
I recall reading the source for a (mostly-) portable alloca() that
checked where on the call-stack is was invoked from and released memory
for any alloca() invocation from lower on the stack. (The allocations
themselves were on the heap.)
You are probably referring to Doug Gwyn's portable alloca().
It relies on a static var to keep track of malloced alloca
blocks. At first I thought it won't work in presence of
threads but I guess if you used thread local storage for this,
alloca() might be made to work but it is pretty bletcherous!

Here's what Gwyn had to say about alloca() later.... [From
https://www.securecoding.cert.org/confluence/display/seccode/08.+Memory+Management+(MEM)

Douglas A. Gwyn

Never use alloca. (See my comments in the Gnu source for
alloca.) Under C99, you can use VLAs. Cince they require
a FIFO lifetime model, neither is as general as dynamic
allocation.

Funny that he recommends using VLAs instead of alloca()!
Comeau At9Fans
2012-01-17 19:31:48 UTC
Permalink
Post by Joel C. Salomon
Post by Bakul Shah
Post by Comeau At9Fans
What we do in problematic cases with Comeau is to generate code to
arrange for the allocation of the VLA on the heap. I'm not saying
this is perfect, but at least it gets the feature implementable and up
and running as "a portable implementation" versus perhaps not being
able to implement it at all on some platforms.
How do you deal with longjmp?
I recall reading the source for a (mostly-) portable alloca() that
checked where on the call-stack is was invoked from and released memory
for any alloca() invocation from lower on the stack. (The allocations
themselves were on the heap.)
We do some analogous book keeping as well.
--
Greg Comeau / 4.3.10.1 with C++0xisms now in beta!
Comeau C/C++ ONLINE ==> http://www.comeaucomputing.com/tryitout
World Class Compilers: Breathtaking C++, Amazing C99, Fabulous C90.
Comeau C/C++ with Dinkumware's Libraries... Have you tried it?
Comeau At9Fans
2012-01-17 19:21:53 UTC
Permalink
Post by Bakul Shah
How do you deal with longjmp?
I don't have it in front of me, but I do seem to recall the Standard allows
that the VLA might still be around though, believe it has an example with
said, for better or worse... Anyway, at some point we're able to detect
that the previous VLA(s) is no longer active and "toss" them.
Post by Bakul Shah
Post by Bakul Shah
A frame pointer is needed for C99's variable length arrays but not
otherwise. Only an issue if ever plan9 C is extended to handle C99 or C1x.
gcc has to do the right thing even with -fno-frame-pointer.
What we do in problematic cases with Comeau is to generate code to arrange
for the allocation of the VLA on the heap. I'm not saying this is perfect,
but at least it gets the feature implementable and up and running as "a
portable implementation" versus perhaps not being able to implement it at
all on some platforms.
--
Greg Comeau / 4.3.10.1 with C++0xisms now in beta!
Comeau C/C++ ONLINE ==> http://www.comeaucomputing.com/tryitout
World Class Compilers: Breathtaking C++, Amazing C99, Fabulous C90.
Comeau C/C++ with Dinkumware's Libraries... Have you tried it?
Bakul Shah
2012-01-18 17:48:28 UTC
Permalink
Post by Bakul Shah
How do you deal with longjmp?
I don't have it in front of me, but I do seem to recall the Standard allows that the VLA might still be around though, believe it has an example with said, for better or worse...
Do you have a reference?
Post by Bakul Shah
Post by Bakul Shah
A frame pointer is needed for C99's variable length arrays but not otherwise. Only an issue if ever plan9 C is extended to handle C99 or C1x. gcc has to do the right thing even with -fno-frame-pointer.
What we do in problematic cases with Comeau is to generate code to arrange for the allocation of the VLA on the heap. I'm not saying this is perfect, but at least it gets the feature implementable and up and running as "a portable implementation" versus perhaps not being able to implement it at all on some platforms.
Seems to me if you can port C, you can use a FP to implement VLAs without alloca games and more efficiently. You can always store the FP in stack local memory if out of registers.
Comeau At9Fans
2012-01-18 18:32:37 UTC
Permalink
Post by Bakul Shah
How do you deal with longjmp?
I don't have it in front of me, but I do seem to recall the Standard
allows that the VLA might still be around though, believe it has an example
with said, for better or worse...
Do you have a reference?
Ok, so, gunna make me look, let's see, ok: 7.13.2.1p5, note the may's and
might's. There should be narrative backing those up.
Post by Bakul Shah
Post by Comeau At9Fans
Post by Bakul Shah
A frame pointer is needed for C99's variable length arrays but not
otherwise. Only an issue if ever plan9 C is extended to handle C99 or C1x.
gcc has to do the right thing even with -fno-frame-pointer.
What we do in problematic cases with Comeau is to generate code to
arrange for the allocation of the VLA on the heap. I'm not saying this is
perfect, but at least it gets the feature implementable and up and running
as "a portable implementation" versus perhaps not being able to implement
it at all on some platforms.
Seems to me if you can port C, you can use a FP to implement VLAs without
alloca games and more efficiently. You can always store the FP in stack
local memory if out of registers.
I probably overstated the situation by saying not being able to implement
it at all... probably should have said I never thought of it beyond the
obvious implementations.
--
Greg Comeau / 4.3.10.1 with C++0xisms now in beta!
Comeau C/C++ ONLINE ==> http://www.comeaucomputing.com/tryitout
World Class Compilers: Breathtaking C++, Amazing C99, Fabulous C90.
Comeau C/C++ with Dinkumware's Libraries... Have you tried it?
Joel C. Salomon
2012-01-16 16:07:47 UTC
Permalink
Post by Charles Forsyth
Plan 9 doesn't use a base pointer, because everything can be addressed
relative to the stack pointer, and the loader keeps track of the SP
level. thus FP is a virtual register, that the loader implements by
replacing offsets relative to it by the current appropriate offset from
the hardware stack pointer register (whatever that might be on a given
platform). That's esp on the x86. the TEXT directive specifies the
space a function requires for its stack frame, and the loader then adds
appropriate code at start and end to provide it. 0(FP) is the first
argument, 4(FP) is the second, and so on. 0(SP) is the bottom of the
current frame, and 0(SP), 4(SP) etc are referenced to build the
arguments for outgoing calls (but that space must be accounted for in
the TEXT directive).
This would make it difficult to implement C99's variable-length
(actually, run-time-determined--length) arrays. The best compiler-only
change I can think of would be to define a hidden variable `size_t
__size_of_all_vlas`, and add code to adjust SP by that amount before &
after each function call.

[Or we could just skip C99, and make the compiler C11-compliant by
pre-defining __STDC_NO_VLA__. ☺]
Post by Charles Forsyth
(it's probably not very different in effect from -fno-frame-pointer or
whatever it is for gcc, which also doesn't use ebp except that is
implemented entirely by the compiler.)
Google turns up <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39337>,
indicating that GCC had issues combining VLAs and -fomit-frame-pointer;
I don't know how they managed the combination.

--Joel
erik quanstrom
2012-01-16 16:27:42 UTC
Permalink
Post by Joel C. Salomon
[Or we could just skip C99, and make the compiler C11-compliant by
pre-defining __STDC_NO_VLA__. ☺]
i think the the compilers have taken c99 under advisement. see
/sys/src/cmd/cc/c99. most reasonable features of c99 have
been implemented.
of the remaining entries in the "Not Done (yet?)" section, 9, 19 and
and 25 stand out to me as the most worth implementing. (although proper
implementation of 25 is likely to break some things.) other folks might
be more excited about _Imaginary, _Complex and
_Surelythisisobscureenoughtonotbreakstuff.

but otoh, we seem to have bigger fish to fry.

- erik
Charles Forsyth
2012-01-16 16:40:30 UTC
Permalink
Not really. One just implements them. For instance, there's no requirement
for all function bodies to use the same scheme.
The unusual bit is that you need to tell the loader what's going on, but
there are still a few bits free for that.
I haven't looked at the details here, but I've had to implement this
before, for Ada, in a different environment,
and don't remember it being too hard, compared to a big list of much harder
things.
Post by Joel C. Salomon
This would make it difficult to implement C99's variable-length
(actually, run-time-determined--length) arrays.
Bakul Shah
2012-01-16 16:54:09 UTC
Permalink
Post by Joel C. Salomon
This would make it difficult to implement C99's variable-length
(actually, run-time-determined--length) arrays. The best compiler-only
change I can think of would be to define a hidden variable `size_t
__size_of_all_vlas`, and add code to adjust SP by that amount before &
after each function call.
Length can be derived from user input, or diff. arrays can be allocated in diff. branches of switch or if stmt. so your trick won't always work.
Post by Joel C. Salomon
Google turns up <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39337>,
indicating that GCC had issues combining VLAs and -fomit-frame-pointer;
I don't know how they managed the combination.
Must use a frame pointer in any function that has VLAs and must save it before calling another function from it.
Loading...