Add a fallback path for arch_scrub_control_stack

This commit is contained in:
Douglas Katzman 2026-08-31 22:59:19 -04:00
parent ba8cedba53
commit c0ab42f560
2 changed files with 30 additions and 9 deletions

View file

@ -80,6 +80,8 @@ static const unsigned char vector_fill_expect_bytes[] = {
0xEB, 0x10
};
unsigned int cpuid_fn1_ecx = 0;
// Poke in a byte that changes an opcode to enable faster vector fill.
// Using fixed offsets and bytes is no worse than what we do elsewhere.
void tune_asm_routines_for_microarch(void)
@ -109,7 +111,6 @@ void tune_asm_routines_for_microarch(void)
#endif
unsigned int eax, ebx, ecx, edx, xcr0;
unsigned int cpuid_fn1_ecx = 0;
cpuid(0, 0, &eax, &ebx, &ecx, &edx);
if (eax >= 1) { // see if we can execute basic id function 1

View file

@ -36,8 +36,10 @@
// macOS does not like the general way we do this, so do something different.
#if defined(LISP_FEATURE_DARWIN) || defined(LISP_FEATURE_WIN32)
#define LOAD_PIC_VAR(x,dest) mov GNAME(x)(%rip), dest
#define LOAD_PIC_UINT(x,reg) mov GNAME(x)(%rip), %e##reg
#else
#define LOAD_PIC_VAR(x,dest) mov GNAME(x)@GOTPCREL(%rip), dest ; mov (dest), dest
#define LOAD_PIC_UINT(x,reg) mov GNAME(x)@GOTPCREL(%rip), %r##reg ; mov (%r##reg), %e##reg
#endif
/* Get the right type of alignment. Linux, FreeBSD and OpenBSD
@ -421,14 +423,9 @@ GNAME(arch_scrub_control_stack):
cmp %r9, %rdi
jbe .Lhit_bottom
/* Check 8 quadwords (64 bytes) below RDI */
.Lprobe:
movdqa -64(%rdi), %xmm0
por -48(%rdi), %xmm0
por -32(%rdi), %xmm0
por -16(%rdi), %xmm0
ptest %xmm0, %xmm0 // Sets ZF=1 if all 64 bytes are zero
jz .Lfound_clear
LOAD_PIC_UINT(cpuid_fn1_ecx, ax)
test $(1 << 19), %eax
jnz .Lprobe_sse
/* This loop differs from its previous incarnation in several ways:
* 1. We're no longer interleaving the looking-for-stopping-point and zeroing.
@ -441,9 +438,32 @@ GNAME(arch_scrub_control_stack):
* 3. There's no reason to operate on 4k at a time. That granularity
* has nothing to do with anything about how the stack is used. */
.Lprobe: // slower way
/* Check 8 quadwords (64 bytes) below RDI */
movq -64(%rdi), %rax
orq -56(%rdi), %rax
orq -48(%rdi), %rax
orq -40(%rdi), %rax
orq -32(%rdi), %rax
orq -24(%rdi), %rax
orq -16(%rdi), %rax
orq -8(%rdi), %rax
jz .Lfound_clear
sub $1024, %rdi // Step arbitrarily -128 words (1KiB)
cmp %r9, %rdi
ja .Lprobe
jmp .Lhit_bottom
.Lprobe_sse: // faster way
movdqa -64(%rdi), %xmm0
por -48(%rdi), %xmm0
por -32(%rdi), %xmm0
por -16(%rdi), %xmm0
ptest %xmm0, %xmm0 // Sets ZF=1 if all 64 bytes are zero
jz .Lfound_clear
sub $1024, %rdi // Step arbitrarily -128 words (1KiB)
cmp %r9, %rdi
ja .Lprobe_sse
.Lhit_bottom:
/* %rdi landed somewhere at or below the cutoff, so restore it to the exact