~skeeto/public-inbox

1

Let's write a setjmp

Steadman Dillroper <dillstead@gmail.com>
Details
Message ID
<CAOJH3v5rbc1GNQyVNgfo0Qq+iChUmHMUDBWkKpcnmX7+9pVwKA@mail.gmail.com>
DKIM signature
missing
Download raw message
Hi Chris,

I ported your set/longjmp to ARM and as expected it took < 1/2 hour to
port and run a few quick tests:
https://gist.github.com/dillstead/874bf051bb528199327ec7087c2de3cf

I have a bare metal threading implementation complete with custom
implementations for whatever standard library features I need and this
will fit in nicely.  It'll allow me to port over David Hanson's
exception framework from his "C Interfaces and Implementations" book:
https://github.com/dillstead/cii/blob/master/src/except.c

I'm not sure how familiar you are with ARM assembly but I figured I'd
share a few details with you.

The procedure calls standard for ARM specifies 9 non-volatile
registers r4 - r8, r10, r11, and SP (r13).  In addition I preserve the
LR (link register r14) which contains the return address when the
program executes a branch instruction to call a function.  I noticed
that the return address is pushed on the stack in your x86 code.

Also, the assembler provides a nice pseudo-instruction to push/pop a
range of registers given a base address:
  stm r0, { r4-r11, sp, lr }

I played around a bit with the returns-twice function attribute, and
indeed I was able to break the program pretty easily when I removed it
and only stored SP and LR in the jmp buf.  Examining the difference in
the assembly code for main with and without the attribute showed what
I expected to see.  Without the attribute it kept a non-volatile local
variable in a non-volatile register across calls and as soon as I
added back the attribute the compiler made sure to save and restore
that variable from the stack.

I wonder if I could get away with no-return and only storing two
registers into the jmp buf, SP and LR?

Best,

Steadman
Details
Message ID
<20231006201208.b4mepvtgnx6wta6q@nullprogram.com>
In-Reply-To
<CAOJH3v5rbc1GNQyVNgfo0Qq+iChUmHMUDBWkKpcnmX7+9pVwKA@mail.gmail.com> (view parent)
DKIM signature
missing
Download raw message
Very nice! I'm far less familiar with ARM, especially ARM32, so thanks for 
the explanation. The stm and ldm mnemonics make it really simple!

One small thing, which I noticed myself but then was surprised to see GCC 
warn about, is that the arena should have your jmp_buf, not a GCC built-in 
jmp_buf:

--- a/arm_setjmp.c
+++ b/arm_setjmp.c
@@ -39,3 +39,3 @@ struct arena
     size_t off;
     -    void *jmp_buf[5];
     +    jmp_buf jmp_buf;
      };

> I wonder if I could get away with no-return and only storing two 
> registers into the jmp buf, SP and LR?

I suggest compiling some programs using __builtin_{setjmp,longjmp} to see 
how GCC or Clang does it using only 3 saves (I think?). My understanding 
is that it effectively stores part of the jmp_buf on the stack at the call 
site, which it finds through the saved stack pointer.
Reply to thread Export thread (mbox)