From b24f13c613814c2b3464aed3b00c7f3fa642a365 Mon Sep 17 00:00:00 2001 From: alex Date: Mon, 7 Sep 2026 22:01:49 -0400 Subject: [PATCH] addresses: GlobalConst/map layouts + float-scale global (M1 recon) --- ghidra/addresses.json | 16 ++++++++++++---- ghidra/generated/sots_addresses.h | 8 +++++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/ghidra/addresses.json b/ghidra/addresses.json index 2a1ec1a..c3a84f7 100644 --- a/ghidra/addresses.json +++ b/ghidra/addresses.json @@ -222,7 +222,7 @@ "name": "GlobalConst_ctor", "addr": "0x008b76a0", "convention": "thiscall", - "prototype": "GlobalConst* (GlobalConst* this, void* storage, const char* key, GlobalConstParseFn parser, const char* file) /* RET 0x10; static-init stub call */", + "prototype": "GlobalConst* (GlobalConst* this, void* storage, const char* key, GlobalConstParseFn parser, const char* file) /* RET 0x10; static-init stub call. GlobalConst 0x10 bytes: {+0 void* storage (int/float/float[4]), +4 const char* key, +8 parser, +c const char* file} */", "status": "verified", "source": "handoff/loader-prototypes.md#m1" }, @@ -254,7 +254,7 @@ "name": "GlobalConst_ParseFloatScaled", "addr": "0x008b70e0", "convention": "cdecl", - "prototype": "void (float* storage, const char* text) /* *storage = sscanf(%f) * *(float*)0x00af5210 */", + "prototype": "void (float* storage, const char* text) /* sscanf(%f) into *storage, then *storage = (float)((double)*storage * *(double*)0x00af5210) */", "status": "verified", "source": "handoff/loader-prototypes.md#m1" }, @@ -278,7 +278,7 @@ "name": "GlobalConsts_LoadFile", "addr": "0x008b73c0", "convention": "cdecl", - "prototype": "void (const char* file, GlobalConstMap* consts) /* consts = std::map of the keys registered for this file; hook this for the file-level read */", + "prototype": "void (const char* file, GlobalConstMap* consts) /* consts = std::map of the keys registered for this file; MSVC2010 layout: map {+4 head node, +8 size}; node {+0 left, +4 parent, +8 right, +0xc const char* key, +0x10 GlobalConst*, +0x14 color, +0x15 isnil}; head: isnil=1, parent=root. Consumed keys are erased from the map. Hook this for the file-level read */", "status": "verified", "source": "handoff/loader-prototypes.md#m1" }, @@ -298,6 +298,14 @@ "status": "verified", "source": "handoff/loader-prototypes.md#m1" }, + { + "name": "g_GlobalConstFloatScale", + "addr": "0x00af5210", + "convention": "data", + "prototype": "double /* pi/180 as a DOUBLE (0x3f91df46a2529d39); GlobalConst_ParseFloatScaled does float word *= this in x87 and stores float */", + "status": "verified", + "source": "handoff/loader-prototypes.md#m1" + }, { "name": "Script_ctor", "addr": "0x008cd700", @@ -819,4 +827,4 @@ "source": "handoff/loader-prototypes.md#effect" } ] -} \ No newline at end of file +} diff --git a/ghidra/generated/sots_addresses.h b/ghidra/generated/sots_addresses.h index f73b87e..e466db2 100644 --- a/ghidra/generated/sots_addresses.h +++ b/ghidra/generated/sots_addresses.h @@ -1,5 +1,5 @@ // GENERATED — do not edit. Facts about Sword of the Stars.exe (GOG 1.8.1). -// Source: sots-re ghidra/addresses.json @ f1c7f55, generated 2026-09-07 by tools/gen_addresses.py +// Source: sots-re ghidra/addresses.json @ 254a077, generated 2026-09-07 by tools/gen_addresses.py // Runtime address = (uintptr_t)GetModuleHandle(NULL) + RVA (the exe is ASLR-relocated). #pragma once #include @@ -61,7 +61,7 @@ constexpr uint32_t RNG_NextInt = 0x000271c0; constexpr uint32_t Mars_Application_MountModules = 0x004a0a20; // cdecl void (int* count, const char*** table) /* count 3 @0x00b2d514, table @0x00a35e98 */ [verified] constexpr uint32_t Game_GetDefaultMounts = 0x004991c0; -// thiscall GlobalConst* (GlobalConst* this, void* storage, const char* key, GlobalConstParseFn parser, const char* file) /* RET 0x10; static-init stub call */ [verified] +// thiscall GlobalConst* (GlobalConst* this, void* storage, const char* key, GlobalConstParseFn parser, const char* file) /* RET 0x10; static-init stub call. GlobalConst 0x10 bytes: {+0 void* storage (int/float/float[4]), +4 const char* key, +8 parser, +c const char* file} */ [verified] constexpr uint32_t GlobalConst_ctor = 0x004b76a0; // cdecl void (GlobalConst* g) [verified] constexpr uint32_t GlobalConst_Register = 0x004b7610; @@ -75,12 +75,14 @@ constexpr uint32_t GlobalConst_ParseFloatScaled = 0x004b70e0; constexpr uint32_t GlobalConst_ParseColour = 0x004b7110; // cdecl void (void) /* called once from Application::Initialize; sets g_GlobalConstsLoaded */ [verified] constexpr uint32_t GlobalConsts_LoadAll = 0x004b76d0; -// cdecl void (const char* file, GlobalConstMap* consts) /* consts = std::map of the keys registered for this file; hook this for the file-level read */ [verified] +// cdecl void (const char* file, GlobalConstMap* consts) /* consts = std::map of the keys registered for this file; MSVC2010 layout: map {+4 head node, +8 size}; node {+0 left, +4 parent, +8 right, +0xc const char* key, +0x10 GlobalConst*, +0x14 color, +0x15 isnil}; head: isnil=1, parent=root. Consumed keys are erased from the map. Hook this for the file-level read */ [verified] constexpr uint32_t GlobalConsts_LoadFile = 0x004b73c0; // data bool [verified] constexpr uint32_t g_GlobalConstsLoaded = 0x0072d740; // data std::map /* +4 (0x00b2d748) = header node pointer */ [verified] constexpr uint32_t g_GlobalConstRegistry = 0x0072d744; +// data float /* multiplier applied by GlobalConst_ParseFloatScaled after the %f scan */ [verified] +constexpr uint32_t g_GlobalConstFloatScale = 0x006f5210; // thiscall Script* (Script* this) /* sizeof(Script) = 0x28 */ [verified] constexpr uint32_t Script_ctor = 0x004cd700; // thiscall void (Script* this) [verified]