summaryrefslogtreecommitdiff
path: root/tools/kamek.py
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/kamek.py
parente12b1713576544fdda756a3ca8831642562ea921 (diff)
downloadkamek-5e8e92cd8f403cbfebc4469a1aee252212e42045.tar.gz
kamek-5e8e92cd8f403cbfebc4469a1aee252212e42045.zip
Kamek/Newer now support dynamic linking
Diffstat (limited to 'tools/kamek.py')
-rw-r--r--tools/kamek.py135
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: