renamed code generator to arm assembler (more appropriate)
This commit is contained in:
parent
7478b65fb0
commit
fc81122bc4
@ -1,8 +1,104 @@
|
|||||||
require 'asm/assembler'
|
require 'asm/assembler'
|
||||||
require "asm/arm/addr_table_object"
|
require "asm/arm/addr_table_object"
|
||||||
|
require 'asm/arm/arm_assembler'
|
||||||
|
require 'asm/arm/instruction'
|
||||||
|
require 'asm/arm/generator_label'
|
||||||
|
require 'asm/nodes'
|
||||||
|
require 'stream_reader'
|
||||||
|
require 'stringio'
|
||||||
|
require "asm/data_object"
|
||||||
|
|
||||||
module Asm
|
module Asm
|
||||||
module Arm
|
module Arm
|
||||||
|
|
||||||
|
class ArmAssembler < Asm::Assembler
|
||||||
|
|
||||||
|
def add_data(str)
|
||||||
|
add_object Asm::DataObject.new(str)
|
||||||
|
end
|
||||||
|
|
||||||
|
%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) {
|
||||||
|
[:reg, reg]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def instruction(name, *args)
|
||||||
|
node = Asm::InstructionNode.new
|
||||||
|
node.opcode = name.to_s
|
||||||
|
node.args = []
|
||||||
|
|
||||||
|
args.each { |arg|
|
||||||
|
if (arg.is_a?(Array))
|
||||||
|
if (arg[0] == :reg)
|
||||||
|
node.args << Asm::RegisterNode.new(arg[1])
|
||||||
|
end
|
||||||
|
elsif (arg.is_a?(Integer))
|
||||||
|
node.args << Asm::NumLiteralNode.new(arg)
|
||||||
|
elsif (arg.is_a?(Symbol))
|
||||||
|
node.args << Asm::LabelRefNode.new(arg.to_s)
|
||||||
|
elsif (arg.is_a?(Asm::Arm::GeneratorLabel) or arg.is_a?(Asm::Arm::GeneratorExternLabel))
|
||||||
|
node.args << arg
|
||||||
|
else
|
||||||
|
raise 'Invalid argument `%s\' for instruction' % arg.inspect
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
add_object Asm::Arm::Instruction.new(node)
|
||||||
|
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 label
|
||||||
|
Asm::Arm::GeneratorLabel.new(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
def label!
|
||||||
|
lbl = Asm::Arm::GeneratorLabel.new(self)
|
||||||
|
lbl.set!
|
||||||
|
lbl
|
||||||
|
end
|
||||||
|
|
||||||
|
#externs dropped for now
|
||||||
|
def extern(sym)
|
||||||
|
if (lbl = @externs.find { |extern| extern.name == sym })
|
||||||
|
lbl
|
||||||
|
else
|
||||||
|
@externs << lbl = Asm::Arm::GeneratorExternLabel.new(sym)
|
||||||
|
add_object lbl
|
||||||
|
lbl
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def assemble_to_string
|
||||||
|
io = StringIO.new
|
||||||
|
assemble(io)
|
||||||
|
io.string
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
# Relocation constants
|
# Relocation constants
|
||||||
# Note that in this assembler, a relocation simply means any
|
# Note that in this assembler, a relocation simply means any
|
||||||
# reference to a label that can only be determined at assembly time
|
# reference to a label that can only be determined at assembly time
|
||||||
|
@ -1,102 +0,0 @@
|
|||||||
require 'asm/arm/arm_assembler'
|
|
||||||
require 'asm/arm/instruction'
|
|
||||||
require_relative 'generator_label'
|
|
||||||
require 'asm/nodes'
|
|
||||||
require 'stream_reader'
|
|
||||||
require 'stringio'
|
|
||||||
require "asm/data_object"
|
|
||||||
|
|
||||||
class Asm::Arm::CodeGenerator
|
|
||||||
def initialize
|
|
||||||
@asm = Asm::Assembler.new
|
|
||||||
# @externs = []
|
|
||||||
end
|
|
||||||
|
|
||||||
def data(str)
|
|
||||||
@asm.add_object Asm::DataObject.new(str)
|
|
||||||
end
|
|
||||||
|
|
||||||
%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) {
|
|
||||||
[:reg, reg]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def instruction(name, *args)
|
|
||||||
node = Asm::InstructionNode.new
|
|
||||||
node.opcode = name.to_s
|
|
||||||
node.args = []
|
|
||||||
|
|
||||||
args.each { |arg|
|
|
||||||
if (arg.is_a?(Array))
|
|
||||||
if (arg[0] == :reg)
|
|
||||||
node.args << Asm::RegisterNode.new(arg[1])
|
|
||||||
end
|
|
||||||
elsif (arg.is_a?(Integer))
|
|
||||||
node.args << Asm::NumLiteralNode.new(arg)
|
|
||||||
elsif (arg.is_a?(Symbol))
|
|
||||||
node.args << Asm::LabelRefNode.new(arg.to_s)
|
|
||||||
elsif (arg.is_a?(Asm::Arm::GeneratorLabel) or arg.is_a?(Asm::Arm::GeneratorExternLabel))
|
|
||||||
node.args << arg
|
|
||||||
else
|
|
||||||
raise 'Invalid argument `%s\' for instruction' % arg.inspect
|
|
||||||
end
|
|
||||||
}
|
|
||||||
|
|
||||||
@asm.add_object Asm::Arm::Instruction.new(node)
|
|
||||||
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 label
|
|
||||||
Asm::Arm::GeneratorLabel.new(@asm)
|
|
||||||
end
|
|
||||||
|
|
||||||
def label!
|
|
||||||
lbl = Asm::Arm::GeneratorLabel.new(@asm)
|
|
||||||
lbl.set!
|
|
||||||
lbl
|
|
||||||
end
|
|
||||||
|
|
||||||
#externs dropped for now
|
|
||||||
def extern(sym)
|
|
||||||
if (lbl = @externs.find { |extern| extern.name == sym })
|
|
||||||
lbl
|
|
||||||
else
|
|
||||||
@externs << lbl = Asm::Arm::GeneratorExternLabel.new(sym)
|
|
||||||
@asm.add_object lbl
|
|
||||||
lbl
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def assemble
|
|
||||||
io = StringIO.new
|
|
||||||
@asm.assemble(io)
|
|
||||||
io.string
|
|
||||||
end
|
|
||||||
|
|
||||||
def relocations
|
|
||||||
@asm.relocations
|
|
||||||
end
|
|
||||||
end
|
|
@ -74,7 +74,7 @@ module Asm
|
|||||||
:vs => 0b0110
|
:vs => 0b0110
|
||||||
}
|
}
|
||||||
|
|
||||||
RelocHandler = Asm::Arm.method(:write_resolved_relocation)
|
RelocHandler = nil # Asm::Arm.method(:write_resolved_relocation)
|
||||||
|
|
||||||
def assemble(io, as)
|
def assemble(io, as)
|
||||||
s = @s ? 1 : 0
|
s = @s ? 1 : 0
|
||||||
|
@ -30,4 +30,4 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'test'))
|
|||||||
|
|
||||||
require 'crystal'
|
require 'crystal'
|
||||||
require 'asm/object_writer'
|
require 'asm/object_writer'
|
||||||
require "asm/arm/code_generator"
|
require "asm/arm/arm_assembler"
|
||||||
|
@ -5,7 +5,7 @@ require_relative 'helper'
|
|||||||
class TestExtern < MiniTest::Test
|
class TestExtern < MiniTest::Test
|
||||||
# need a code generator, for arm
|
# need a code generator, for arm
|
||||||
def setup
|
def setup
|
||||||
@generator = Asm::Arm::CodeGenerator.new
|
@generator = Asm::Arm::ArmAssembler.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_extern
|
def test_extern
|
||||||
@ -24,7 +24,7 @@ class TestExtern < MiniTest::Test
|
|||||||
#helper to write the file
|
#helper to write the file
|
||||||
def write len ,name
|
def write len ,name
|
||||||
writer = Asm::ObjectWriter.new(Elf::Constants::TARGET_ARM)
|
writer = Asm::ObjectWriter.new(Elf::Constants::TARGET_ARM)
|
||||||
assembly = @generator.assemble
|
assembly = @generator.assemble_to_string
|
||||||
assert_equal len * 4 , assembly.length
|
assert_equal len * 4 , assembly.length
|
||||||
writer.set_text assembly
|
writer.set_text assembly
|
||||||
writer.save("#{name}_test.o")
|
writer.save("#{name}_test.o")
|
||||||
|
@ -9,7 +9,7 @@ require_relative 'helper'
|
|||||||
class TestSmallProg < MiniTest::Test
|
class TestSmallProg < MiniTest::Test
|
||||||
# need a code generator, for arm
|
# need a code generator, for arm
|
||||||
def setup
|
def setup
|
||||||
@generator = Asm::Arm::CodeGenerator.new
|
@generator = Asm::Arm::ArmAssembler.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_generate_small
|
def test_generate_small
|
||||||
@ -45,7 +45,7 @@ class TestSmallProg < MiniTest::Test
|
|||||||
#helper to write the file
|
#helper to write the file
|
||||||
def write len ,name
|
def write len ,name
|
||||||
writer = Asm::ObjectWriter.new(Elf::Constants::TARGET_ARM)
|
writer = Asm::ObjectWriter.new(Elf::Constants::TARGET_ARM)
|
||||||
assembly = @generator.assemble
|
assembly = @generator.assemble_to_string
|
||||||
assert_equal len * 4 , assembly.length
|
assert_equal len * 4 , assembly.length
|
||||||
writer.set_text assembly
|
writer.set_text assembly
|
||||||
writer.save("#{name}_test.o")
|
writer.save("#{name}_test.o")
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
require_relative 'helper'
|
require_relative 'helper'
|
||||||
require "asm/arm/code_generator"
|
require "asm/arm/arm_assembler"
|
||||||
|
|
||||||
# try to test that the generation of basic instructions works
|
# try to test that the generation of basic instructions works
|
||||||
# one instruction at a time, reverse testing from objdump --demangle -Sfghxp
|
# one instruction at a time, reverse testing from objdump --demangle -Sfghxp
|
||||||
@ -9,7 +9,7 @@ require "asm/arm/code_generator"
|
|||||||
class TestArmAsm < MiniTest::Test
|
class TestArmAsm < MiniTest::Test
|
||||||
# need a code generator, for arm
|
# need a code generator, for arm
|
||||||
def setup
|
def setup
|
||||||
@generator = Asm::Arm::CodeGenerator.new
|
@generator = Asm::Arm::ArmAssembler.new
|
||||||
end
|
end
|
||||||
|
|
||||||
# code is what the generator spits out, at least one instruction worth (.first)
|
# code is what the generator spits out, at least one instruction worth (.first)
|
||||||
@ -17,7 +17,7 @@ class TestArmAsm < MiniTest::Test
|
|||||||
# is reversed and in 4 bytes as ruby can only do 31 bits and so we can't test with just one int (?)
|
# is reversed and in 4 bytes as ruby can only do 31 bits and so we can't test with just one int (?)
|
||||||
def assert_code code , op , should
|
def assert_code code , op , should
|
||||||
assert_equal op , code.opcode
|
assert_equal op , code.opcode
|
||||||
binary = @generator.assemble
|
binary = @generator.assemble_to_string
|
||||||
assert_equal 4 , binary.length
|
assert_equal 4 , binary.length
|
||||||
index = 0
|
index = 0
|
||||||
binary.each_byte do |byte |
|
binary.each_byte do |byte |
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
require "asm/arm/code_generator"
|
require "asm/arm/code_generator"
|
||||||
|
|
||||||
if (__FILE__ == $0)
|
if (__FILE__ == $0)
|
||||||
gen = Asm::Arm::CodeGenerator.new
|
gen = Asm::Arm::ArmAssembler.new
|
||||||
|
|
||||||
gen.instance_eval {
|
gen.instance_eval {
|
||||||
mov r0, 5
|
mov r0, 5
|
||||||
@ -13,10 +13,10 @@ if (__FILE__ == $0)
|
|||||||
swi 0
|
swi 0
|
||||||
}
|
}
|
||||||
|
|
||||||
gen.data("printf"+ "\x00")
|
gen.add_data("printf"+ "\x00")
|
||||||
require 'asm/object_writer'
|
require 'asm/object_writer'
|
||||||
writer = Asm::ObjectWriter.new(Elf::Constants::TARGET_ARM)
|
writer = Asm::ObjectWriter.new(Elf::Constants::TARGET_ARM)
|
||||||
writer.set_text gen.assemble
|
writer.set_text gen.assemble_to_string
|
||||||
|
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
Loading…
Reference in New Issue
Block a user