RISC VM Translation Defect
Posted: Wed Oct 07, 2026 9:45 am
## Summary
Inside a function wrapped by `EP_MarkerVMRiscBegin()/EP_MarkerVMRiscEnd()` (vm_risc marker region), the Enigma 8.10 RISC virtual machine **translates a specific call sequence incorrectly**, producing wrong values. A minimal, self-contained pure C reproducer is provided: build with `cl`, protect with one `enigma64.exe` command, run, and compare. Failure is 100% deterministic (3/3), RISC-only (Classic VM unaffected in all our tests), and reproducible across repeated protections (random VM seed each time).
Two observable corruptions occur in the same run, both consistent with **32→64-bit zero-extension during translation**:
1. A negative `long long` argument (`-1`) passed as the 4th register argument (r9) to a function is received by the callee as a large positive value (its `if (idx < 0)` branch is not taken).
2. A negative constant (`-999`) materialized inside the region is printed as `4294966297`, which is exactly the zero-extension of `-999` (`0xFFFFFC19` → `0x00000000FFFFFC19`). This exact-match arithmetic is very strong evidence of zero-extension, not of random corruption.
## Environment
- Windows 10 x64; Enigma Protector x64 **8.10** (CLI banner build **20260930**)
- Protection project settings: `VMType=1`; `RISCVMTrashgen/RISCVMObfuscation/RISCVMDuplicates/RISCVMEncryption` all = 0 (minimum); `VirtualMachine/Enabled=False` (marker-driven); `DoNotSearchMarkers=False`; Compression=Best
- Reproducer compiled with: MSVC 2026 (cl 14.51) `cl /O2 /W3`, linked against the official SDK `enigma_ide64.lib` from the Enigma installation
## Documentation conformance (verified against the official Help)
The marker usage in this reproducer follows the official documentation exactly ("Markers VM RISC" and "Rules of markers usage" pages):
- Marker names and call form match the official C++ sample verbatim: `EP_Marker("vm_risc_begin")` / `EP_Marker("vm_risc_end")` (used in the classic-API variant below); the native variant uses the dedicated imports `EP_MarkerVMRiscBegin()/End()` declared in the official `enigma_ide.h` (lines 408-409).
- Marker pairing/nesting/statement-completeness rules are respected; the protection log shows every marker pair found, with **no rejection warnings**.
- The documentation recommends `#pragma optimize("", off)` when optimization causes markers to be "placed chaotically" and rejected (a log warning appears in that case). Our sample deviates by keeping full `/O2` and pinning each marker with `_ReadWriteBarrier()` compiler barriers; disassembly confirms no reordering, and the protection log confirms all markers were accepted. An opt-off variant can be produced on request if needed for comparison.
## A/B result: marker API ruled out — the defect is internal to the RISC VM translation
An identical variant of this reproducer (`risc_argpos_classic.c`, included in this package) uses the **classic string-form markers** `EP_Marker("vm_risc_begin")` / `EP_Marker("vm_risc_end")` — the exact form from the official C++ documentation sample — instead of the native dedicated imports. Everything else is byte-identical.
It fails in **exactly the same way**: `lookup_const(-1@r9) risc=4294966297 plain=303 MISMATCH` (deterministic, 3/3; all markers found, no log warnings).
Therefore the fault does not depend on which marker API is used. Both APIs only define the region boundaries; the corruption occurs inside the translated region — **an internal defect of the RISC VM code translation**.
## Reproduction steps
```
:: 1) build (from the Enigma SDK sample convention; vcvars64 environment)
cl /nologo /O2 /W3 risc_argpos.c /Fe:risc_argpos.exe /Fo:risc_argpos.obj ^
/link /LIBPATH:"C:\Program Files\The Enigma Protector\EnigmaSDK\VC" enigma_ide64.lib
:: 2) protect (project with default/minimum VM settings; -input/-output override)
enigma64.exe <project.enigma64> -input risc_argpos.exe -output risc_argpos_p.exe
:: 3) run both
risc_argpos.exe & :: expected: all six probes "ok", exit 0
risc_argpos_p.exe & :: actual: lookup_const prints 4294966297 (expected 303), "MISMATCH", exit 3
```
Actual protected output (deterministic, 3/3):
```
call1(rcx=-1) risc=130 plain=130 ok
call2(rdx=-2) risc=128 plain=128 ok
call3(r8=-3) risc=126 plain=126 ok
call4(r9=-4) risc=124 plain=124 ok
lookup_const(-1@r9) risc=4294966297 plain=303 MISMATCH
lookup_dyn risc=101 plain=101 ok
FAIL-DIFF
```
## What the probe does
Six marked regions; each has an identical unmarked twin executed natively as the runtime gold standard (the unmarked twin is untouched by protection, so any mismatch isolates the fault to the translation of the marked copy):
- `call1..call4`: call a `noinline` 4-argument function with a negative immediate (`-1/-2/-3/-4`) in argument position 1/2/3/4 (rcx/rdx/r8/r9) respectively. **All four pass** — a bare negative immediate in any argument register is translated correctly.
- `lookup_const` (**fails**): mimics a real-world subscript lookup:
a `struct` list object built on the stack (initialized via SSE `movdqa` stores), called as
`lookup_sub_const(tstate_ptr, &list, &global_key_object, -1)`
where the callee bounds-checks a negative index (`if (idx < 0) { if (-idx > size) return NULL; idx += size; }`) and returns NULL on out-of-range; the caller branches on NULL and yields `-999` on the error path.
- `lookup_dyn` (passes): same, but the 4th argument is a negative value computed at runtime.
Conclusion: the mistranslation is triggered by the **combination** — stack structure + pointer arguments + negative imm64 4th argument (+ the SSE-initialized frame) — not by the negative immediate alone.
## Pre-protection disassembly of the failing region (for reference)
```asm
sub rsp,88h
mov rax,[__security_cookie] ; /GS
xor rax,rsp
mov [rsp+70h],rax
movdqa xmm0,[const] ; struct L init (SSE)
lea r8,[g_key_neg1] ; arg3: &global const object (-1)
movdqa xmm1,[const]
lea rdx,[rsp+20h] ; arg2: &L (stack struct)
mov r9,0FFFFFFFFFFFFFFFFh ; arg4: -1 <-- bytes: 49 C7 C1 FF FF FF FF
movdqa [rsp+20h],xmm0
lea rcx,[g_tstate] ; arg1
movdqa [rsp+30h],xmm1
call lookup_sub_const
test rax,rax
je error_path ; callee returned NULL -> -999 path
mov rax,[rax]
...
```
## Additional manifestations (secondary; larger program, package available on request)
In a large program containing 30 vm_risc regions we additionally observed, deterministically and RISC-only: crashes (SIGILL / access violations) from runtime-computed negative subscripts and from instantiating classes generated at runtime by `exec`, plus layout-dependent corruption of multiple regions. These involved a third-party compiler toolchain (Nuitka), so the pure C file above is provided as the primary reproduction; the full package (unprotected inputs + logs) is available if useful.
Inside a function wrapped by `EP_MarkerVMRiscBegin()/EP_MarkerVMRiscEnd()` (vm_risc marker region), the Enigma 8.10 RISC virtual machine **translates a specific call sequence incorrectly**, producing wrong values. A minimal, self-contained pure C reproducer is provided: build with `cl`, protect with one `enigma64.exe` command, run, and compare. Failure is 100% deterministic (3/3), RISC-only (Classic VM unaffected in all our tests), and reproducible across repeated protections (random VM seed each time).
Two observable corruptions occur in the same run, both consistent with **32→64-bit zero-extension during translation**:
1. A negative `long long` argument (`-1`) passed as the 4th register argument (r9) to a function is received by the callee as a large positive value (its `if (idx < 0)` branch is not taken).
2. A negative constant (`-999`) materialized inside the region is printed as `4294966297`, which is exactly the zero-extension of `-999` (`0xFFFFFC19` → `0x00000000FFFFFC19`). This exact-match arithmetic is very strong evidence of zero-extension, not of random corruption.
## Environment
- Windows 10 x64; Enigma Protector x64 **8.10** (CLI banner build **20260930**)
- Protection project settings: `VMType=1`; `RISCVMTrashgen/RISCVMObfuscation/RISCVMDuplicates/RISCVMEncryption` all = 0 (minimum); `VirtualMachine/Enabled=False` (marker-driven); `DoNotSearchMarkers=False`; Compression=Best
- Reproducer compiled with: MSVC 2026 (cl 14.51) `cl /O2 /W3`, linked against the official SDK `enigma_ide64.lib` from the Enigma installation
## Documentation conformance (verified against the official Help)
The marker usage in this reproducer follows the official documentation exactly ("Markers VM RISC" and "Rules of markers usage" pages):
- Marker names and call form match the official C++ sample verbatim: `EP_Marker("vm_risc_begin")` / `EP_Marker("vm_risc_end")` (used in the classic-API variant below); the native variant uses the dedicated imports `EP_MarkerVMRiscBegin()/End()` declared in the official `enigma_ide.h` (lines 408-409).
- Marker pairing/nesting/statement-completeness rules are respected; the protection log shows every marker pair found, with **no rejection warnings**.
- The documentation recommends `#pragma optimize("", off)` when optimization causes markers to be "placed chaotically" and rejected (a log warning appears in that case). Our sample deviates by keeping full `/O2` and pinning each marker with `_ReadWriteBarrier()` compiler barriers; disassembly confirms no reordering, and the protection log confirms all markers were accepted. An opt-off variant can be produced on request if needed for comparison.
## A/B result: marker API ruled out — the defect is internal to the RISC VM translation
An identical variant of this reproducer (`risc_argpos_classic.c`, included in this package) uses the **classic string-form markers** `EP_Marker("vm_risc_begin")` / `EP_Marker("vm_risc_end")` — the exact form from the official C++ documentation sample — instead of the native dedicated imports. Everything else is byte-identical.
It fails in **exactly the same way**: `lookup_const(-1@r9) risc=4294966297 plain=303 MISMATCH` (deterministic, 3/3; all markers found, no log warnings).
Therefore the fault does not depend on which marker API is used. Both APIs only define the region boundaries; the corruption occurs inside the translated region — **an internal defect of the RISC VM code translation**.
## Reproduction steps
```
:: 1) build (from the Enigma SDK sample convention; vcvars64 environment)
cl /nologo /O2 /W3 risc_argpos.c /Fe:risc_argpos.exe /Fo:risc_argpos.obj ^
/link /LIBPATH:"C:\Program Files\The Enigma Protector\EnigmaSDK\VC" enigma_ide64.lib
:: 2) protect (project with default/minimum VM settings; -input/-output override)
enigma64.exe <project.enigma64> -input risc_argpos.exe -output risc_argpos_p.exe
:: 3) run both
risc_argpos.exe & :: expected: all six probes "ok", exit 0
risc_argpos_p.exe & :: actual: lookup_const prints 4294966297 (expected 303), "MISMATCH", exit 3
```
Actual protected output (deterministic, 3/3):
```
call1(rcx=-1) risc=130 plain=130 ok
call2(rdx=-2) risc=128 plain=128 ok
call3(r8=-3) risc=126 plain=126 ok
call4(r9=-4) risc=124 plain=124 ok
lookup_const(-1@r9) risc=4294966297 plain=303 MISMATCH
lookup_dyn risc=101 plain=101 ok
FAIL-DIFF
```
## What the probe does
Six marked regions; each has an identical unmarked twin executed natively as the runtime gold standard (the unmarked twin is untouched by protection, so any mismatch isolates the fault to the translation of the marked copy):
- `call1..call4`: call a `noinline` 4-argument function with a negative immediate (`-1/-2/-3/-4`) in argument position 1/2/3/4 (rcx/rdx/r8/r9) respectively. **All four pass** — a bare negative immediate in any argument register is translated correctly.
- `lookup_const` (**fails**): mimics a real-world subscript lookup:
a `struct` list object built on the stack (initialized via SSE `movdqa` stores), called as
`lookup_sub_const(tstate_ptr, &list, &global_key_object, -1)`
where the callee bounds-checks a negative index (`if (idx < 0) { if (-idx > size) return NULL; idx += size; }`) and returns NULL on out-of-range; the caller branches on NULL and yields `-999` on the error path.
- `lookup_dyn` (passes): same, but the 4th argument is a negative value computed at runtime.
Conclusion: the mistranslation is triggered by the **combination** — stack structure + pointer arguments + negative imm64 4th argument (+ the SSE-initialized frame) — not by the negative immediate alone.
## Pre-protection disassembly of the failing region (for reference)
```asm
sub rsp,88h
mov rax,[__security_cookie] ; /GS
xor rax,rsp
mov [rsp+70h],rax
movdqa xmm0,[const] ; struct L init (SSE)
lea r8,[g_key_neg1] ; arg3: &global const object (-1)
movdqa xmm1,[const]
lea rdx,[rsp+20h] ; arg2: &L (stack struct)
mov r9,0FFFFFFFFFFFFFFFFh ; arg4: -1 <-- bytes: 49 C7 C1 FF FF FF FF
movdqa [rsp+20h],xmm0
lea rcx,[g_tstate] ; arg1
movdqa [rsp+30h],xmm1
call lookup_sub_const
test rax,rax
je error_path ; callee returned NULL -> -999 path
mov rax,[rax]
...
```
## Additional manifestations (secondary; larger program, package available on request)
In a large program containing 30 vm_risc regions we additionally observed, deterministically and RISC-only: crashes (SIGILL / access violations) from runtime-computed negative subscripts and from instantiating classes generated at runtime by `exec`, plus layout-dependent corruption of multiple regions. These involved a third-party compiler toolchain (Nuitka), so the pure C file above is provided as the primary reproduction; the full package (unprotected inputs + logs) is available if useful.
Code: Select all
risc_argpos.c
/*
* RISC VM 翻译正确性探针 5(纯 C,无 Python/Nuitka 依赖):
* 负 imm64 实参的"参数位置"敏感性 + Nuitka 故障调用形态逐字模拟
*
* 背景(为什么之前的纯 C 探针全过而 Nuitka 生成的代码失败):
* - risc_neg64.c 把负 imm64 放在第 1 参(rcx)→ 加壳后正确
* - Nuitka 的故障调用 LOOKUP_SUBSCRIPT_CONST(tstate, list, key, -1)
* 中负 imm64 是第 4 参(Win64 x64: rcx/rdx/r8/r9 → r9);
* 反汇编 5 处 mov r9,-N 与 5 个失败下标一一对应
* 本探针:
* R1-R4:负 imm64 分别只出现在第 1/2/3/4 参(rcx/rdx/r8/r9)
* R5 :逐字模拟故障形态——带边界检查的 4 参 helper(负值分支判界、
* 越界返回 NULL)+ 从全局对象取负常量作第 3 参 + -1 作第 4 参
* R6 :同 R5 但第 4 参为运行期计算的负值(动态负下标形态)
* 判定:某区域 risc != plain 或进程崩溃 → 该形态被 RISC VM 错误翻译。
*/
#include <stdio.h>
#ifdef _MSC_VER
#include <intrin.h>
#endif
#ifndef ENIGMA_BARRIER
#ifdef _MSC_VER
#define ENIGMA_BARRIER() _ReadWriteBarrier()
#else
#define ENIGMA_BARRIER() __asm__ __volatile__("" ::: "memory")
#endif
#endif
__declspec(dllimport) void __stdcall EP_MarkerVMRiscBegin(void);
__declspec(dllimport) void __stdcall EP_MarkerVMRiscEnd(void);
/* 防常量折叠的运行期取值 */
static long long g_seed = 0;
__declspec(noinline) static long long rt(void) { return ++g_seed; }
__declspec(noinline) static long long negidx(long long v) { return -v; }
/* 4 参 noinline helper(a=rcx b=rdx c=r8 d=r9):
* 任一参数为负 → 返回四参和×2;全非负 → 返回哨兵(模拟"负值被零扩展
* 后变正值"的观测后果:走了错误分支) */
__declspec(noinline) static long long f4(long long a, long long b, long long c, long long d)
{
if (a < 0 || b < 0 || c < 0 || d < 0)
return (a + b + c + d) * 2;
return 0x7BAD7BAD7BAD7BADLL;
}
/* ---- 模拟 Nuitka 的 LOOKUP_SUBSCRIPT_CONST(list 快速路径,subscripts.h:76-105 同构) ---- */
struct pyobj_like {
long long ob_size; /* PyList_GET_SIZE */
long long items[8];
};
static long long g_key_neg1 = -1; /* 模拟 const_int_neg_1 全局常量对象 */
static long long g_key_pos0 = 0;
/* tstate 对应第 1 参(rcx);const_subscript 是全局常量对象指针(第 3 参 r8);
* int_subscript 是负 imm64(第 4 参 r9)。负值分支判界,越界返回 NULL(=IndexError) */
__declspec(noinline) static long long *lookup_sub_const(void *tstate, struct pyobj_like *source,
long long *const_subscript, long long int_subscript)
{
long long n = source->ob_size;
long long idx = int_subscript;
(void)tstate; (void)const_subscript;
if (idx < 0) {
if (-idx > n)
return 0; /* IndexError: list index out of range */
idx += n;
} else {
if (idx >= n)
return 0; /* IndexError: list index out of range */
}
return &source->items[idx];
}
/* 区域骨架:MARKED=1 时带标记与屏障;每个区域配套一个无标记孪生函数 */
#define REGION_BODY_CALL4(VAR, NEGPOS) \
do { \
long long x = 11, y = 22, z = 33; \
if (NEGPOS == 1) VAR = f4(-1, x, y, z); \
else if (NEGPOS == 2) VAR = f4(x, -2, y, z); \
else if (NEGPOS == 3) VAR = f4(x, y, -3, z); \
else VAR = f4(x, y, z, -4); \
} while (0)
#define REGION_BODY_LOOKUP_CONST(VAR, IDXEXPR) \
do { \
struct pyobj_like L; \
long long *e; \
L.ob_size = 3; \
L.items[0] = 101; L.items[1] = 202; L.items[2] = 303; \
e = lookup_sub_const((void *)&g_seed, &L, &g_key_neg1, (IDXEXPR));\
VAR = (e != 0) ? *e : -999; /* -999 = 模拟 IndexError 被观测 */ \
} while (0)
#define DEFINE_PAIR(NAME, CALLMACRO, ARG) \
static long long risc_##NAME(void) \
{ \
long long v; \
ENIGMA_BARRIER(); EP_MarkerVMRiscBegin(); ENIGMA_BARRIER(); \
CALLMACRO(v, ARG); \
ENIGMA_BARRIER(); EP_MarkerVMRiscEnd(); ENIGMA_BARRIER(); \
return v; \
} \
static long long plain_##NAME(void) \
{ \
long long v; \
CALLMACRO(v, ARG); \
return v; \
}
#ifdef _MSC_VER
#define NOINLINE __declspec(noinline)
#else
#define NOINLINE __attribute__((noinline))
#endif
NOINLINE static long long risc_call1(void){ long long v; ENIGMA_BARRIER(); EP_MarkerVMRiscBegin(); ENIGMA_BARRIER(); REGION_BODY_CALL4(v, 1); ENIGMA_BARRIER(); EP_MarkerVMRiscEnd(); ENIGMA_BARRIER(); return v; }
NOINLINE static long long plain_call1(void){ long long v; REGION_BODY_CALL4(v, 1); return v; }
NOINLINE static long long risc_call2(void){ long long v; ENIGMA_BARRIER(); EP_MarkerVMRiscBegin(); ENIGMA_BARRIER(); REGION_BODY_CALL4(v, 2); ENIGMA_BARRIER(); EP_MarkerVMRiscEnd(); ENIGMA_BARRIER(); return v; }
NOINLINE static long long plain_call2(void){ long long v; REGION_BODY_CALL4(v, 2); return v; }
NOINLINE static long long risc_call3(void){ long long v; ENIGMA_BARRIER(); EP_MarkerVMRiscBegin(); ENIGMA_BARRIER(); REGION_BODY_CALL4(v, 3); ENIGMA_BARRIER(); EP_MarkerVMRiscEnd(); ENIGMA_BARRIER(); return v; }
NOINLINE static long long plain_call3(void){ long long v; REGION_BODY_CALL4(v, 3); return v; }
NOINLINE static long long risc_call4(void){ long long v; ENIGMA_BARRIER(); EP_MarkerVMRiscBegin(); ENIGMA_BARRIER(); REGION_BODY_CALL4(v, 4); ENIGMA_BARRIER(); EP_MarkerVMRiscEnd(); ENIGMA_BARRIER(); return v; }
NOINLINE static long long plain_call4(void){ long long v; REGION_BODY_CALL4(v, 4); return v; }
NOINLINE static long long risc_lookup_const(void)
{
long long v;
ENIGMA_BARRIER(); EP_MarkerVMRiscBegin(); ENIGMA_BARRIER();
REGION_BODY_LOOKUP_CONST(v, -1); /* 负 imm64:第 4 参 r9 */
ENIGMA_BARRIER(); EP_MarkerVMRiscEnd(); ENIGMA_BARRIER();
return v;
}
NOINLINE static long long plain_lookup_const(void)
{
long long v;
REGION_BODY_LOOKUP_CONST(v, -1);
return v;
}
NOINLINE static long long risc_lookup_dyn(void)
{
long long v;
ENIGMA_BARRIER(); EP_MarkerVMRiscBegin(); ENIGMA_BARRIER();
REGION_BODY_LOOKUP_CONST(v, negidx(3)); /* 运行期取负:动态负下标形态 */
ENIGMA_BARRIER(); EP_MarkerVMRiscEnd(); ENIGMA_BARRIER();
return v;
}
NOINLINE static long long plain_lookup_dyn(void)
{
long long v;
REGION_BODY_LOOKUP_CONST(v, negidx(3));
return v;
}
int main(void)
{
struct { const char *name; long long (*r)(void); long long (*p)(void); } t[] = {
{"call1(rcx=-1)", risc_call1, plain_call1},
{"call2(rdx=-2)", risc_call2, plain_call2},
{"call3(r8=-3)", risc_call3, plain_call3},
{"call4(r9=-4)", risc_call4, plain_call4},
{"lookup_const(-1@r9)", risc_lookup_const, plain_lookup_const},
{"lookup_dyn", risc_lookup_dyn, plain_lookup_dyn},
};
int k, fail = 0;
for (k = 0; k < 6; ++k) {
long long a = t[k].r();
long long b = t[k].p();
printf("%-22s risc=%-22lld plain=%-22lld %s\n",
t[k].name, a, b, (a == b) ? "ok" : "MISMATCH");
if (a != b) fail = 1;
fflush(stdout);
}
if (fail) { printf("FAIL-DIFF\n"); return 3; }
printf("PASS: all arg positions risc == plain\n");
return 0;
}
Code: Select all
risc_argpos_classic.c
/*
* CLASSIC-API VARIANT of risc_argpos.c: identical regions, but markers
* use the string-form API EP_Marker("vm_risc_begin"/"vm_risc_end")
* instead of the native dedicated imports. A/B axis: marker API vs
* internal RISC translation. Same project must still process the regions
* with the RISC virtual machine (vm_risc_* marker names).
*/
/*
* RISC VM 翻译正确性探针 5(纯 C,无 Python/Nuitka 依赖):
* 负 imm64 实参的"参数位置"敏感性 + Nuitka 故障调用形态逐字模拟
*
* 背景(为什么之前的纯 C 探针全过而 Nuitka 生成的代码失败):
* - risc_neg64.c 把负 imm64 放在第 1 参(rcx)→ 加壳后正确
* - Nuitka 的故障调用 LOOKUP_SUBSCRIPT_CONST(tstate, list, key, -1)
* 中负 imm64 是第 4 参(Win64 x64: rcx/rdx/r8/r9 → r9);
* 反汇编 5 处 mov r9,-N 与 5 个失败下标一一对应
* 本探针:
* R1-R4:负 imm64 分别只出现在第 1/2/3/4 参(rcx/rdx/r8/r9)
* R5 :逐字模拟故障形态——带边界检查的 4 参 helper(负值分支判界、
* 越界返回 NULL)+ 从全局对象取负常量作第 3 参 + -1 作第 4 参
* R6 :同 R5 但第 4 参为运行期计算的负值(动态负下标形态)
* 判定:某区域 risc != plain 或进程崩溃 → 该形态被 RISC VM 错误翻译。
*/
#include <stdio.h>
#ifdef _MSC_VER
#include <intrin.h>
#endif
#ifndef ENIGMA_BARRIER
#ifdef _MSC_VER
#define ENIGMA_BARRIER() _ReadWriteBarrier()
#else
#define ENIGMA_BARRIER() __asm__ __volatile__("" ::: "memory")
#endif
#endif
__declspec(dllimport) void __stdcall EP_Marker(const char *);
/* 防常量折叠的运行期取值 */
static long long g_seed = 0;
__declspec(noinline) static long long rt(void) { return ++g_seed; }
__declspec(noinline) static long long negidx(long long v) { return -v; }
/* 4 参 noinline helper(a=rcx b=rdx c=r8 d=r9):
* 任一参数为负 → 返回四参和×2;全非负 → 返回哨兵(模拟"负值被零扩展
* 后变正值"的观测后果:走了错误分支) */
__declspec(noinline) static long long f4(long long a, long long b, long long c, long long d)
{
if (a < 0 || b < 0 || c < 0 || d < 0)
return (a + b + c + d) * 2;
return 0x7BAD7BAD7BAD7BADLL;
}
/* ---- 模拟 Nuitka 的 LOOKUP_SUBSCRIPT_CONST(list 快速路径,subscripts.h:76-105 同构) ---- */
struct pyobj_like {
long long ob_size; /* PyList_GET_SIZE */
long long items[8];
};
static long long g_key_neg1 = -1; /* 模拟 const_int_neg_1 全局常量对象 */
static long long g_key_pos0 = 0;
/* tstate 对应第 1 参(rcx);const_subscript 是全局常量对象指针(第 3 参 r8);
* int_subscript 是负 imm64(第 4 参 r9)。负值分支判界,越界返回 NULL(=IndexError) */
__declspec(noinline) static long long *lookup_sub_const(void *tstate, struct pyobj_like *source,
long long *const_subscript, long long int_subscript)
{
long long n = source->ob_size;
long long idx = int_subscript;
(void)tstate; (void)const_subscript;
if (idx < 0) {
if (-idx > n)
return 0; /* IndexError: list index out of range */
idx += n;
} else {
if (idx >= n)
return 0; /* IndexError: list index out of range */
}
return &source->items[idx];
}
/* 区域骨架:MARKED=1 时带标记与屏障;每个区域配套一个无标记孪生函数 */
#define REGION_BODY_CALL4(VAR, NEGPOS) \
do { \
long long x = 11, y = 22, z = 33; \
if (NEGPOS == 1) VAR = f4(-1, x, y, z); \
else if (NEGPOS == 2) VAR = f4(x, -2, y, z); \
else if (NEGPOS == 3) VAR = f4(x, y, -3, z); \
else VAR = f4(x, y, z, -4); \
} while (0)
#define REGION_BODY_LOOKUP_CONST(VAR, IDXEXPR) \
do { \
struct pyobj_like L; \
long long *e; \
L.ob_size = 3; \
L.items[0] = 101; L.items[1] = 202; L.items[2] = 303; \
e = lookup_sub_const((void *)&g_seed, &L, &g_key_neg1, (IDXEXPR));\
VAR = (e != 0) ? *e : -999; /* -999 = 模拟 IndexError 被观测 */ \
} while (0)
#define DEFINE_PAIR(NAME, CALLMACRO, ARG) \
static long long risc_##NAME(void) \
{ \
long long v; \
ENIGMA_BARRIER(); EP_Marker("vm_risc_begin"); ENIGMA_BARRIER(); \
CALLMACRO(v, ARG); \
ENIGMA_BARRIER(); EP_Marker("vm_risc_end"); ENIGMA_BARRIER(); \
return v; \
} \
static long long plain_##NAME(void) \
{ \
long long v; \
CALLMACRO(v, ARG); \
return v; \
}
#ifdef _MSC_VER
#define NOINLINE __declspec(noinline)
#else
#define NOINLINE __attribute__((noinline))
#endif
NOINLINE static long long risc_call1(void){ long long v; ENIGMA_BARRIER(); EP_Marker("vm_risc_begin"); ENIGMA_BARRIER(); REGION_BODY_CALL4(v, 1); ENIGMA_BARRIER(); EP_Marker("vm_risc_end"); ENIGMA_BARRIER(); return v; }
NOINLINE static long long plain_call1(void){ long long v; REGION_BODY_CALL4(v, 1); return v; }
NOINLINE static long long risc_call2(void){ long long v; ENIGMA_BARRIER(); EP_Marker("vm_risc_begin"); ENIGMA_BARRIER(); REGION_BODY_CALL4(v, 2); ENIGMA_BARRIER(); EP_Marker("vm_risc_end"); ENIGMA_BARRIER(); return v; }
NOINLINE static long long plain_call2(void){ long long v; REGION_BODY_CALL4(v, 2); return v; }
NOINLINE static long long risc_call3(void){ long long v; ENIGMA_BARRIER(); EP_Marker("vm_risc_begin"); ENIGMA_BARRIER(); REGION_BODY_CALL4(v, 3); ENIGMA_BARRIER(); EP_Marker("vm_risc_end"); ENIGMA_BARRIER(); return v; }
NOINLINE static long long plain_call3(void){ long long v; REGION_BODY_CALL4(v, 3); return v; }
NOINLINE static long long risc_call4(void){ long long v; ENIGMA_BARRIER(); EP_Marker("vm_risc_begin"); ENIGMA_BARRIER(); REGION_BODY_CALL4(v, 4); ENIGMA_BARRIER(); EP_Marker("vm_risc_end"); ENIGMA_BARRIER(); return v; }
NOINLINE static long long plain_call4(void){ long long v; REGION_BODY_CALL4(v, 4); return v; }
NOINLINE static long long risc_lookup_const(void)
{
long long v;
ENIGMA_BARRIER(); EP_Marker("vm_risc_begin"); ENIGMA_BARRIER();
REGION_BODY_LOOKUP_CONST(v, -1); /* 负 imm64:第 4 参 r9 */
ENIGMA_BARRIER(); EP_Marker("vm_risc_end"); ENIGMA_BARRIER();
return v;
}
NOINLINE static long long plain_lookup_const(void)
{
long long v;
REGION_BODY_LOOKUP_CONST(v, -1);
return v;
}
NOINLINE static long long risc_lookup_dyn(void)
{
long long v;
ENIGMA_BARRIER(); EP_Marker("vm_risc_begin"); ENIGMA_BARRIER();
REGION_BODY_LOOKUP_CONST(v, negidx(3)); /* 运行期取负:动态负下标形态 */
ENIGMA_BARRIER(); EP_Marker("vm_risc_end"); ENIGMA_BARRIER();
return v;
}
NOINLINE static long long plain_lookup_dyn(void)
{
long long v;
REGION_BODY_LOOKUP_CONST(v, negidx(3));
return v;
}
int main(void)
{
struct { const char *name; long long (*r)(void); long long (*p)(void); } t[] = {
{"call1(rcx=-1)", risc_call1, plain_call1},
{"call2(rdx=-2)", risc_call2, plain_call2},
{"call3(r8=-3)", risc_call3, plain_call3},
{"call4(r9=-4)", risc_call4, plain_call4},
{"lookup_const(-1@r9)", risc_lookup_const, plain_lookup_const},
{"lookup_dyn", risc_lookup_dyn, plain_lookup_dyn},
};
int k, fail = 0;
for (k = 0; k < 6; ++k) {
long long a = t[k].r();
long long b = t[k].p();
printf("%-22s risc=%-22lld plain=%-22lld %s\n",
t[k].name, a, b, (a == b) ? "ok" : "MISMATCH");
if (a != b) fail = 1;
fflush(stdout);
}
if (fail) { printf("FAIL-DIFF\n"); return 3; }
printf("PASS: all arg positions risc == plain\n");
return 0;
}