adds code class as base for anything that can be assembled
This commit is contained in:
parent
d08e6702f0
commit
6261451c4b
46
lib/asm/code.rb
Normal file
46
lib/asm/code.rb
Normal 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
|
@ -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
|
@ -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
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user