Re: kern/60426 (Signal handler corrupts AVX (YMM) registers)
Taylor R Campbell <[email protected]>
| Newsgroups | gmane.os.netbsd.bugs |
|---|---|
| Message-ID | <[email protected]> |
> Date: Thu, 09 Jul 2026 10:33:14 +0700 > From: Robert Elz <[email protected]> > > Date: Wed, 8 Jul 2026 23:48:44 +0000 (UTC) > From: [email protected] > > | 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