Add hacks to fix PCH .data causing fake mismatches with decompctx

This commit is contained in:
LagoLunatic
2025-09-03 22:20:36 -04:00
parent 3ebf69a870
commit 78d9b53a52
11 changed files with 135 additions and 7 deletions
+7
View File
@@ -191,6 +191,13 @@ config.reconfig_deps = []
# Can be overridden in libraries or objects
config.scratch_preset_id = 72 # The Wind Waker (DOL)
# Globs to exclude from context files
# *.mch excludes precompiled header output (which cannot be parsed)
config.context_exclude_globs = ["*.mch"]
# Macro definitions to inject into context files
config.context_defines = ["DECOMPCTX"]
# Base flags, common to most GC/Wii games.
# Generally leave untouched, with overrides added below.
cflags_base = [
@@ -51,7 +51,9 @@ public:
virtual ~J3DMtxCalcBasic() {}
virtual void init(const Vec& vec, const Mtx& mtx) {
J3DSys::mCurrentS = vec;
#ifndef DECOMPCTX // Hack, see comment in dolzel.pch for details
J3DSys::mParentS = (Vec){1.0f, 1.0f, 1.0f};
#endif
J3DSys::mCurrentMtx[0][0] = mtx[0][0] * J3DSys::mCurrentS.x;
J3DSys::mCurrentMtx[0][1] = mtx[0][1] * J3DSys::mCurrentS.y;
J3DSys::mCurrentMtx[0][2] = mtx[0][2] * J3DSys::mCurrentS.z;
@@ -93,7 +95,9 @@ public:
J3DMtxCalcMaya() : J3DMtxCalcBasic() {}
virtual ~J3DMtxCalcMaya() {}
virtual void init(const Vec& vec, const Mtx& mtx) {
#ifndef DECOMPCTX // Hack, see comment in dolzel.pch for details
J3DSys::mParentS = (Vec){1.0f, 1.0f, 1.0f};
#endif
J3DSys::mCurrentS = vec;
J3DSys::mCurrentMtx[0][0] = mtx[0][0] * J3DSys::mCurrentS.x;
J3DSys::mCurrentMtx[0][1] = mtx[0][1] * J3DSys::mCurrentS.y;
@@ -987,8 +987,12 @@ struct J3DColorChan {
}
J3DColorChan(u16 id) : mChanCtrl(id) {}
u8 getAttnFn() const {
#ifdef DECOMPCTX // Hack, see comment in dolzel.pch for details
return 0;
#else
u8 attnFnTbl[] = { GX_AF_NONE, GX_AF_SPEC, GX_AF_NONE, GX_AF_SPOT };
return attnFnTbl[(u32)(mChanCtrl & (3 << 9)) >> 9];
#endif
}
u8 getDiffuseFn() const { return ((u32)(mChanCtrl & (3 << 7)) >> 7); }
u8 getLightMask() const { return ((mChanCtrl >> 2) & 0x0f) | ((mChanCtrl >> 11) & 0x0f) << 4; }
+1 -1
View File
@@ -1,7 +1,7 @@
#ifndef DOLZEL_H
#define DOLZEL_H
#ifdef __MWERKS__
#if defined(__MWERKS__) && !defined(DECOMPCTX)
#include "d/dolzel.mch"
#else
#include "d/dolzel.pch"
+8
View File
@@ -1,6 +1,14 @@
#ifndef DOLZEL_PCH
#define DOLZEL_PCH
#ifdef DECOMPCTX
// Hack to mitigate fake mismatches when building from decompctx output
// (which doesn't support precompiled headers).
// When built without a PCH, these constants would end up .rodata instead of .data
// which causes a variety of knock-on effects in individual functions' assembly.
#include "weak_data.h" // IWYU pragma: export
#endif
// Fixes weak .data
#include "math.h" // IWYU pragma: export
#include "JSystem/J3DGraphBase/J3DMatBlock.h" // IWYU pragma: export
+1 -1
View File
@@ -1,7 +1,7 @@
#ifndef DOLZEL_REL_H
#define DOLZEL_REL_H
#ifdef __MWERKS__
#if defined(__MWERKS__) && !defined(DECOMPCTX)
#include "d/dolzel_rel.mch"
#else
#include "d/dolzel_rel.pch"
+9
View File
@@ -6,10 +6,19 @@
// Goes in either .bss (for RELs) or .rodata (for main.dol: d_snap, J3DUClipper).
// Its true source is currently unknown, so include this header in TUs that need it to match for now.
#ifdef DECOMPCTX // Hack, see comment in dolzel.pch for details
#include "dolphin/types.h"
template <typename T> struct bss_3569 { u8 val[0xC]; };
static inline void dummy_bss_3569() {
bss_3569<void*>(); // @3569
}
#else
#include "dolphin/mtx/mtx.h"
static inline void dummy_bss_3569() {
Vec vec = (Vec){0.0f, 0.0f, 0.0f}; // @3569 / @3599
}
#endif
#endif /* WEAK_BSS_3569_H */
+27
View File
@@ -0,0 +1,27 @@
#ifndef WEAK_DATA_H
#define WEAK_DATA_H
#ifdef DECOMPCTX
#include "dolphin/mtx/mtx.h"
static inline void fake_data_2100() {
static Vec data_2100 = {1.0f, 1.0f, 1.0f};
}
static inline void fake_data_2080() {
static Vec data_2080 = {1.0f, 1.0f, 1.0f};
}
#include "dolphin/gx/GXEnum.h"
static inline void fake_getAttnFn() {
static u8 attnFnTbl_1811[] = { GX_AF_NONE, GX_AF_SPEC, GX_AF_NONE, GX_AF_SPOT };
}
extern inline void fake_sqrtf(float x) {
static double _three[1] = {3.0};
static double _half[1] = {.5};
}
#endif
#endif /* WEAK_DATA_H */
@@ -86,8 +86,13 @@ inline float tanf(float x) { return tan(x); }
namespace std {
#endif
extern inline float sqrtf(float x) {
#ifdef DECOMPCTX // Hack, see comment in dolzel.pch for details
const double _half = .5;
const double _three = 3.0;
#else
static const double _half = .5;
static const double _three = 3.0;
#endif
volatile float y;
if (x > 0.0f) {
double guess = __frsqrte((double)x); // returns an approximation to
+46 -2
View File
@@ -11,6 +11,7 @@
###
import argparse
import fnmatch
import os
import re
from typing import List
@@ -19,6 +20,7 @@ script_dir = os.path.dirname(os.path.realpath(__file__))
root_dir = os.path.abspath(os.path.join(script_dir, ".."))
src_dir = os.path.join(root_dir, "src")
include_dirs: List[str] = [] # Set with -I flag
exclude_globs: List[str] = [] # Set with -x flag
include_pattern = re.compile(r'^#\s*include\s*[<"](.+?)[>"]')
guard_pattern = re.compile(r"^#\s*ifndef\s+(.*)$")
@@ -28,6 +30,23 @@ defines = set()
deps = []
def generate_prelude(defines) -> str:
if len(defines) == 0:
return ""
out_text = "/* decompctx prelude */\n"
for define in defines:
parts = define.split("=", 1)
if len(parts) == 2:
macro_name, macro_val = parts
out_text += f"#define {macro_name} {macro_val}\n"
else:
out_text += f"#define {parts[0]}\n"
out_text += "/* end decompctx prelude */\n\n"
return out_text
def import_h_file(in_file: str, r_path: str) -> str:
rel_path = os.path.join(root_dir, r_path, in_file)
if os.path.exists(rel_path):
@@ -73,8 +92,17 @@ def process_file(in_file: str, lines: List[str]) -> str:
print("Processing file", in_file)
include_match = include_pattern.match(line.strip())
if include_match and not include_match[1].endswith(".s"):
excluded = False
for glob in exclude_globs:
if fnmatch.fnmatch(include_match[1], glob):
excluded = True
break
out_text += f'/* "{in_file}" line {idx} "{include_match[1]}" */\n'
out_text += import_h_file(include_match[1], os.path.dirname(in_file))
if excluded:
out_text += "/* Skipped excluded file */\n"
else:
out_text += import_h_file(include_match[1], os.path.dirname(in_file))
out_text += f'/* end "{include_match[1]}" */\n'
else:
out_text += line
@@ -111,13 +139,29 @@ def main():
help="""Include directory""",
action="append",
)
parser.add_argument(
"-x",
"--exclude",
help="""Excluded file name glob""",
action="append",
)
parser.add_argument(
"-D",
"--define",
help="""Macro definition""",
action="append",
)
args = parser.parse_args()
if args.include is None:
exit("No include directories specified")
global include_dirs
include_dirs = args.include
output = import_c_file(args.c_file)
global exclude_globs
exclude_globs = args.exclude or []
prelude_defines = args.define or []
output = generate_prelude(prelude_defines)
output += import_c_file(args.c_file)
with open(os.path.join(root_dir, args.output), "w", encoding="utf-8") as f:
f.write(output)
+23 -3
View File
@@ -198,6 +198,12 @@ class ProjectConfig:
self.link_order_callback: Optional[Callable[[int, List[str]], List[str]]] = (
None # Callback to add/remove/reorder units within a module
)
self.context_exclude_globs: List[str] = (
[] # Globs to exclude from context files
)
self.context_defines: List[str] = (
[] # Macros to define at the top of context files
)
# Progress output and report.json config
self.progress = True # Enable report.json generation and CLI progress output
@@ -492,7 +498,7 @@ def generate_build_ninja(
decompctx = config.tools_dir / "decompctx.py"
n.rule(
name="decompctx",
command=f"$python {decompctx} $in -o $out -d $out.d $includes",
command=f"$python {decompctx} $in -o $out -d $out.d $includes $excludes $defines",
description="CTX $in",
depfile="$out.d",
deps="gcc",
@@ -1048,12 +1054,19 @@ def generate_build_ninja(
):
include_dirs.append(flag[3:])
includes = " ".join([f"-I {d}" for d in include_dirs])
excludes = " ".join([f"-x {d}" for d in config.context_exclude_globs])
defines = " ".join([f"-D {d}" for d in config.context_defines])
n.build(
outputs=obj.ctx_path,
rule="decompctx",
inputs=src_path,
implicit=decompctx,
variables={"includes": includes},
variables={
"includes": includes,
"excludes": excludes,
"defines": defines,
},
)
n.newline()
@@ -1545,13 +1558,20 @@ def generate_objdiff_config(
"build_target": False,
"watch_patterns": [
"*.c",
"*.cc",
"*.cp",
"*.cpp",
"*.cxx",
"*.c++",
"*.h",
"*.hh",
"*.hp",
"*.hpp",
"*.inc",
"*.hxx",
"*.h++",
"*.pch",
"*.pch++",
"*.inc",
"*.py",
"*.yml",
"*.txt",