diff options
| author | Anghelo Carvajal <angheloalf95@gmail.com> | 2026-08-02 09:40:32 -0400 |
|---|---|---|
| committer | Anghelo Carvajal <angheloalf95@gmail.com> | 2026-08-02 09:40:32 -0400 |
| commit | f9f5c56d07c549497c49359407c04a8e1e1eb7da (patch) | |
| tree | 51f53f915cb55620d303ba77eb5ed4fe528d3cc0 | |
| parent | 08d6fe1084e1a7bbfbf41230d1f8eec94e8be13a (diff) | |
Incorporate fix_bss tiebreaking algorithm from https://github.com/zeldaret/oot/pull/2779gha
| -rw-r--r-- | requirements.txt | 2 | ||||
| -rwxr-xr-x | tools/fix_bss.py | 49 |
2 files changed, 37 insertions, 14 deletions
diff --git a/requirements.txt b/requirements.txt index 8a78b826c..f5fe93f61 100644 --- a/requirements.txt +++ b/requirements.txt @@ -22,4 +22,4 @@ pycparser toml # map parsing -mapfile-parser>=2.3.5,<3.0.0 +mapfile-parser>=2.13.0,<3.0.0 diff --git a/tools/fix_bss.py b/tools/fix_bss.py index 282c9c7d9..871b8e48c 100755 --- a/tools/fix_bss.py +++ b/tools/fix_bss.py @@ -12,7 +12,6 @@ import colorama from dataclasses import dataclass import io import multiprocessing -import multiprocessing.pool from pathlib import Path import re import shlex @@ -30,8 +29,7 @@ from ido_block_numbers import ( ) import elftools.elf.elffile -import mapfile_parser.mapfile - +import mapfile_parser # Set on program start since we replace sys.stdout in worker processes stdout_isatty = sys.stdout.isatty() @@ -137,7 +135,7 @@ def read_relocs(object_path: Path, section_name: str) -> list[Reloc]: def get_file_pointers( - file: mapfile_parser.mapfile.File, + file: mapfile_parser.Section, base: BinaryIO, build: BinaryIO, ) -> list[Pointer]: @@ -196,7 +194,7 @@ def get_file_pointers_worker_init(base_path: Path, build_path: Path): build = open(build_path, "rb") -def get_file_pointers_worker(file: mapfile_parser.mapfile.File) -> list[Pointer]: +def get_file_pointers_worker(file: mapfile_parser.Section) -> list[Pointer]: assert base is not None assert build is not None return get_file_pointers(file, base, build) @@ -215,8 +213,15 @@ def compare_pointers(version: str) -> dict[Path, BssSection]: if not build_path.exists(): raise FixBssException(f"Could not open {build_path}") - mapfile = mapfile_parser.mapfile.MapFile() + mapfile = mapfile_parser.MapFile() mapfile.readMapFile(mapfile_path) + def resolver(x: Path) -> Path|None: + if x.suffix == ".plf": + plf_map_path = x.with_suffix(".map") + if plf_map_path.exists(): + return plf_map_path + return None + mapfile = mapfile.resolvePartiallyLinkedFiles(resolver) # Segments built from source code (filtering out assets) source_code_segments = [] @@ -279,7 +284,7 @@ def compare_pointers(version: str) -> dict[Path, BssSection]: bss_sections = {} for mapfile_segment in source_code_segments: for file in mapfile_segment: - if not file.sectionType == ".bss": + if file.sectionType != ".bss": continue pointers_in_section = [ @@ -326,6 +331,7 @@ class Pragma: @dataclass class BssVariable: block_number: int + is_top_level: bool name: str size: int align: int @@ -345,7 +351,7 @@ class BssSymbol: INCREMENT_BLOCK_NUMBER_RE = re.compile(r"increment_block_number_(\d+)_(\d+)") -# Find increment_block_number pragmas by parsing the symbol names generated by preprocess.py. +# Find increment_block_number pragmas by parsing the symbol names generated by preprocess.sh. # This is pretty ugly but it seems more reliable than trying to determine the line numbers of # BSS variables in the C file. def find_pragmas(symbol_table: list[SymbolTableEntry]) -> list[Pragma]: @@ -384,9 +390,12 @@ def find_bss_variables( if block_number in init_block_numbers: continue # not BSS - name = symbol_table[block_number].name if op.opcode_name == "fsym": - name = f"{last_function_name}::{name}" + name = f"{last_function_name}::{symbol_table[block_number].name}" + is_top_level = False + else: + name = symbol_table[block_number].name + is_top_level = True size = op.args[0] align = 1 << op.lexlev @@ -397,7 +406,14 @@ def find_bss_variables( referenced_in_data = block_number in referenced_in_data_block_numbers bss_variables.append( - BssVariable(block_number, name, size, align, referenced_in_data) + BssVariable( + block_number, + is_top_level, + name, + size, + align, + referenced_in_data, + ) ) elif op.opcode_name == "init": if op.dtype == 10: # Ndt, "non-local label" @@ -428,10 +444,16 @@ def predict_bss_ordering(variables: list[BssVariable]) -> list[BssSymbol]: # For variables referenced in .data or .rodata, keep the original order. referenced_in_data = [var for var in variables if var.referenced_in_data] - # For the others, sort by block number mod 256. For ties, sort by block number. + # For the others, sort by block number mod 256. Ties are broken with the following priority: + # 1. top-level global and static variables, in original (block number) order + # 2. in-function static variables, in reverse order not_referenced_in_data = [var for var in variables if not var.referenced_in_data] not_referenced_in_data.sort( - key=lambda var: (var.block_number % 256, var.block_number) + key=lambda var: ( + var.block_number % 256, + not var.is_top_level, + var.block_number if var.is_top_level else -var.block_number, + ) ) sorted_variables = referenced_in_data + not_referenced_in_data @@ -577,6 +599,7 @@ def solve_bss_ordering( new_bss_variables.append( BssVariable( new_block_number, + var.is_top_level, var.name, var.size, var.align, |
