[Wisp-cvs] wisp/users/dig linkie.py,NONE,1.1
Status: Alpha
Brought to you by:
digg
From: <di...@us...> - 2003-02-05 20:46:30
|
Update of /cvsroot/wisp/wisp/users/dig In directory sc8-pr-cvs1:/tmp/cvs-serv5683 Added Files: linkie.py Log Message: imported linkie.py --- NEW FILE: linkie.py --- #### linkie.py - a Python module for low-level linkable objects # # Copyleft © 2002 by Andres Soolo (di...@us...) # This file is licensed under the GNU GPL v2. If you # don't know what that means, please do read the GPL. # #### @(#) $Id: linkie.py,v 1.1 2003/02/05 20:46:25 digg Exp $ from struct import pack, unpack from array import array class Linkie: def __init__ (this, byte_order): this._symbols = {} # symbol -> address this._alignment = 1 # minimal required alignment constraint this._binary = array('c') this._skipped = 0 # uninitialized space after bits this._locals = [] # label no -> address this._unresolved_locals = [] # order is irrelevant if byte_order == '<': this.emit_wyde = this.emit_lewyde this.emit_tetra = this.emit_letetra elif byte_order == '>': this.emit_wyde = this.emit_bewyde this.emit_tetra = this.emit_betetra else: raise "Unknown byte order", byte_order this._byte_order = byte_order this._linker_notes = [] # list of (location, type, data) def emit_byte (this, b): """emit_byte(b) Places a byte to the byte collector.""" if this._skipped <> 0: raise "Events out of order", this this._binary.append(chr(b & 0xff)) def emit_bewyde (this, w): """emit_bewyde(w) Places a BigEndian wyde to the byte collector.""" if this._skipped <> 0: raise "Events out of order", this this._binary.fromstring(pack('>H', w)) # FIXME? def emit_lewyde (this, w): """emit_bewyde(w) Places a LittleEndian wyde to the byte collector.""" if this._skipped <> 0: raise "Events out of order", this this._binary.fromstring(pack('<H', w)) # FIXME? def emit_betetra (this, t): """emit_betetra(t) Places a BigEndian tetra to the byte collector.""" if this._skipped <> 0: raise "Events out of order", this this._binary.fromstring(pack('>L', t)) # FIXME? def emit_letetra (this, t): """emit_letetra(t) Places a LittleEndian tetra to the byte collector.""" if this._skipped <> 0: raise "Events out of order", this this._binary.fromstring(pack('<L', t)) # FIXME? def emit_string (this, s): """emit_string(s) Places the specified bytes to the byte collector.""" if this._skipped <> 0: raise "Events out of order", this this._binary.fromstring(s) def add_byte (this, ofs, value): this._binary[ofs] = chr(ord(this._binary[ofs]) + value) def add_wyde (this, ofs, value): tpl = this._byte_order + 'H' datum, = unpack(tpl, this._binary[ofs : ofs + 2]) this._binary[ofs : ofs + 2] = array('c', pack(tpl, datum + value)) def add_tetra (this, ofs, value): tpl = this._byte_order + 'L' datum, = unpack(tpl, this._binary[ofs : ofs + 4]) this._binary[ofs : ofs + 4] = array('c', pack(tpl, datum + value)) def _emit_sum (this, size, addends, delta = 0): if this._skipped <> 0: raise "Events out of order", this for a in addends: if type(a) == IntType: # local reference if this._locals[a] <> None: # backwards delta += this._locals[a] else: # forwards this._unresolved_locals.append((a, size, len(this._binary))) elif type(a) == StringType: # global reference this.notify_linker(size, a) else: raise 'Invalid addend', a return delta def emit_byte_sum (this, addends, delta = 0): this.emit_byte(this._emit_sum(1, addends, delta)) def emit_wyde_sum (this, addends, delta = 0): this.emit_wyde(this._emit_sum(2, addends, delta)) def emit_tetra_sum (this, addends, delta = 0): this.emit_tetra(this._emit_sum(4, addends, delta)) def skip (this, amount): """skip(amount) Reserves the specified amount of bytes.""" if amount < 0: raise "Not a cardinal number", amount this._skipped += amount def deskip (this): """deskip() Converts all reserved bytes to null bytes.""" this._binary.fromstring(this._skipped * '\0') this._skipped = 0; def memsz (this): """memsz() -> int Returns the memory image size of the linkie.""" return len(this._binary) + this._skipped def filesz (this): """filesz() -> int Returns the file image size of the linkie.""" return len(this._binary) def generate_label (this): """generate_label() -> int Allocates a new local label number. Doesn't place the label. See also place_label.""" i = len(this._locals) this._locals.append(None) return i def place_label (this, label): """place_label(label) Places a label previously returned by generate_label.""" if this._locals[label] <> None: raise 'Duplicate label', label this._locals[label] = len(this._binary) + this._skipped # Resolve open references to that label, if any for i in range(len(this._unresolved_locals) - 1, -1, -1): referee, type, data = this._unresolved_locals[i] if referee == label: if type == -1: this.add_byte(data, this._locals[label] - data) elif type == -2: this.add_wyde(data, this._locals[label] - data) elif type == -4: this.add_tetra(data, this._locals[label] - data) else: raise "Can't happen: unknown local reference type", this del this._unresolved_locals[i] # close the entry def place_symbol (this, symbol, value = None): """place_symbol(symbol, value = None) Places a globally visible symbol in the linkie. Does NOT check uniqueness. None signifies the current offset.""" if type(symbol) <> StringType: raise 'Not a string', symbol if value == None: value = len(this._binary) + this._skipped this._symbols.append((symbol, value)) def align (this, boundary): """align(boundary) Ensures that the following byte's memory address is divisible by the specified boundary (which must be a power of 2).""" if this._alignment < boundary: this._alignment = boundary delta = (boundary - 1) & - (len(this._binary) + this._skipped) if this._skipped: this._skipped += delta else: this._binary.fromstring(delta * '\0') def get_file (this): """get_file() -> array of chars Returns a copy of the file image of the linkie. See also get_memory.""" if this._unresolved_locals: raise 'Incomplete linkie', this return this._binary[:] def get_memory (this): """get_memory() -> array of chars Returns a copy of the memory image of the linkie. See also get_file and get_alignment.""" if this._unresolved_locals: raise 'Incomplete linkie', this return this._binary + array('c', '\0') * this._skipped def get_alignment (this): """get_alignment() -> int Returns the alignment constraint of the linkie. See also get_memory.""" if this._unresolved_locals: raise 'Incomplete linkie', this return this._alignment def get_symbols (this): """get_symbols() -> list of (string, int) tuples Returns a list of the globals placed in the linkie by place_symbol.""" if this._unresolved_locals: raise 'Incomplete linkie', this return this._symbols[:] def copy (this): if this._unresolved_locals: raise 'Incomplete linkie', this that = Linkie(this._byte_order) that._alignment = this._alignment that._binary = this._binary[:] that._skipped = this._skipped that._symbols = this._symbols[:] |