rubyx/lib/asm/arm_assembler.rb

122 lines
3.4 KiB
Ruby
Raw Normal View History

require 'asm/assembler'
2014-04-23 11:51:09 +02:00
require 'asm/arm_assembler'
require 'asm/instruction'
require 'asm/generator_label'
require 'asm/nodes'
require 'stream_reader'
require 'stringio'
2014-04-23 11:51:09 +02:00
require "asm/string_literal"
module Asm
class ArmAssembler < Asm::Assembler
%w(r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12
r13 r14 r15 a1 a2 a3 a4 v1 v2 v3 v4 v5 v6
rfp sl fp ip sp lr pc
).each { |reg|
define_method(reg) {
Asm::Register.new(reg)
}
}
def instruction(name, *args)
2014-04-23 11:51:09 +02:00
opcode = name.to_s
arg_nodes = []
args.each { |arg|
if (arg.is_a?(Asm::Register))
2014-04-23 11:51:09 +02:00
arg_nodes << arg
elsif (arg.is_a?(Integer))
2014-04-23 11:51:09 +02:00
arg_nodes << Asm::NumLiteral.new(arg)
2014-04-22 21:24:22 +02:00
elsif (arg.is_a?(String))
2014-04-23 11:51:09 +02:00
arg_nodes << add_string(arg)
elsif (arg.is_a?(Symbol))
2014-04-23 11:51:09 +02:00
arg_nodes << Asm::Label.new(arg.to_s)
elsif (arg.is_a?(Asm::GeneratorLabel))
arg_nodes << arg
else
raise 'Invalid argument `%s\' for instruction' % arg.inspect
end
}
2014-04-23 11:51:09 +02:00
add_value Asm::Instruction.new(opcode , arg_nodes)
end
%w(adc add and bic eor orr rsb rsc sbc sub mov mvn cmn cmp teq tst b bl bx
push pop swi str strb ldr ldrb
).each { |inst|
define_method(inst) { |*args|
instruction inst.to_sym, *args
}
define_method(inst+'s') { |*args|
instruction (inst+'s').to_sym, *args
}
%w(al eq ne cs mi hi cc pl ls vc lt le ge gt vs
).each { |cond_suffix|
define_method(inst+cond_suffix) { |*args|
instruction (inst+cond_suffix).to_sym, *args
}
define_method(inst+'s'+cond_suffix) { |*args|
instruction (inst+'s'+cond_suffix).to_sym, *args
}
}
}
def assemble_to_string
#put the strings at the end of the assembled code.
# adding them will fix their position and make them assemble after
@string_table.values.each do |data|
add_value data
end
io = StringIO.new
assemble(io)
io.string
end
end
# Relocation constants
# Note that in this assembler, a relocation simply means any
# reference to a label that can only be determined at assembly time
# or later (as in the normal meaning)
R_ARM_PC24 = 0x01
R_ARM_ABS32 = 0x02
# Unofficial (cant be used for extern relocations)
R_ARM_PC12 = 0xF0
def self.write_resolved_relocation(io, addr, type)
case type
when R_ARM_PC24
diff = addr - io.tell - 8
2014-04-20 01:28:57 +02:00
if (diff.abs > (1 << 25))
raise Asm::AssemblyError.new('offset too large for R_ARM_PC24 relocation', nil)
end
packed = [diff >> 2].pack('l')
io << packed[0,3]
when R_ARM_ABS32
packed = [addr].pack('l')
io << packed
when R_ARM_PC12
diff = addr - io.tell - 8
if (diff.abs > 2047)
2014-04-20 01:28:57 +02:00
raise Asm::AssemblyError.new('offset too large for R_ARM_PC12 relocation', nil)
end
val = diff.abs
sign = (diff>0)?1:0
curr = io.read_uint32
io.seek(-4, IO::SEEK_CUR)
io.write_uint32 (curr & ~0b00000000100000000000111111111111) |
val | (sign << 23)
else
raise 'unknown relocation type'
end
end
end