On Sat, Jul 27, 2013 at 12:12:57PM -0400, Rich Felker wrote: > On Sat, Jul 27, 2013 at 05:44:05PM +0200, Ondřej Bílka wrote: > > On Thu, Jul 25, 2013 at 12:50:53PM -0400, Rich Felker wrote: > > > On Thu, Jul 25, 2013 at 08:55:38AM +0200, Ondřej Bílka wrote: > > > You can't add call-saved registers without breaking the ABI, because > > > they need to be saved in the jmp_buf, which does not have space for > > > them. > > > > > Well you can. Use versioning, structure will not change and layout for > > old setjmp/longjmp is unchanged. For new setjmp we set jump address to > > jmp_buf address to distinguish it from first case. Then for each thread > > we keep a stack with extra space needed to save additional registers. > > When setjmp/longjmp is called we prune frames from exited functions. > > This required unbounded storage which does not exist. From a practical > standpoint you would either have to reserve a huge amount of storage > (e.g. double the allocated thread stack size and use half of it as > reserved space for jmp_buf) or make the calling program crash when the
Standard trick mmap and double. > small, reasonable amount of reserved space is exhausted. The latter is > highly unacceptable since the main purpose (IMO:) of jmp_buf is to > work around bad library code that can't handle resource exhaustion by > replacing its 'xmalloc' type functions with ones that longjmp to a > thread-local jmp_buf set by the caller (e.g. this is the only way to > use glib robustly). > Well what I wrote is to work around pathologic cases. With versioning and changing size of structure I could do trick with distinguishing by pointing to itself and it would mostly work. It would break when function that uses setjmp obtains jmp_buf by parameter from other unit. To avoid it we need allocate some extra space. Most programs would have number of jmp_buf instances limited so not deallocating extra would not cause problem. To violate that limit you need to have variation to these: int rec(..){ jmp_buf x; setjmp(x); ... rec(x); } while (cond){ jmp_buf *x= malloc(...); setjmp(x); ... free(x); } > By the way, I do have another horrible idea for how you could do it. Next idea would be hack gcc to mark all variables volatile in functions with setjmp. > glibc's jmp_buf is actually a sigjmp_buf and contains 120 wasted bytes > of sigset_t for nonexistant HURD signals. So you could store a few > registers after the actually-used part of the sigset_t. > > > > Also, unless you add them at the same time the registers are added to > > > the machine (so there's no existing code using those registers), > > > you'll have ABI problems like this: function using the new call-saved > > > registers calls qsort, which calls application code, which assumes the > > > registers are call-clobbered and clobbers them; after qsort returns, > > > the original caller's state is gone. > > > > > What are you talking about? Do you mean that user wrongly marked qsort > > as a function that does not clobber arguments? > > OK, you're obviously thinking of some kind of special way of tagging > individual functions as preserving new registers, rather than whole > object or shared library files, in which case it's plausible that you > can make this part work. > > Rich