Skip to content

Commit

Permalink
assemble class for assembling
Browse files Browse the repository at this point in the history
  • Loading branch information
katsyoshi committed Aug 13, 2023
1 parent e0c1cb4 commit 75bea27
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 11 deletions.
18 changes: 18 additions & 0 deletions lib/vaporware/compiler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,30 @@ def self.compile(source, compiler: "gcc", dest: "tmp", debug: false, compiler_op
_precompile = "#{dest}.s"
s = new(source, _precompile: _precompile, debug:, shared:)
s.compile(compiler:, compiler_options:)
obj = s.assemble(input: _precompile, compmiler:, compiler_options:, debug:)
s.link(input: obj,link_options:)
end

def initialize(source, _precompile: "tmp.s", debug: false, shared: false)
@generator = Vaporware::Compiler::Generator.new(source, precompile: _precompile, debug:, shared:)
end

def assemble(input: precompile, output: File.basename(precompile, ".*") + ".o", compiler: "gcc", compiler_options: ["-O0"], debug: false)
base_name = File.basename(input, ".*")
name = shared ? "lib#{base_name}.so" : base_name
if compiler == "gcc"
compile_commands = [compiler, *compiler_options, "-o", name, input].compact
call_compiler(compile_commands)
else
Vaporware::Compiler::Assemble.assemble!(input, name)
end

File.delete(input) unless debug
nil
end

def call_compiler(compile_commands) = IO.popen(compile_commands).close

def compile(compiler: "gcc", compiler_options: ["-O0"])
@generator.register_var_and_method(@generator.ast)

Expand Down
144 changes: 135 additions & 9 deletions lib/vaporware/compiler/assemble.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,143 @@
# frozen_string_literal: true

module Vaporware
class Compiler::Assemble
attr_reader :input, :output
def self.compile!(input, output = File.basename(input, ".*")) = new(input, output).compile
class Compiler
class Assemble
EXEC_ELF_HEADER = %w(
7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
01 00 3e 00 01 00 00 00 b0 00 40 00 00 00 00 00
40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 40 00 38 00 00 00 40 00 00 00 00 00
).map { _1.to_i(16) }.pack("C*")

def initialize(input, output = File.basename(input, ".*"))
@input, @output = input, output
@target_file = File.open(output, "wb")
end
PREFIX = {
REX_W: 0x48,
}

REGISTER_CODE = {
RAX: 0,
RDI: 7,
}

OPECODE = {
ADD: 0x01,
CQO: 0x99,
IDIV: 0xf7,
IMUL: 0x0f,
MOV: 0x89,
SUB: 0x83,
}.freeze

attr_reader :input, :output
def self.assemble!(input, output = File.basename(input, ".*")) = new(input, output).assemble

def initialize(input, output = File.basename(input, ".*") + ".o")
@input, @output = input, output
@target_file = File.open(output, "wb")
end

def assemble(assemble_command: "as", assemble_options: [], input: @input, f: @target_file)
read = { main: false }
opecodes = []
l = 0
File.open(input, "r") do |r|
r.each_line do |line|
read[:main] = /main:/.match(line) unless read[:main]
next unless read[:main] && !/main:/.match(line)
op, *args = line.split(/\s+/).reject{ _1 == "" }.map { _1.gsub(/,/, "") }
puts "% 10x: %s\t%s\t%s" % [l, opecode(op, args).map{ "%02x" % _1 }.join(" ").ljust(25), op, args.join(", ")]
opecodes << opecode(op, args).pack("C*")
l+=opecodes.last.bytesize
end
end
f.write(EXEC_ELF_HEADER)
# f.write(ELF_PROGRAM_HEADER)
opecodes.each { f.write(_1) }
f.close
f.path
end

private

def opecode(op, args)
case op
when "push"
push(args)
when "mov"
[PREFIX[:REX_W], *mov(op, *args)]
when "sub", "add", "imul", "cqo", "idiv"
[PREFIX[:REX_W], *calc(op, *args)]
when "pop"
pop(args)
when "ret"
[0xc3]
end
end

def mov(op, *arguments)
reg = case arguments
in ["rbp", "rsp"]
[0xe5]
in ["rsp", "rbp"]
[0xec]
else
arguments&.map { reg(_1) }
end
[OPECODE[op.upcase.to_sym], *reg]
end

def calc(op, *arguments)
ope_code = OPECODE[op.upcase.to_sym]
case [op, *arguments]
in ["sub", "rax", "rdi"]
[0x29, 0xf8]
in ["add", "rax", "rdi"]
[ope_code, 0xf8]
in ["imul", "rax", "rdi"]
[ope_code, 0xaf, 0xc7]
in ["idiv", "rdi"]
[ope_code, 0xff]
in ["sub", "rsp", *num]
[ope_code, 0xec, *num.map { |n| n.to_i(16) }]
in ["cqo"]
[0x99]
end
end

def push(args)
case args
in ["rbp"] | ["rdi"]
[0x55]
in ["rax"]
[0x50]
else
[0x6a, *args.map { reg(_1) }]
end
end

def pop(args)
case args
in ["rax"] | ["rdi"]
[0x58 + REGISTER_CODE[args.first.upcase.to_sym]]
in ["rbp"]
[0x5d]
end
end

def compile(compile_options = [])
self
def reg(r)
case r
in "rsp"
0xec
in "rbp"
0x5e
in "rax"
0x29
in "rdi"
0xf8
in /\d+/
("%02x" % r).to_i(16)
end
end
end
end
end
2 changes: 1 addition & 1 deletion lib/vaporware/compiler/generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def to_elf(input: precompile, compiler: "gcc", compiler_options: ["-O0"], debug:
base_name = File.basename(input, ".*")
name = shared ? "lib#{base_name}.so" : base_name
if compiler.nil?
Vaporware::Compiler::Assemble.compile!(name, input)
Vaporware::Compiler::Assemble.assemble!(name, input)
else
compile_commands = [compiler, *compiler_options, "-o", name, input].compact
call_compiler(compile_commands)
Expand Down
2 changes: 2 additions & 0 deletions sig/vaporware/compiler.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ class Vaporware::Compiler

@generator: Vaporware::Compiler::Generator
# instance methods
def assemble: (?output: String, ?compiler: String, ?compiler_options: Array[String]) -> void
def link: (?output: String, ?linker: String, ?linker_options: Array[String]) -> void
def compile: (?compiler: String, ?compiler_options: Array[String]) -> void
end

9 changes: 9 additions & 0 deletions sig/vaporware/compiler/assemble.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class Vaporware::Compiler::Assemble
attr_reader input: String
attr_reader output: String

@target_file: File

def initialize: (String, String) -> void
def compile: (?compiler_options: Array[String]) -> void
end
1 change: 0 additions & 1 deletion sig/vaporware/compiler/generator.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ class Vaporware::Compiler::Generator

# instance private methods
def already_build_methods?: -> bool
def call_compiler: (?output: String, ?compiler: String, ?compiler_options: Array[String]) -> void
def call_method: (RubyVM::AbstractSyntaxTree::Node, File, bool) -> void
def comp: (String, File) -> void
def compile_shared_option: () -> Array[String]
Expand Down

0 comments on commit 75bea27

Please sign in to comment.