diff --git a/src/crypto/randomx/asm/program_epilogue_store.inc b/src/crypto/randomx/asm/program_epilogue_store.inc index b94fa4d99..6fa1a1fcf 100644 --- a/src/crypto/randomx/asm/program_epilogue_store.inc +++ b/src/crypto/randomx/asm/program_epilogue_store.inc @@ -1,4 +1,5 @@ ;# save VM register values + add rsp, 24 pop rcx mov qword ptr [rcx+0], r8 mov qword ptr [rcx+8], r9 diff --git a/src/crypto/randomx/asm/program_loop_load.inc b/src/crypto/randomx/asm/program_loop_load.inc index c29332313..1c53e8314 100644 --- a/src/crypto/randomx/asm/program_loop_load.inc +++ b/src/crypto/randomx/asm/program_loop_load.inc @@ -1,5 +1,5 @@ lea rcx, [rsi+rax] - push rcx + mov [rsp+8], rcx xor r8, qword ptr [rcx+0] xor r9, qword ptr [rcx+8] xor r10, qword ptr [rcx+16] @@ -9,7 +9,7 @@ xor r14, qword ptr [rcx+48] xor r15, qword ptr [rcx+56] lea rcx, [rsi+rdx] - push rcx + mov [rsp+16], rcx cvtdq2pd xmm0, qword ptr [rcx+0] cvtdq2pd xmm1, qword ptr [rcx+8] cvtdq2pd xmm2, qword ptr [rcx+16] diff --git a/src/crypto/randomx/asm/program_loop_store.inc b/src/crypto/randomx/asm/program_loop_store.inc index 1ba1635c6..f778f134f 100644 --- a/src/crypto/randomx/asm/program_loop_store.inc +++ b/src/crypto/randomx/asm/program_loop_store.inc @@ -1,4 +1,4 @@ - pop rcx + mov rcx, [rsp+16] mov qword ptr [rcx+0], r8 mov qword ptr [rcx+8], r9 mov qword ptr [rcx+16], r10 @@ -7,7 +7,7 @@ mov qword ptr [rcx+40], r13 mov qword ptr [rcx+48], r14 mov qword ptr [rcx+56], r15 - pop rcx + mov rcx, [rsp+8] xorpd xmm0, xmm4 xorpd xmm1, xmm5 xorpd xmm2, xmm6 diff --git a/src/crypto/randomx/jit_compiler_x86.cpp b/src/crypto/randomx/jit_compiler_x86.cpp index e7a413704..4f3e86d47 100644 --- a/src/crypto/randomx/jit_compiler_x86.cpp +++ b/src/crypto/randomx/jit_compiler_x86.cpp @@ -36,6 +36,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "crypto/randomx/program.hpp" #include "crypto/randomx/reciprocal.h" #include "crypto/randomx/virtual_memory.hpp" +#include "crypto/rx/Rx.h" #ifdef _MSC_VER # include @@ -168,8 +169,8 @@ namespace randomx { static const uint8_t REX_MAXPD[] = { 0x66, 0x41, 0x0f, 0x5f }; static const uint8_t REX_DIVPD[] = { 0x66, 0x41, 0x0f, 0x5e }; static const uint8_t SQRTPD[] = { 0x66, 0x0f, 0x51 }; - static const uint8_t AND_OR_MOV_LDMXCSR[] = { 0x25, 0x00, 0x60, 0x00, 0x00, 0x0D, 0xC0, 0x9F, 0x00, 0x00, 0x89, 0x44, 0x24, 0xFC, 0x0F, 0xAE, 0x54, 0x24, 0xFC }; - static const uint8_t AND_OR_MOV_LDMXCSR_RYZEN[] = { 0x25, 0x00, 0x60, 0x00, 0x00, 0x0D, 0xC0, 0x9F, 0x00, 0x00, 0x3B, 0x44, 0x24, 0xFC, 0x74, 0x09, 0x89, 0x44, 0x24, 0xFC, 0x0F, 0xAE, 0x54, 0x24, 0xFC }; + static const uint8_t AND_OR_MOV_LDMXCSR[] = { 0x25, 0x00, 0x60, 0x00, 0x00, 0x0D, 0xC0, 0x9F, 0x00, 0x00, 0x89, 0x04, 0x24, 0x0F, 0xAE, 0x14, 0x24 }; + static const uint8_t AND_OR_MOV_LDMXCSR_RYZEN[] = { 0x25, 0x00, 0x60, 0x00, 0x00, 0x0D, 0xC0, 0x9F, 0x00, 0x00, 0x3B, 0x04, 0x24, 0x74, 0x07, 0x89, 0x04, 0x24, 0x0F, 0xAE, 0x14, 0x24 }; static const uint8_t ROL_RAX[] = { 0x48, 0xc1, 0xc0 }; static const uint8_t XOR_ECX_ECX[] = { 0x33, 0xC9 }; static const uint8_t REX_CMP_R32I[] = { 0x41, 0x81 }; @@ -380,10 +381,12 @@ namespace randomx { *(uint32_t*)(code + codePos + 10) = RandomX_CurrentConfig.ScratchpadL3Mask64_Calculated; *(uint32_t*)(code + codePos + 20) = RandomX_CurrentConfig.ScratchpadL3Mask64_Calculated; if (hasAVX) { - uint32_t* p = (uint32_t*)(code + codePos + 29); + uint32_t* p = (uint32_t*)(code + codePos + 32); *p = (*p & 0xFF000000U) | 0x0077F8C5U; } + xmrig::Rx::setMainLoopBounds(code + prologueSize, code + epilogueOffset); + codePos = prologueSize; memcpy(code + codePos - 48, &pcfg.eMask, sizeof(pcfg.eMask)); memcpy(code + codePos, codeLoopLoad, loopLoadSize); diff --git a/src/crypto/randomx/jit_compiler_x86_static.S b/src/crypto/randomx/jit_compiler_x86_static.S index 774118809..e5709cdc2 100644 --- a/src/crypto/randomx/jit_compiler_x86_static.S +++ b/src/crypto/randomx/jit_compiler_x86_static.S @@ -93,7 +93,8 @@ DECL(randomx_program_prologue_first_load): and eax, RANDOMX_SCRATCHPAD_MASK ror rdx, 32 and edx, RANDOMX_SCRATCHPAD_MASK - stmxcsr dword ptr [rsp-20] + sub rsp, 24 + stmxcsr dword ptr [rsp] nop nop nop diff --git a/src/crypto/randomx/jit_compiler_x86_static.asm b/src/crypto/randomx/jit_compiler_x86_static.asm index 9a4d82b92..4b3542e3a 100644 --- a/src/crypto/randomx/jit_compiler_x86_static.asm +++ b/src/crypto/randomx/jit_compiler_x86_static.asm @@ -81,7 +81,8 @@ randomx_program_prologue_first_load PROC and eax, RANDOMX_SCRATCHPAD_MASK ror rdx, 32 and edx, RANDOMX_SCRATCHPAD_MASK - stmxcsr dword ptr [rsp-20] + sub rsp, 24 + stmxcsr dword ptr [rsp] nop nop nop diff --git a/src/crypto/rx/Rx.cpp b/src/crypto/rx/Rx.cpp index 7ff7e1c45..2887ab151 100644 --- a/src/crypto/rx/Rx.cpp +++ b/src/crypto/rx/Rx.cpp @@ -74,6 +74,7 @@ bool xmrig::Rx::init(const Job &job, const RxConfig &config, const CpuConfig &cp if (!osInitialized) { msrInit(config); + SetupMainLoopExceptionFrame(); osInitialized = true; } diff --git a/src/crypto/rx/Rx.h b/src/crypto/rx/Rx.h index 200523e96..bcbaa8571 100644 --- a/src/crypto/rx/Rx.h +++ b/src/crypto/rx/Rx.h @@ -57,9 +57,20 @@ public: static void destroy(); static void init(IRxListener *listener); + static void setMainLoopBounds(const void* loopBegin, const void* loopEnd) + { + mainLoopBounds.first = loopBegin; + mainLoopBounds.second = loopEnd; + } + + static const std::pair& getMainLoopBounds() { return mainLoopBounds; } + private: static void msrInit(const RxConfig &config); static void msrDestroy(); + static void SetupMainLoopExceptionFrame(); + + static thread_local std::pair mainLoopBounds; }; diff --git a/src/crypto/rx/Rx_linux.cpp b/src/crypto/rx/Rx_linux.cpp index 991151253..f16ac7e7b 100644 --- a/src/crypto/rx/Rx_linux.cpp +++ b/src/crypto/rx/Rx_linux.cpp @@ -43,6 +43,8 @@ #include #include #include +#include +#include namespace xmrig { @@ -178,6 +180,29 @@ static bool wrmsr(const MsrItems &preset, bool save) } +static void MainLoopHandler(int sig, siginfo_t *info, void *ucontext) +{ +# if defined(__x86_64__) || defined(__amd64__) + ucontext_t *ucp = (ucontext_t*) ucontext; + + LOG_INFO(YELLOW_BOLD("%s at %p"), (sig == SIGSEGV) ? "SIGSEGV" : "SIGILL", ucp->uc_mcontext.gregs[REG_RIP]); + + void* p = reinterpret_cast(ucp->uc_mcontext.gregs[REG_RIP]); + const std::pair& loopBounds = xmrig::Rx::getMainLoopBounds(); + + if ((loopBounds.first <= p) && (p < loopBounds.second)) { + ucp->uc_mcontext.gregs[REG_RIP] = reinterpret_cast(loopBounds.second); + } + else { + abort(); + } +# endif +} + + +thread_local std::pair Rx::mainLoopBounds = { nullptr, nullptr }; + + } // namespace xmrig @@ -208,3 +233,16 @@ void xmrig::Rx::msrDestroy() LOG_ERR(CLEAR "%s" RED_BOLD_S "failed to restore initial state" BLACK_BOLD(" (%" PRIu64 " ms)"), tag, Chrono::steadyMSecs() - ts); } } + + +void xmrig::Rx::SetupMainLoopExceptionFrame() +{ +# if defined(__x86_64__) || defined(__amd64__) + struct sigaction act = {}; + act.sa_sigaction = MainLoopHandler; + act.sa_flags = SA_RESTART | SA_SIGINFO; + sigaction(SIGSEGV, &act, nullptr); + sigaction(SIGILL, &act, nullptr); +# endif +} + diff --git a/src/crypto/rx/Rx_win.cpp b/src/crypto/rx/Rx_win.cpp index 8e9c198f4..483ebe562 100644 --- a/src/crypto/rx/Rx_win.cpp +++ b/src/crypto/rx/Rx_win.cpp @@ -303,6 +303,37 @@ static bool wrmsr(const MsrItems &preset, bool save) } +static LONG WINAPI MainLoopHandler(_EXCEPTION_POINTERS *ExceptionInfo) +{ + if (ExceptionInfo->ExceptionRecord->ExceptionCode == 0xC0000005) { + const char* accessType; + switch (ExceptionInfo->ExceptionRecord->ExceptionInformation[0]) { + case 0: accessType = "read"; break; + case 1: accessType = "write"; break; + case 8: accessType = "DEP violation"; break; + default: accessType = "unknown"; break; + } + LOG_INFO(YELLOW_BOLD("[THREAD %u] Access violation at 0x%p: %s at address 0x%p"), GetCurrentThreadId(), ExceptionInfo->ExceptionRecord->ExceptionAddress, accessType, ExceptionInfo->ExceptionRecord->ExceptionInformation[1]); + } + else { + LOG_INFO(YELLOW_BOLD("[THREAD %u] Exception 0x%08X at 0x%p"), GetCurrentThreadId(), ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionInfo->ExceptionRecord->ExceptionAddress); + } + + void* p = reinterpret_cast(ExceptionInfo->ContextRecord->Rip); + const std::pair& loopBounds = xmrig::Rx::getMainLoopBounds(); + + if ((loopBounds.first <= p) && (p < loopBounds.second)) { + ExceptionInfo->ContextRecord->Rip = reinterpret_cast(loopBounds.second); + return EXCEPTION_CONTINUE_EXECUTION; + } + + return EXCEPTION_CONTINUE_SEARCH; +} + + +thread_local std::pair Rx::mainLoopBounds = { nullptr, nullptr }; + + } // namespace xmrig @@ -333,3 +364,9 @@ void xmrig::Rx::msrDestroy() LOG_ERR(CLEAR "%s" RED_BOLD_S "failed to restore initial state" BLACK_BOLD(" (%" PRIu64 " ms)"), tag, Chrono::steadyMSecs() - ts); } } + + +void xmrig::Rx::SetupMainLoopExceptionFrame() +{ + AddVectoredExceptionHandler(1, MainLoopHandler); +}