runtime: allow arm64 SEH to be called if illegal instruction

DLLs built with recent Microsoft toolchains for ARM64 test for ARMv8.1
atomics by potentially calling an illegal instruction, and then trapping
the exception to disable use of them by way of a structured exception
handler. However, vectored exception handlers are always called before
structured exception handlers. When LoadLibrary-ing DLLs that do this
probing during initialization, our lastcontinuehandler winds up being
called, and then crashing, but actually it should give execution back to
the library to handle the exception and fix up the state. So special
case this for arm64 with illegal instructions, and hope that we're not
masking other things in external DLLs that might more fatally trigger an
illegal instruction exception.

Updates #47576.

Change-Id: I341ab99cd8d513ae999b75596749d49779072022
Reviewed-on: https://go-review.googlesource.com/c/go/+/340070
Trust: Jason A. Donenfeld <Jason@zx2c4.com>
Run-TryBot: Jason A. Donenfeld <Jason@zx2c4.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
diff --git a/src/runtime/signal_windows.go b/src/runtime/signal_windows.go
index f2ce24d..b720ddc 100644
--- a/src/runtime/signal_windows.go
+++ b/src/runtime/signal_windows.go
@@ -183,6 +183,17 @@
 		return _EXCEPTION_CONTINUE_SEARCH
 	}
 
+	// VEH is called before SEH, but arm64 MSVC DLLs use SEH to trap
+	// illegal instructions during runtime initialization to determine
+	// CPU features, so if we make it to the last handler and we're
+	// arm64 and it's an illegal instruction and this is coming from
+	// non-Go code, then assume it's this runtime probing happen, and
+	// pass that onward to SEH.
+	if GOARCH == "arm64" && info.exceptioncode == _EXCEPTION_ILLEGAL_INSTRUCTION &&
+		(r.ip() < firstmoduledata.text || firstmoduledata.etext < r.ip()) {
+		return _EXCEPTION_CONTINUE_SEARCH
+	}
+
 	winthrow(info, r, gp)
 	return 0 // not reached
 }