Fix release-mode crashes: inline asm register clobbers and fastcall ABI

Root cause: hook.fastcall used "r" constraints + explicit MOV to set
ECX/EDX. LLVM can allocate "r" inputs to clobbered registers, causing
cross-assignment (ecx_in→EDX, edx_in→ECX) or function address stomping
when func lands in ECX/EDX. Debug works by luck (trivial regalloc);
Release optimizes aggressively and hits the conflicts.

Fix: explicit "{ecx}", "{edx}", "{eax}" register constraints in zhook
fastcall — compiler places values directly, no MOV needed, no ambiguity.

Also fix 9 inline asm blocks across main.zig, interact.zig,
screenshot.zig, markers.zig missing ECX/EDX clobbers after CALL
instructions. Without clobbers the optimizer assumes registers retain
input values after the call — stale reuse in release builds.

Other changes in this commit:
- Rename markers→worldmarkers (build flag, DLL, Lua table)
- Rename assetfix→looseassets
- lua.zig: add .never_tail to pushcclosure, pcall, openlib, pushnumber
- Move internal marker functions into WorldMarkers Lua table via openlib
- Remove unused GetCurrentAreaId function
- Fix cleanup_file_handle_hook.original() → .callOriginal()
This commit is contained in:
MarcelineVQ
2026-03-02 23:38:04 -08:00
parent b69c3a55a1
commit c04680788d
11 changed files with 126 additions and 104 deletions
+5 -4
View File
@@ -66,8 +66,9 @@ pub fn pushnil(L: State) void {
pub fn pushnumber(L: State, n: f64) void {
// __thiscall: ECX=L, f64 on stack [EBP+8]/[EBP+0xc], ret 8.
// .never_tail: callee-cleanup pops stack args — tail-call would corrupt the stack.
const f: *const fn (State, f64) callconv(.{ .x86_thiscall = .{} }) void = @ptrFromInt(0x6F3810);
f(L, n);
@call(.never_tail, f, .{ L, n });
}
pub fn pushstring(L: State, s: [*:0]const u8) void {
@@ -82,7 +83,7 @@ pub fn pushboolean(L: State, b: i32) void {
pub fn pushcclosure(L: State, func: usize, n: i32) void {
const f: *const fn (State, usize, i32) callconv(fc) void = @ptrFromInt(0x6F3920);
f(L, func, n);
@call(.never_tail, f, .{ L, func, n });
}
pub fn tonumber(L: State, index: i32) f64 {
@@ -122,7 +123,7 @@ pub fn next(L: State, index: i32) i32 {
pub fn pcall(L: State, nargs: i32, nresults: i32, errfunc: i32) i32 {
const f: *const fn (State, i32, i32, i32) callconv(fc) i32 = @ptrFromInt(0x6F41A0);
return f(L, nargs, nresults, errfunc);
return @call(.never_tail, f, .{ L, nargs, nresults, errfunc });
}
pub fn luaError(L: State, msg: [*:0]const u8) void {
@@ -146,7 +147,7 @@ pub const LuaReg = extern struct {
pub fn openlib(L: State, libname: ?[*:0]const u8, funcs: [*]const LuaReg, nup: i32) void {
const f: *const fn (State, ?[*:0]const u8, [*]const LuaReg, i32) callconv(fc) void = @ptrFromInt(0x6F4DC0);
f(L, libname, funcs, nup);
@call(.never_tail, f, .{ L, libname, funcs, nup });
}
pub fn checknumber(L: State, index: i32) f64 {