Update dsd to v0.12.0; dsprot OK (#135)

* `Actor::mType` field

* Remove fake symbol `data_027e0254`

* `dsd format`

* eur: Enable dsprot decomp

* jp: Enable dsprot decomp

* dsprot OK

* `dsd format`

* Use new `weak` attribute

* Add relocations for exception table link-time constants

* Add exception table symbols

* Bump dsd to v0.12.0

* `#define FALSE 1` ???
Why did I make it 1?

* Truncate `data_ov001_020c27a8`
That data belongs to dsprot
This commit is contained in:
Aetias
2026-08-15 01:07:14 +02:00
committed by GitHub
parent ce24ddfc4e
commit 521100caed
104 changed files with 4547 additions and 2014 deletions
+119 -2
View File
@@ -4,8 +4,9 @@ import json
import argparse
import subprocess
import glob
import ninja_syntax
from typing import List, Dict, Any
from typing import List, Dict, Any, Callable
from pathlib import Path
from project import ProjectConfig, Object, process_project
@@ -20,7 +21,7 @@ parser.add_argument("--noclangd", "-c", help='Do not create clangd config', requ
args = parser.parse_args()
config = ProjectConfig("st", args.compiler, "dsi/1.2p1", args.wine, args.dsd, Path(__file__).resolve())
config.dsd_tag = "v0.11.0"
config.dsd_tag = "v0.12.0"
config.wibo_tag = "1.1.0"
config.objdiff_tag = "v3.7.1"
config.sjiswrap_tag = "v1.2.2"
@@ -65,6 +66,10 @@ config.cflags_base = [
"-ipa file", # InterProcedural Analysis
]
config.asflags = [
"-proc arm5TE", # Target processor
]
config.ldflags = [
"-proc arm946e", # Target processor
"-dead", # Strip unused code
@@ -75,6 +80,8 @@ config.ldflags = [
]
type NinjaBuild = Callable[[ProjectConfig, str, ninja_syntax.Writer], None]
# Helper function for Nitro libraries
def NitroLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]:
return {
@@ -96,6 +103,57 @@ def NNSLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]:
"objects": objects,
}
# Helper function for dsprot library
DSPROT_SRC = "libs/dsprot/src"
DSPROT_MW_VERSION = "2.0/sp2p3"
def DSProtLib(lib_name: str, objects: List[Object], extra_builds: list[NinjaBuild]) -> Dict[str, Any]:
return {
"lib": lib_name,
"mw_version": DSPROT_MW_VERSION,
"src_dir": DSPROT_SRC,
"cflags": [*config.cflags_base, "-lang c"],
"objects": objects,
"rules": [dsprot_asmwriter_rule],
"extra_builds": extra_builds,
}
def dsprot_asmwriter_rule(cfg: ProjectConfig, n: ninja_syntax.Writer):
n.rule(
name="dsprot_asmwriter",
command=f"{cfg.python_path} libs/dsprot/tools/asmwriter.py -i $in -o $out $flags"
)
def DSProtAsmwriter(asm_file: str, src_objects: list[str], *, flags: list[str]):
def build(cfg: ProjectConfig, version: str, n: ninja_syntax.Writer):
src_obj_path: list[Path] = [
cfg.get_game_build(version) / DSPROT_SRC / src_object
for src_object in src_objects
]
asm_path: Path = cfg.get_game_build(version) / DSPROT_SRC / asm_file
asm_obj_path = asm_path.with_suffix(".o")
n.build(
inputs=list(map(str, src_obj_path)),
implicit="libs/dsprot/tools/asmwriter.py",
rule="dsprot_asmwriter",
outputs=str(asm_path),
variables={
"flags": " ".join(flags)
},
)
n.build(
inputs=str(asm_path),
rule="mwas",
outputs=str(asm_obj_path),
variables={
"game_version": version.upper(),
"mw_version": DSPROT_MW_VERSION,
"as_flags": " ".join(cfg.asflags or []),
"basedir": str(asm_obj_path.parent),
"basefile": str(asm_obj_path.with_suffix("")),
},
)
n.newline()
return build
# Helper function for libc libraries
def LibC(lib_name: str, objects: List[Object]) -> Dict[str, Any]:
@@ -1494,6 +1552,65 @@ config.libs = [
[
Object("g3d/sbc.c"),
]
),
DSProtLib(
"dsprot",
[
Object("dsprot_main.c"),
Object("integrity.c"),
Object("encryptor.c"),
Object("mac_owner.c"),
Object("rom_util.c"),
Object("rom_test.c"),
Object("rc4.c"),
Object("extra.c"),
],
extra_builds=[
DSProtAsmwriter("dsprot_main_decryptor.s", ["dsprot_main.o"], flags=[
"--key 0x2e8b",
"--prefix DSProt_",
"--symbols DetectFlashcart DetectNotFlashcart DetectEmulator DetectNotEmulator DetectDummy DetectNotDummy",
]),
DSProtAsmwriter("dsprot_main_decoder.s", ["dsprot_main_decryptor.o"], flags=[
"--garbage DSProt_Garbage",
"--prefix DSProt_",
"--symbols DetectFlashcart DetectNotFlashcart DetectEmulator DetectNotEmulator DetectDummy DetectNotDummy",
]),
DSProtAsmwriter("integrity_decryptor.s", ["integrity.o"], flags=[
"--key 0xbe28",
"--symbols Integrity_MACOwner_IsBad Integrity_MACOwner_IsGood Integrity_ROMTest_IsBad Integrity_ROMTest_IsGood",
]),
DSProtAsmwriter("integrity_decoder.s", ["integrity_decryptor.o"], flags=[
"--symbols Integrity_MACOwner_IsBad Integrity_MACOwner_IsGood Integrity_ROMTest_IsBad Integrity_ROMTest_IsGood",
]),
DSProtAsmwriter("encryptor_decryptor.s", ["encryptor.o"], flags=[
"--prefix ''",
"--symbols Encryptor_EncryptFunction Encryptor_DecryptFunction",
]),
DSProtAsmwriter("mac_owner_decryptor.s", ["mac_owner.o"], flags=[
"--key 0xc7ea",
"--symbols MACOwner_IsBad MACOwner_IsGood",
]),
DSProtAsmwriter("rom_util_decryptor.s", ["rom_util.o"], flags=[
"--key 0xc7ea",
"--symbols ROMUtil_Read ROMUtil_CRC32",
]),
DSProtAsmwriter("rom_test_decryptor.s", ["rom_test.o"], flags=[
"--key 0xc7ea",
"--symbols ROMTest_IsBad ROMTest_IsGood",
]),
DSProtAsmwriter(
"coretests_decoder.s",
["mac_owner_decryptor.o", "rom_util_decryptor.o", "rom_test_decryptor.o"],
flags=[
"--symbols ROMTest_IsBad ROMTest_IsGood MACOwner_IsBad MACOwner_IsGood ROMUtil_Read ROMUtil_CRC32",
]
),
DSProtAsmwriter("rc4_decoder.s", ["rc4.o"], flags=[
"--prefix ''",
"--symbols RC4_Init RC4_Byte RC4_InitSBox RC4_EncryptInstructions RC4_DecryptInstructions RC4_InitAndEncryptInstructions RC4_InitAndDecryptInstructions",
]),
],
)
]
+1 -1
View File
@@ -26,7 +26,7 @@ CXX_FLAGS = [
'-Ilibs/runtime/include',
'-Ilibs/nitro/include',
'-Ilibs/nns/include',
'-Ilibs/dsprotect/include',
'-Ilibs/dsprot/include',
f'-DVERSION={args.version}',
'-D__MWERKS__',
]
+125 -36
View File
@@ -1,3 +1,4 @@
from collections.abc import Generator
import os
import sys
import json
@@ -10,6 +11,7 @@ from get_platform import get_platform
COMPILER_MAP = {
"1.2/b56": "mwcc_20_56",
"1.2/base": "mwcc_20_72",
"1.2/sp2": "mwcc_20_79",
"1.2/sp2p3": "mwcc_20_82",
@@ -38,13 +40,25 @@ COMPILER_MAP = {
Library = Dict[str, Any]
def get_c_cpp_files(dirs: list[Path]):
def traverse_files(dirs: list[Path]) -> Generator[Path]:
for dir in dirs:
for root, _, files in os.walk(dir):
root = Path(root)
for file in files:
if is_cpp(file) or is_c(file):
yield root / file
yield root / file
def get_c_cpp_files(dirs: list[Path]) -> Generator[Path]:
for file in traverse_files(dirs):
if is_cpp(file) or is_c(file):
yield file
def get_asm_files(dirs: list[Path]) -> Generator[Path]:
for file in traverse_files(dirs):
if is_asm(file):
yield file
def is_cpp(name: str | Path):
@@ -54,9 +68,15 @@ def is_cpp(name: str | Path):
def is_c(name: str | Path):
return Path(name).suffix in [".c"]
def is_c_cpp(name: str | Path):
return is_c(name) or is_cpp(name)
def is_asm(name: str | Path):
return Path(name).suffix in [".s"]
class Object:
def __init__(self, name: str, **options: Any):
self.name = name
@@ -132,8 +152,9 @@ class ProjectConfig:
self.objdiff_path = (self.root_path / f"objdiff-cli{self.platform.exe}").resolve()
self.sjiswrap_path = (self.root_path / "tools" / "sjiswrap.exe").resolve()
self.cc_path = (self.mwcc_path / "mwccarm.exe").resolve()
self.as_path = (self.mwcc_path / "mwasmarm.exe").resolve()
self.ld_path = (self.mwcc_path / "mwldarm.exe").resolve()
self.python_path = Path(sys.executable).resolve()
self.python_path = Path(sys.executable)
self.dsd_base_flags = [
"--force-color", # Force color output
@@ -295,11 +316,15 @@ class ProjectConfig:
return self.get_game_build(version) / "build" / "rom_config.yaml"
def source_object_files(self, version: str) -> list[str]:
files: list[str] = []
for source_file in get_c_cpp_files([self.src_path, self.libs_path]):
def to_object(source_file: Path) -> str:
src_obj_path = self.get_game_build(version) / source_file
files.append(str(src_obj_path.with_suffix(".o")))
return files
return str(src_obj_path.with_suffix(".o"))
dirs = [self.src_path, self.libs_path]
c_cpp_objects = list(map(to_object, get_c_cpp_files(dirs)))
asm_objects = list(map(to_object, get_asm_files(dirs)))
return c_cpp_objects + asm_objects
def arm9_o(self, version: str) -> Path:
return self.get_game_build(version) / "arm9.o"
@@ -532,44 +557,40 @@ def add_disassemble_builds(cfg: ProjectConfig, version: str, n: ninja_syntax.Wri
def add_mwcc_builds(cfg: ProjectConfig, version: str, objects: Dict[str, Object], n: ninja_syntax.Writer, mwcc_implicit: list[str]):
file_map: dict[str, list[str] | None] = {}
file_map: dict[str, Object] = {}
for object in objects.values():
file_map[str(object.src_path)] = object.options["cflags"] + object.options["extra_cflags"]
assert object.src_path is not None, f"Object '{object.name}' is not resolved"
if is_asm(object.src_path):
# file_map[str(object.src_path)] = object.options["asflags"] or [] + object.options["extra_asflags"] or []
file_map[str(object.src_path)] = object
else:
# file_map[str(object.src_path)] = object.options["cflags"] or [] + object.options["extra_cflags"] or []
file_map[str(object.src_path)] = object
if cfg.auto_add_sources:
for source_file in get_c_cpp_files([cfg.src_path, cfg.libs_path]):
if str(source_file) not in file_map:
file_map[str(source_file)] = cfg.cflags_base
source_file = str(source_file)
if source_file not in file_map:
# file_map[source_file] = cfg.cflags_base or []
file_map[source_file] = Object(source_file, cflags=cfg.cflags_base)
for source_file in get_asm_files([cfg.src_path, cfg.libs_path]):
source_file = str(source_file)
if source_file not in file_map:
# file_map[source_file] = cfg.asflags or []
file_map[source_file] = Object(source_file, asflags=cfg.asflags)
for src_file, cc_flags in file_map.items():
for src_file, object in file_map.items():
source_file = Path(src_file)
src_obj_path = cfg.get_game_build(version) / source_file
if cfg.warn_missing_source and not source_file.exists():
print(f"WARNING: path not found for `{source_file}`")
assert cc_flags is not None, "cc_flags is None"
if "-lang=c++" not in cc_flags or "-lang=c" not in cc_flags:
if is_cpp(source_file):
cc_flags.append("-lang=c++")
elif is_c(source_file):
cc_flags.append("-lang=c")
n.build(
inputs=str(source_file),
implicit=mwcc_implicit,
rule="mwcc",
outputs=str(src_obj_path.with_suffix(".o")),
variables={
"game_version": version.upper(),
"cc_flags": " ".join(cc_flags),
"basedir": str(src_obj_path.parent),
"basefile": str(src_obj_path.with_suffix("")),
},
# order_only="objdiff",
)
n.newline()
if is_asm(src_file):
add_mwas_build(cfg, version, n, source_file, object, mwcc_implicit)
else:
add_mwcc_build(cfg, version, n, source_file, object, mwcc_implicit)
extension = source_file.suffix
ctx_file = str(src_obj_path.with_suffix(f".ctx{extension}"))
@@ -584,6 +605,53 @@ def add_mwcc_builds(cfg: ProjectConfig, version: str, objects: Dict[str, Object]
n.newline()
def add_mwcc_build(cfg: ProjectConfig, version: str, n: ninja_syntax.Writer, source_file: Path, object: Object, mwcc_implicit: list[str]):
src_obj_path = cfg.get_game_build(version) / source_file
cc_flags: list[str] = object.options["cflags"] or [] + object.options["extra_cflags"] or []
if "-lang=c++" not in cc_flags or "-lang=c" not in cc_flags:
if is_cpp(source_file):
cc_flags.append("-lang=c++")
elif is_c(source_file):
cc_flags.append("-lang=c")
n.build(
inputs=str(source_file),
implicit=mwcc_implicit,
rule="mwcc",
outputs=str(src_obj_path.with_suffix(".o")),
variables={
"game_version": version.upper(),
"mw_version": object.options["mw_version"],
"cc_flags": " ".join(cc_flags),
"basedir": str(src_obj_path.parent),
"basefile": str(src_obj_path.with_suffix("")),
},
)
n.newline()
def add_mwas_build(cfg: ProjectConfig, version: str, n: ninja_syntax.Writer, source_file: Path, object: Object, mwcc_implicit: list[str]):
src_obj_path = cfg.get_game_build(version) / source_file
as_flags: list[str] = object.options["asflags"] or [] + object.options["extra_asflags"] or []
n.build(
inputs=str(source_file),
implicit=mwcc_implicit,
rule="mwas",
outputs=str(src_obj_path.with_suffix(".o")),
variables={
"game_version": version.upper(),
"mw_version": object.options["mw_version"],
"as_flags": " ".join(as_flags),
"basedir": str(src_obj_path.parent),
"basefile": str(src_obj_path.with_suffix("")),
},
)
n.newline()
def add_mwld_and_rom_builds(cfg: ProjectConfig, version: str, n: ninja_syntax.Writer):
n.comment("Run linker")
objects_to_link = [file['object_to_link'] for file in cfg.files(version)]
@@ -1025,11 +1093,14 @@ def process_project(cfg: ProjectConfig, args: Any):
# -MMD excludes all includes instead of just system includes for some reason, so use -MD instead.
includes = " ".join(include for include in cfg.includes)
mwcc_cmd = f'{cfg.wine_path} {cfg.sjiswrap_path} "{cfg.cc_path}" $cc_flags {includes} -DVERSION=$game_version -MD -c $in -o $basedir'
mwcc_cmd = f'{cfg.wine_path} {cfg.sjiswrap_path} "{cfg.mwcc_root}/$mw_version/mwccarm.exe" $cc_flags {includes} -DVERSION=$game_version -MD -c $in -o $basedir'
mwas_cmd = f'{cfg.wine_path} {cfg.sjiswrap_path} "{cfg.mwcc_root}/$mw_version/mwasmarm.exe" $as_flags {includes} -DVERSION=$game_version -MD -c $in -o $basedir'
mwcc_implicit = [str(cfg.cc_path), str(cfg.sjiswrap_path)]
if cfg.platform and cfg.platform.system != "windows":
transform_dep = "tools/transform_dep.py"
mwcc_cmd += f" && $python {transform_dep} $basefile.d $basefile.d"
transform_dep_cmd = f" && $python {transform_dep} $basefile.d $basefile.d"
mwcc_cmd += transform_dep_cmd
mwas_cmd += transform_dep_cmd
mwcc_implicit.append(transform_dep)
if cfg.wine_path == cfg.default_wibo_path:
mwcc_implicit.append(cfg.wine_path)
@@ -1040,6 +1111,13 @@ def process_project(cfg: ProjectConfig, args: Any):
)
n.newline()
n.rule(
name="mwas",
command=mwas_cmd,
depfile="$basefile.d",
)
n.newline()
n.rule(
name="lcf",
command=f"{cfg.dsd_path} {cfg.dsd_flags} lcf -c $config_path"
@@ -1134,6 +1212,12 @@ def process_project(cfg: ProjectConfig, args: Any):
)
n.newline()
# Custom rules
for lib in cfg.libs or []:
for rule in lib.get("rules") or []:
rule(cfg, n)
n.newline()
add_download_tool_builds(cfg, n, args)
add_configure_build(cfg, n)
@@ -1159,6 +1243,11 @@ def process_project(cfg: ProjectConfig, args: Any):
add_mwcc_builds(cfg, version, objects, n, mwcc_implicit)
# Custom builds
for lib in cfg.libs or []:
for extra_build in lib.get("extra_builds") or []:
extra_build(cfg, version, n)
add_mwld_and_rom_builds(cfg, version, n)
cmds_map["sha1"].append(f"sha1_{version}")
+1
View File
@@ -1,3 +1,4 @@
pre-commit
pyelftools
pyperclip
requests