134 lines
3.8 KiB
Python
Executable file
134 lines
3.8 KiB
Python
Executable file
#!/usr/bin/env nix-shell
|
|
#! nix-shell -i python3 -p python3
|
|
#
|
|
# Usage: dump_common_data.py file.s
|
|
# Dumps all incbin data and prints the revised file to stdout.
|
|
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
# Reads a bytearray from baserom.dol
|
|
def read_baserom(start, size):
|
|
with open('baserom.dol', 'rb') as f:
|
|
f.seek(start, os.SEEK_SET)
|
|
return bytearray(f.read(size))
|
|
|
|
if len(sys.argv) != 2:
|
|
print('Usage: %s ASM_FILE' % sys.argv[0])
|
|
exit()
|
|
|
|
# reads a 32-bit big endian value starting at pos
|
|
def read_u32(data, pos):
|
|
return (data[pos]<<24) | (data[pos+1]<<16) | (data[pos+2]<<8) | (data[pos+3])
|
|
|
|
def is_ascii(code):
|
|
if code >= 0x20 and code <= 0x7E: # normal characters
|
|
return True
|
|
if code in [0x09, 0x0A]: # tab, newline
|
|
return True
|
|
return False
|
|
|
|
# reads a string starting at pos
|
|
def read_string(data, pos):
|
|
text = ''
|
|
while pos < len(data) and is_ascii(data[pos]):
|
|
text += chr(data[pos])
|
|
pos += 1
|
|
if pos < len(data) and data[pos] == 0:
|
|
return text
|
|
return ''
|
|
|
|
# escapes special characters in the string for use in a C string literal
|
|
def escape_string(text):
|
|
return text.replace('\\','\\\\').replace('"','\\"').replace('\n','\\n').replace('\t','\\t')
|
|
|
|
# returns True if value is 4-byte aligned
|
|
def is_aligned(num):
|
|
return num % 4 == 0
|
|
|
|
# returns True if value is a possible pointer
|
|
def is_pointer(num):
|
|
return num >= 0x80003100 and num <= 0x802F6C80
|
|
|
|
# returns True if all elements are zero
|
|
def is_all_zero(arr):
|
|
for val in arr:
|
|
if val != 0:
|
|
return False
|
|
return True
|
|
|
|
# returns string of comma-separated hex bytes
|
|
def hex_bytes(data):
|
|
return ', '.join('0x%02X' % n for n in data)
|
|
|
|
def convert_data(data, offset):
|
|
text = ''
|
|
size = len(data)
|
|
pos = 0
|
|
|
|
if size == 1:
|
|
return f'\t.byte {hex_bytes(data[:1])}\n'
|
|
|
|
while pos < size:
|
|
# pad unaligned
|
|
pad = []
|
|
while not is_aligned(offset + pos) and pos < size:
|
|
pad.append(data[pos])
|
|
pos += 1
|
|
if len(pad) > 0:
|
|
if is_all_zero(pad):
|
|
text += '\t.balign 4\n'
|
|
else:
|
|
text += '\t.byte %s\n' % hex_bytes(pad)
|
|
|
|
# string?
|
|
string = read_string(data, pos)
|
|
if len(string) > 3:
|
|
text += '\t.asciz "%s"\n' % escape_string(string)
|
|
pos += len(string) + 1
|
|
continue
|
|
|
|
assert(is_aligned(offset + pos))
|
|
|
|
if pos + 1 == size:
|
|
text += f'\t.byte {hex_bytes(data[pos:pos+1])}\n'
|
|
break
|
|
if pos + 2 == size:
|
|
text += f'\t.byte {hex_bytes(data[pos:pos+2])}\n'
|
|
break
|
|
if pos + 3 == size:
|
|
text += f'\t.byte {hex_bytes(data[pos:pos+3])}\n'
|
|
break
|
|
|
|
if pos + 4 <= size:
|
|
val = read_u32(data, pos)
|
|
if is_pointer(val):
|
|
text += '\t.4byte 0x%08X ;# ptr\n' % val
|
|
elif val == 0:
|
|
text += '\t.4byte 0\n'
|
|
else:
|
|
text += '\t.4byte 0x%08X\n' % val
|
|
pos += 4
|
|
return text
|
|
|
|
currSection = ''
|
|
|
|
with open(sys.argv[1], 'rt') as f:
|
|
for line in f.readlines():
|
|
line = line.rstrip('\n')
|
|
# Section directive
|
|
m = re.match(r'\s*\.section\s+([\._A-Za-z0-9]+)', line)
|
|
if m:
|
|
currSection = m.groups()[0]
|
|
elif currSection in ['.rodata', '.data', '.sdata', '..ctors', '.ctors', '.dtors', 'extab', 'extabindex', '.sdata2']:
|
|
# Incbin directive
|
|
m = re.match(r'\s*\.incbin\s+"baserom.dol"\s*,\s*([^,]+),\s*([^,]+)', line)
|
|
if m:
|
|
g = m.groups()
|
|
start = int(g[0], 0)
|
|
size = int(g[1], 0)
|
|
data = read_baserom(start, size)
|
|
print(convert_data(data, start).rstrip())
|
|
continue
|
|
print(line)
|