view python/ppci/objectfile.py @ 385:d056b552d3f4

Made better use of layout
author Windel Bouwman
date Thu, 01 May 2014 14:03:12 +0200
parents 94f5b719ad0b
children
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, make_num

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 = []
        self.images = {}

    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 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 \
            (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 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):
        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))
        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'] = bin2asc(x.data)
    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 deserialize(d):
    obj = ObjectFile()
    for section in d['sections']:
        so = obj.get_section(section['name'])
        so.address = make_num(section['address'])
        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