Skip to content

Commit

Permalink
add max segment size checked at build time
Browse files Browse the repository at this point in the history
  • Loading branch information
bates64 committed Oct 7, 2024
1 parent a24d942 commit 8b0087e
Show file tree
Hide file tree
Showing 3 changed files with 195 additions and 4 deletions.
41 changes: 41 additions & 0 deletions tools/build/check_section_sizes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from sys import argv
import json
import subprocess
import sys

# Checks each segment-size pair in JSON object are valid for the given ELF.
# usage: python3 check_section_sizes.py <elf> <json>

argv.pop(0) # python3
elf_path = argv.pop(0)
jsonstr = argv.pop(0)

def read_elf():
result = subprocess.run(["mips-linux-gnu-nm", elf_path], stdout=subprocess.PIPE)
lines = result.stdout.decode().split("\n")
symbols = {}
for line in lines:
splitted = line.split(" ")
if len(splitted) == 3:
address, kind, symbol = splitted
if symbol.endswith("_VRAM") or symbol.endswith("_VRAM_END"):
symbols[symbol] = int(address, 16)
return symbols

segment_size_map = json.loads(jsonstr)
symbols = read_elf()

fail = False
for segment_name, max_size in segment_size_map.items():
start_address = symbols[segment_name + "_VRAM"]
end_address = symbols[segment_name + "_VRAM_END"]
true_size = end_address - start_address
if true_size > max_size:
size_diff = true_size - max_size
print(f"\033[31msegment '{segment_name}' is oversized!\033[0m (size is {true_size:X}; +{size_diff:X} compared to max size {max_size:X})", file=sys.stderr)
fail = True
if fail:
print("help: segment(s) are too big to fit in their overlay(s). to fix this, write less code/data, or modify the engine and splat.yaml to increase the limit", file=sys.stderr)
exit(1)
else:
print("ok")
32 changes: 28 additions & 4 deletions tools/build/configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import sys
import ninja_syntax
from glob import glob
import json

# Configuration:
VERSIONS = ["us"]
Expand Down Expand Up @@ -327,6 +328,8 @@ def write_ninja_rules(

ninja.rule("flips", command=f"bash -c '{BUILD_TOOLS}/floating/flips $baserom $in $out || true'")

ninja.rule("check_section_sizes", command=f"$python {BUILD_TOOLS}/check_section_sizes.py $in $data > $out")


def write_ninja_for_tools(ninja: ninja_syntax.Writer):
ninja.rule(
Expand Down Expand Up @@ -1275,6 +1278,13 @@ def build(
f"ver/{self.version}/checksum.sha1",
implicit=[str(self.rom_path())],
)
else:
ninja.build(
str(self.rom_ok_path()),
"check_section_sizes",
str(self.elf_path()),
variables={"data": json.dumps(json.dumps(self.get_segment_max_sizes(), separators=(',', ':')))}
)

ninja.build(
str(self.patch_path()),
Expand All @@ -1286,6 +1296,23 @@ def build(
ninja.build("generated_code_" + self.version, "phony", generated_code)
ninja.build("inc_img_bins_" + self.version, "phony", inc_img_bins)



def get_segment_max_sizes(self):
assert self.linker_entries is not None
segment_size_map = {}

# depth-first search
def visit(segment):
if hasattr(segment, "parent") and segment.parent is not None:
visit(segment.parent)
if hasattr(segment, "yaml") and isinstance(segment.yaml, dict) and "max_size" in segment.yaml:
segment_size_map[segment.name] = segment.yaml["max_size"]
for entry in self.linker_entries:
visit(entry.segment)

return segment_size_map

def make_current(self, ninja: ninja_syntax.Writer):
current = Path("ver/current")

Expand Down Expand Up @@ -1505,8 +1532,5 @@ def make_current(self, ninja: ninja_syntax.Writer):
assert first_configure, "no versions configured"
first_configure.make_current(ninja)

if non_matching:
ninja.build("all", "phony", [str(first_configure.rom_path())])
else:
ninja.build("all", "phony", all_rom_oks)
ninja.build("all", "phony", all_rom_oks)
ninja.default("all")
Loading

0 comments on commit 8b0087e

Please sign in to comment.