# HG changeset patch # User Windel Bouwman # Date 1392666090 -3600 # Node ID 582a1aaa39832bb7be7e19ba09c8e2071aef3ecc # Parent 6f4753202b9ac91e0269644653ad82beb6795469 Added long branch format diff -r 6f4753202b9a -r 582a1aaa3983 python/outstream.py --- a/python/outstream.py Thu Feb 13 22:02:08 2014 +0100 +++ b/python/outstream.py Mon Feb 17 20:41:30 2014 +0100 @@ -1,5 +1,6 @@ import binascii -from target import Instruction, Label, DebugInfo +from target import Instruction, DebugInfo, Alignment +from ppci.objectfile import ObjectFile """ The output stream is a stream of instructions that can be output @@ -7,76 +8,19 @@ """ -class Section: - def __init__(self): - self.address = 0 - self.instructions = [] - +class OutputStream: def emit(self, item): - assert isinstance(item, Instruction) - self.instructions.append(item) - - def to_bytes(self): - d = bytearray() - for i in self.instructions: - addr = i.address - insword = i.encode() - assert type(insword) is bytes - d.extend(insword) - return bytes(d) - - @property - def Size(self): - return len(self.to_bytes()) - - def debugInfos(self): - di = [i for i in self.instructions if isinstance(i, DebugInfo)] - return di - - -class OutputStream: - def __init__(self): - self.sections = {} - self.currentSection = None - - def emit(self, item): - assert self.currentSection - self.currentSection.emit(item) + raise NotImplementedError('Abstract base class') def selectSection(self, sname): - self.currentSection = self.getSection(sname) - - def getLabelAddress(self, lname): - assert isinstance(lname, str) - for s in self.sections.values(): - for i in s.instructions: - if type(i) is Label: - if i.name == lname: - return i.address - return 0 + raise NotImplementedError('Abstract base class') - def getSection(self, name): - if not name in self.sections: - self.sections[name] = Section() - return self.sections[name] - - def backpatch(self): - """ Fixup references to other parts in the assembler """ - for s in self.sections.values(): - address = s.address - for i in s.instructions: - i.address = address - i.resolve(self.getLabelAddress) - bts = i.encode() - address += len(bts) class OutputStreamWriter: def __init__(self, extra_indent=''): self.extra_indent = extra_indent def dump(self, stream, f): - stream.backpatch() - stream.backpatch() for s in sorted(stream.sections.keys()): # print('.section '+ s) self.dumpSection(stream.sections[s], f) @@ -96,19 +40,30 @@ print(' 0x{0:08x} 0x{1} {2}'.format(addr, insword, asm), file=f) -class TextOutputStream(OutputStream): - pass - - -class BinOutputStream(OutputStream): +class BinaryOutputStream(OutputStream): + """ Output stream that writes to object file """ + def __init__(self, obj_file): + super().__init__() + self.obj_file = obj_file - @property - def Data(self): - d = self.dump() - return bytes(d) + def emit(self, item): + """ Encode instruction and add symbol and relocation information """ + assert isinstance(item, Instruction) + assert self.currentSection + section = self.currentSection + address = self.currentSection.Size + b = item.encode() + syms = item.symbols() + relocs = item.relocations() + section.add_data(b) + for sym in syms: + self.obj_file.add_symbol(sym, address, section.name) + for sym, typ in relocs: + self.obj_file.add_relocation(sym, address, typ, section.name) + # Special case for align, TODO do this different? + if type(item) is Alignment: + while section.Size % item.align != 0: + section.add_data(bytes([0])) - def dump(self): - self.backpatch() - self.backpatch() - section = self.sections[list(self.sections.keys())[0]] - return section.to_bytes() + def selectSection(self, sname): + self.currentSection = self.obj_file.get_section(sname) diff -r 6f4753202b9a -r 582a1aaa3983 python/ppci/buildtasks.py --- a/python/ppci/buildtasks.py Thu Feb 13 22:02:08 2014 +0100 +++ b/python/ppci/buildtasks.py Mon Feb 17 20:41:30 2014 +0100 @@ -17,6 +17,7 @@ from .linker import Linker import outstream + class BuildTask(Task): """ Base task for all kind of weird build tasks """ def __init__(self, name): @@ -71,7 +72,7 @@ # Code generation: d = {'ircode':ircode} self.logger.debug('Starting code generation for {}'.format(ircode), extra=d) - o = outstream.TextOutputStream() + o = outstream.BinaryOutputStream(self.output) cg.generate(ircode, o) if not c3b.ok: @@ -88,10 +89,6 @@ self.duration = 0.1337 def run(self): - print('LNK') - print('LNK', self.objects) - print('LNK') - print('LNK') self.linker.link(self.objects) diff -r 6f4753202b9a -r 582a1aaa3983 python/ppci/linker.py --- a/python/ppci/linker.py Thu Feb 13 22:02:08 2014 +0100 +++ b/python/ppci/linker.py Mon Feb 17 20:41:30 2014 +0100 @@ -1,19 +1,112 @@ +import struct from .objectfile import ObjectFile +from . import CompilerError + +def align(x, m): + while ((x % m) != 0): + x = x + 1 + return x + +def wrap_negative(x, bits): + b = struct.unpack('> 2 + section.data[reloc.offset] = rel8 + elif reloc.typ == 'wrap_new11': + offset = sym.value - (align(reloc.offset, 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 + elif reloc.typ == 'rel8': + assert sym.value % 2 == 0 + offset = sym.value - (align(reloc.offset, 2) + 4) + assert offset in range(-256, 254, 2), str(offset) + str(reloc) + imm8 = wrap_negative(offset >> 1, 8) + section.data[reloc.offset] = imm8 + elif reloc.typ == 'bl_imm11_imm10': + assert sym.value % 2 == 0 + offset = sym.value - (align(reloc.offset, 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) + elif reloc.typ == 'b_imm11_imm6': + assert sym.value % 2 == 0 + offset = sym.value - (align(reloc.offset, 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) + else: + raise NotImplementedError('Unknown relocation type {}'.format(reloc.typ)) + return self.dst diff -r 6f4753202b9a -r 582a1aaa3983 python/ppci/objectfile.py --- a/python/ppci/objectfile.py Thu Feb 13 22:02:08 2014 +0100 +++ b/python/ppci/objectfile.py Mon Feb 17 20:41:30 2014 +0100 @@ -5,19 +5,41 @@ """ class Symbol: - def __init__(self, name, value): + def __init__(self, name, value, section): self.name = name self.value = value + self.section = section + + def __repr__(self): + return 'SYM {}, val={} sec={}'.format(self.name, self.value, self.section) class Relocation: - def __init__(self, typ): - pass + def __init__(self, sym, offset, typ, section): + self.sym = sym + self.offset = offset + self.typ = typ + self.section = section + + def __repr__(self): + return 'RELOC {} off={} t={} sec={}'.format(self.sym, self.offset, self.typ, self.section) class Section: def __init__(self, name): self.name = name + self.address = 0 + self.data = bytearray() + + def add_data(self, data): + self.data += data + + @property + def Size(self): + return len(self.data) + + def __repr__(self): + return 'SECTION {}'.format(self.name) class ObjectFile: @@ -26,7 +48,17 @@ self.sections = {} self.relocations = [] - def add_symbol(self, name, value): - sym = Symbol(name, value) + def add_symbol(self, name, value, section): + sym = Symbol(name, value, section) self.symbols[name] = sym return sym + + def add_relocation(self, sym_name, offset, typ, section): + reloc = Relocation(sym_name, offset, typ, section) + self.relocations.append(reloc) + return reloc + + def get_section(self, name): + if not name in self.sections: + self.sections[name] = Section(name) + return self.sections[name] diff -r 6f4753202b9a -r 582a1aaa3983 python/target/arminstructions.py --- a/python/target/arminstructions.py Thu Feb 13 22:02:08 2014 +0100 +++ b/python/target/arminstructions.py Mon Feb 17 20:41:30 2014 +0100 @@ -216,13 +216,13 @@ else: raise NotImplementedError() - def resolve(self, f): - if self.label: - self.expr = f(self.label.name) - def encode(self): return u32(self.expr) + def relocations(self): + assert not isinstance(self.expr, LabelRef) + return [] + def __repr__(self): return 'DCD 0x{0:X}'.format(self.expr) @@ -325,12 +325,8 @@ def fromim(cls, im): return cls(im.dst[0], im.others[0]) - def resolve(self, f): - la = f(self.label.name) - sa = align(self.address + 2, 4) - self.offset = (la - sa) - if self.offset < 0: - self.offset = 0 + def relocations(self): + return [(self.label.name, 'lit_add_8')] def encode(self): rt = self.rt.num @@ -488,7 +484,7 @@ def __repr__(self): return '{} {}, {}'.format(self.mnemonic, self.rd, self.rm) - + @instruction class Mul(ArmInstruction): @@ -602,15 +598,15 @@ self.target = target_label self.offset = 0 - def resolve(self, f): - la = f(self.target.name) - sa = self.address + 4 - self.offset = (la - sa) - def __repr__(self): return '{} {}'.format(self.mnemonic, self.target.name) +class Imm11Reloc: + def apply(self, P, S): + pass + + @instruction class B(jumpBase_ins): mnemonic = 'B' @@ -619,6 +615,8 @@ h = (0b11100 << 11) | imm11 # | 1 # 1 to enable thumb mode return u16(h) + def relocations(self): + return [(self.target.name, 'wrap_new11')] @instruction class Bl(jumpBase_ins): @@ -634,13 +632,32 @@ h2 = (0b1101 << 12) | (j1 << 13) | (j2 << 11) | imm11 return u16(h1) + u16(h2) + def relocations(self): + return [(self.target.name, 'bl_imm11_imm10')] -class cond_base_ins(jumpBase_ins): + +class cond_base_ins_short(jumpBase_ins): def encode(self): imm8 = wrap_negative(self.offset >> 1, 8) h = (0b1101 << 12) | (self.cond << 8) | imm8 return u16(h) + def relocations(self): + return [(self.target.name, 'rel8')] + + +class cond_base_ins(jumpBase_ins): + """ Encoding T3 """ + def encode(self): + j1 = 1 # TODO: what do these mean? + j2 = 1 + h1 = (0b11110 << 11) | (self.cond << 6) + h2 = (0b1101 << 12) | (j1 << 13) | (j2 << 11) + return u16(h1) + u16(h2) + + def relocations(self): + return [(self.target.name, 'b_imm11_imm6')] + @instruction class Beq(cond_base_ins): diff -r 6f4753202b9a -r 582a1aaa3983 python/target/basetarget.py --- a/python/target/basetarget.py Thu Feb 13 22:02:08 2014 +0100 +++ b/python/target/basetarget.py Mon Feb 17 20:41:30 2014 +0100 @@ -58,10 +58,13 @@ class Instruction: """ Base instruction class """ def encode(self): - raise NotImplementedError('Instruction {0} has no encode yet, TODO'.format(type(self))) + return bytes() - def resolve(self, f): - pass + def relocations(self): + return [] + + def symbols(self): + return [] class Nop(Instruction): @@ -77,13 +80,12 @@ class Label(PseudoInstruction): def __init__(self, name): self.name = name - self.address = 0 def __repr__(self): return '{}:'.format(self.name) - def encode(self): - return bytes() + def symbols(self): + return [self.name] @classmethod def Create(cls, vop): @@ -112,7 +114,8 @@ def encode(self): pad = [] - address = self.address + # TODO + address = 0 while (address % self.align) != 0: address += 1 pad.append(0) @@ -126,9 +129,6 @@ def __repr__(self): return 'DebugInfo: {}'.format(self.info) - def encode(self): - return bytes() - class Register(Operand): def __init__(self, name): diff -r 6f4753202b9a -r 582a1aaa3983 test/testarmasm.py --- a/test/testarmasm.py Thu Feb 13 22:02:08 2014 +0100 +++ b/test/testarmasm.py Mon Feb 17 20:41:30 2014 +0100 @@ -1,5 +1,6 @@ import unittest import outstream +from ppci.objectfile import ObjectFile from asm import Assembler from testasm import AsmTestCaseBase from target.target_list import armtarget @@ -8,7 +9,8 @@ class AssemblerARMTestCase(AsmTestCaseBase): def setUp(self): self.t = armtarget - self.o = outstream.BinOutputStream() + self.obj = ObjectFile() + self.o = outstream.BinaryOutputStream(self.obj) self.o.selectSection('.text') self.a = Assembler(target=self.t, stream=self.o) diff -r 6f4753202b9a -r 582a1aaa3983 test/testasm.py --- a/test/testasm.py Thu Feb 13 22:02:08 2014 +0100 +++ b/test/testasm.py Mon Feb 17 20:41:30 2014 +0100 @@ -4,6 +4,8 @@ from ppci import CompilerError from ppci.asmnodes import AInstruction, ABinop, AUnop, ASymbol, ALabel, ANumber from ppci.assembler import tokenize, Assembler +from ppci.objectfile import ObjectFile +from ppci.linker import Linker import outstream from target import Label @@ -92,10 +94,11 @@ class OustreamTestCase(unittest.TestCase): def test1(self): - o = outstream.BinOutputStream() + obj = ObjectFile() + o = outstream.BinaryOutputStream(obj) o.selectSection('.text') o.emit(Label('a')) - self.assertSequenceEqual(bytes(), o.Data) + self.assertSequenceEqual(bytes(), obj.get_section('.text').data) class AsmTestCaseBase(unittest.TestCase): @@ -104,7 +107,10 @@ self.a.assemble(line) def check(self, hexstr): - self.assertSequenceEqual(bytes.fromhex(hexstr), self.o.Data) + l = Linker() + self.obj = l.link([self.obj]) + data = bytes(self.obj.get_section('.text').data) + self.assertSequenceEqual(bytes.fromhex(hexstr), data) if __name__ == '__main__': diff -r 6f4753202b9a -r 582a1aaa3983 test/testcg.py --- a/test/testcg.py Thu Feb 13 22:02:08 2014 +0100 +++ b/test/testcg.py Mon Feb 17 20:41:30 2014 +0100 @@ -18,7 +18,7 @@ self.cg = CodeGenerator(armtarget) def testFunction(self): - s = outstream.OutputStream() + s = outstream.BinaryOutputStream(ppci.objectfile.ObjectFile()) m, f, bb = genTestFunction() bb.addInstruction(ir.Exp(ir.Const(123))) bb.addInstruction(ir.Jump(f.epiloog)) @@ -28,7 +28,7 @@ class testArmCodeGeneration(unittest.TestCase): def testStack(self): - s = outstream.OutputStream() + s = outstream.BinaryOutputStream(ppci.objectfile.ObjectFile()) cg = CodeGenerator(armtarget) m, f, bb = genTestFunction() bb.addInstruction(ir.Move(ir.Mem(ir.Const(1)), ir.Const(22))) diff -r 6f4753202b9a -r 582a1aaa3983 test/testmsp430asm.py --- a/test/testmsp430asm.py Thu Feb 13 22:02:08 2014 +0100 +++ b/test/testmsp430asm.py Mon Feb 17 20:41:30 2014 +0100 @@ -3,6 +3,7 @@ import unittest from ppci.asmnodes import AInstruction, ABinop, AUnop, ASymbol, ALabel, ANumber from ppci.assembler import tokenize, Assembler +from ppci.objectfile import ObjectFile import outstream from target import Label from target.target_list import msp430target @@ -12,7 +13,8 @@ class AssemblerMSP430TestCase(AsmTestCaseBase): def setUp(self): self.t = msp430target - self.o = outstream.BinOutputStream() + self.obj = ObjectFile() + self.o = outstream.BinaryOutputStream(self.obj) self.o.selectSection('.text') self.a = Assembler(target=self.t, stream=self.o) diff -r 6f4753202b9a -r 582a1aaa3983 test/testzcc.py --- a/test/testzcc.py Thu Feb 13 22:02:08 2014 +0100 +++ b/test/testzcc.py Mon Feb 17 20:41:30 2014 +0100 @@ -3,7 +3,7 @@ import sys import zcc -import outstream +from ppci.objectfile import ObjectFile import ppci import io import target @@ -83,12 +83,12 @@ function void t2() {var int t3; t3 = 2;} """ f = io.StringIO(src) - outs = outstream.TextOutputStream() + out = ObjectFile() tg = target.target_list.armtarget tr = ppci.tasks.TaskRunner() - tr.add_task(ppci.buildtasks.Compile([f], [], tg, outs)) + tr.add_task(ppci.buildtasks.Compile([f], [], tg, out)) tr.run_tasks() - code = outs.getSection('code') + code = out.get_section('code') self.assertEqual(0x0, code.address)