Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 4 additions & 16 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,8 @@ jobs:
pip install -r requirements.txt
pip install types-PyYAML

- name: ruff split
run: ruff check split.py

- name: ruff create_config
run: ruff check create_config.py

- name: ruff test
run: ruff check test.py
- name: ruff
run: ruff check .

mypy_splat_checks:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -94,11 +88,5 @@ jobs:
pip install -r requirements.txt
pip install types-PyYAML

- name: mypy split
run: mypy --show-column-numbers --hide-error-context split.py

- name: mypy create_config
run: mypy --show-column-numbers --hide-error-context create_config.py

- name: mypy test
run: mypy --show-column-numbers --hide-error-context test.py
- name: mypy
run: mypy --show-column-numbers --hide-error-context *.py
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# splat Release Notes

### 0.37.3

* create_config: Avoid emitting relocations for addresses paired by using `ori`

### 0.37.2

* Add new option `sort_segments_by_vram_dependency` to help with non-matching builds for binaries with complicated memory layouts. See the wiki for details.
* Fix create_config missing bss segments due to unsigned LO instructions.

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ The brackets corresponds to the optional dependencies to install while installin
If you use a `requirements.txt` file in your repository, then you can add this library with the following line:

```txt
splat64[mips]>=0.37.2,<1.0.0
splat64[mips]>=0.37.3,<1.0.0
```

### Optional dependencies
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[project]
name = "splat64"
# Should be synced with src/splat/__init__.py
version = "0.37.2"
version = "0.37.3"
description = "A binary splitting tool to assist with decompilation and modding projects"
readme = "README.md"
license = {file = "LICENSE"}
Expand Down
2 changes: 1 addition & 1 deletion src/splat/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
__package_name__ = __name__

# Should be synced with pyproject.toml
__version__ = "0.37.2"
__version__ = "0.37.3"
__author__ = "ethteck"

from . import util as util
Expand Down
47 changes: 26 additions & 21 deletions src/splat/scripts/create_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,32 +193,37 @@ def create_n64_config(rom_path: Path):
file_presets.write_all_files()

# Write reloc_addrs.txt file
reloc_addrs = []
if rom.entrypoint_info.bss_start_address is not None:
reloc_addrs.append(
f"rom:0x{rom.entrypoint_info.bss_start_address.rom_hi:06X} reloc:MIPS_HI16 symbol:main_BSS_START"
)
reloc_addrs.append(
f"rom:0x{rom.entrypoint_info.bss_start_address.rom_lo:06X} reloc:MIPS_LO16 symbol:main_BSS_START"
)
reloc_addrs.append("")
if rom.entrypoint_info.bss_size is not None:
reloc_addrs.append(
f"rom:0x{rom.entrypoint_info.bss_size.rom_hi:06X} reloc:MIPS_HI16 symbol:main_BSS_SIZE"
)
reloc_addrs.append(
f"rom:0x{rom.entrypoint_info.bss_size.rom_lo:06X} reloc:MIPS_LO16 symbol:main_BSS_SIZE"
)
reloc_addrs.append("")
if rom.entrypoint_info.bss_end_address is not None:
reloc_addrs: list[str] = []

addresses_info: list[tuple[Optional[rominfo.EntryAddressInfo], str]] = [
(rom.entrypoint_info.main_address, "main"),
(rom.entrypoint_info.bss_start_address, "main_BSS_START"),
(rom.entrypoint_info.bss_size, "main_BSS_SIZE"),
(rom.entrypoint_info.bss_end_address, "main_BSS_END"),
]

for addr_info, sym_name in addresses_info:
if addr_info is None:
continue
if addr_info.ori:
# Avoid emitting relocations for `ori`s since `%lo` doesn't support it.
continue
if addr_info.rom_hi == addr_info.rom_lo:
# hi and lo may be the same for the "main" address, i.e. a direct jal.
continue

reloc_addrs.append(
f"rom:0x{rom.entrypoint_info.bss_end_address.rom_hi:06X} reloc:MIPS_HI16 symbol:main_BSS_END"
f"rom:0x{addr_info.rom_hi:06X} reloc:MIPS_HI16 symbol:{sym_name}"
)
reloc_addrs.append(
f"rom:0x{rom.entrypoint_info.bss_end_address.rom_lo:06X} reloc:MIPS_LO16 symbol:main_BSS_END"
f"rom:0x{addr_info.rom_lo:06X} reloc:MIPS_LO16 symbol:{sym_name}"
)
reloc_addrs.append("")
if rom.entrypoint_info.stack_top is not None:

if (
rom.entrypoint_info.stack_top is not None
and not rom.entrypoint_info.stack_top.ori
):
reloc_addrs.append(
'// This entry corresponds to the "stack top", which is the end of the array used as the stack for the main segment.'
)
Expand Down
23 changes: 20 additions & 3 deletions src/splat/util/n64/rominfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,14 @@ class EntryAddressInfo:
value: int
rom_hi: int
rom_lo: int
ori: bool

@staticmethod
def new(
value: Optional[int], hi: Optional[int], lo: Optional[int]
value: Optional[int], hi: Optional[int], lo: Optional[int], ori: Optional[int]
) -> Optional["EntryAddressInfo"]:
if value is not None and hi is not None and lo is not None:
return EntryAddressInfo(value, hi, lo)
return EntryAddressInfo(value, hi, lo, ori == lo)
return None


Expand All @@ -94,6 +95,7 @@ class N64EntrypointInfo:
main_address: Optional[EntryAddressInfo]
stack_top: Optional[EntryAddressInfo]
traditional_entrypoint: bool
ori_entrypoint: bool

def segment_size(self) -> int:
if self.data_size is not None:
Expand All @@ -120,6 +122,10 @@ def parse_rom_bytes(
completed_pair = [False for _ in range(32)]
hi_assignments: List[Optional[int]] = [None for _ in range(32)]
lo_assignments: List[Optional[int]] = [None for _ in range(32)]
# We need to track if something was paired using an ori instead of an
# addiu or similar, because if that's the case we can't emit normal
# relocations in the generated symbol_addrs file for it.
ori_assignments: List[Optional[int]] = [None for _ in range(32)]

register_bss_address: Optional[int] = None
register_bss_size: Optional[int] = None
Expand All @@ -130,6 +136,7 @@ def parse_rom_bytes(
bss_end_address: Optional[EntryAddressInfo] = None

traditional_entrypoint = True
ori_entrypoint = False
decrementing_bss_routine = True
data_size: Optional[int] = None
func_call_target: Optional[EntryAddressInfo] = None
Expand Down Expand Up @@ -163,6 +170,9 @@ def parse_rom_bytes(
)
completed_pair[insn.rt.value] = True
lo_assignments[insn.rt.value] = current_rom
if insn.isUnsigned():
ori_assignments[insn.rt.value] = current_rom
ori_entrypoint = True
elif insn.doesStore():
if insn.rt == rabbitizer.RegGprO32.zero:
# Try to detect the zero-ing bss algorithm
Expand Down Expand Up @@ -208,11 +218,13 @@ def parse_rom_bytes(
register_values[insn.rs.value],
hi_assignments[insn.rs.value],
lo_assignments[insn.rs.value],
ori_assignments[insn.rs.value],
)
bss_end_address = EntryAddressInfo.new(
register_values[insn.rt.value],
hi_assignments[insn.rt.value],
lo_assignments[insn.rt.value],
ori_assignments[insn.rt.value],
)

elif insn.isFunctionCall():
Expand All @@ -221,7 +233,7 @@ def parse_rom_bytes(
# entrypoint to actual code.
traditional_entrypoint = False
func_call_target = EntryAddressInfo(
insn.getInstrIndexAsVram(), current_rom, current_rom
insn.getInstrIndexAsVram(), current_rom, current_rom, False
)

elif insn.uniqueId == rabbitizer.InstrId.cpu_break:
Expand Down Expand Up @@ -254,19 +266,22 @@ def parse_rom_bytes(
register_values[register_bss_address],
hi_assignments[register_bss_address],
lo_assignments[register_bss_address],
ori_assignments[register_bss_address],
)
if register_bss_size is not None:
bss_size = EntryAddressInfo.new(
register_values[register_bss_size],
hi_assignments[register_bss_size],
lo_assignments[register_bss_size],
ori_assignments[register_bss_size],
)

if register_main_address is not None:
main_address = EntryAddressInfo.new(
register_values[register_main_address],
hi_assignments[register_main_address],
lo_assignments[register_main_address],
ori_assignments[register_main_address],
)
else:
main_address = None
Expand All @@ -275,6 +290,7 @@ def parse_rom_bytes(
register_values[rabbitizer.RegGprO32.sp.value],
hi_assignments[rabbitizer.RegGprO32.sp.value],
lo_assignments[rabbitizer.RegGprO32.sp.value],
ori_assignments[rabbitizer.RegGprO32.sp.value],
)

if not traditional_entrypoint:
Expand All @@ -299,6 +315,7 @@ def parse_rom_bytes(
main_address,
stack_top,
traditional_entrypoint,
ori_entrypoint,
)


Expand Down
Loading