cleanup, requires, namespacing to actually get it to work

This commit is contained in:
Torsten Ruger
2014-04-14 21:52:16 +03:00
parent 5ad36bbd56
commit 2e6b90b12e
16 changed files with 379 additions and 299 deletions

View File

@ -1,4 +1,4 @@
class Asm::ARM::AddrTableObject
class Asm::Arm::AddrTableObject
def initialize
@table = []
@const = []
@ -21,8 +21,8 @@ class Asm::ARM::AddrTableObject
@table.each do |pair|
target_label, here_label = *pair
here_label.assemble io, as
as.add_relocation io.tell, target_label, Asm::ARM::R_ARM_ABS32,
Asm::ARM::Instruction::RelocHandler
as.add_relocation io.tell, target_label, Asm::Arm::R_ARM_ABS32,
Asm::Arm::Instruction::RelocHandler
io.write_uint32 0
end
@const.each do |pair|

View File

@ -1,54 +1,54 @@
require_relative 'assembler'
require 'asm/assembler'
module Asm
module Arm
# 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)
# 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
R_ARM_PC24 = 0x01
R_ARM_ABS32 = 0x02
# Unofficial (cant be used for extern relocations)
R_ARM_PC12 = 0xF0
# Unofficial (cant be used for extern relocations)
R_ARM_PC12 = 0xF0
# TODO actually find the closest somehow
def self.closest_addrtable(as)
as.objects.find do |obj|
obj.is_a?(Asm::ARM::AddrTableObject)
end || (raise Asm::AssemblyError.new('could not find addrtable to use', nil))
end
# TODO actually find the closest somehow
def self.closest_addrtable(as)
as.objects.find do |obj|
obj.is_a?(Asm::Arm::AddrTableObject)
end || (raise Asm::AssemblyError.new('could not find addrtable to use', nil))
end
def self.write_resolved_relocation(io, addr, type)
case type
when R_ARM_PC24
diff = addr - io.tell - 8
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)
raise Asm::AssemblyError.new('offset too large for R_ARM_PC12 relocation',
nil)
def self.write_resolved_relocation(io, addr, type)
case type
when R_ARM_PC24
diff = addr - io.tell - 8
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)
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
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

View File

@ -3,7 +3,7 @@ module Asm
# ADDRESSING MODE 1
# Complete!
class BuilderA
include Asm::ARM::InstructionTools
include Asm::Arm::InstructionTools
def initialize
@cond = 0b1110

View File

@ -1,9 +1,11 @@
require "asm/parser"
module Asm
module Arm
# ADDRESSING MODE 2
# Implemented: immediate offset with offset=0
class BuilderB
include Asm::ARM::InstructionTools
include Asm::Arm::InstructionTools
def initialize
@cond = 0b1110
@ -96,15 +98,15 @@ module Asm
(pre_post_index << 12+4+4+1+1+1+1) | (i << 12+4+4+1+1+1+1+1) |
(inst_class << 12+4+4+1+1+1+1+1+1) | (cond << 12+4+4+1+1+1+1+1+1+2)
if (@use_addrtable_reloc)
closest_addrtable = Asm::ARM.closest_addrtable(as)
closest_addrtable = Asm::Arm.closest_addrtable(as)
if (@addrtable_reloc_target.is_a?(Asm::Parser::LabelEquivAddrArgNode))
obj = ast_asm.object_for_label(@addrtable_reloc_target.label, inst)
ref_label = closest_addrtable.add_label(obj)
elsif (@addrtable_reloc_target.is_a?(Asm::Parser::NumEquivAddrArgNode))
ref_label = closest_addrtable.add_const(@addrtable_reloc_target.value)
end
as.add_relocation io.tell, ref_label, Asm::ARM::R_ARM_PC12,
Asm::ARM::Instruction::RelocHandler
as.add_relocation io.tell, ref_label, Asm::Arm::R_ARM_PC12,
Asm::Arm::Instruction::RelocHandler
end
io.write_uint32 val
end

View File

@ -2,11 +2,11 @@ module Asm
module Arm
# ADDRESSING MODE 4
class BuilderD
include Asm::ARM::InstructionTools
include Asm::Arm::InstructionTools
def initialize
@cond = 0b1110
@inst_class = Asm::ARM::Instruction::OPC_STACK
@inst_class = Asm::Arm::Instruction::OPC_STACK
@pre_post_index = 0
@up_down = 0
@s = 0

View File

@ -1,5 +1,8 @@
require_relative 'arm_assembler'
require_relative 'parser'
require 'asm/arm/arm_assembler'
require 'asm/arm/instruction'
require 'asm/label_object'
require 'asm/parser'
require 'stream_reader'
require 'stringio'
module Asm
@ -51,7 +54,7 @@ module Asm
end
}
@asm.add_object Asm::ARM::Instruction.new(node)
@asm.add_object Asm::Arm::Instruction.new(node)
end
%w(adc add and bic eor orr rsb rsc sbc sub

View File

@ -1,7 +1,13 @@
require "asm/arm/instruction_tools"
require "asm/arm/builder_a"
require "asm/arm/builder_b"
require "asm/arm/builder_d"
module Asm
module Arm
class Asm::ARM::Instruction
include Asm::ARM::InstructionTools
class Instruction
include InstructionTools
COND_POSTFIXES = Regexp.union(%w(eq ne cs cc mi pl vs vc hi ls ge lt gt le al)).source
def initialize(node, ast_asm = nil)
@ -63,7 +69,7 @@ module Asm
:vs => 0b0110
}
RelocHandler = Asm::ARM.method(:write_resolved_relocation)
RelocHandler = Asm::Arm.method(:write_resolved_relocation)
def assemble(io, as)
s = @s ? 1 : 0
@ -123,7 +129,7 @@ module Asm
io << packed[0,3]
elsif (arg.is_a?(Asm::LabelObject) or arg.is_a?(Asm::Parser::LabelRefArgNode))
arg = @ast_asm.object_for_label(arg.label, self) if arg.is_a?(Asm::Parser::LabelRefArgNode)
as.add_relocation(io.tell, arg, Asm::ARM::R_ARM_PC24, RelocHandler)
as.add_relocation(io.tell, arg, Asm::Arm::R_ARM_PC24, RelocHandler)
io << "\x00\x00\x00"
end
io.write_uint8 OPCODES[opcode] | (COND_BITS[@cond] << 4)

View File

@ -1,6 +1,6 @@
module Asm
module Arm
module Asm::ARM::InstructionTools
module Asm::Arm::InstructionTools
def reg_ref(arg)
if (not arg.is_a?(Asm::Parser::RegisterArgNode))
raise Asm::AssemblyError.new('argument must be a register', arg)

View File

@ -39,8 +39,8 @@ module Asm
elsif (cmd.name == "asciz")
str = eval(cmd.value) + "\x00"
@asm.add_object Asm::DataObject.new(str)
elsif (defined?(Asm::ARM) and cmd.name == 'addrtable')
@asm.add_object Asm::ARM::AddrTableObject.new
elsif (defined?(Asm::Arm) and cmd.name == 'addrtable')
@asm.add_object Asm::Arm::AddrTableObject.new
else
raise Asm::AssemblyError.new('unknown directive', cmd)
end

View File

@ -86,7 +86,7 @@ module Asm
case options.target
when :arm
require_relative 'arm_assembler.rb'
as_module = Asm::ARM
as_module = Asm::Arm
as_target = Elf::Constants::TARGET_ARM
when :ttk91
require_relative 'ttk91_assembler.rb'

View File

@ -1,6 +1,6 @@
require_relative 'str_scanner'
module AS
module Asm
class ParseError < StandardError
def initialize(message, s)
super(message)
@ -10,258 +10,259 @@ module AS
end
attr_reader :line, :column
end
end
class Asm::Parser
def initialize(str)
scanner = Asm::Scanner.new(str)
class Parser
def initialize(str)
scanner = Asm::Scanner.new(str)
@ast = parse_toplevel scanner
end
attr_reader :ast
@ast = parse_toplevel scanner
end
attr_reader :ast
def self.parse(str)
new(str).ast
end
def self.parse(str)
new(str).ast
end
class Node
def initialize(s = nil)
if (s)
@line = s.prev_line
@column = s.prev_column
else
@line = 0
@column = 0
class Node
def initialize(s = nil)
if (s)
@line = s.prev_line
@column = s.prev_column
else
@line = 0
@column = 0
end
yield self if block_given?
end
yield self if block_given?
attr_reader :line, :column
end
attr_reader :line, :column
end
class ToplevelNode < Node
attr_accessor :children
end
def parse_toplevel(s)
node = ToplevelNode.new(s)
node.children = []
while (not s.eos?)
node.children << parse(s)
class ToplevelNode < Node
attr_accessor :children
end
node
end
def parse(s)
s.scan /\s*/
node = nil
%w(comment directive label instruction).each { |em|
if (node = send('parse_'+em, s))
break
end
}
raise Asm::ParseError.new('could not parse element', s) unless node
s.scan /\s*/
node
end
class CommentNode < Node; end
def parse_comment(s)
if (s.scan(/;.*?$/))
CommentNode.new(s)
end
end
class DirectiveNode < Node
attr_accessor :name, :value
end
def parse_directive(s)
if (m = s.scan(/\.(\w+)(?:(?!$)\s+(.+)\s*?$)?/))
DirectiveNode.new(s) { |n|
n.name = m[0]
n.value = m[1]
}
end
end
class LabelNode < Node
attr_accessor :name
end
def parse_label(s)
if (m = s.scan(/(\/*\w+):/))
LabelNode.new(s) { |n|
n.name = m[0]
}
end
end
class InstructionNode < Node
attr_accessor :opcode, :args
end
def parse_instruction(s)
if (m = s.scan(/(\w+)/))
node = InstructionNode.new(s) { |n|
n.opcode = m[0]
n.args = []
}
if (not s.scan(/\s*($|;)/))
loop {
arg = parse_arg(s)
node.args << arg
break if not s.scan(/\s*,/)
}
def parse_toplevel(s)
node = ToplevelNode.new(s)
node.children = []
while (not s.eos?)
node.children << parse(s)
end
node
end
end
class ArgNode < Node
end
def parse_arg(s)
s.scan /\s*/
node = nil
%w(reference register register_list num_literal label_ref).each { |em|
if (node = send('parse_'+em, s))
break
end
}
raise Asm::ParseError.new('expected argument but none found', s) unless node
if (node2 = parse_arg_op(s))
node2.argument = node
node = node2
end
s.scan /\s*/
node
end
def parse_arg_op(s)
s.scan /\s*/
node = nil
%w(shift math).each do |em|
if (node = send('parse_'+em, s))
break
end
end
s.scan /\s*/
node
end
class ShiftNode < Node
attr_accessor :type, :value, :argument
end
def parse_shift(s)
if (m = s.scan(/(lsl|lsr|asr|ror|rrx)\s+/i))
op = m[0].downcase
if (op == 'rrx' or arg = parse_arg(s))
ShiftNode.new(s) { |n|
n.type = m[0].downcase
n.value = arg
}
else
nil
end
end
end
class MathNode < Node
attr_accessor :left, :right, :op
alias_method :argument, :left
alias_method :argument=, :left=
end
def parse_math(s)
if (m = s.scan_str(/[\+\-]/))
if (arg1 = parse_arg(s))
MathNode.new(s) do |n|
n.right = arg1
n.op = m
def parse(s)
s.scan /\s*/
node = nil
%w(comment directive label instruction).each { |em|
if (node = send('parse_'+em, s))
break
end
else
raise Asm::ParseError.new('expected right side for arithmetic op', s)
end
end
end
REGISTER_REGEXP = Regexp.union(*%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
))
class RegisterArgNode < ArgNode
attr_accessor :name
end
def parse_register(s)
if (m = s.scan_str(REGISTER_REGEXP))
RegisterArgNode.new(s) { |n|
n.name = m
}
raise Asm::ParseError.new('could not parse element', s) unless node
s.scan /\s*/
node
end
end
class RegisterListArgNode < ArgNode
attr_accessor :registers
end
def parse_register_list(s)
if (m = s.scan(/\{/))
node = RegisterListArgNode.new(s) do |n|
n.registers = []
class CommentNode < Node; end
def parse_comment(s)
if (s.scan(/;.*?$/))
CommentNode.new(s)
end
loop do
s.scan /\s*/
reg = parse_register(s)
if (not reg)
return nil
end
class DirectiveNode < Node
attr_accessor :name, :value
end
def parse_directive(s)
if (m = s.scan(/\.(\w+)(?:(?!$)\s+(.+)\s*?$)?/))
DirectiveNode.new(s) { |n|
n.name = m[0]
n.value = m[1]
}
end
end
class LabelNode < Node
attr_accessor :name
end
def parse_label(s)
if (m = s.scan(/(\/*\w+):/))
LabelNode.new(s) { |n|
n.name = m[0]
}
end
end
class InstructionNode < Node
attr_accessor :opcode, :args
end
def parse_instruction(s)
if (m = s.scan(/(\w+)/))
node = InstructionNode.new(s) { |n|
n.opcode = m[0]
n.args = []
}
if (not s.scan(/\s*($|;)/))
loop {
arg = parse_arg(s)
node.args << arg
break if not s.scan(/\s*,/)
}
end
s.scan /\s*,?/
node.registers << reg
if (s.scan(/\}/))
node
end
end
class ArgNode < Node
end
def parse_arg(s)
s.scan /\s*/
node = nil
%w(reference register register_list num_literal label_ref).each { |em|
if (node = send('parse_'+em, s))
break
end
}
raise Asm::ParseError.new('expected argument but none found', s) unless node
if (node2 = parse_arg_op(s))
node2.argument = node
node = node2
end
s.scan /\s*/
node
end
def parse_arg_op(s)
s.scan /\s*/
node = nil
%w(shift math).each do |em|
if (node = send('parse_'+em, s))
break
end
end
s.scan /\s*/
node
end
end
class NumLiteralArgNode < ArgNode
attr_accessor :value
end
class NumEquivAddrArgNode < NumLiteralArgNode
end
def parse_num_literal(s)
if (m = s.scan(/(=?)#(-?(?:0x)?[0-9A-Fa-f]+)/))
(m[0] == '=' ? NumEquivAddrArgNode : NumLiteralArgNode).new(s) { |n|
n.value = Integer(m[1])
}
class ShiftNode < Node
attr_accessor :type, :value, :argument
end
end
class LabelRefArgNode < ArgNode
attr_accessor :label, :label_object
end
class LabelEquivAddrArgNode < LabelRefArgNode
end
def parse_label_ref(s)
if (m = s.scan(/(=?)(\/*\w+)/))
(m[0] == '=' ? LabelEquivAddrArgNode : LabelRefArgNode).new(s) { |n|
n.label = m[1]
}
def parse_shift(s)
if (m = s.scan(/(lsl|lsr|asr|ror|rrx)\s+/i))
op = m[0].downcase
if (op == 'rrx' or arg = parse_arg(s))
ShiftNode.new(s) { |n|
n.type = m[0].downcase
n.value = arg
}
else
nil
end
end
end
end
class ReferenceArgNode < ArgNode
attr_accessor :argument
end
def parse_reference(s)
if (m = s.scan(/\[/))
arg = parse_arg(s)
if (arg and s.scan(/\]/))
ReferenceArgNode.new(s) do |n|
n.argument = arg
class MathNode < Node
attr_accessor :left, :right, :op
alias_method :argument, :left
alias_method :argument=, :left=
end
def parse_math(s)
if (m = s.scan_str(/[\+\-]/))
if (arg1 = parse_arg(s))
MathNode.new(s) do |n|
n.right = arg1
n.op = m
end
else
raise Asm::ParseError.new('expected right side for arithmetic op', s)
end
end
end
REGISTER_REGEXP = Regexp.union(*%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
))
class RegisterArgNode < ArgNode
attr_accessor :name
end
def parse_register(s)
if (m = s.scan_str(REGISTER_REGEXP))
RegisterArgNode.new(s) { |n|
n.name = m
}
end
end
class RegisterListArgNode < ArgNode
attr_accessor :registers
end
def parse_register_list(s)
if (m = s.scan(/\{/))
node = RegisterListArgNode.new(s) do |n|
n.registers = []
end
loop do
s.scan /\s*/
reg = parse_register(s)
if (not reg)
return nil
end
s.scan /\s*,?/
node.registers << reg
if (s.scan(/\}/))
break
end
end
node
end
end
class NumLiteralArgNode < ArgNode
attr_accessor :value
end
class NumEquivAddrArgNode < NumLiteralArgNode
end
def parse_num_literal(s)
if (m = s.scan(/(=?)#(-?(?:0x)?[0-9A-Fa-f]+)/))
(m[0] == '=' ? NumEquivAddrArgNode : NumLiteralArgNode).new(s) { |n|
n.value = Integer(m[1])
}
end
end
class LabelRefArgNode < ArgNode
attr_accessor :label, :label_object
end
class LabelEquivAddrArgNode < LabelRefArgNode
end
def parse_label_ref(s)
if (m = s.scan(/(=?)(\/*\w+)/))
(m[0] == '=' ? LabelEquivAddrArgNode : LabelRefArgNode).new(s) { |n|
n.label = m[1]
}
end
end
class ReferenceArgNode < ArgNode
attr_accessor :argument
end
def parse_reference(s)
if (m = s.scan(/\[/))
arg = parse_arg(s)
if (arg and s.scan(/\]/))
ReferenceArgNode.new(s) do |n|
n.argument = arg
end
end
end
end
end
end
if (__FILE__ == $0)