summaryrefslogtreecommitdiff
path: root/tools/patch_data_with_rodata_mdebug.py
blob: 48059c51e1459922b7579bc3365e29254cc4f166 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#!/usr/bin/env python3

# SPDX-FileCopyrightText: © 2025 ZeldaRET
# SPDX-License-Identifier: CC0-1.0

import argparse
import struct

import elftools.elf.elffile

# Patches mdebug for files linked with data_with_rodata.ld by replacing storage
# class stData with stRData, since .data symbols are now in the .rodata section

SC_MASK = 0x03E00000
SC_SHIFT = 21


def read_u32(f, offset):
    f.seek(offset)
    return struct.unpack(">I", f.read(4))[0]


def write_u32(f, offset, value):
    f.seek(offset)
    f.write(struct.pack(">I", value))


def patch_sc(f, offset):
    value = read_u32(f, offset)
    sc = (value & SC_MASK) >> SC_SHIFT
    if sc == 2:  # scData
        value = (value & ~SC_MASK) | (15 << SC_SHIFT)  # scRData
        write_u32(f, offset, value)


def main():
    parser = argparse.ArgumentParser()

    parser.add_argument("file", help="input file")
    args = parser.parse_args()

    with open(args.file, "r+b") as f:
        elf = elftools.elf.elffile.ELFFile(f)

        mdebug_offset = 0
        for section in elf.iter_sections():
            if section.name == ".mdebug":
                mdebug_offset = section["sh_offset"]
                break

        if mdebug_offset == 0:
            return

        isymMax = read_u32(f, mdebug_offset + 0x20)
        cbSymOffset = read_u32(f, mdebug_offset + 0x24)
        iextMax = read_u32(f, mdebug_offset + 0x58)
        cbExtOffset = read_u32(f, mdebug_offset + 0x5C)

        for i in range(isymMax):
            patch_sc(f, cbSymOffset + i * 0xC + 0x8)

        for i in range(iextMax):
            patch_sc(f, cbExtOffset + i * 0x10 + 0xC)


if __name__ == "__main__":
    main()