view python/ppci/objectfile.py @ 382:0c44e494ef58

Made lexer more generic
author Windel Bouwman
date Sun, 27 Apr 2014 12:24:21 +0200
parents 9667d78ba79e
children 94f5b719ad0b
line wrap: on
line source


"""
Object files are used to store assembled code. Information contained
is code, symbol table and relocation information.
"""

import json
import binascii
from . import CompilerError

class Symbol:
    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)

    def __eq__(self, other):
        return (self.name, self.value, self.section) == \
            (other.name, other.value, other.section)


class Relocation:
    """ Represents a relocation entry. A relocation always has a symbol to refer to
     and a relocation type """
    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)

    def __eq__(self, other):
        return (self.sym, self.offset, self.typ, self.section) ==\
            (other.sym, other.offset, other.typ, other.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)

    def __eq__(self, other):
        return (self.name == other.name) and (self.address == other.address) \
            and (self.data == other.data)


class ObjectFile:
    """ Container for sections with compiled code or data.
        Also contains symbols and relocation entries """
    def __init__(self):
        self.symbols = {}
        self.sections = {}
        self.relocations = []

    def find_symbol(self, name):
        return self.symbols[name]

    def add_symbol(self, name, value, section):
        if name in self.symbols:
            raise CompilerError('{} already defined'.format(name))
        assert section in self.sections
        sym = Symbol(name, value, section)
        self.symbols[name] = sym
        return sym

    def add_relocation(self, sym_name, offset, typ, section):
        assert type(sym_name) is str, str(sym_name)
        assert section in self.sections
        # assert sym_name in self.symbols
        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]

    def __eq__(self, other):
        return (self.symbols == other.symbols) and \
            (self.sections == other.sections) and \
            (self.relocations == other.relocations)

    def save(self, f):
        save_object(self, f)


def save_object(o, f):
    json.dump(serialize(o), f, indent=2, sort_keys=True)


def load_object(f):
    return deserialize(json.load(f))


def serialize(x):
    res = {}
    if isinstance(x, ObjectFile):
        res['sections'] = []
        for sname in sorted(x.sections.keys()):
            s = x.sections[sname]
            res['sections'].append(serialize(s))
        res['symbols'] = []
        for sname in sorted(x.symbols.keys()):
            s = x.symbols[sname]
            res['symbols'].append(serialize(s))
        res['relocations'] = []
        for reloc in x.relocations:
            res['relocations'].append(serialize(reloc))
    elif isinstance(x, Section):
        res['name'] = x.name
        res['address'] = hex(x.address)
        res['data'] = binascii.hexlify(x.data).decode('ascii')
    elif isinstance(x, Symbol):
        res['name'] = x.name
        res['value'] = hex(x.value)
        res['section'] = x.section
    elif isinstance(x, Relocation):
        res['symbol'] = x.sym
        res['offset'] = hex(x.offset)
        res['type'] = x.typ
        res['section'] = x.section
    return res


def make_int(txt):
    if txt.startswith('0x'):
        return int(txt[2:], 16)
    else:
        return int(txt)


def deserialize(d):
    obj = ObjectFile()
    for section in d['sections']:
        so = obj.get_section(section['name'])
        so.address = make_int(section['address'])
        so.data = bytearray(binascii.unhexlify(section['data'].encode('ascii')))
    for reloc in d['relocations']:
        obj.add_relocation(reloc['symbol'], make_int(reloc['offset']),
            reloc['type'], reloc['section'])
    for sym in d['symbols']:
        obj.add_symbol(sym['name'], make_int(sym['value']), sym['section'])
    return obj