NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: kern/60426 (Signal handler corrupts AVX (YMM) registers)
> Date: Thu, 09 Jul 2026 10:33:14 +0700
> From: Robert Elz <kre%munnari.OZ.AU@localhost>
>
> Date: Wed, 8 Jul 2026 23:48:44 +0000 (UTC)
> From: riastradh%NetBSD.org@localhost
>
> | But the signal delivery logic, and return-from-signal logic, simply
> | doesn't save and restore anything beyond the xmm registers.
>
> Does it really need to? There are lots of restrictions on what
> signal handlers are allowed to do, couldn't one of them simply be
> that if these YMM registers are to be touched in the signal handler,
> (or anything it calls) then it becomes the handler's responsibility
> to save and restore them?
The xmm registers, which have always been available on amd64 since the
beginning, are aliases for the low halves of the ymm registers. Any
SSE2 instruction (again: available on amd64 since the beginning)
writing to xmmN will generally zero the high half of ymmN as a side
effect.
So it's not enough to say that signal handlers must avoid using new
instructions that modify the ymm registers, because old instructions
which have always been reliable in signal handlers modify the ymm
registers too.
> Since (as I understand things) not all processors even have the things
> (if running on one old enough) and I think I have seen firmware options
> to disable them as well, I am guessing that the compilers don't just
> emit instructions to use those registers for everyday normal code, and
> that the application needs to do something special to access them.
Compilers will routinely generate SSE2 instructions for amd64 and i686
code. And libraries often use SSE2 instructions for basic (and
async-signal-safe) functions like memcpy and strlen, like these in
glibc (used on i686 and amd64 targets, respectively):
https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/i386/i686/multiarch/memcpy-sse2-unaligned.S;h=f5d3582d638c80043e77459deaa6a76d411e28c0;hb=f762ccf84f122d1354f103a151cba8bde797d521
https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/x86_64/multiarch/strlen-sse2.S;h=1b118a0245b4a40e4f8e1c434cbb7a0426efdfc5;hb=f762ccf84f122d1354f103a151cba8bde797d521
I expect golang is doing similarly, either in a library or in compiler
codegen, in its signal handler, e.g. to copy a 16-byte object on the
stack using a pair of MOVDQA instructions to move from memory to xmmN
and back to memory, which will clear the high half of ymmN.
Here's an example of gcc16 doing something like that, with only the
-O2 option, nothing to ask it to go out of its way to use the vector
unit:
/* input */
struct bigstruct {
long x[2];
};
void
copybigstruct(struct bigstruct *dst, const struct bigstruct *src)
{
*dst = *src;
}
/* output */
"copybigstruct":
movdqu xmm0, XMMWORD PTR [rsi]
movups XMMWORD PTR [rdi], xmm0
ret
https://godbolt.org/z/1ccGYTEdE
Home |
Main Index |
Thread Index |
Old Index