Discussion:
[9fans] a jmp_buf in APE question
(too old to reply)
Jens Staal
2013-01-07 05:45:42 UTC
Permalink
Hi all. Perhaps I have been looking at completely the wrong places and perhaps
I am just not grasping it at all.

For a package that I want to build under APE, I need to put in the stack
pointer (sp) and the program counter (pc) part of jmp_buf specific for Plan9
(since APE does not expose any stack-related functions that could have been
used)

according to /sys/include/ape/setjmp.h, jmp_buf is an array of 10 int:s.

I then went to check out /sys/src/ape/lib/ap/$objtype/setjmp.s
but I could not really understand anything in those files

luckily, I also looked at the GAS-formatted setjmp.s in the GCC-port of the
APE libs.
There, it seems that each function with a jmp_buf variable as an argument has
a set of 10 rows of operations (which I guess correspond to the 10 values in
jmp_buf). Based on that, it would seem that the value for sp is in jmp_buf[2]
and for pc in jmp_buf[3].

Am I correct or have I totally misunderstood how these things work? I am a
self-taught hobbyist so sometimes really basic stuff can have eluded me.

The second question would be, is the position of those two values in jmp_buf
architecture-specific so that I should make a note of that it is working on
i386 only?
erik quanstrom
2013-01-07 10:31:44 UTC
Permalink
Post by Jens Staal
Hi all. Perhaps I have been looking at completely the wrong places and perhaps
I am just not grasping it at all.
For a package that I want to build under APE, I need to put in the stack
pointer (sp) and the program counter (pc) part of jmp_buf specific for Plan9
(since APE does not expose any stack-related functions that could have been
used)
according to /sys/include/ape/setjmp.h, jmp_buf is an array of 10 int:s.
I then went to check out /sys/src/ape/lib/ap/$objtype/setjmp.s
but I could not really understand anything in those files
as you point out, the interface is opaque.

but if you look under the covers, PC and SP are stored in first two
"entries" of the jmp_buf blob. obviously PC and SP are not properly
ints, but rather uintptrs, so the absolute offset will depend on the
pointer size (0 and 4 for 386). a better definition of jmp_buf might be
typedef uchar jmp_buf[4 * sizeof uintptr];
note, a structure will not do, since a structure would be passed in by
value and therefore any values set would disappear on return from setjmp.

for amd64 the setjmp code is (comments changed assuming that jmp_buf is an
array of uintptrs)

TEXT setjmp(SB), $0 /* RARG is set to &jmp_buf[0] */
MOVQ SP, 0(RARG) /* store sp in RARG offset 0; jmp_buf[0] = SP */
MOVQ 0(SP), BX /* return pc */
MOVQ BX, 8(RARG) /* stored at offset 8; jmp_buf[1] = PC */
MOVL $0, AX /* return 0 */
RET

note that in this case the absolute offsets are 0 and 8, since pointers on
amd64 take 8 bytes.
Post by Jens Staal
The second question would be, is the position of those two values in jmp_buf
architecture-specific so that I should make a note of that it is working on
i386 only?
the structure within jmp_buf is entirely determined by the code in setjmp.s

i don't think it would be wise to rely on the structure of jmp_buf. it's
not exposing any structure, so it seems unwise to assume it. the typical
way around this would be to create $objtype.s for each $objtype you wish
to support and store the PC and SP as you like them. i think what you want
is

enum {
Spidx,
Pcidx,
Nregsave,
};
typedef uintptr myjmpbuf[Nregsave];
then it should be a simple matter of reappropriating the code from setjmp.

- erik
Jens Staal
2013-01-07 11:05:20 UTC
Permalink
Post by erik quanstrom
the structure within jmp_buf is entirely determined by the code in setjmp.s
i don't think it would be wise to rely on the structure of jmp_buf.
Do you mean by this that it would be unwise to do something like

"variable that needs to be = sp" = (jmp_buf) jb[0]
"variable that needs to be = pc" = (jmp_buf) jb[1]


this is how other similar ports of this package (GNU portable threads) have
been made, for example for win32

"variant 4", "variant 5" and "variant X" in the file pth_mctx.c are examples
of this strategy.*


*
for reference:
http://www.opensource.apple.com/source/ChatServer/ChatServer-37.1/jabberd-
src/jabberd/pth-1.4.0/pth_mctx.c?txt
erik quanstrom
2013-01-07 11:15:08 UTC
Permalink
Post by Jens Staal
Do you mean by this that it would be unwise to do something like
"variable that needs to be = sp" = (jmp_buf) jb[0]
"variable that needs to be = pc" = (jmp_buf) jb[1]
yes, i think it would be unwise. i think you mean

sp = ((uintptr*)jb)[0]
pc = ((uintptr*)jb)[1]
Post by Jens Staal
this is how other similar ports of this package (GNU portable threads) have
been made, for example for win32
it's just my opinion. i would see such code as peeking through
an deliberately-opaque interface. and to me that's almost always
a bad idea. even if it works, and even if other people do it.

others might have other thoughts.

- erik
Jens Staal
2013-01-07 16:43:28 UTC
Permalink
Post by erik quanstrom
yes, i think it would be unwise. i think you mean
sp = ((uintptr*)jb)[0]
pc = ((uintptr*)jb)[1]
yeah sorry I did not mean it to look like C-code and the paranthesis was meant
to indicate that jb got #defined to jmp_buf.
Post by erik quanstrom
Post by Jens Staal
this is how other similar ports of this package (GNU portable threads) have
been made, for example for win32
it's just my opinion. i would see such code as peeking through
an deliberately-opaque interface. and to me that's almost always
a bad idea. even if it works, and even if other people do it.
others might have other thoughts.
- erik
I thank you for your feedback and help I did the build despite your warnings,
and the result can be found either at:

http://code.google.com/p/ports2plan9/downloads/list

or:

/n/sources/contrib/staal1978/pkg

Tests and pre-compiled test binaries can also be found at:

/n/sources/contrib/staal1978/pkg/pth_test

There are some scary stuff in there, like the test_sig result, but others seem
to work...

Loading...