Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# splat Release Notes

### 0.36.0

* New yaml options:
* `ld_gp_expression`: Allows setting a custom expression for the `_gp` symbol in the generated linker script, making this symbol to properly shift around instead of hardcoding it to the given `gp_value`.

### 0.35.2

* Miscellaneous updates to generated macro labels.
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.35.2,<1.0.0
splat64[mips]>=0.36.0,<1.0.0
```

### Optional dependencies
Expand Down
42 changes: 42 additions & 0 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ Defaults to `False`.

The value of the `$gp` register to correctly calculate offset to `%gp_rel` relocs.

It is strongly encouraged to provide a [`ld_gp_expression`](#ld_gp_expression) once the sections of the binary are properly understood.
Not setting this expression makes splat to always emit a hardcoded value for `_gp` in the linker script, preventing proper shiftability.

### check_consecutive_segment_types

Expand Down Expand Up @@ -615,6 +617,46 @@ Sets the default option for the `bss_contains_common` attribute of all segments.

Defaults to `False`.

### ld_gp_expression

Provides an expression for the `_gp` symbol to be emitted in the generated linker script.

Most projects start by only setting a [`gp_value`](#gp_value) on their yamls. This is fine while matching the project, but it is bad for shiftable builds, becuase it prevents the `_gp` symbol to shift around as needed.

This expression is used as-is in the generated linker script, so care must be taken to provide an expression that makes sense for shiftable builds and also matches the original gp value on matching builds.

Usually this expression is relative to the start of an "small section" (`.sdata`, `.srodata`, `.sbss`, etc.) plus an optional offset (usually `0x7FF0` or `0x8000`).

The recommended approach to know what to set here is to try to understand where the first small section is, take the difference between the [`gp_value`](#gp_value) and the address of the small section to know what the offset is and then use the linker symbol for the start of that small section.

For example, say your gp value is `0x00397FF0` and you found the first small section on the rom is a `.sdata` section at vram address `0x00390000` (note *vram* address, not rom address) which is part of the top-level segment `main`. The difference between those two addresses is `0x7FF0`, so that's your offset. Given this information the expression you want for gp is `main_SDATA_START + 0x7FF0`; where `main` is the top-level segment, `SDATA` comes from the `.sdata` section and the `+ 0x7FF0` is your calculated offset. If you did this process right, then the matching build should still match after setting the gp expression.

Note you should **not** remove the `gp_value` from your yaml when you set `ld_gp_expression`. `gp_value` is still used for the disassembly, without it you wouldn't get symbolized gp-accesses.

#### Usage

Not using `ld_gp_expression` makes splat to hardcoded the value:

```yaml
gp_value: 0x0039DD70
```

```txt
_gp = 0x0039DD70;
```

When a `ld_gp_expression` is given then splat is able to emit a non-hardcoded expression for `_gp` without interfering with the disassembly process:

```yaml
gp_value: 0x0039DD70
ld_gp_expression: main_SDATA_START + 0x7FF0
```

```txt
_gp = main_SDATA_START + 0x7FF0;
```


## C file options

### create_c_files
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.35.2"
version = "0.36.0"
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.35.2"
__version__ = "0.36.0"
__author__ = "ethteck"

from . import util as util
Expand Down
1 change: 1 addition & 0 deletions src/splat/scripts/create_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ def create_psx_config(exe_path: Path, exe_bytes: bytes):

find_file_boundaries: False
gp_value: 0x{exe.initial_gp:08X}
# ld_gp_expression: main_SCOMMON_START + 0x7FF0

o_as_suffix: True
use_legacy_include_asm: False
Expand Down
6 changes: 4 additions & 2 deletions src/splat/segtypes/linker_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,10 @@ def __init__(self, is_partial: bool = False):
if not self.is_partial:
self._writeln(f"__romPos = {options.opts.ld_rom_start};")

if options.opts.gp is not None:
self._writeln("_gp = " + f"0x{options.opts.gp:X};")
if options.opts.ld_gp_expression is not None:
self._writeln(f"_gp = {options.opts.ld_gp_expression};")
elif options.opts.gp is not None:
self._writeln(f"_gp = 0x{options.opts.gp:X};")

# Write a series of statements which compute a symbol that represents the highest address among a list of segments' end addresses
def write_max_vram_end_sym(self, symbol: str, overlays: List[Segment]):
Expand Down
5 changes: 5 additions & 0 deletions src/splat/util/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ class SplatOpts:
ld_generate_symbol_per_data_segment: bool
# Sets the default option for the `bss_contains_common` attribute of all segments.
ld_bss_contains_common: bool
# Specify an expression to be used for the `_gp` symbol in the generated linker script instead of a hardcoded value.
ld_gp_expression: Optional[str]

################################################################################
# C file options
Expand Down Expand Up @@ -507,6 +509,9 @@ def parse_endianness() -> Literal["big", "little"]:
"ld_generate_symbol_per_data_segment", bool, False
),
ld_bss_contains_common=p.parse_opt("ld_bss_contains_common", bool, False),
ld_gp_expression=p.parse_optional_opt_with_default(
"ld_gp_expression", str, None
),
create_c_files=p.parse_opt("create_c_files", bool, True),
auto_decompile_empty_functions=p.parse_opt(
"auto_decompile_empty_functions", bool, True
Expand Down
Loading