From 7d4f79d6ca70dc4e226119d70d4100e639f40137 Mon Sep 17 00:00:00 2001 From: ShellWen Date: Tue, 22 Sep 2026 13:14:37 +0800 Subject: [PATCH 1/6] :test_tube: capture MSVC ABI baseline and assembly diagnostics --- .github/workflows/build.yaml | 12 ++++++++++++ crates/core/native/CMakeLists.txt | 3 +++ crates/core/native/abi_test.cc | 15 +++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index a82b27e..7beaf35 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -124,6 +124,7 @@ jobs: fi python scripts/test-ci.py - name: Native ABI regression + id: native_abi env: TARGET: ${{ matrix.target }} run: | @@ -136,6 +137,17 @@ jobs: cmake -S crates/core/native -B ".cache/native-tests/$TARGET" -DCMAKE_BUILD_TYPE=Release "${options[@]}" cmake --build ".cache/native-tests/$TARGET" --config Release --parallel 2 --target v8_killer_abi_test ".cache/native-tests/$TARGET/$executable" + - name: Upload native ABI diagnostics + if: failure() && steps.native_abi.outcome == 'failure' + uses: actions/upload-artifact@v4 + with: + name: native-abi-${{ matrix.target }} + path: | + .cache/native-tests/${{ matrix.target }}/abi_test.asm + .cache/native-tests/${{ matrix.target }}/Release/v8_killer_abi_test.exe + .cache/native-tests/${{ matrix.target }}/v8_killer_abi_test + retention-days: 7 + if-no-files-found: ignore - name: Build, test and lint env: TARGET: ${{ matrix.target }} diff --git a/crates/core/native/CMakeLists.txt b/crates/core/native/CMakeLists.txt index eb0a184..dd15df3 100644 --- a/crates/core/native/CMakeLists.txt +++ b/crates/core/native/CMakeLists.txt @@ -31,6 +31,9 @@ install(FILES ${dobby_SOURCE_DIR}/LICENSE DESTINATION share/licenses/dobby) add_executable(v8_killer_abi_test EXCLUDE_FROM_ALL abi_test.cc) target_link_libraries(v8_killer_abi_test PRIVATE v8_killer_native dobby ${CMAKE_DL_LIBS}) +if(MSVC) + target_compile_options(v8_killer_abi_test PRIVATE /FAs "/Fa${CMAKE_CURRENT_BINARY_DIR}/abi_test.asm") +endif() if(WIN32) target_link_libraries(v8_killer_abi_test PRIVATE psapi) endif() diff --git a/crates/core/native/abi_test.cc b/crates/core/native/abi_test.cc index 67593c3..1cc57be 100644 --- a/crates/core/native/abi_test.cc +++ b/crates/core/native/abi_test.cc @@ -52,13 +52,27 @@ static NOINLINE MaybeLocal compile_module(void *isolate, uintptr_t *source, return MaybeLocal((uintptr_t)isolate + *source + options + reason); } +static void print_entry(const char *name, const void *address) { + auto bytes = static_cast(address); + std::printf("%s entry:", name); + for (size_t i = 0; i < 32; ++i) std::printf(" %02x", static_cast(bytes[i])); + std::putchar('\n'); +} + int main() { std::setvbuf(stdout, nullptr, _IONBF, 0); uintptr_t source = 10; auto volatile internal = compile_internal; auto volatile public_compile = compile; + auto baseline = public_compile(Local{(void *)1}, &source, 2, (Local *)3, 4, (Local *)5, 6, 7); + std::printf("CompileFunction baseline: source=%" PRIuPTR " expected=10 result=%" PRIuPTR " expected=38\n", + source, baseline.value); + if (source != 10 || baseline.value != 38) return 7; std::printf("CompileFunctionInternal=%p CompileFunction=%p CompileModule=%p source=%p\n", (void *)compile_internal, (void *)compile, (void *)compile_module, (void *)&source); + print_entry("CompileFunctionInternal original", (void *)compile_internal); + print_entry("CompileFunction original", (void *)compile); + print_entry("CompileModule original", (void *)compile_module); auto status = v8_killer_instrument((void *)compile_internal); std::printf("CompileFunctionInternal hook status=%d\n", status); if (status) return 1; @@ -69,6 +83,7 @@ int main() { status = v8_killer_instrument((void *)compile); std::printf("CompileFunction hook status=%d\n", status); if (status) return 3; + print_entry("CompileFunction patched", (void *)compile); source = 10; seen_context = nullptr; seen_source = nullptr; From 2b1a76db142b818241833f5260348927e19a5f21 Mon Sep 17 00:00:00 2001 From: ShellWen Date: Tue, 22 Sep 2026 13:23:41 +0800 Subject: [PATCH 2/6] :test_tube: isolate MSVC instruction decoder boundary failure --- crates/core/native/CMakeLists.txt | 1 + crates/core/native/abi_test.cc | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/crates/core/native/CMakeLists.txt b/crates/core/native/CMakeLists.txt index dd15df3..74a1ae9 100644 --- a/crates/core/native/CMakeLists.txt +++ b/crates/core/native/CMakeLists.txt @@ -30,6 +30,7 @@ install(TARGETS v8_killer_native dobby ARCHIVE DESTINATION lib) install(FILES ${dobby_SOURCE_DIR}/LICENSE DESTINATION share/licenses/dobby) add_executable(v8_killer_abi_test EXCLUDE_FROM_ALL abi_test.cc) +target_include_directories(v8_killer_abi_test PRIVATE ${dobby_SOURCE_DIR}/source ${dobby_SOURCE_DIR}/source/include ${dobby_SOURCE_DIR}/external/logging) target_link_libraries(v8_killer_abi_test PRIVATE v8_killer_native dobby ${CMAKE_DL_LIBS}) if(MSVC) target_compile_options(v8_killer_abi_test PRIVATE /FAs "/Fa${CMAKE_CURRENT_BINARY_DIR}/abi_test.asm") diff --git a/crates/core/native/abi_test.cc b/crates/core/native/abi_test.cc index 1cc57be..d85aa01 100644 --- a/crates/core/native/abi_test.cc +++ b/crates/core/native/abi_test.cc @@ -2,6 +2,9 @@ #include #include #include +extern "C" { +#include "InstructionRelocation/x86/x86_insn_decode/x86_insn_decode.h" +} extern "C" int v8_killer_instrument(void *); extern "C" int v8_killer_instrument_module(void *); @@ -61,6 +64,18 @@ static void print_entry(const char *name, const void *address) { int main() { std::setvbuf(stdout, nullptr, _IONBF, 0); + uint8_t instructions[16] = {0x48, 0x63, 0x44, 0x24, 0x48, 0x4c, 0x63, 0x54, 0x24, 0x40}; + x86_options_t config = {}; + config.mode = 64; + for (size_t offset = 0; offset < 10; offset += 5) { + x86_insn_decode_t decoded = {}; + x86_insn_decode(&decoded, instructions + offset, &config); + std::printf("decoder offset=%zu length=%u rex=%02x opcode=%02x operands=%c%c,%c%c flags=%u\n", + offset, unsigned(decoded.length), unsigned(decoded.rex), unsigned(decoded.primary_opcode), + decoded.insn_spec.operands[0].code, decoded.insn_spec.operands[0].type, + decoded.insn_spec.operands[1].code, decoded.insn_spec.operands[1].type, unsigned(decoded.flags)); + if (decoded.length != 5) return 8; + } uintptr_t source = 10; auto volatile internal = compile_internal; auto volatile public_compile = compile; From 7e8ad91b1d92aab2a376b9c7a32ebfc965fa7431 Mon Sep 17 00:00:00 2001 From: ShellWen Date: Tue, 22 Sep 2026 13:28:15 +0800 Subject: [PATCH 3/6] :bug: initialize Dobby decoder operands portably on MSVC --- crates/core/native/patch.cmake | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/crates/core/native/patch.cmake b/crates/core/native/patch.cmake index 04cb9c6..38f859b 100644 --- a/crates/core/native/patch.cmake +++ b/crates/core/native/patch.cmake @@ -18,6 +18,15 @@ if(NOT content MATCHES "PAGE_READWRITE") endif() file(WRITE "${windows}" "${content}") +set(decoder "${dobby_SOURCE_DIR}/source/InstructionRelocation/x86/x86_insn_decode/x86_insn_decode.c") +file(READ "${decoder}" content) +string(FIND "${content}" "#define op3_flag" macro_start) +string(FIND "${content}" "#define op2_flag" macro_end) +string(SUBSTRING "${content}" 0 ${macro_start} before_macro) +string(SUBSTRING "${content}" ${macro_end} -1 after_macro) +# MSVC drops the nested array designators in the upstream operand table initializer. +file(WRITE "${decoder}" "${before_macro}#define op3_flag(x, f, o0, o1, o2) { #x, { {{ (#o0)[0], (#o0)[1] }}, {{ (#o1)[0], (#o1)[1] }}, {{ (#o2)[0], (#o2)[1] }} }, (f) }\n${after_macro}") + set(build_file "${dobby_SOURCE_DIR}/CMakeLists.txt") file(READ "${build_file}" content) string(REPLACE "string(TIMESTAMP TODAY \"%Y%m%d\")" "set(TODAY \"20210615-223aabced043\")" content "${content}") From d3c1749e62fc78eeb7ecfedf2a132395e9f2c4ad Mon Sep 17 00:00:00 2001 From: ShellWen Date: Tue, 22 Sep 2026 13:31:49 +0800 Subject: [PATCH 4/6] :bug: use constant array initializers for MSVC decoder tables --- crates/core/native/patch.cmake | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/core/native/patch.cmake b/crates/core/native/patch.cmake index 38f859b..0bf0504 100644 --- a/crates/core/native/patch.cmake +++ b/crates/core/native/patch.cmake @@ -25,7 +25,11 @@ string(FIND "${content}" "#define op2_flag" macro_end) string(SUBSTRING "${content}" 0 ${macro_start} before_macro) string(SUBSTRING "${content}" ${macro_end} -1 after_macro) # MSVC drops the nested array designators in the upstream operand table initializer. -file(WRITE "${decoder}" "${before_macro}#define op3_flag(x, f, o0, o1, o2) { #x, { {{ (#o0)[0], (#o0)[1] }}, {{ (#o1)[0], (#o1)[1] }}, {{ (#o2)[0], (#o2)[1] }} }, (f) }\n${after_macro}") +file(WRITE "${decoder}" "${before_macro}#define op3_flag(x, f, o0, o1, o2) { #x, { { #o0 }, { #o1 }, { #o2 } }, (f) }\n${after_macro}") +set(decoder_header "${dobby_SOURCE_DIR}/source/InstructionRelocation/x86/x86_insn_decode/x86_insn_decode.h") +file(READ "${decoder_header}" content) +string(REPLACE " struct {\n uint8_t code;\n uint8_t type;\n };\n uint8_t data[2];" " uint8_t data[2];\n struct {\n uint8_t code;\n uint8_t type;\n };" content "${content}") +file(WRITE "${decoder_header}" "${content}") set(build_file "${dobby_SOURCE_DIR}/CMakeLists.txt") file(READ "${build_file}" content) From 1403a57c2a331ac81ccdf85ff41580527d09da3c Mon Sep 17 00:00:00 2001 From: ShellWen Date: Tue, 22 Sep 2026 13:36:19 +0800 Subject: [PATCH 5/6] :green_heart: select the MSVC linker explicitly for Cargo --- .github/workflows/build.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 7beaf35..eb447d0 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -81,6 +81,7 @@ jobs: if [[ $TARGET == x86_64-pc-windows-msvc ]]; then command -v cl cl 2>&1 || true + echo "CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER=$(cygpath -w "${VCToolsInstallDir}bin/Hostx64/x64/link.exe")" >> "$GITHUB_ENV" printf '%s\n' "$VCToolsVersion" "$WindowsSDKVersion" "$VCToolsInstallDir" "$WindowsSdkDir" else gcc --version From 2bdb9368cf1f649862aa1a0b51153915c0118554 Mon Sep 17 00:00:00 2001 From: ShellWen Date: Tue, 22 Sep 2026 13:40:31 +0800 Subject: [PATCH 6/6] :bug: use compiler Windows macro for Dobby memory search --- crates/core/native/patch.cmake | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crates/core/native/patch.cmake b/crates/core/native/patch.cmake index 0bf0504..4f391b6 100644 --- a/crates/core/native/patch.cmake +++ b/crates/core/native/patch.cmake @@ -19,6 +19,11 @@ endif() file(WRITE "${windows}" "${content}") set(decoder "${dobby_SOURCE_DIR}/source/InstructionRelocation/x86/x86_insn_decode/x86_insn_decode.c") +set(arena "${dobby_SOURCE_DIR}/source/MemoryAllocator/NearMemoryArena.cc") +file(READ "${arena}" content) +string(REPLACE "#if defined(WIN32)" "#if defined(_WIN32)" content "${content}") +file(WRITE "${arena}" "${content}") + file(READ "${decoder}" content) string(FIND "${content}" "#define op3_flag" macro_start) string(FIND "${content}" "#define op2_flag" macro_end)