From 5e8e92cd8f403cbfebc4469a1aee252212e42045 Mon Sep 17 00:00:00 2001 From: Treeki Date: Tue, 27 Mar 2012 21:38:52 +0200 Subject: Kamek/Newer now support dynamic linking --- tools/dumprelocs.py | 19 ++++++++ tools/hooks.py | 73 +++++++++++++++------------- tools/kamek.py | 135 +++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 177 insertions(+), 50 deletions(-) create mode 100644 tools/dumprelocs.py (limited to 'tools') diff --git a/tools/dumprelocs.py b/tools/dumprelocs.py new file mode 100644 index 0000000..d5773e3 --- /dev/null +++ b/tools/dumprelocs.py @@ -0,0 +1,19 @@ +import struct +up = struct.Struct('>II').unpack +u32 = struct.Struct('>I').unpack + +data = open('NewerASM/pal_dlrelocs.bin', 'rb').read() +addr_offset = struct.unpack('>xxxxxxxxI', data[0:0xC])[0] - 0xC +data = data[0xC:] + +reloc_count = addr_offset / 8 + +for i in xrange(reloc_count): + entry = up(data[i*8:i*8+8]) + reltype = entry[0] >> 24 + addr_id = entry[0] & 0xFFFFFF + offset = entry[1] + + offs = addr_offset+(addr_id*4) + print "%2d: %08x => %08x" % (reltype, offset, u32(data[offs:offs+4])[0]) + diff --git a/tools/hooks.py b/tools/hooks.py index 13c4e19..388efcb 100755 --- a/tools/hooks.py +++ b/tools/hooks.py @@ -3,14 +3,18 @@ import struct u32 = struct.Struct('>I') +BRANCH_TYPES = ['b', 'bl', 'ba', 'bla'] def make_branch_insn(fromAddr, toAddr, branchType): - branchTypes = ['b', 'bl', 'ba', 'bla'] - if branchType not in branchTypes: + if branchType not in BRANCH_TYPES: raise ValueError, 'invalid branch type: %s' % branchType - extra = branchTypes.index(branchType) + extra = BRANCH_TYPES.index(branchType) - distance = toAddr - fromAddr + if toAddr == -1: + distance = 0 # placeholder, will be added later by relocs + else: + distance = toAddr - fromAddr + if distance >= 0x2000000 or distance <= -0x2000000: raise ValueError, 'branching too far: %08x to %08x' % (fromAddr, toAddr) @@ -44,7 +48,7 @@ class Hook(object): self.context.hooks.append(self) # validate the hook's data - current_config_name = builder._config_short_name + current_config_name = builder.config_short_name for field in self.required_data: field = field.replace('%CONFIG%', current_config_name) @@ -65,7 +69,7 @@ class BasicPatchHook(Hook): Hook.__init__(self, builder, module, data) def create_patches(self): - addr = self.data['addr_%s' % self.builder._config_short_name] + addr = self.data['addr_%s' % self.builder.config_short_name] hex_data = self.data['data'] @@ -75,7 +79,7 @@ class BasicPatchHook(Hook): patch = binascii.unhexlify(hex_data) - self.builder._add_patch(addr, patch) + self.builder.add_patch(addr, patch) @@ -91,19 +95,23 @@ class BranchInsnHook(Hook): try: target_func = self.data['target_func'] except KeyError: - target_func = self.data['target_func_%s' % self.builder._config_short_name] - - if isinstance(target_func, str): - target_func = self.builder._find_func_by_symbol(target_func) + target_func = self.data['target_func_%s' % self.builder.config_short_name] + + src_addr = self.data['src_addr_%s' % self.builder.config_short_name] + is_symbol_name = isinstance(target_func, str) + + if is_symbol_name: + target_func = self.builder.find_func_by_symbol(target_func) + + if is_symbol_name and self.builder.dynamic_link: + branch_insn = make_branch_insn(src_addr, -1, self.data['branch_type']) + self.builder.add_patch(src_addr, u32.pack(branch_insn)) + + dylink = self.builder.dynamic_link + dylink.add_reloc(dylink.R_PPC_REL24, src_addr, target_func) else: - # assume it's an address - pass - - - src_addr = self.data['src_addr_%s' % self.builder._config_short_name] - branch_insn = make_branch_insn(src_addr, target_func, self.data['branch_type']) - - self.builder._add_patch(src_addr, u32.pack(branch_insn)) + branch_insn = make_branch_insn(src_addr, target_func, self.data['branch_type']) + self.builder.add_patch(src_addr, u32.pack(branch_insn)) @@ -119,18 +127,19 @@ class AddFunctionPointerHook(Hook): try: target_func = self.data['target_func'] except KeyError: - target_func = self.data['target_func_%s' % self.builder._config_short_name] - - if isinstance(target_func, str): - target_func = self.builder._find_func_by_symbol(target_func) + target_func = self.data['target_func_%s' % self.builder.config_short_name] + + src_addr = self.data['src_addr_%s' % self.builder.config_short_name] + is_symbol_name = isinstance(target_func, str) + + if is_symbol_name: + target_func = self.builder.find_func_by_symbol(target_func) + + if is_symbol_name and self.builder.dynamic_link: + dylink = self.builder.dynamic_link + dylink.add_reloc(dylink.R_PPC_ADDR32, src_addr, target_func) else: - # assume it's an address - pass - - - src_addr = self.data['src_addr_%s' % self.builder._config_short_name] - - self.builder._add_patch(src_addr, u32.pack(target_func)) + self.builder.add_patch(src_addr, u32.pack(target_func)) @@ -143,7 +152,7 @@ class NopInsnHook(Hook): Hook.__init__(self, builder, module, data) def create_patches(self): - area = self.data['area_%s' % self.builder._config_short_name] + area = self.data['area_%s' % self.builder.config_short_name] if isinstance(area, list): addr, end = area @@ -153,7 +162,7 @@ class NopInsnHook(Hook): addr = area nop_patch = '\x60\x00\x00\x00' - self.builder._add_patch(addr, nop_patch) + self.builder.add_patch(addr, nop_patch) 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: -- cgit v1.2.3