changeset 383:173e20a47fda

Added linker description loader
author Windel Bouwman
date Sun, 27 Apr 2014 17:40:39 +0200
parents 0c44e494ef58
children 94f5b719ad0b
files examples/c3/stm32f4.mmap examples/qemu_a9_hello/qemu.mmap kernel/arch/qemu_vexpress/vexpressA9.mmap python/ppci/__init__.py python/ppci/buildfunctions.py python/ppci/buildtasks.py python/ppci/c3/lexer.py python/ppci/layout.py python/ppci/linker.py python/pyyacc.py python/yacc.py test/m3_bare/m3bare.mmap test/testarmasm.py test/testasm.py test/testbintools.py test/testmsp430asm.py test/testsamples.py test/testthumbasm.py user/app.mmap
diffstat 19 files changed, 294 insertions(+), 167 deletions(-) [+]
line wrap: on
line diff
--- a/examples/c3/stm32f4.mmap	Sun Apr 27 12:24:21 2014 +0200
+++ b/examples/c3/stm32f4.mmap	Sun Apr 27 17:40:39 2014 +0200
@@ -1,7 +1,9 @@
 
 
-{
-    "code": "0x08000000",
-    "data": "0x20000000"
+MEMORY flash LOCATION=0x08000000 SIZE=0x10000 {
+ SECTION(code)
 }
 
+MEMORY ram LOCATION=0x20000000 SIZE=0x10000 {
+ SECTION(data)
+}
--- a/examples/qemu_a9_hello/qemu.mmap	Sun Apr 27 12:24:21 2014 +0200
+++ b/examples/qemu_a9_hello/qemu.mmap	Sun Apr 27 17:40:39 2014 +0200
@@ -1,5 +1,9 @@
 
-{
-     "code": "0x60010000",
-     "data": "0x60020000"
+MEMORY flash LOCATION=0x60010000 SIZE=0x10000 {
+ SECTION(code)
 }
+
+MEMORY ram LOCATION=0x60020000 SIZE=0x10000 {
+ SECTION(data)
+}
+
--- a/kernel/arch/qemu_vexpress/vexpressA9.mmap	Sun Apr 27 12:24:21 2014 +0200
+++ b/kernel/arch/qemu_vexpress/vexpressA9.mmap	Sun Apr 27 17:40:39 2014 +0200
@@ -1,7 +1,10 @@
 
-{
-    "code": "0x10000",
-    "mem_tables": "0x60000",
-    "data": "0x20000"
+MEMORY image LOCATION=0x10000 SIZE=0x10000 {
+    SECTION(reset)
+    SECTION(code)
 }
 
+MEMORY ram LOCATION=0x20000 SIZE=0x10000 {
+    SECTION(data)
+}
+
--- a/python/ppci/__init__.py	Sun Apr 27 12:24:21 2014 +0200
+++ b/python/ppci/__init__.py	Sun Apr 27 17:40:39 2014 +0200
@@ -17,3 +17,11 @@
 
 def same_dir(full_path, filename):
     return os.path.join(os.path.dirname(os.path.abspath(full_path)), filename)
+
+
+def make_num(txt):
+    if txt.startswith('0x'):
+        return int(txt[2:], 16)
+    else:
+        return int(txt)
+
--- a/python/ppci/buildfunctions.py	Sun Apr 27 12:24:21 2014 +0200
+++ b/python/ppci/buildfunctions.py	Sun Apr 27 17:40:39 2014 +0200
@@ -12,11 +12,12 @@
 from .codegen import CodeGenerator
 from .transform import CleanPass, RemoveAddZero
 from .linker import Linker
+from .layout import Layout, load_layout
 from .target.target_list import targets
 from .outstream import BinaryAndLoggingStream
 from .objectfile import ObjectFile, load_object
 from . import DiagnosticsManager, CompilerError
-
+from .tasks import TaskError
 
 def fix_target(tg):
     """ Try to return an instance of the Target class """
@@ -49,6 +50,19 @@
         raise TaskError('Cannot use {} as objectfile'.format(o))
 
 
+def fix_layout(l):
+    if isinstance(l, Layout):
+        return l
+    elif hasattr(l, 'read'):
+        # Assume file handle
+        return load_layout(l)
+    elif isinstance(l, str):
+        with open(l, 'r') as f:
+            return load_layout(f)
+    else:
+        raise TaskError('Cannot use {} as layout'.format(l))
+
+
 def assemble(source, target):
     """ Invoke the assembler on the given source, returns an object containing
         the output. """
@@ -111,6 +125,7 @@
 def link(objects, layout):
     """ Links the iterable of objects into one using the given layout """
     objects = list(map(fix_object, objects))
+    layout = fix_layout(layout)
     linker = Linker()
     output_obj = linker.link(objects, layout)
     return output_obj
--- a/python/ppci/buildtasks.py	Sun Apr 27 12:24:21 2014 +0200
+++ b/python/ppci/buildtasks.py	Sun Apr 27 17:40:39 2014 +0200
@@ -5,7 +5,6 @@
 """
 
 import logging
-import json
 
 from .tasks import Task, TaskError, register_task
 from .buildfunctions import c3compile, link, assemble
@@ -78,31 +77,11 @@
             output.save(f)
 
 
-def make_num(txt):
-    if txt.startswith('0x'):
-        return int(txt[2:], 16)
-    else:
-        return int(txt)
-
-
-def load_layout(filename):
-    """ Load a linker layout file which contains directives where sections
-        must be placed into memory. """
-    try:
-        with open(filename, 'r') as f:
-            layout = json.load(f)
-    except OSError as e:
-        raise TaskError(str(e))
-    for s in layout:
-        layout[s] = make_num(layout[s])
-    return layout
-
-
 @register_task("link")
 class LinkTask(Task):
     """ Link together a collection of object files """
     def run(self):
-        layout = load_layout(self.relpath(self.get_argument('layout')))
+        layout = self.relpath(self.get_argument('layout'))
         objects = self.open_file_set(self.get_argument('objects'))
         output_file = self.relpath(self.get_argument('output'))
 
--- a/python/ppci/c3/lexer.py	Sun Apr 27 12:24:21 2014 +0200
+++ b/python/ppci/c3/lexer.py	Sun Apr 27 17:40:39 2014 +0200
@@ -1,6 +1,6 @@
 import re
 from ppci import CompilerError, SourceLocation, Token
-import baselex
+from baselex import BaseLexer
 
 """
  Lexical analyzer part. Splits the input character stream into tokens.
--- a/python/ppci/layout.py	Sun Apr 27 12:24:21 2014 +0200
+++ b/python/ppci/layout.py	Sun Apr 27 17:40:39 2014 +0200
@@ -1,58 +1,131 @@
+from baselex import BaseLexer
+import pyyacc
+from . import make_num
+
 
 class Layout:
     def __init__(self):
         self.mems = []
 
+    def add_memory(self, memory):
+        self.mems.append(memory)
+
     def __eq__(self, other):
         return self.mems == other.mems
 
+    def __repr__(self):
+        return str(self.mems)
+
 
 class Memory:
-    def __init__(self, address=0x0):
+    def __init__(self, name):
         self.inputs = []
-        self.address = address
+        self.name = name
+        self.location = 0x0
         self.size = 0x0
 
     def add_input(self, inp):
         assert isinstance(inp, Input)
         self.inputs.append(inp)
 
+    def __repr__(self):
+        return 'MEM {} loc={:08X} size={:08X}'.format(self.name, self.location, self.size) + str(self.inputs)
+
+    def __eq__(self, other):
+        return str(self) == str(other)
 
 class Input:
     pass
 
 
-class SectionInput(Input):
+class Section(Input):
     def __init__(self, section_name):
         self.section_name = section_name
 
+    def __repr__(self):
+        return 'Section({})'.format(self.section_name)
 
-def load_layout(f):
-    return deserialize(json.load(f))
+
+class Align(Input):
+    def __init__(self, alignment):
+        self.alignment = alignment
+
+    def __repr__(self):
+        return 'Align({})'.format(self.alignment)
 
 
-def make_int(txt):
-    if txt.startswith('0x'):
-        return int(txt[2:], 16)
-    else:
-        return int(txt)
+class LayoutLexer(BaseLexer):
+    def __init__(self):
+        tok_spec = [
+           ('HEXNUMBER', r'0x[\da-fA-F]+', self.handle_number),
+           ('NUMBER', r'\d+', self.handle_number),
+           ('ID', r'[A-Za-z][A-Za-z\d_]*', self.handle_id),
+           ('SKIP', r'[ \t\r\n]', None),
+           ('LEESTEKEN', r':=|[\.,=:\-+*\[\]/\(\)]|>=|<=|<>|>|<|}|{', lambda typ, val: (val, val)),
+           ('STRING', r"'.*?'", lambda typ, val: (typ, val[1:-1])),
+        ]
+        super().__init__(tok_spec)
+        self.kws = ['MEMORY', 'ALIGN', 'LOCATION','SECTION','SIZE']
+
+    def handle_id(self, typ, val):
+        if val in self.kws:
+            typ = val
+        return typ, val
+
+    def handle_number(self, typ, val):
+        val = make_num(val)
+        typ = 'NUMBER'
+        return typ, val
 
 
 class LayoutParser:
-    def __init__(self):
-        toks = ['ID', '{', '}', 'MEMORY', 'ALIGN', '.', pyyacc.EPS, pyyacc.EOF]
+    def __init__(self, kws):
+        toks = ['ID', 'NUMBER', '{', '}', '.', ':', '=', '(', ')', pyyacc.EPS, pyyacc.EOF] + kws
         g = pyyacc.Grammar(toks)
-        g.add_production('layout', ['MEMORY', '{', 'input_list', '}'])
-        g.add_production('input_list', ['MEMORY', '{', 'input_list', '}'])
+        g.add_production('layout', ['mem_list'])
+        g.add_one_or_more('mem', 'mem_list')
+        g.add_production('mem', ['MEMORY', 'ID', 'LOCATION', '=', 'NUMBER', 'SIZE', '=', 'NUMBER', '{', 'input_list', '}'], self.handle_mem)
+        g.add_one_or_more('input', 'input_list')
+        g.add_production('input', ['ALIGN', '(', 'NUMBER', ')'], self.handle_align)
+        g.add_production('input', ['SECTION', '(', 'ID', ')'], self.handle_section)
+
+        g.start_symbol = 'layout'
+        self.p = g.generate_parser()
+
+    def parse(self, lexer, layout):
+        self.layout = layout
+        self.p.parse(lexer)
+
+    def handle_mem(self, mem_tag, mem_name, loc_tag, eq1, loc, size_tag, eq2, size, lbrace, inps, rbrace):
+        m = Memory(mem_name.val)
+        m.size = size.val
+        m.location = loc.val
+        for inp in inps:
+            m.add_input(inp)
+        self.layout.add_memory(m)
+
+    def handle_align(self, align_tag, lbrace, alignment, rbrace):
+        return Align(alignment.val)
+
+    def handle_section(self, section_tag, lbrace, section_name, rbrace):
+        return Section(section_name.val)
 
 
-def deserialize(d):
-    layout = Layout()
-    for mem_node in d['memories']:
-        m = Memory()
-        m.address = make_int(mem_node['address'])
-        m.size = make_int(mem_node['size'])
-        for input_node in mem_node['inputs']:
-            pass
-    return layout
+class LayoutLoader:
+    def __init__(self):
+        self.lexer = LayoutLexer()
+        self.parser = LayoutParser(self.lexer.kws)
 
+    def load_layout(self, f):
+        layout = Layout()
+        self.lexer.feed(f.read())  # TODO: perhaps the read is better in the lexer?
+        self.parser.parse(self.lexer, layout)
+        return layout
+
+# Single definition:
+_lloader = LayoutLoader()
+
+
+def load_layout(f):
+    return _lloader.load_layout(f)
+
--- a/python/ppci/linker.py	Sun Apr 27 12:24:21 2014 +0200
+++ b/python/ppci/linker.py	Sun Apr 27 17:40:39 2014 +0200
@@ -3,6 +3,8 @@
 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):
@@ -138,12 +140,15 @@
 
     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 section_name, address in layout.items():
-            self.dst.get_section(section_name).address = 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
 
         # First copy all sections into output sections:
         for iobj in objs:
--- a/python/pyyacc.py	Sun Apr 27 12:24:21 2014 +0200
+++ b/python/pyyacc.py	Sun Apr 27 17:40:39 2014 +0200
@@ -110,6 +110,19 @@
         self.nonterminals.add(name)
         self._first = None  # Invalidate cached version
 
+    def add_one_or_more(self, element_nonterm, list_nonterm):
+        """ Helper to add the rule
+           lst: elem
+           lst: lst elem
+        """
+        def a(el):
+            return [el]
+        def b(ls, el):
+            ls.append(el)
+            return ls
+        self.add_production(list_nonterm, [element_nonterm], a)
+        self.add_production(list_nonterm, [list_nonterm, element_nonterm], b)
+
     def productionsForName(self, name):
         """ Retrieve all productions for a non terminal """
         return [p for p in self.productions if p.name == name]
--- a/python/yacc.py	Sun Apr 27 12:24:21 2014 +0200
+++ b/python/yacc.py	Sun Apr 27 17:40:39 2014 +0200
@@ -43,81 +43,42 @@
 import io
 import logging
 from pyyacc import Grammar
+from baselex import BaseLexer
+from ppci import Token
 
 
-class XaccLexer:
+class XaccLexer(BaseLexer):
     def __init__(self):
-        pass
-
-    def feed(self, txt):
-        # Create a regular expression for the lexing part:
         tok_spec = [
-           ('ID', r'[A-Za-z][A-Za-z\d_]*'),
-           ('STRING', r"'[^']*'"),
-           ('BRACEDCODE', r"\{[^\}]*\}"),
-           ('OTHER', r'[:;\|]'),
-           ('SKIP', r'[ ]')
+           ('ID', r'[A-Za-z][A-Za-z\d_]*', lambda typ, val: (typ, val)),
+           ('STRING', r"'[^']*'", lambda typ, val: ('ID', val[1:-1])),
+           ('BRACEDCODE', r"\{[^\}]*\}", lambda typ, val: (typ, val)),
+           ('OTHER', r'[:;\|]', lambda typ, val: (val, val)),
+           ('SKIP', r'[ ]', None)
             ]
-        tok_re = '|'.join('(?P<%s>%s)' % pair for pair in tok_spec)
-        gettok = re.compile(tok_re).match
-
-        lines = txt.split('\n')
+        super().__init__(tok_spec)
 
-        def tokenize_line(line):
-            """ Generator that splits up a line into tokens """
-            mo = gettok(line)
-            pos = 0
-            while mo:
-                typ = mo.lastgroup
-                val = mo.group(typ)
-                if typ == 'ID':
-                    yield (typ, val)
-                elif typ == 'STRING':
-                    typ = 'ID'
-                    yield (typ, val[1:-1])
-                elif typ == 'OTHER':
-                    typ = val
-                    yield (typ, val)
-                elif typ == 'BRACEDCODE':
-                    yield (typ, val)
-                elif typ == 'SKIP':
-                    pass
+    def tokenize(self, txt):
+        lines = txt.split('\n')
+        section = 0
+        for line in lines:
+            line = line.strip()
+            if not line:
+                continue  # Skip empty lines
+            if line == '%%':
+                section += 1
+                yield Token('%%', '%%')
+                continue
+            if section == 0:
+                if line.startswith('%tokens'):
+                    yield Token('%tokens', '%tokens')
+                    for tk in super().tokenize(line[7:]):
+                        yield tk
                 else:
-                    raise NotImplementedError(str(typ))
-                pos = mo.end()
-                mo = gettok(line, pos)
-            if len(line) != pos:
-                raise ParseError('Lex fault at {}'.format(line))
-
-        def tokenize():
-            section = 0
-            for line in lines:
-                line = line.strip()
-                if not line:
-                    continue  # Skip empty lines
-                if line == '%%':
-                    section += 1
-                    yield('%%', '%%')
-                    continue
-                if section == 0:
-                    if line.startswith('%tokens'):
-                        yield('%tokens', '%tokens')
-                        for tk in tokenize_line(line[7:]):
-                            yield tk
-                    else:
-                        yield ('HEADER', line)
-                elif section == 1:
-                    for tk in tokenize_line(line):
-                        yield tk
-            yield ('eof', 'eof')
-        self.tokens = tokenize()
-        self.token = self.tokens.__next__()
-
-    def next_token(self):
-        t = self.token
-        if t[0] != 'eof':
-            self.token = self.tokens.__next__()
-        return t
+                    yield Token('HEADER', line)
+            elif section == 1:
+                for tk in super().tokenize(line):
+                    yield tk
 
 
 class ParseError(Exception):
@@ -129,17 +90,23 @@
         We could have made an generated parser, but that would yield a chicken
         egg issue.
     """
-    def __init__(self, lexer):
+    def __init__(self):
+        pass
+
+    def prepare_peak(self, lexer):
         self.lexer = lexer
+        self.look_ahead = self.lexer.next_token()
 
     @property
     def Peak(self):
         """ Sneak peak to the next token in line """
-        return self.lexer.token[0]
+        return self.look_ahead.typ
 
     def next_token(self):
         """ Take the next token """
-        return self.lexer.next_token()
+        token = self.look_ahead
+        self.look_ahead = self.lexer.next_token()
+        return token
 
     def consume(self, typ):
         """ Eat next token of type typ or raise an exception """
@@ -155,27 +122,27 @@
             return True
         return False
 
-    def parse_grammar(self):
+    def parse_grammar(self, lexer):
         """ Entry parse function into recursive descent parser """
+        self.prepare_peak(lexer)
         # parse header
-        headers = []
+        self.headers = []
         terminals = []
         while self.Peak in ['HEADER', '%tokens']:
             if self.Peak == '%tokens':
                 self.consume('%tokens')
                 while self.Peak == 'ID':
-                    terminals.append(self.consume('ID')[1])
+                    terminals.append(self.consume('ID').val)
             else:
-                headers.append(self.consume('HEADER')[1])
+                self.headers.append(self.consume('HEADER').val)
         self.consume('%%')
-        self.headers = headers
         self.grammar = Grammar(terminals)
-        while self.Peak != 'eof':
+        while self.Peak != 'EOF':
             self.parse_rule()
         return self.grammar
 
     def parse_symbol(self):
-        return self.consume('ID')[1]
+        return self.consume('ID').val
 
     def parse_rhs(self):
         """ Parse the right hand side of a rule definition """
@@ -183,7 +150,7 @@
         while self.Peak not in [';', 'BRACEDCODE', '|']:
             symbols.append(self.parse_symbol())
         if self.Peak == 'BRACEDCODE':
-            action = self.consume('BRACEDCODE')[1]
+            action = self.consume('BRACEDCODE').val
             action = action[1:-1].strip()
         else:
             action = None
@@ -295,12 +262,12 @@
 
     # Construction of generator parts:
     lexer = XaccLexer()
-    parser = XaccParser(lexer)
+    parser = XaccParser()
     generator = XaccGenerator()
 
     # Sequence source through the generator parts:
     lexer.feed(src)
-    grammar = parser.parse_grammar()
+    grammar = parser.parse_grammar(lexer)
     generator.generate(grammar, parser.headers, args.output)
 
 
--- a/test/m3_bare/m3bare.mmap	Sun Apr 27 12:24:21 2014 +0200
+++ b/test/m3_bare/m3bare.mmap	Sun Apr 27 17:40:39 2014 +0200
@@ -1,5 +1,10 @@
 
-{
-"code": "0x0",
-"data": "0x20000000"
+MEMORY flash LOCATION=0x0 SIZE=0x10000 {
+ SECTION(code)
 }
+
+MEMORY ram LOCATION=0x20000000 SIZE=0x10000 {
+ SECTION(data)
+}
+
+
--- a/test/testarmasm.py	Sun Apr 27 12:24:21 2014 +0200
+++ b/test/testarmasm.py	Sun Apr 27 17:40:39 2014 +0200
@@ -1,8 +1,10 @@
 import unittest
+import io
 from ppci.outstream import BinaryOutputStream
 from ppci.objectfile import ObjectFile
 from testasm import AsmTestCaseBase
 from ppci.target.target_list import arm_target
+from ppci.layout import load_layout
 
 
 class ArmAssemblerTestCase(AsmTestCaseBase):
@@ -11,7 +13,7 @@
         self.t = arm_target
         self.obj = ObjectFile()
         self.ostream = BinaryOutputStream(self.obj)
-        self.ostream.select_section('.text')
+        self.ostream.select_section('code')
         self.assembler = arm_target.assembler
 
     def testMovImm(self):
@@ -122,7 +124,13 @@
         """ Link code at 0x10000 and check if symbol was correctly patched """
         self.feed('ldr r8, =a')
         self.feed('a:')
-        self.check('04801fe5 04000100', {'.text':0x10000})
+        spec = """
+            MEMORY flash LOCATION=0x10000 SIZE=0x10000 {
+                SECTION(code)
+            }
+        """
+        layout = load_layout(io.StringIO(spec))
+        self.check('04801fe5 04000100', layout)
 
     def testCmp(self):
         self.feed('cmp r4, r11')
--- a/test/testasm.py	Sun Apr 27 12:24:21 2014 +0200
+++ b/test/testasm.py	Sun Apr 27 17:40:39 2014 +0200
@@ -7,6 +7,7 @@
 from ppci.outstream import BinaryOutputStream
 from ppci.target.basetarget import Label
 from ppci.buildfunctions import link
+from ppci.layout import Layout
 
 
 class AssemblerLexingCase(unittest.TestCase):
@@ -60,10 +61,10 @@
     def feed(self, line):
         self.assembler.assemble(line, self.ostream)
 
-    def check(self, hexstr, layout={}):
+    def check(self, hexstr, layout=Layout()):
         self.assembler.flush()
         self.obj = link([self.obj], layout)
-        data = bytes(self.obj.get_section('.text').data)
+        data = bytes(self.obj.get_section('code').data)
         self.assertSequenceEqual(bytes.fromhex(hexstr), data)
 
 
--- a/test/testbintools.py	Sun Apr 27 12:24:21 2014 +0200
+++ b/test/testbintools.py	Sun Apr 27 17:40:39 2014 +0200
@@ -8,6 +8,7 @@
 from ppci.tasks import TaskRunner, TaskError
 from ppci.buildtasks import EmptyTask
 from ppci.buildfunctions import link
+from ppci import layout
 
 
 class TaskTestCase(unittest.TestCase):
@@ -59,7 +60,7 @@
         o1.add_relocation('undefined_sym', 0, 'rel8', '.text')
         o2 = ObjectFile()
         with self.assertRaises(CompilerError):
-            o3 = link([o1, o2], {})
+            o3 = link([o1, o2], layout.Layout())
 
     def testDuplicateSymbol(self):
         o1 = ObjectFile()
@@ -69,7 +70,7 @@
         o2.get_section('.text')
         o2.add_symbol('a', 0, '.text')
         with self.assertRaises(CompilerError):
-            o3 = link([o1, o2], {})
+            o3 = link([o1, o2], layout.Layout())
 
     def testRel8Relocation(self):
         o1 = ObjectFile()
@@ -78,7 +79,7 @@
         o2 = ObjectFile()
         o2.get_section('.text').add_data(bytes([0]*100))
         o2.add_symbol('a', 24, '.text')
-        o3 = link([o1, o2], {})
+        o3 = link([o1, o2], layout.Layout())
 
     def testSymbolValues(self):
         o1 = ObjectFile()
@@ -87,27 +88,35 @@
         o2 = ObjectFile()
         o2.get_section('.text').add_data(bytes([0]*100))
         o2.add_symbol('a', 2, '.text')
-        o3 = link([o1, o2], {})
+        o3 = link([o1, o2], layout.Layout())
         self.assertEqual(110, o3.find_symbol('a').value)
         self.assertEqual(24, o3.find_symbol('b').value)
         self.assertEqual(208, o3.get_section('.text').Size)
 
     def testMemoryLayout(self):
-        memory_layout = {'.text': 0x08000000, '.data':0x20000000}
+        spec = """
+            MEMORY flash LOCATION=0x08000000 SIZE=0x3000 {
+              SECTION(code)
+            }
+            MEMORY flash LOCATION=0x20000000 SIZE=0x3000 {
+              SECTION(data)
+            }
+        """
+        memory_layout = layout.load_layout(io.StringIO(spec))
         o1 = ObjectFile()
-        o1.get_section('.text').add_data(bytes([0]*108))
-        o1.add_symbol('b', 24, '.text')
+        o1.get_section('code').add_data(bytes([0]*108))
+        o1.add_symbol('b', 24, 'code')
         o2 = ObjectFile()
-        o2.get_section('.text').add_data(bytes([0]*100))
-        o2.get_section('.data').add_data(bytes([0]*100))
-        o2.add_symbol('a', 2, '.data')
-        o2.add_symbol('c', 2, '.text')
+        o2.get_section('code').add_data(bytes([0]*100))
+        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)
-        self.assertEqual(208, o3.get_section('.text').Size)
-        self.assertEqual(100, o3.get_section('.data').Size)
+        self.assertEqual(208, o3.get_section('code').Size)
+        self.assertEqual(100, o3.get_section('data').Size)
 
 
 class ObjectFileTestCase(unittest.TestCase):
@@ -142,6 +151,25 @@
         self.assertEqual(o3, o1)
 
 
+class LayoutFileTestCase(unittest.TestCase):
+    def testLayout1(self):
+        spec = """
+            MEMORY flash LOCATION=0x1000 SIZE=0x3000 {
+              SECTION(code)
+              ALIGN(4)
+            }
+        """
+        layout1 = layout.load_layout(io.StringIO(spec))
+        layout2 = layout.Layout()
+        m = layout.Memory('flash')
+        m.location = 0x1000
+        m.size = 0x3000
+        m.add_input(layout.Section('code'))
+        m.add_input(layout.Align(4))
+        layout2.add_memory(m)
+        self.assertEqual(layout2, layout1)
+
+
 if __name__ == '__main__':
     unittest.main()
     sys.exit()
--- a/test/testmsp430asm.py	Sun Apr 27 12:24:21 2014 +0200
+++ b/test/testmsp430asm.py	Sun Apr 27 17:40:39 2014 +0200
@@ -12,7 +12,7 @@
         self.t = msp430target
         self.obj = ObjectFile()
         self.ostream = BinaryOutputStream(self.obj)
-        self.ostream.select_section('.text')
+        self.ostream.select_section('code')
         self.assembler = msp430target.assembler
 
     def testMov(self):
--- a/test/testsamples.py	Sun Apr 27 12:24:21 2014 +0200
+++ b/test/testsamples.py	Sun Apr 27 17:40:39 2014 +0200
@@ -24,6 +24,17 @@
 
 """
 
+arch_mmap = """
+MEMORY image LOCATION=0x10000 SIZE=0x10000 {
+    SECTION(reset)
+    SECTION(code)
+}
+
+MEMORY ram LOCATION=0x20000 SIZE=0x10000 {
+    SECTION(data)
+}
+"""
+
 class Samples:
     def testPrint(self):
         snippet = """
@@ -136,8 +147,7 @@
             relpath('..', 'kernel', 'src', 'io.c3'),
             io.StringIO(modarchcode),
             io.StringIO(src)], [], 'arm')
-        layout = {'code': 0x10000, 'data': 0x20000}
-        o3 = link([o1, o2], layout)
+        o3 = link([o1, o2], io.StringIO(arch_mmap))
 
         sample_filename = 'testsample.bin'
         with open(sample_filename, 'wb') as f:
@@ -152,6 +162,9 @@
         self.assertEqual(expected_output, res)
 
 
+# TODO: test samples on thumb target..
+
+
 if __name__ == '__main__':
     unittest.main()
 
--- a/test/testthumbasm.py	Sun Apr 27 12:24:21 2014 +0200
+++ b/test/testthumbasm.py	Sun Apr 27 17:40:39 2014 +0200
@@ -10,7 +10,7 @@
         self.t = thumb_target
         self.obj = ObjectFile()
         self.ostream = BinaryOutputStream(self.obj)
-        self.ostream.select_section('.text')
+        self.ostream.select_section('code')
         self.assembler = thumb_target.assembler
 
     def testMovImm8(self):
--- a/user/app.mmap	Sun Apr 27 12:24:21 2014 +0200
+++ b/user/app.mmap	Sun Apr 27 17:40:39 2014 +0200
@@ -1,6 +1,9 @@
 
-{
- "code": "0x0",
- "data":"0x20000000"
+MEMORY flash LOCATION=0x0 SIZE=0x10000 {
+ SECTION(code)
 }
 
+MEMORY ram LOCATION=0x20000000 SIZE=0x10000 {
+ SECTION(data)
+}
+