summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorTreeki <treeki@gmail.com>2012-03-27 21:38:52 +0200
committerTreeki <treeki@gmail.com>2012-03-27 21:38:52 +0200
commit5e8e92cd8f403cbfebc4469a1aee252212e42045 (patch)
tree316022f62e20bbb066550ab541dfb7290d8ca6e5 /tools
parente12b1713576544fdda756a3ca8831642562ea921 (diff)
downloadkamek-5e8e92cd8f403cbfebc4469a1aee252212e42045.tar.gz
kamek-5e8e92cd8f403cbfebc4469a1aee252212e42045.zip
Kamek/Newer now support dynamic linking
Diffstat (limited to 'tools')
-rw-r--r--tools/dumprelocs.py19
-rwxr-xr-xtools/hooks.py73
-rw-r--r--tools/kamek.py135
3 files changed, 177 insertions, 50 deletions
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: