From a1b7313162f362df4e0e30f04f13096a56faa368 Mon Sep 17 00:00:00 2001 From: Yanis002 <35189056+Yanis002@users.noreply.github.com> Date: Wed, 17 Dec 2025 19:52:47 +0100 Subject: [PATCH] create formatter script for delinks.txt files --- config/eur/arm9/delinks.txt | 36 ++-- config/eur/arm9/overlays/ov110/delinks.txt | 2 +- config/jp/arm9/delinks.txt | 34 ++-- config/jp/arm9/overlays/ov110/delinks.txt | 2 +- tools/configure.py | 14 +- tools/format_delinks.py | 190 +++++++++++++++++++++ 6 files changed, 240 insertions(+), 38 deletions(-) create mode 100644 tools/format_delinks.py diff --git a/config/eur/arm9/delinks.txt b/config/eur/arm9/delinks.txt index 929f8889..c29a5529 100644 --- a/config/eur/arm9/delinks.txt +++ b/config/eur/arm9/delinks.txt @@ -13,33 +13,28 @@ src/Main/Main.cpp: src/Main/System/OverlayManager.cpp: .text start:0x020147fc end:0x02014944 -libs/cpp/src/__register_global_object.c: - complete - .text start:0x0203ce74 end:0x0203ce94 - .bss start:0x02051ad4 end:0x02051ad8 - src/Main/func_02017ea4.cpp: .text start:0x02017ea4 end:0x02017f38 -libs/c/src/locale.c: - complete - .data start:0x02044790 end:0x020449ac - libs/c/src/abort_exit_arm_eabi.c: complete - .bss start:0x02051570 end:0x02051680 .text start:0x020336e8 end:0x02033870 + .bss start:0x02051570 end:0x02051680 libs/c/src/ansi_files.c: complete - .data start:0x020446a8 end:0x0204478c - .bss start:0x020517a0 end:0x02051aa0 .text start:0x02033870 end:0x020338d4 + .data start:0x020446a8 end:0x0204478c + .bss start:0x020517a0 end:0x02051aa0 libs/c/src/float.c: complete .data start:0x0204478c end:0x02044790 +libs/c/src/locale.c: + complete + .data start:0x02044790 end:0x020449ac + libs/c/src/arith.c: complete .text start:0x020338d4 end:0x020338ec @@ -70,8 +65,8 @@ libs/c/src/mem_funcs.c: libs/c/src/secure_error.c: complete - .bss start:0x02051aa4 end:0x02051aa8 .text start:0x02033e28 end:0x02033e54 + .bss start:0x02051aa4 end:0x02051aa8 libs/c/src/signal.c: complete @@ -87,16 +82,16 @@ libs/c/src/wmem.c: .text start:0x020341f8 end:0x02034230 libs/c/src/wprintf.c: - .data start:0x020449ac end:0x02044a2c .text start:0x02034230 end:0x0203615c + .data start:0x020449ac end:0x02044a2c libs/c/src/wstring.c: complete .text start:0x0203615c end:0x0203621c libs/c/src/ansi_fp.c: - .data start:0x02044a2c end:0x02044b00 .text start:0x0203621c end:0x02036ba4 + .data start:0x02044a2c end:0x02044b00 libs/c/src/extras.c: complete @@ -104,18 +99,18 @@ libs/c/src/extras.c: libs/c/src/math/e_log.c: complete - .bss start:0x02051ac4 end:0x02051acc .text start:0x02036bd0 end:0x02037300 + .bss start:0x02051ac4 end:0x02051acc libs/c/src/math/e_log10.c: complete - .bss start:0x02051acc end:0x02051ad4 .text start:0x02037300 end:0x020374d8 + .bss start:0x02051acc end:0x02051ad4 libs/c/src/math/e_pow.c: complete - .rodata start:0x02043188 end:0x020431b8 .text start:0x020374d8 end:0x02038660 + .rodata start:0x02043188 end:0x020431b8 libs/c/src/math/s_ceil.c: complete @@ -148,3 +143,8 @@ libs/c/src/math/w_log10f.c: libs/c/src/math/w_pow.c: complete .text start:0x02038ba0 end:0x02038bac + +libs/cpp/src/__register_global_object.c: + complete + .text start:0x0203ce74 end:0x0203ce94 + .bss start:0x02051ad4 end:0x02051ad8 diff --git a/config/eur/arm9/overlays/ov110/delinks.txt b/config/eur/arm9/overlays/ov110/delinks.txt index 61eb6923..9f65fbd0 100644 --- a/config/eur/arm9/overlays/ov110/delinks.txt +++ b/config/eur/arm9/overlays/ov110/delinks.txt @@ -7,8 +7,8 @@ src/110_PlayerGet/PlayerGet.cpp: .text start:0x02184a40 end:0x02185dc4 - .rodata start:0x02185dc4 end:0x02186190 .init start:0x02186190 end:0x021861bc + .rodata start:0x02185dc4 end:0x02186190 .ctor start:0x021861bc end:0x021861c4 .data start:0x021861e0 end:0x02186240 .bss start:0x02186240 end:0x0218a1c0 diff --git a/config/jp/arm9/delinks.txt b/config/jp/arm9/delinks.txt index 2745502c..1ac852ef 100644 --- a/config/jp/arm9/delinks.txt +++ b/config/jp/arm9/delinks.txt @@ -13,18 +13,9 @@ src/Main/Main.cpp: src/Main/System/OverlayManager.cpp: .text start:0x02014800 end:0x02014948 -libs/cpp/src/__register_global_object.c: - complete - .text start:0x0203e3a4 end:0x0203e3c4 - .bss start:0x02053054 end:0x02053058 - src/Main/func_02017ea4.cpp: .text start:0x02017e3c end:0x02017ed0 -libs/c/src/locale.c: - complete - .data start:0x02045d04 end:0x02045f20 - libs/c/src/abort_exit_arm_eabi.c: complete .text start:0x02034c18 end:0x02034da0 @@ -32,14 +23,18 @@ libs/c/src/abort_exit_arm_eabi.c: libs/c/src/ansi_files.c: complete - .bss start:0x02052d20 end:0x02053020 - .data start:0x02045c1c end:0x02045d00 .text start:0x02034da0 end:0x02034e04 + .data start:0x02045c1c end:0x02045d00 + .bss start:0x02052d20 end:0x02053020 libs/c/src/float.c: complete .data start:0x02045d00 end:0x02045d04 +libs/c/src/locale.c: + complete + .data start:0x02045d04 end:0x02045f20 + libs/c/src/arith.c: complete .text start:0x02034e04 end:0x02034e1c @@ -70,8 +65,8 @@ libs/c/src/mem_funcs.c: libs/c/src/secure_error.c: complete - .bss start:0x02053024 end:0x02053028 .text start:0x02035358 end:0x02035384 + .bss start:0x02053024 end:0x02053028 libs/c/src/signal.c: complete @@ -87,16 +82,16 @@ libs/c/src/wmem.c: .text start:0x02035728 end:0x02035760 libs/c/src/wprintf.c: - .data start:0x02045f20 end:0x02045fa0 .text start:0x02035760 end:0x0203768c + .data start:0x02045f20 end:0x02045fa0 libs/c/src/wstring.c: complete .text start:0x0203768c end:0x0203774c libs/c/src/ansi_fp.c: - .data start:0x02045fa0 end:0x02046074 .text start:0x0203774c end:0x020380d4 + .data start:0x02045fa0 end:0x02046074 libs/c/src/extras.c: complete @@ -104,18 +99,18 @@ libs/c/src/extras.c: libs/c/src/math/e_log.c: complete - .bss start:0x02053044 end:0x0205304c .text start:0x02038100 end:0x02038830 + .bss start:0x02053044 end:0x0205304c libs/c/src/math/e_log10.c: complete - .bss start:0x0205304c end:0x02053054 .text start:0x02038830 end:0x02038a08 + .bss start:0x0205304c end:0x02053054 libs/c/src/math/e_pow.c: complete - .rodata start:0x020446d4 end:0x02044704 .text start:0x02038a08 end:0x02039b90 + .rodata start:0x020446d4 end:0x02044704 libs/c/src/math/s_ceil.c: complete @@ -148,3 +143,8 @@ libs/c/src/math/w_log10f.c: libs/c/src/math/w_pow.c: complete .text start:0x0203a0d0 end:0x0203a0dc + +libs/cpp/src/__register_global_object.c: + complete + .text start:0x0203e3a4 end:0x0203e3c4 + .bss start:0x02053054 end:0x02053058 diff --git a/config/jp/arm9/overlays/ov110/delinks.txt b/config/jp/arm9/overlays/ov110/delinks.txt index b1b5038c..ecaa3a1d 100644 --- a/config/jp/arm9/overlays/ov110/delinks.txt +++ b/config/jp/arm9/overlays/ov110/delinks.txt @@ -7,8 +7,8 @@ src/110_PlayerGet/PlayerGet.cpp: .text start:0x021865c0 end:0x021879c4 - .rodata start:0x021879c4 end:0x02187d90 .init start:0x02187d90 end:0x02187dbc + .rodata start:0x021879c4 end:0x02187d90 .ctor start:0x02187dbc end:0x02187dc4 .data start:0x02187de0 end:0x02187e40 .bss start:0x02187e40 end:0x0218bdc0 diff --git a/tools/configure.py b/tools/configure.py index 80cf12a1..4a95ae6e 100755 --- a/tools/configure.py +++ b/tools/configure.py @@ -360,6 +360,12 @@ def main(): ) n.newline() + n.rule( + name="format_delinks", + command=f'{PYTHON} tools/format_delinks.py' + ) + n.newline() + add_download_tool_builds(n, project) add_configure_build(n, project) @@ -373,7 +379,13 @@ def main(): add_objdiff_builds(n, project) add_apply_build(n, project) - n.default(["objdiff", "check", "sha1"]) + n.build( + rule="format_delinks", + outputs="format_delinks" + ) + n.newline() + + n.default(["format_delinks", "objdiff", "check", "sha1"]) else: n.default(["download_tools"]) diff --git a/tools/format_delinks.py b/tools/format_delinks.py new file mode 100644 index 00000000..5c29bc5c --- /dev/null +++ b/tools/format_delinks.py @@ -0,0 +1,190 @@ +#!/usr/bin/env python + +import copy + +from pathlib import Path +from dataclasses import dataclass, field +from typing import Optional + + +INDENT = " " * 4 +SECTION_NAMES = [ + "text", + "exception", + "exceptix", + "init", + "rodata", + "ctor", + "data", + "bss", +] + + +@dataclass +class Section: + name: str + start: str = "0x00000000" + end: str = "0x00000000" + attributes: tuple[str] = field(default_factory=tuple) + + def is_used(self): + return int(self.start, base=16) > 0 + + def has_attributes(self): + return len(self.attributes) > 0 + + def to_txt(self): + extras = "\n" + + if self.has_attributes(): + extras = f" {' '.join(attr for attr in self.attributes)}\n" + + return INDENT + f"{self.name:11} start:{self.start} end:{self.end}" + extras + + +class Sections: + def __init__(self): + self.text = Section(".text") + self.exception = Section(".exception") + self.exceptix = Section(".exceptix") + self.init = Section(".init") + self.rodata = Section(".rodata") + self.ctor = Section(".ctor") + self.data = Section(".data") + self.bss = Section(".bss") + + def get_hash_key(self): + return ( + self.text, + self.exception, + self.exceptix, + self.init, + self.rodata, + self.ctor, + self.data, + self.bss + ) + + def to_txt(self): + data = "" + + for name in SECTION_NAMES: + section: Optional[Section] = getattr(self, name) + assert section is not None + + if section.is_used(): + data += section.to_txt() + + assert len(data) > 0 + return data + + +@dataclass +class Delink: + filename: str + sections: Sections + completed: bool + + def to_txt(self): + completed = (INDENT + "complete\n") if self.completed else "" + return f"{self.filename}:\n{completed}" + self.sections.to_txt() + + +class Delinks: + def __init__(self, file: Path): + self.header = "" + + # filename: sections + self.entries: list[Delink] = [] + + assert file.exists() + + with file.open("r") as f: + filedata = f.readlines() + [""] + + first_file = False + cur_delink: Optional[Delink] = None + for original_line in filedata: + line = original_line.strip() + + if cur_delink is not None: + if original_line not in {"", "\n"}: + if "complete" in line: + cur_delink.completed = True + else: + split = list(dict.fromkeys(line.split(" ")).keys()) + split.remove("") + + section: Section = getattr(cur_delink.sections, split[0].removeprefix(".")) + section.start = split[1].removeprefix("start:") + section.end = split[2].removeprefix("end:") + + if len(split) > 3: + section.attributes = tuple(split[3:]) + else: + self.entries.append(cur_delink) + cur_delink = None + elif line.endswith(".c:") or line.endswith(".cpp:"): + cur_delink = Delink(line.removesuffix(":"), Sections(), False) + + if not first_file: + first_file = True + + if not first_file: + self.header += original_line + + def to_txt(self): + return self.header + "\n".join(delink.to_txt() for delink in self.entries) + + def sort(self): + sorted_entries: list[Delink] = [] + + def get_section_map(section_name: str): + section_map = {} + + for delink in self.entries: + self_section: Optional[Section] = getattr(delink.sections, section_name) + assert self_section is not None + + if self_section.is_used(): + section_map[int(self_section.start, 16)] = delink + + return dict(sorted(section_map.items())) + + def sort_section(section_name: str): + section_map = get_section_map(section_name) + + if section_name == "text": + sorted_entries.extend(list(section_map.values())) + else: + index = None + + for delink in section_map.values(): + if delink in sorted_entries: + index = sorted_entries.index(delink) + 1 + elif index is not None: + sorted_entries.insert(index, delink) + index += 1 + else: + sorted_entries.append(delink) + + for name in SECTION_NAMES: + sort_section(name) + + assert len(self.entries) == len(sorted_entries) + self.entries.clear() + self.entries = copy.copy(sorted_entries) + + +def main(): + config_path = Path("config").resolve() + assert config_path.exists() + + for delinks_path in config_path.rglob("delinks.txt"): + delinks = Delinks(delinks_path) + delinks.sort() + delinks_path.write_text(delinks.to_txt()) + + +if __name__ == "__main__": + main()