make elf symbols optional

and default to false. Smaller executables  by at least half
also add option for compiler cli
This commit is contained in:
Torsten Rüger 2019-09-03 02:02:21 +03:00
parent 160d860db2
commit 91995dc1b3
5 changed files with 21 additions and 115 deletions

View File

@ -7,7 +7,9 @@ require_relative 'string_table_section'
module Elf module Elf
class ObjectWriter class ObjectWriter
def initialize( linker ) attr_reader :text
def initialize( linker , options = {} )
@linker = linker @linker = linker
target = Elf::Constants::TARGET_ARM target = Elf::Constants::TARGET_ARM
@object = Elf::ObjectFile.new(target) @object = Elf::ObjectFile.new(target)
@ -22,7 +24,15 @@ module Elf
assembler = Risc::TextWriter.new(@linker) assembler = Risc::TextWriter.new(@linker)
set_text assembler.write_as_string set_text assembler.write_as_string
# for debug add labels for labels add_debug_symbols(options)
end
# for debug add labels for labels
def add_debug_symbols(options)
debug = options[:debug]
return unless debug
@linker.assemblers.each do |asm| @linker.assemblers.each do |asm|
meth = asm.callable meth = asm.callable
asm.instructions.each do |label| asm.instructions.each do |label|
@ -34,7 +44,6 @@ module Elf
add_symbol label , Risc::Position.get(code).at add_symbol label , Risc::Position.get(code).at
end end
end end
@linker.object_positions.each do |slot , position| @linker.object_positions.each do |slot , position|
next if slot.is_a?(Parfait::BinaryCode) next if slot.is_a?(Parfait::BinaryCode)
next if slot.class.name.include?("Arm") next if slot.class.name.include?("Arm")
@ -48,8 +57,6 @@ module Elf
end end
end end
attr_reader :text
def set_text(text) def set_text(text)
@text.text = text @text.text = text
add_symbol "_start", 0 add_symbol "_start", 0

View File

@ -5,6 +5,7 @@ require "risc/interpreter"
class RubyXC < Thor class RubyXC < Thor
class_option :integers , type: :numeric class_option :integers , type: :numeric
class_option :mesages , type: :numeric class_option :mesages , type: :numeric
class_option :elf , type: :boolean
desc "compile FILE" , "Compile given FILE to binary" desc "compile FILE" , "Compile given FILE to binary"
@ -27,11 +28,13 @@ class RubyXC < Thor
puts "compiling #{file}" puts "compiling #{file}"
linker = ::RubyX::RubyXCompiler.new(extract_options).ruby_to_binary( ruby , :arm ) linker = ::RubyX::RubyXCompiler.new(extract_options).ruby_to_binary( ruby , :arm )
writer = Elf::ObjectWriter.new(linker) elf = { debug: options[:elf] || false }
writer = Elf::ObjectWriter.new(linker , elf)
outfile = file.split("/").last.gsub(".rb" , ".o") outfile = file.split("/").last.gsub(".rb" , ".o")
writer.save outfile writer.save outfile
system "arm-linux-gnu-ld -N #{outfile}"
File.delete outfile
return outfile return outfile
end end
@ -92,16 +95,15 @@ class RubyXC < Thor
def execute(file) def execute(file)
outfile = compile(file) outfile = compile(file)
system "arm-linux-gnu-ld -N #{outfile}" puts "Running #{outfile}\n\n"
puts "Linked ok, now running #{outfile}" system "qemu-arm ./a.out ;echo $?"
system "qemu-arm ./a.out ; echo $?"
end end
private private
def extract_options def extract_options
opt = { Integer: options[:integers] || 1024 , opt = { Integer: options[:integers] || 1024 ,
Message: options[:messages] || 1024} Message: options[:messages] || 1024}
return {parfait: opt} return {parfait: opt }
end end
end end

View File

@ -1,47 +0,0 @@
require_relative 'helper'
require "yaml"
require "parslet/convenience"
class TestRunner < MiniTest::Test
# this creates test methods dynamically , one for each file in runners directory
def self.runnable_methods
methods = []
Dir[File.join(File.dirname(__FILE__) , "runners" , "*.rb")].each do |file|
meth = File.basename(file).split(".").first
name = "test_#{meth}"
methods << name
self.send(:define_method, name ) {
execute file
}
end
methods
end
def execute file
string = File.read(file)
parser = Parser::RubyX.new
object_space = Risc::Program.new "Arm"
#TODO : files would have to include s-expressions now
syntax = parser.parse_with_debug(string, reporter: Parslet::ErrorReporter::Deepest.new)
assert syntax
parts = Parser::Transform.new.apply(syntax)
# file is a list of statements, all but the last must be a function
# and the last is wrapped as a main
parts.each_with_index do |part,index|
if index == (parts.length - 1)
expr = part.compile( program.context )
else
expr = part.compile( program.context )
raise "should be function definition for now" unless expr.is_a? Risc::Function
end
end
#object writer takes machine
writer = Elf::ObjectWriter.new(program , Elf::Constants::TARGET_ARM)
writer.save(file.gsub(".rb" , ".o"))
# puts program.to_yaml
end
end

View File

@ -21,61 +21,5 @@ module Elf
writer = Elf::ObjectWriter.new(linker) writer = Elf::ObjectWriter.new(linker)
writer.save "test/#{file}.o" writer.save "test/#{file}.o"
end end
def check_remote(file)
check(file)
stdout , exit_code = run_ssh(file)
@stdout = "" unless @stdout
assert_equal @stdout , stdout
assert_equal @exit_code , exit_code
end
def run_ssh( file )
host = ENV["ARM_HOST"]
return unless host
port = (ENV["ARM_PORT"] || 2222)
user = (ENV["ARM_USER"] || "pi")
binary_file = "/tmp/#{file}"
object_file = binary_file + ".o"
Net::SCP.start(host, user , port: port ) do |scp|
puts "Copying test/#{file}.o to #{object_file}" if DEBUG
scp.upload! "test/#{file}.o", object_file
end
Net::SSH.start(host, user , port: port ) do |ssh|
puts "Linking #{object_file}" if DEBUG
stdout , exit_code = ssh_exec!(ssh , "ld -N -o #{binary_file} #{object_file}")
assert_equal 0 , exit_code , "Linking #{binary_file} failed"
puts "Running #{binary_file}" if DEBUG
stdout , exit_code = ssh_exec!(ssh , binary_file)
puts "Result #{stdout} #{exit_code}" if DEBUG
return stdout , exit_code
end
end
def ssh_exec!(ssh, command)
stdout_data = ""
exit_code = nil
ssh.open_channel do |channel|
channel.exec(command) do |ch, success|
unless success
raise "FAILED: couldn't execute command (ssh.channel.exec)"
end
channel.on_data do |c,data|
stdout_data+=data
end
channel.on_extended_data do |c,type,data|
raise "#{ssh} received stderr #{data}"
end
channel.on_request("exit-status") do |c,data|
exit_code = data.read_long
end
channel.on_request("exit-signal") do |c, data|
raise "#{ssh} received signal #{data.read_long}"
end
end
end
ssh.loop
[stdout_data, exit_code]
end
end end
end end

View File

@ -15,7 +15,7 @@ module RubyX
end end
def test_file_open def test_file_open
assert_output(/compiling/) {RubyXC.start(["compile" , "test/mains/source/add__4.rb"])} assert_output(/compiling/) {RubyXC.start(["compile" , "test/mains/source/add__4.rb"])}
File.delete "add__4.o" #File.delete "add__4.o"
end end
def test_interpret def test_interpret
assert_output(/interpreting/) {RubyXC.start(["interpret" , "test/mains/source/add__4.rb"])} assert_output(/interpreting/) {RubyXC.start(["interpret" , "test/mains/source/add__4.rb"])}