adds code class as base for anything that can be assembled

This commit is contained in:
Torsten Ruger 2014-04-25 12:28:23 +03:00
parent d08e6702f0
commit 6261451c4b
4 changed files with 91 additions and 41 deletions

46
lib/asm/code.rb Normal file
View File

@ -0,0 +1,46 @@
module Asm
# Base class for anything that we can assemble
# Derived classes include instrucitons, blocks and data(strings)
# The commonality abstracted here is the length and position
# and the ability to assemble itself into the stream
# All code is position independant once assembled.
# But for jumps and calls two passes are neccessary.
# The first setting the position, the second assembling
class Code
# just sets position to nil, so we can sell that it has not been set
def initialize
@position = nil
end
# the position in the stream. Think of it as an address if you want. The difference is small.
# Especially since we produce _only_ position independant code
# in other words, during assembly the position _must_ be resolved into a pc relative address
# and not used as is
def position
throw "Not set" unless @address
@address
end
# The containing class (assembler/function) call this to tell the instruction/data where it is in the
# stream. During assembly the position is then used to calculate pc relative addresses.
def at address
@address = address
end
# length for this code in bytes
def length
throw "Not implemented #{self}"
end
# so currently the interface passes the io (usually string_io) in for the code to assemble itself.
# this may change as the writing is still done externally (or that will change)
def assemble(io)
throw "Not implemented #{self}"
end
end
end

View File

@ -1,10 +1,18 @@
require "asm/assembly_error"
require "asm/instruction_tools"
require "asm/label"
require_relative "label"
require_relative "assembly_error"
require_relative "instruction_tools"
module Asm
class Instruction
# Not surprisingly represents an cpu instruction.
# This is an abstract base class, with derived classes
# Logic / Move / Compare / Stack / Memory (see there)
#
# Opcode is a (<= three) letter accronym (same as in assembly code). Though in arm, suffixes can
# make the opcode longer, we chop those off in the constructor
# Argurments are registers or labels or string/num Literals
class Instruction < Code
include InstructionTools
COND_POSTFIXES = Regexp.union( COND_CODES.keys.collect{|k|k.to_s} ).source
@ -32,16 +40,9 @@ module Asm
@s
end
def at position
@position = position
end
# arm intrucioons are pretty sensible, and always 4 bytes (thumb not supported)
def length
4
end
def assemble(io)
raise "Abstract class, should not be called/instantiated #{self.inspect}"
end
end
end

View File

@ -1,35 +1,34 @@
require_relative "code"
module Asm
class Label
# Labels are, like in assembler, a point to jump/branch to. An address in the stream.
# To allow for forward branches creation does not fix the position. Set does that.
class Label < Code
def initialize(name , asm)
super
@name = name
@asm = asm
@position = nil
end
attr_writer :position , :name
def position
if (@position.nil?)
raise 'Tried to use label object that has not been set'
end
@position
end
def at pos
@position = pos
end
def length
0
end
def assemble(io)
self.position = io.tell
end
# setting a label fixes it's position in the stream.
# For backwards jumps, positions of labels are known at creation, but for forward off course not.
# So then one can create a label, branch to it and set it later.
def set!
@asm.add_value self
self
end
# Label has no length , 0
def length
0
end
# nothing to write, we check that the position is what was set
def assemble(io)
raise "Hmm hmm hmm, me thinks i should be somewhere else" if self.position != io.tell
end
end
end

View File

@ -1,7 +1,15 @@
require_relative "code"
module Asm
# The name really says it all.
# The only interesting thing is storage.
# Currently string are stored "inline" , ie in the code segment.
# Mainly because that works an i aint no elf expert.
class StringLiteral
# currently aligned to 4 (ie padded with 0) and off course 0 at the end
def initialize(str)
#align
length = str.length
# rounding up to the next 4 (always adding one for zero pad)
pad = ((length / 4 ) + 1 ) * 4 - length
@ -9,16 +17,12 @@ module Asm
@string = str + "\x00" * pad
end
def position
throw "Not set" unless @address
@address
end
def at address
@address = address
end
# the strings length plus padding
def length
@string.length
end
# just writing the string
def assemble(io)
io << @string
end