changeset 385:d056b552d3f4

Made better use of layout
author Windel Bouwman
date Thu, 01 May 2014 14:03:12 +0200
parents 94f5b719ad0b
children 2a970e7270e2
files examples/c3/build.xml examples/qemu_a9_hello/build.xml kernel/arch/qemu_vexpress/startup_a9.asm kernel/build.xml python/ppci/buildfunctions.py python/ppci/buildtasks.py python/ppci/layout.py python/ppci/linker.py python/ppci/objectfile.py python/ppci/target/basetarget.py test/m3_bare/build.xml test/testarmasm.py test/testasm.py test/testbintools.py test/testmsp430asm.py test/testsamples.py test/testthumbasm.py user/build.xml
diffstat 18 files changed, 272 insertions(+), 193 deletions(-) [+]
line wrap: on
line diff
--- a/examples/c3/build.xml	Sun Apr 27 17:50:25 2014 +0200
+++ b/examples/c3/build.xml	Thu May 01 14:03:12 2014 +0200
@@ -10,7 +10,9 @@
     <target name="burn2">
         <assemble source="startup_stm32f4.asm" target="thumb" output="startup.o" />
         <compile target="thumb" sources="burn2.c3" includes="stm32f4xx.c3" output="burn2.o" />
-        <link output="burn2.bin" layout="stm32f4.mmap" objects="startup.o;burn2.o" />
+        <link output="burn2.bin" layout="stm32f4.mmap" 
+            target="thumb"
+            objects="startup.o;burn2.o" />
     </target>
 
 </project>
--- a/examples/qemu_a9_hello/build.xml	Sun Apr 27 17:50:25 2014 +0200
+++ b/examples/qemu_a9_hello/build.xml	Thu May 01 14:03:12 2014 +0200
@@ -4,7 +4,13 @@
     <target name="hello">
         <assemble source="startup_a9.asm" target="arm" output="start.o" />
         <compile target="arm" sources='hello.c3' output="hello.o" />
-        <link objects="start.o;hello.o" output="hello.bin" layout="qemu.mmap" />
+        <link objects="start.o;hello.o" output="hello.o"
+            target="arm"
+            layout="qemu.mmap" />
+        <objcopy
+            objectfile="hello.o"
+            imagename="flash"
+            output="hello.bin" />
     </target>
 </project>
 
--- a/kernel/arch/qemu_vexpress/startup_a9.asm	Sun Apr 27 17:50:25 2014 +0200
+++ b/kernel/arch/qemu_vexpress/startup_a9.asm	Thu May 01 14:03:12 2014 +0200
@@ -1,5 +1,5 @@
 
-section code
+section reset
 
 interrupt_vector_table:
 ivt_reset: B start  ; 0x0 reset
--- a/kernel/build.xml	Sun Apr 27 17:50:25 2014 +0200
+++ b/kernel/build.xml	Thu May 01 14:03:12 2014 +0200
@@ -8,7 +8,14 @@
         <assemble source="arch/qemu_vexpress/startup_a9.asm" target="arm" output="start.o" />
         <compile target="arm" sources='arch/vexpressA9.c3' includes="${src}/*.c3" output="vexp.o" />
         <compile target="arm" sources='${src}/*.c3' output="henkie.o" />
-        <link output="kernel_arm.bin" layout="arch/qemu_vexpress/vexpressA9.mmap" objects="start.o;henkie.o;vexp.o" />
+        <link output="kernel.o"
+            target="arm"
+            layout="arch/qemu_vexpress/vexpressA9.mmap"
+            objects="henkie.o;vexp.o;start.o" />
+        <objcopy
+            objectfile="kernel.o"
+            imagename="image"
+            output="kernel_arm.bin" />
     </target>
 
 </project>
--- a/python/ppci/buildfunctions.py	Sun Apr 27 17:50:25 2014 +0200
+++ b/python/ppci/buildfunctions.py	Thu May 01 14:03:12 2014 +0200
@@ -19,6 +19,7 @@
 from . import DiagnosticsManager, CompilerError
 from .tasks import TaskError
 
+
 def fix_target(tg):
     """ Try to return an instance of the Target class """
     if isinstance(tg, Target):
@@ -122,14 +123,12 @@
     return output
 
 
-def link(objects, layout):
+def link(objects, layout, target):
     """ Links the iterable of objects into one using the given layout """
     objects = list(map(fix_object, objects))
     layout = fix_layout(layout)
-    linker = Linker()
+    target = fix_target(target)
+    linker = Linker(target)
     output_obj = linker.link(objects, layout)
     return output_obj
 
-
-def objcopy(obj):
-    return
--- a/python/ppci/buildtasks.py	Sun Apr 27 17:50:25 2014 +0200
+++ b/python/ppci/buildtasks.py	Thu May 01 14:03:12 2014 +0200
@@ -7,7 +7,7 @@
 import logging
 
 from .tasks import Task, TaskError, register_task
-from .buildfunctions import c3compile, link, assemble
+from .buildfunctions import c3compile, link, assemble, fix_object
 from pyyacc import ParserException
 from . import CompilerError
 
@@ -82,20 +82,29 @@
     """ Link together a collection of object files """
     def run(self):
         layout = self.relpath(self.get_argument('layout'))
+        target = self.get_argument('target')
         objects = self.open_file_set(self.get_argument('objects'))
-        output_file = self.relpath(self.get_argument('output'))
+        output_filename = self.relpath(self.get_argument('output'))
 
         try:
-            output_obj = link(objects, layout)
+            output_obj = link(objects, layout, target)
         except CompilerError as e:
             raise TaskError(e.msg)
-        # TODO: use layout here:
-        code = output_obj.get_section('code').data
-        with open(output_file, 'wb') as f:
-            f.write(code)
+
+        # Store output:
+        with open(output_filename, 'w') as f:
+            output_obj.save(f)
 
 
+@register_task("objcopy")
 class ObjCopyTask(Task):
     def run(self):
-        pass
+        image_name = self.get_argument('imagename')
+        output_filename = self.relpath(self.get_argument('output'))
+        object_filename = self.relpath(self.get_argument('objectfile'))
 
+        obj = fix_object(object_filename)
+        image = obj.get_image(image_name)
+        with open(output_filename, 'wb') as f:
+            f.write(image)
+
--- a/python/ppci/layout.py	Sun Apr 27 17:50:25 2014 +0200
+++ b/python/ppci/layout.py	Thu May 01 14:03:12 2014 +0200
@@ -5,19 +5,20 @@
 
 class Layout:
     def __init__(self):
-        self.mems = []
+        self.memories = []
 
     def add_memory(self, memory):
-        self.mems.append(memory)
+        self.memories.append(memory)
 
     def __eq__(self, other):
-        return self.mems == other.mems
+        return self.memories == other.memories
 
     def __repr__(self):
-        return str(self.mems)
+        return str(self.memories)
 
 
 class Memory:
+    """ Specification of how a memory may look like and what it contains. """
     def __init__(self, name):
         self.inputs = []
         self.name = name
@@ -34,6 +35,7 @@
     def __eq__(self, other):
         return str(self) == str(other)
 
+
 class Input:
     pass
 
--- a/python/ppci/linker.py	Sun Apr 27 17:50:25 2014 +0200
+++ b/python/ppci/linker.py	Thu May 01 14:03:12 2014 +0200
@@ -1,161 +1,46 @@
 import logging
-import struct
 from .objectfile import ObjectFile
 from . import CompilerError
-from .bitfun import encode_imm32
 from .layout import Layout, Section
 
 
-def align(x, m):
-    while ((x % m) != 0):
-        x = x + 1
-    return x
-
-def wrap_negative(x, bits):
-    b = struct.unpack('<I', struct.pack('<i', x))[0]
-    mask = (1 << bits) - 1
-    return b & mask
-
-reloc_map = {}
-
-def reloc(t):
-    def f(c):
-        reloc_map[t] = c
-    return f
-
-
-@reloc('lit_add_8')
-def apply_lit8(reloc, sym, section, reloc_value):
-    assert sym.value % 4 == 0
-    offset = (sym.value - (align(reloc_value + 2, 4)))
-    assert offset in range(0, 1024, 4), str(offset)+str( self.dst.sections)
-    rel8 = offset >> 2
-    section.data[reloc.offset] = rel8
-
-
-@reloc('wrap_new11')
-def apply_wrap_new11(reloc, sym, section, reloc_value):
-    offset = sym.value - (align(reloc_value, 2) + 4)
-    assert offset in range(-2048, 2046, 2)
-    imm11 = wrap_negative(offset >> 1, 11)
-    section.data[reloc.offset] = (imm11 & 0xff)
-    section.data[reloc.offset + 1] |= (imm11 >> 8) & 0x7
-
-
-@reloc('rel8')
-def apply_rel8(reloc, sym, section, reloc_value):
-    assert sym.value % 2 == 0
-    offset = sym.value - (align(reloc_value, 2) + 4)
-    assert offset in range(-256, 254, 2), str(offset) + str(reloc)
-    imm8 = wrap_negative(offset >> 1, 8)
-    section.data[reloc.offset] = imm8
-
-
-@reloc('bl_imm11_imm10')
-def apply_bl_imm11(reloc, sym, section, reloc_value):
-    assert sym.value % 2 == 0
-    offset = sym.value - (align(reloc_value, 2) + 4)
-    assert offset in range(-16777216, 16777214, 2), str(offset)
-    imm32 = wrap_negative(offset >> 1, 32)
-    imm11 = imm32 & 0x7FF
-    imm10 = (imm32 >> 11) & 0x3FF
-    s = (imm32 >> 24) & 0x1
-    section.data[reloc.offset + 2] = imm11 & 0xFF
-    section.data[reloc.offset + 3] |= (imm11 >> 8) & 0x7
-    section.data[reloc.offset] = imm10 & 0xff
-    section.data[reloc.offset + 1] |= ((imm10 >> 8) & 0x3) | (s << 2)
+class Linker:
+    """ Merges the sections of several object files and
+        performs relocation """
+    def __init__(self, target):
+        self.logger = logging.getLogger('Linker')
+        self.target = target
 
-@reloc('b_imm11_imm6')
-def apply_b_imm11_imm6(reloc, sym, section, reloc_value):
-    assert sym.value % 2 == 0
-    offset = sym.value - (align(reloc_value, 2) + 4)
-    assert offset in range(-1048576, 1048574, 2), str(offset)
-    imm32 = wrap_negative(offset >> 1, 32)
-    imm11 = imm32 & 0x7FF
-    imm6 = (imm32 >> 11) & 0x3F
-    s = (imm32 >> 24) & 0x1
-    section.data[reloc.offset + 2] = imm11 & 0xFF
-    section.data[reloc.offset + 3] |= (imm11 >> 8) & 0x7
-    section.data[reloc.offset] |= imm6
-    section.data[reloc.offset + 1] |= (s << 2)
-
-# ARM reloc!!
-# TODO: move to target classes???
-@reloc('b_imm24')
-def apply_b_imm24(reloc, sym, section, reloc_value):
-    assert sym.value % 4 == 0
-    assert reloc_value % 4 == 0
-    offset = (sym.value - (reloc_value + 8))
-    rel24 = wrap_negative(offset >> 2, 24)
-    section.data[reloc.offset+2] = (rel24 >> 16) & 0xFF
-    section.data[reloc.offset+1] = (rel24 >> 8) & 0xFF
-    section.data[reloc.offset+0] = rel24 & 0xFF
-
-
-@reloc('ldr_imm12')
-def apply_ldr_imm12(reloc, sym, section, reloc_value):
-    assert sym.value % 4 == 0
-    assert reloc_value % 4 == 0
-    offset = (sym.value - (reloc_value + 8))
-    U = 1
-    if offset < 0:
-        offset = -offset
-        U = 0
-    assert offset < 4096, str(sym) + str(section) + str(reloc)
-    section.data[reloc.offset+2] |= (U << 7)
-    section.data[reloc.offset+1] |= (offset >> 8) & 0xF
-    section.data[reloc.offset+0] = offset & 0xFF
-
-@reloc('adr_imm12')
-def apply_adr_imm12(reloc, sym, section, reloc_value):
-    assert sym.value % 4 == 0
-    assert reloc_value % 4 == 0
-    offset = (sym.value - (reloc_value + 8))
-    U = 2
-    if offset < 0:
-        offset = -offset
-        U = 1
-    assert offset < 4096
-    offset = encode_imm32(offset)
-    section.data[reloc.offset+2] |= (U << 6)
-    section.data[reloc.offset+1] |= (offset >> 8) & 0xF
-    section.data[reloc.offset+0] = offset & 0xFF
-
-@reloc('absaddr32')
-def apply_absaddr32(reloc, sym, section, reloc_value):
-    assert sym.value % 4 == 0
-    assert reloc_value % 4 == 0
-    offset = sym.value
-    section.data[reloc.offset+3] = (offset >> 24) & 0xFF
-    section.data[reloc.offset+2] = (offset >> 16) & 0xFF
-    section.data[reloc.offset+1] = (offset >> 8) & 0xFF
-    section.data[reloc.offset+0] = offset & 0xFF
-
-
-class Linker:
-    """ Merges the sections of several object files and 
-        performs relocation """
-    def __init__(self):
-        self.logger = logging.getLogger('Linker')
+    def layout_sections(self, dst, layout):
+        """ Use the given layout to place sections into memories """
+        # Create sections with address:
+        dst.images = {}
+        for mem in layout.memories:
+            cur_addr = mem.location
+            output_memory = bytearray()
+            for memory_input in mem.inputs:
+                if type(memory_input) is Section:
+                    section = dst.get_section(memory_input.section_name)
+                    section.address = cur_addr
+                    cur_addr += section.Size
+                    output_memory += section.data
+                    # TODO: align sections
+                else:
+                    print(memory_input)
+            dst.images[mem.name] = bytes(output_memory)
 
     def link(self, objs, layout):
         assert type(objs) is list
         assert type(layout) is Layout
         # Create new object file to store output:
-        self.dst = ObjectFile()
-
-        # Create sections with address:
-        for mem in layout.mems:
-            for inp in mem.inputs:
-                if type(inp) is Section:
-                    self.dst.get_section(inp.section_name).address = mem.location
+        dst = ObjectFile()
 
         # First copy all sections into output sections:
         for iobj in objs:
             offsets = {}
             # Merge sections:
             for in_s in iobj.sections.values():
-                out_s = self.dst.get_section(in_s.name)
+                out_s = dst.get_section(in_s.name)
                 # TODO: align section in other way:
                 while out_s.Size % 4 != 0:
                     out_s.add_data(bytes([0]))
@@ -167,35 +52,39 @@
 
             # Merge symbols:
             for sym in iobj.symbols.values():
-                out_s = self.dst.get_section(sym.section)
-                value = offsets[sym.section] + out_s.address + sym.value
-                self.dst.add_symbol(sym.name, value, sym.section)
+                out_s = dst.get_section(sym.section)
+                value = offsets[sym.section] + sym.value
+                dst.add_symbol(sym.name, value, sym.section)
                 self.logger.debug('{} at 0x{:08X} in section {}'.format(sym.name, value, sym.section))
 
             # Merge relocations:
             for reloc in iobj.relocations:
                 offset = offsets[reloc.section] + reloc.offset
-                self.dst.add_relocation(reloc.sym, offset, reloc.typ, reloc.section)
+                dst.add_relocation(reloc.sym, offset, reloc.typ, reloc.section)
 
         # Apply layout rules:
-        # TODO
+        self.layout_sections(dst, layout)
 
         # Perform relocations:
-        for reloc in self.dst.relocations:
+        for reloc in dst.relocations:
             # Lookup symbol:
-            if reloc.sym not in self.dst.symbols:
+            if reloc.sym not in dst.symbols:
                 raise CompilerError('Undefined reference "{}"'.format(reloc.sym))
-            sym = self.dst.symbols[reloc.sym]
-            # patch up:
-            section = self.dst.get_section(reloc.section)
+
+            sym_value = dst.get_symbol_value(reloc.sym)
+            section = dst.get_section(reloc.section)
 
             # Determine location in memory of reloc patchup position:
             reloc_value = section.address + reloc.offset
 
-            if reloc.typ in reloc_map:
-                f = reloc_map[reloc.typ]
-                f(reloc, sym, section, reloc_value)
+            if reloc.typ in self.target.reloc_map:
+                f = self.target.reloc_map[reloc.typ]
+                f(reloc, sym_value, section, reloc_value)
             else:
                 raise NotImplementedError('Unknown relocation type {}'.format(reloc.typ))
 
-        return self.dst
+        # Create memories for the second time
+        # TODO: make this nicer?
+        self.layout_sections(dst, layout)
+
+        return dst
--- a/python/ppci/objectfile.py	Sun Apr 27 17:50:25 2014 +0200
+++ b/python/ppci/objectfile.py	Thu May 01 14:03:12 2014 +0200
@@ -67,6 +67,7 @@
         self.symbols = {}
         self.sections = {}
         self.relocations = []
+        self.images = {}
 
     def find_symbol(self, name):
         return self.symbols[name]
@@ -92,6 +93,14 @@
             self.sections[name] = Section(name)
         return self.sections[name]
 
+    def get_image(self, name):
+        return self.images[name]
+
+    def get_symbol_value(self, name):
+        symbol = self.find_symbol(name)
+        section = self.get_section(symbol.section)
+        return symbol.value + section.address
+
     def __eq__(self, other):
         return (self.symbols == other.symbols) and \
             (self.sections == other.sections) and \
@@ -109,6 +118,13 @@
     return deserialize(json.load(f))
 
 
+def bin2asc(data):
+    return binascii.hexlify(data).decode('ascii')
+
+def asc2bin(data):
+    return bytearray(binascii.unhexlify(data.encode('ascii')))
+
+
 def serialize(x):
     res = {}
     if isinstance(x, ObjectFile):
@@ -123,10 +139,13 @@
         res['relocations'] = []
         for reloc in x.relocations:
             res['relocations'].append(serialize(reloc))
+        res['images'] = {}
+        for image_name in x.images:
+            res['images'][image_name] = bin2asc(x.images[image_name])
     elif isinstance(x, Section):
         res['name'] = x.name
         res['address'] = hex(x.address)
-        res['data'] = binascii.hexlify(x.data).decode('ascii')
+        res['data'] = bin2asc(x.data)
     elif isinstance(x, Symbol):
         res['name'] = x.name
         res['value'] = hex(x.value)
@@ -144,11 +163,13 @@
     for section in d['sections']:
         so = obj.get_section(section['name'])
         so.address = make_num(section['address'])
-        so.data = bytearray(binascii.unhexlify(section['data'].encode('ascii')))
+        so.data = asc2bin(section['data'])
     for reloc in d['relocations']:
         obj.add_relocation(reloc['symbol'], make_num(reloc['offset']),
             reloc['type'], reloc['section'])
     for sym in d['symbols']:
         obj.add_symbol(sym['name'], make_num(sym['value']), sym['section'])
+    for image_name in d['images']:
+        obj.images[image_name] = asc2bin(d['images'][image_name])
     return obj
 
--- a/python/ppci/target/basetarget.py	Sun Apr 27 17:50:25 2014 +0200
+++ b/python/ppci/target/basetarget.py	Thu May 01 14:03:12 2014 +0200
@@ -1,5 +1,7 @@
 import types
 from ppci import CompilerError
+from ..bitfun import encode_imm32
+import struct
 
 """
   Base classes for defining a target
@@ -101,6 +103,7 @@
         self.asm_keywords = []
 
         self.generate_base_rules()
+        self.reloc_map = reloc_map  # TODO: make this target specific.
 
     def generate_base_rules(self):
         # Base rules for constants:
@@ -148,3 +151,134 @@
     def add_lowering(self, cls, f):
         """ Add a function to the table of lowering options for this target """
         self.lower_functions[cls] = f
+
+    def add_reloc(self, name, f):
+        self.reloc_map[name] = f
+
+
+
+def align(x, m):
+    while ((x % m) != 0):
+        x = x + 1
+    return x
+
+def wrap_negative(x, bits):
+    b = struct.unpack('<I', struct.pack('<i', x))[0]
+    mask = (1 << bits) - 1
+    return b & mask
+
+
+reloc_map = {}
+
+def reloc(t):
+    def f(c):
+        reloc_map[t] = c
+    return f
+
+
+@reloc('lit_add_8')
+def apply_lit8(reloc, sym_value, section, reloc_value):
+    assert sym_value % 4 == 0
+    offset = (sym_value - (align(reloc_value + 2, 4)))
+    assert offset in range(0, 1024, 4), str(offset)+str( self.dst.sections)
+    rel8 = offset >> 2
+    section.data[reloc.offset] = rel8
+
+
+@reloc('wrap_new11')
+def apply_wrap_new11(reloc, sym_value, section, reloc_value):
+    offset = sym_value - (align(reloc_value, 2) + 4)
+    assert offset in range(-2048, 2046, 2)
+    imm11 = wrap_negative(offset >> 1, 11)
+    section.data[reloc.offset] = (imm11 & 0xff)
+    section.data[reloc.offset + 1] |= (imm11 >> 8) & 0x7
+
+
+@reloc('rel8')
+def apply_rel8(reloc, sym_value, section, reloc_value):
+    assert sym_value % 2 == 0
+    offset = sym_value - (align(reloc_value, 2) + 4)
+    assert offset in range(-256, 254, 2), str(offset) + str(reloc)
+    imm8 = wrap_negative(offset >> 1, 8)
+    section.data[reloc.offset] = imm8
+
+
+@reloc('bl_imm11_imm10')
+def apply_bl_imm11(reloc, sym_value, section, reloc_value):
+    assert sym_value % 2 == 0
+    offset = sym_value - (align(reloc_value, 2) + 4)
+    assert offset in range(-16777216, 16777214, 2), str(offset)
+    imm32 = wrap_negative(offset >> 1, 32)
+    imm11 = imm32 & 0x7FF
+    imm10 = (imm32 >> 11) & 0x3FF
+    s = (imm32 >> 24) & 0x1
+    section.data[reloc.offset + 2] = imm11 & 0xFF
+    section.data[reloc.offset + 3] |= (imm11 >> 8) & 0x7
+    section.data[reloc.offset] = imm10 & 0xff
+    section.data[reloc.offset + 1] |= ((imm10 >> 8) & 0x3) | (s << 2)
+
+@reloc('b_imm11_imm6')
+def apply_b_imm11_imm6(reloc, sym_value, section, reloc_value):
+    assert sym_value % 2 == 0
+    offset = sym_value - (align(reloc_value, 2) + 4)
+    assert offset in range(-1048576, 1048574, 2), str(offset)
+    imm32 = wrap_negative(offset >> 1, 32)
+    imm11 = imm32 & 0x7FF
+    imm6 = (imm32 >> 11) & 0x3F
+    s = (imm32 >> 24) & 0x1
+    section.data[reloc.offset + 2] = imm11 & 0xFF
+    section.data[reloc.offset + 3] |= (imm11 >> 8) & 0x7
+    section.data[reloc.offset] |= imm6
+    section.data[reloc.offset + 1] |= (s << 2)
+
+# ARM reloc!!
+# TODO: move to target classes???
+@reloc('b_imm24')
+def apply_b_imm24(reloc, sym_value, section, reloc_value):
+    assert sym_value % 4 == 0
+    assert reloc_value % 4 == 0
+    offset = (sym_value - (reloc_value + 8))
+    rel24 = wrap_negative(offset >> 2, 24)
+    section.data[reloc.offset+2] = (rel24 >> 16) & 0xFF
+    section.data[reloc.offset+1] = (rel24 >> 8) & 0xFF
+    section.data[reloc.offset+0] = rel24 & 0xFF
+
+
+@reloc('ldr_imm12')
+def apply_ldr_imm12(reloc, sym_value, section, reloc_value):
+    assert sym_value % 4 == 0
+    assert reloc_value % 4 == 0
+    offset = (sym_value - (reloc_value + 8))
+    U = 1
+    if offset < 0:
+        offset = -offset
+        U = 0
+    assert offset < 4096, str(sym) + str(section) + str(reloc)
+    section.data[reloc.offset+2] |= (U << 7)
+    section.data[reloc.offset+1] |= (offset >> 8) & 0xF
+    section.data[reloc.offset+0] = offset & 0xFF
+
+@reloc('adr_imm12')
+def apply_adr_imm12(reloc, sym_value, section, reloc_value):
+    assert sym_value % 4 == 0
+    assert reloc_value % 4 == 0
+    offset = (sym_value - (reloc_value + 8))
+    U = 2
+    if offset < 0:
+        offset = -offset
+        U = 1
+    assert offset < 4096
+    offset = encode_imm32(offset)
+    section.data[reloc.offset+2] |= (U << 6)
+    section.data[reloc.offset+1] |= (offset >> 8) & 0xF
+    section.data[reloc.offset+0] = offset & 0xFF
+
+@reloc('absaddr32')
+def apply_absaddr32(reloc, sym_value, section, reloc_value):
+    assert sym_value % 4 == 0
+    assert reloc_value % 4 == 0
+    offset = sym_value
+    section.data[reloc.offset+3] = (offset >> 24) & 0xFF
+    section.data[reloc.offset+2] = (offset >> 16) & 0xFF
+    section.data[reloc.offset+1] = (offset >> 8) & 0xFF
+    section.data[reloc.offset+0] = offset & 0xFF
--- a/test/m3_bare/build.xml	Sun Apr 27 17:50:25 2014 +0200
+++ b/test/m3_bare/build.xml	Thu May 01 14:03:12 2014 +0200
@@ -3,7 +3,13 @@
    <target name="m3bare">
      <assemble source="startup_m3.asm" target="thumb" output="start.o"/>
      <compile sources="hello.c3" target="thumb" output="m3bare.o"/>
-     <link output="bare.bin" layout="m3bare.mmap" objects="start.o;m3bare.o"/>
+     <link output="bare.o" layout="m3bare.mmap"
+        target="thumb"
+        objects="start.o;m3bare.o"/>
+        <objcopy
+            objectfile="bare.o"
+            imagename="flash"
+            output="bare.bin" />
     </target>
 </project>
 
--- a/test/testarmasm.py	Sun Apr 27 17:50:25 2014 +0200
+++ b/test/testarmasm.py	Thu May 01 14:03:12 2014 +0200
@@ -10,7 +10,7 @@
 class ArmAssemblerTestCase(AsmTestCaseBase):
     """ ARM-mode (not thumb-mode) instruction assembly test case """
     def setUp(self):
-        self.t = arm_target
+        self.target = arm_target
         self.obj = ObjectFile()
         self.ostream = BinaryOutputStream(self.obj)
         self.ostream.select_section('code')
--- a/test/testasm.py	Sun Apr 27 17:50:25 2014 +0200
+++ b/test/testasm.py	Thu May 01 14:03:12 2014 +0200
@@ -63,7 +63,7 @@
 
     def check(self, hexstr, layout=Layout()):
         self.assembler.flush()
-        self.obj = link([self.obj], layout)
+        self.obj = link([self.obj], layout, self.target)
         data = bytes(self.obj.get_section('code').data)
         self.assertSequenceEqual(bytes.fromhex(hexstr), data)
 
--- a/test/testbintools.py	Sun Apr 27 17:50:25 2014 +0200
+++ b/test/testbintools.py	Thu May 01 14:03:12 2014 +0200
@@ -60,7 +60,7 @@
         o1.add_relocation('undefined_sym', 0, 'rel8', '.text')
         o2 = ObjectFile()
         with self.assertRaises(CompilerError):
-            o3 = link([o1, o2], layout.Layout())
+            o3 = link([o1, o2], layout.Layout(), 'arm')
 
     def testDuplicateSymbol(self):
         o1 = ObjectFile()
@@ -70,7 +70,7 @@
         o2.get_section('.text')
         o2.add_symbol('a', 0, '.text')
         with self.assertRaises(CompilerError):
-            o3 = link([o1, o2], layout.Layout())
+            o3 = link([o1, o2], layout.Layout(), 'arm')
 
     def testRel8Relocation(self):
         o1 = ObjectFile()
@@ -79,7 +79,7 @@
         o2 = ObjectFile()
         o2.get_section('.text').add_data(bytes([0]*100))
         o2.add_symbol('a', 24, '.text')
-        o3 = link([o1, o2], layout.Layout())
+        o3 = link([o1, o2], layout.Layout(), 'arm')
 
     def testSymbolValues(self):
         o1 = ObjectFile()
@@ -88,7 +88,7 @@
         o2 = ObjectFile()
         o2.get_section('.text').add_data(bytes([0]*100))
         o2.add_symbol('a', 2, '.text')
-        o3 = link([o1, o2], layout.Layout())
+        o3 = link([o1, o2], layout.Layout(), 'arm')
         self.assertEqual(110, o3.find_symbol('a').value)
         self.assertEqual(24, o3.find_symbol('b').value)
         self.assertEqual(208, o3.get_section('.text').Size)
@@ -111,10 +111,10 @@
         o2.get_section('data').add_data(bytes([0]*100))
         o2.add_symbol('a', 2, 'data')
         o2.add_symbol('c', 2, 'code')
-        o3 = link([o1, o2], memory_layout)
-        self.assertEqual(0x20000000+2, o3.find_symbol('a').value)
-        self.assertEqual(0x08000000+24, o3.find_symbol('b').value)
-        self.assertEqual(0x08000000+110, o3.find_symbol('c').value)
+        o3 = link([o1, o2], memory_layout, 'arm')
+        self.assertEqual(0x20000000+2, o3.get_symbol_value('a'))
+        self.assertEqual(0x08000000+24, o3.get_symbol_value('b'))
+        self.assertEqual(0x08000000+110, o3.get_symbol_value('c'))
         self.assertEqual(208, o3.get_section('code').Size)
         self.assertEqual(100, o3.get_section('data').Size)
 
--- a/test/testmsp430asm.py	Sun Apr 27 17:50:25 2014 +0200
+++ b/test/testmsp430asm.py	Thu May 01 14:03:12 2014 +0200
@@ -9,7 +9,7 @@
 
 class Msp430AssemblerTestCase(AsmTestCaseBase):
     def setUp(self):
-        self.t = msp430target
+        self.target = msp430target
         self.obj = ObjectFile()
         self.ostream = BinaryOutputStream(self.obj)
         self.ostream.select_section('code')
--- a/test/testsamples.py	Sun Apr 27 17:50:25 2014 +0200
+++ b/test/testsamples.py	Thu May 01 14:03:12 2014 +0200
@@ -6,6 +6,7 @@
 from ppci.buildfunctions import assemble, c3compile, link
 
 startercode = """
+section reset
 mov sp, 0x30000   ; setup stack pointer
 BL sample_start     ; Branch to sample start
 local_loop:
@@ -147,11 +148,12 @@
             relpath('..', 'kernel', 'src', 'io.c3'),
             io.StringIO(modarchcode),
             io.StringIO(src)], [], 'arm')
-        o3 = link([o1, o2], io.StringIO(arch_mmap))
+        o3 = link([o2, o1], io.StringIO(arch_mmap), 'arm')
 
+        img_data = o3.get_image('image')
         sample_filename = 'testsample.bin'
         with open(sample_filename, 'wb') as f:
-            f.write(o3.get_section('code').data)
+            f.write(img_data)
 
         # Check bin file exists:
         self.assertTrue(os.path.isfile(sample_filename))
--- a/test/testthumbasm.py	Sun Apr 27 17:50:25 2014 +0200
+++ b/test/testthumbasm.py	Thu May 01 14:03:12 2014 +0200
@@ -7,7 +7,7 @@
 
 class ThumbAssemblerTestCase(AsmTestCaseBase):
     def setUp(self):
-        self.t = thumb_target
+        self.target = thumb_target
         self.obj = ObjectFile()
         self.ostream = BinaryOutputStream(self.obj)
         self.ostream.select_section('code')
--- a/user/build.xml	Sun Apr 27 17:50:25 2014 +0200
+++ b/user/build.xml	Thu May 01 14:03:12 2014 +0200
@@ -4,7 +4,9 @@
    </target>
    <target name="hello">
      <compile sources="lib.c3;ipc.c3;hello.c3" target="arm" output="hello.o"/>
-     <link output="hello.bin" layout="app.mmap" objects="hello.o"/>
+     <link output="hello.bin" layout="app.mmap"
+        target="arm"
+        objects="hello.o"/>
     </target>
 </project>