From 07a002b5364ac5c303d63564d0c5de9cd4686df6 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Sun, 19 Jan 2025 01:35:07 +0100 Subject: [PATCH] druntime: Update GNU implementation of callWithStackShell --- druntime/src/core/thread/osthread.d | 103 +++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 2 deletions(-) diff --git a/druntime/src/core/thread/osthread.d b/druntime/src/core/thread/osthread.d index ace404fe144..58fca5f7591 100644 --- a/druntime/src/core/thread/osthread.d +++ b/druntime/src/core/thread/osthread.d @@ -1295,8 +1295,107 @@ in (fn) void *sp = void; version (GNU) { - __builtin_unwind_init(); - sp = &sp; + // The generic solution below using a call to __builtin_unwind_init () + // followed by an assignment to sp has two issues: + // 1) On some archs it stores a huge amount of FP and Vector state which + // is not the subject of the scan - and, indeed might produce false + // hits. + // 2) Even on archs like X86, where there are no callee-saved FPRs/VRs there + // tend to be 'holes' in the frame allocations (to deal with alignment) which + // also will contain random data which could produce false positives. + // This solution stores only the integer callee-saved registers. + version (X86) + { + void*[3] regs = void; + asm pure nothrow @nogc + { + "movl %%ebx, %0" : "=m" (regs[0]); + "movl %%esi, %0" : "=m" (regs[1]); + "movl %%edi, %0" : "=m" (regs[2]); + } + sp = cast(void*)®s[0]; + } + else version (X86_64) + { + void*[5] regs = void; + asm pure nothrow @nogc + { + "movq %%rbx, %0" : "=m" (regs[0]); + "movq %%r12, %0" : "=m" (regs[1]); + "movq %%r13, %0" : "=m" (regs[2]); + "movq %%r14, %0" : "=m" (regs[3]); + "movq %%r15, %0" : "=m" (regs[4]); + } + sp = cast(void*)®s[0]; + } + else version (PPC) + { + void*[19] regs = void; + version (Darwin) + enum regname = "r"; + else + enum regname = ""; + static foreach (i; 0 .. regs.length) + {{ + enum int j = 13 + i; // source register + asm pure nothrow @nogc + { + "stw "~regname~j.stringof~", %0" : "=m" (regs[i]); + } + }} + sp = cast(void*)®s[0]; + } + else version (PPC64) + { + void*[19] regs = void; + version (Darwin) + enum regname = "r"; + else + enum regname = ""; + static foreach (i; 0 .. regs.length) + {{ + enum int j = 13 + i; // source register + asm pure nothrow @nogc + { + "std "~regname~j.stringof~", %0" : "=m" (regs[i]); + } + }} + sp = cast(void*)®s[0]; + } + else version (AArch64) + { + // Callee-save registers, x19-x28 according to AAPCS64, section + // 5.1.1. Include x29 fp because it optionally can be a callee + // saved reg + size_t[11] regs = void; + // store the registers in pairs + asm pure nothrow @nogc + { + "stp x19, x20, %0" : "=m" (regs[ 0]), "=m" (regs[1]); + "stp x21, x22, %0" : "=m" (regs[ 2]), "=m" (regs[3]); + "stp x23, x24, %0" : "=m" (regs[ 4]), "=m" (regs[5]); + "stp x25, x26, %0" : "=m" (regs[ 6]), "=m" (regs[7]); + "stp x27, x28, %0" : "=m" (regs[ 8]), "=m" (regs[9]); + "str x29, %0" : "=m" (regs[10]); + "mov %0, sp" : "=r" (sp); + } + } + else version (ARM) + { + // Callee-save registers, according to AAPCS, section 5.1.1. + // arm and thumb2 instructions + size_t[8] regs = void; + asm pure nothrow @nogc + { + "stm %0, {r4-r11}" : : "r" (regs.ptr) : "memory"; + "mov %0, sp" : "=r" (sp); + } + } + else + { + __builtin_unwind_init(); + sp = &sp; + } } else version (AsmX86_Posix) {