diff options
Diffstat (limited to 'tools/kamek.py')
-rw-r--r-- | tools/kamek.py | 135 |
1 files changed, 117 insertions, 18 deletions
diff --git a/tools/kamek.py b/tools/kamek.py index 97b02cf..43b4556 100644 --- a/tools/kamek.py +++ b/tools/kamek.py @@ -1,12 +1,12 @@ #!/usr/bin/env python # Kamek - build tool for custom C++ code in New Super Mario Bros. Wii -# All rights reserved (c) Treeki 2010 -# Some function definitions by megazig +# All rights reserved (c) Treeki 2010 - 2012 +# Header files compiled by Treeki, Tempus and megazig -# Requires PyYAML +# Requires PyYAML and pyelftools -version_str = 'Kamek 0.1 by Treeki' +version_str = 'Kamek 0.2 by Treeki' import binascii import os @@ -18,6 +18,8 @@ import sys import tempfile import yaml +import elftools.elf.elffile + import hooks u32 = struct.Struct('>I') @@ -151,6 +153,78 @@ def generate_kamek_patches(patchlist): return kamekpatch +class DyLinkCreator(object): + R_PPC_ADDR32 = 1 + R_PPC_ADDR16_LO = 4 + R_PPC_ADDR16_HI = 5 + R_PPC_ADDR16_HA = 6 + R_PPC_REL24 = 10 + + VALID_RELOCS = set([1, 4, 5, 6, 10]) + + def __init__(self): + self._relocs = [] + + self._targets = [] + self._target_lookups = {} + + self.elf = None + + def set_elf(self, stream): + if self.elf != None: + raise ValueError('ELF already set') + + self.elf = elftools.elf.elffile.ELFFile(stream) + self.code = self.elf.get_section_by_name('.text').data() + + self._add_relocs(self.elf.get_section_by_name('.rela.text')) + + def _add_relocs(self, section): + sym_values = {} + sym_section = self.elf.get_section_by_name('.symtab') + + for reloc in section.iter_relocations(): + entry = reloc.entry + #print entry + + sym_id = entry['r_info_sym'] + try: + sym_value = sym_values[sym_id] + except KeyError: + sym = sym_section.get_symbol(sym_id) + sym_value = sym.entry['st_value'] + sym_values[sym_id] = sym_value + #print hex(sym_value) + + self.add_reloc(entry['r_info_type'], entry['r_offset'], sym_value+entry['r_addend']) + + def add_reloc(self, reltype, addr, target): + if reltype not in self.VALID_RELOCS: + raise ValueError('Unknown/unsupported rel type: %d (%x => %x)' % (reltype, addr, target)) + + try: + target_id = self._target_lookups[target] + except KeyError: + target_id = len(self._targets) + self._target_lookups[target] = target_id + self._targets.append(target) + + self._relocs.append((reltype, addr, target_id)) + + def build_reloc_data(self): + header_struct = struct.Struct('>8sI') + + rel_struct_pack = struct.Struct('>II').pack + target_struct_pack = struct.Struct('>I').pack + + rel_data = map(lambda x: rel_struct_pack((x[0] << 24) | x[2], x[1]), self._relocs) + target_data = map(target_struct_pack, self._targets) + + header = header_struct.pack('NewerREL', 12 + (len(self._relocs) * 8)) + + return header + ''.join(rel_data) + ''.join(target_data) + + class KamekModule(object): _requiredFields = ['source_files'] @@ -195,6 +269,11 @@ class KamekBuilder(object): self._configTempDir = tempfile.mkdtemp() print_debug('Temp files for this configuration are in: '+self._configTempDir) + + if 'dynamic_link' in self._config and self._config['dynamic_link']: + self.dynamic_link = DyLinkCreator() + else: + self.dynamic_link = None self._builtCodeAddr = 0x80001800 if 'code_address' in self.project.data: @@ -214,6 +293,9 @@ class KamekBuilder(object): self._compile_modules() self._link() self._read_symbol_map() + + if self.dynamic_link: + self.dynamic_link.set_elf(open(self._outFile, 'rb')) for hook in self._hooks: hook.create_patches() @@ -238,7 +320,7 @@ class KamekBuilder(object): print_debug('---') print_debug('Building for configuration: '+config['friendly_name']) - self._config_short_name = config['short_name'] + self.config_short_name = config['short_name'] self._rel_area = (config['rel_area_start'], config['rel_area_end']) @@ -338,14 +420,20 @@ class KamekBuilder(object): print_debug('---') print_debug('Linking project') - self._mapFile = '%s/%s_linkmap.map' % (self._outDir, self._config_short_name) - self._outFile = '%s/%s_out.bin' % (self._outDir, self._config_short_name) + self._mapFile = '%s/%s_linkmap.map' % (self._outDir, self.config_short_name) + outname = 'object.plf' if self.dynamic_link else 'object.bin' + self._outFile = '%s/%s_%s' % (self._outDir, self.config_short_name, outname) ld_command = ['%s%s-ld' % (gcc_path, gcc_type), '-L.'] ld_command.append('-o') ld_command.append(self._outFile) - ld_command.append('-Ttext') - ld_command.append('0x%08X' % self._builtCodeAddr) + if self.dynamic_link: + ld_command.append('-r') + ld_command.append('--oformat=elf32-powerpc') + else: + ld_command.append('--oformat=binary') + ld_command.append('-Ttext') + ld_command.append('0x%08X' % self._builtCodeAddr) ld_command.append('-T') ld_command.append(self._config['linker_script']) ld_command.append('-Map') @@ -429,7 +517,7 @@ class KamekBuilder(object): print_debug('Generated code is at 0x%08X .. 0x%08X' % (self._codeStart, self._codeEnd - 4)) - def _find_func_by_symbol(self, find_symbol): + def find_func_by_symbol(self, find_symbol): for sym in self._symbols: #if show_cmd: # out = "0x%08x - %s - %s" % (sym[0], sym[1], sym[2]) @@ -440,7 +528,7 @@ class KamekBuilder(object): raise ValueError, 'Cannot find function: %s' % find_symbol - def _add_patch(self, offset, data): + def add_patch(self, offset, data): if offset >= self._rel_area[0] and offset <= self._rel_area[1] and use_rels: self._rel_patches.append((offset, data)) else: @@ -457,13 +545,24 @@ class KamekBuilder(object): #self._patches.append((0x817F4800, kamekpatch)) self._patches.append((0x80002F60, kamekpatch)) - # add the outfile as a patch - file = open(self._outFile, 'rb') - patch = (self._codeStart, file.read()) - file.close() - - self._patches.append(patch) - + if self.dynamic_link: + # put together the dynamic link files + dlcode = open('%s/%s_dlcode.bin' % (self._outDir, self._config['short_name']), 'wb') + dlcode.write(self.dynamic_link.code) + dlcode.close() + + dlrelocs = open('%s/%s_dlrelocs.bin' % (self._outDir, self._config['short_name']), 'wb') + dlrelocs.write(self.dynamic_link.build_reloc_data()) + dlrelocs.close() + + else: + # add the outfile as a patch if not using dynamic linking + file = open(self._outFile, 'rb') + patch = (self._codeStart, file.read()) + file.close() + + self._patches.append(patch) + # generate a Riivolution patch riiv = open('%s/%s_riiv.xml' % (self._outDir, self._config['short_name']), 'w') for patch in self._patches: |