Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@
/*.s
/*.so
/.gem_rbs_collection
/node_modules
/package*.json
15 changes: 15 additions & 0 deletions lib/vaporware.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
# frozen_string_literal: true

require_relative "vaporware/version"

require_relative "vaporware/assembler"
require_relative "vaporware/compiler"
require_relative "vaporware/linker"

module Vaporware
module_function
def compile!(input:, assembler: "as", linker: "ld", output: "tmp", debug: false, compiler_options: ["-O0"], shared: false)
d = File.expand_path(output)
basename = "#{File.dirname(d)}/#{File.basename(d, ".*")}"
execf = "#{basename}#{File.extname(d)}"
compiler = Vaporware::Compiler.compile!(input:, output: basename + ".s", debug:, compiler_options:, shared:)
assembler = Vaporware::Assembler.assemble!(input: basename+".s", output: basename+".o", assembler:, debug:)
linker = Vaporware::Linker.link!(input: basename+".o", output: execf, linker:, debug:, shared:)
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
require_relative "assembler/elf/sections"
require_relative "assembler/elf/section_header"

class Vaporware::Compiler::Assembler
class Vaporware::Assembler
GCC_ASSEMBLERS = ["gcc", "as"]
CLANG_ASSEMBLERS = ["clang", "llvm"]
ASSEMBLERS = GCC_ASSEMBLERS + CLANG_ASSEMBLERS
class Error < StandardError; end

def self.assemble!(input, output = File.basename(input, ".*") + ".o", options = {}) = new(input:, output:, **options).assemble
def self.assemble!(input:, output: File.basename(input, ".*") + ".o", assembler: "as", debug: false) = new(input:, output:, assembler:, debug:).assemble

def initialize(input:, output: File.basename(input, ".*") + ".o", assembler: "as", type: :relocatable, debug: false)
@input, @output = input, output
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class Vaporware::Compiler::Assembler
class Vaporware::Assembler
class ELF
class Error < StandardError; end
class Section; end
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require_relative "../elf"

class Vaporware::Compiler::Assembler::ELF::Header
include Vaporware::Compiler::Assembler::ELF::Utils
class Vaporware::Assembler::ELF::Header
include Vaporware::Assembler::ELF::Utils
IDENT = [0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00].freeze
ELF_FILE_TYPE = { NONE: 0, REL: 1, EXEC: 2, DYN: 3, CORE: 4 }.freeze

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@
require_relative "section/shstrtab"
require_relative "section_header"

class Vaporware::Compiler::Assembler::ELF::Section
class Vaporware::Assembler::ELF::Section
attr_reader :header, :body, :name, :section_name
def initialize(type:, options: {})
type_string = type.to_s.capitalize
type_string = type_string.upcase if type_string == "Bss"
@section_name = type_string.downcase
@name = section_name == "null" ? "" : "\0.#{section_name}"
@header = Vaporware::Compiler::Assembler::ELF::SectionHeader.new.send("#{@section_name}!")
@body = Module.const_get("Vaporware::Compiler::Assembler::ELF::Section::#{type_string}").new(**options)
@header = Vaporware::Assembler::ELF::SectionHeader.new.send("#{@section_name}!")
@body = Module.const_get("Vaporware::Assembler::ELF::Section::#{type_string}").new(**options)
end

def name=(name)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class Vaporware::Compiler::Assembler::ELF::Section::BSS
include Vaporware::Compiler::Assembler::ELF::Utils
class Vaporware::Assembler::ELF::Section::BSS
include Vaporware::Assembler::ELF::Utils
def initialize(**opts) = nil
def build = bytes.flatten.pack("C*")
def set! = self
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class Vaporware::Compiler::Assembler::ELF::Section::Data
include Vaporware::Compiler::Assembler::ELF::Utils
class Vaporware::Assembler::ELF::Section::Data
include Vaporware::Assembler::ELF::Utils
def initialize(**opts) = nil
def build = bytes.flatten.pack("C*")
def set! = self
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class Vaporware::Compiler::Assembler::ELF::Section::Note
include Vaporware::Compiler::Assembler::ELF::Utils
class Vaporware::Assembler::ELF::Section::Note
include Vaporware::Assembler::ELF::Utils

def self.gnu_property = new.gnu_property!.build
def self.null = new.null!.build
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class Vaporware::Compiler::Assembler::ELF::Section::Null
include Vaporware::Compiler::Assembler::ELF::Utils
class Vaporware::Assembler::ELF::Section::Null
include Vaporware::Assembler::ELF::Utils
def initialize(**opts) = nil
def build = bytes.flatten.pack("C*")
def set! = self
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class Vaporware::Compiler::Assembler::ELF::Section::Shstrtab
include Vaporware::Compiler::Assembler::ELF::Utils
class Vaporware::Assembler::ELF::Section::Shstrtab
include Vaporware::Assembler::ELF::Utils
def initialize(**opts) = @name = []
def build = bytes.flatten.pack("C*")
def set!(name:) = (@name << name!(name); self)
Expand All @@ -11,12 +11,12 @@ def name!(name)
when String
(name.match(/\A\0\..+\z/) ? name : "\0.#{name}").bytes
when Array
raise Vaporware::Compiler::Assembler::ELF::Error, "unaccepted type in Array" unless name.all? { |elem| elem.is_a?(Integer) }
raise Vaporware::Assembler::ELF::Error, "unaccepted type in Array" unless name.all? { |elem| elem.is_a?(Integer) }
n = name
n.unshift(0) && n.push(0) unless n.first == 0 && n.last == 0
n
else
raise Vaporware::Compiler::Assembler::ELF::Error, "unsupported type"
raise Vaporware::Assembler::ELF::Error, "unsupported type"
end
end
end
5 changes: 5 additions & 0 deletions lib/vaporware/assembler/elf/section/strtab.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class Vaporware::Assembler::ELF::Section::Strtab
include Vaporware::Assembler::ELF::Utils
def initialize(names = "\0main\0", **opts) = @names = names
def build = @names.bytes.pack("C*")
end
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class Vaporware::Compiler::Assembler::ELF::Section::Symtab
include Vaporware::Compiler::Assembler::ELF::Utils
class Vaporware::Assembler::ELF::Section::Symtab
include Vaporware::Assembler::ELF::Utils
def initialize(**opts)
@entsize = []
@name = num2bytes(0, 4)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class Vaporware::Compiler::Assembler::ELF::Section::Text
class Vaporware::Assembler::ELF::Section::Text
PREFIX = {
REX_W: 0x48,
}.freeze
Expand Down Expand Up @@ -55,7 +55,7 @@ def opecode(op, *operands)
when "ret"
[0xc3]
else
raise Vaporware::Compiler::Assembler::ELF::Error, "yet implemented operations: #{op}"
raise Vaporware::Assembler::ELF::Error, "yet implemented operations: #{op}"
end
end

Expand Down Expand Up @@ -177,7 +177,7 @@ def reg(r)
when /\d+/
r.to_i(16)
else
raise Vaporware::Compiler::Assembler::ELF::Error, "yet implemented operand address: #{r}"
raise Vaporware::Assembler::ELF::Error, "yet implemented operand address: #{r}"
end
end
def immediate(operand) = [operand.to_i(16)].pack("L").unpack("C*")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class Vaporware::Compiler::Assembler::ELF::SectionHeader
include Vaporware::Compiler::Assembler::ELF::Utils
class Vaporware::Assembler::ELF::SectionHeader
include Vaporware::Assembler::ELF::Utils
def initialize
@name = nil
@type = nil
Expand Down
19 changes: 19 additions & 0 deletions lib/vaporware/assembler/elf/sections.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
require_relative "section"

class Vaporware::Assembler::ELF::Sections
ATTRIBUTES = %i|null text data bss note symtab strtab shstrtab|
attr_reader *ATTRIBUTES

def initialize
@null = Vaporware::Assembler::ELF::Section.new(type: :null)
@text = Vaporware::Assembler::ELF::Section.new(type: :text)
@data = Vaporware::Assembler::ELF::Section.new(type: :data)
@bss = Vaporware::Assembler::ELF::Section.new(type: :bss)
@note = Vaporware::Assembler::ELF::Section.new(type: :note, options: {type: :gnu})
@symtab = Vaporware::Assembler::ELF::Section.new(type: :symtab)
@strtab = Vaporware::Assembler::ELF::Section.new(type: :strtab)
@shstrtab = Vaporware::Assembler::ELF::Section.new(type: :shstrtab)
end

def each(&block) = ATTRIBUTES.each { |t| yield send(t) }
end
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
module Vaporware::Compiler::Assembler::ELF::Utils
module Vaporware::Assembler::ELF::Utils
def build = (build_errors; bytes.flatten.pack("C*"))
def size = build.bytesize
def set! = (raise Vaporware::Compiler::Assembler::ELF::Error, "should be implementing #{self.class}")
def set! = (raise Vaporware::Assembler::ELF::Error, "should be implementing #{self.class}")
def empties = must_be_filled_section_fields

private
def align(val, bytes)
val << 0 until val.size % bytes == 0
val
end
def bytes = (raise Vaporware::Compiler::Assembler::ELF::Error, "should be implementing #{self.class}")
def bytes = (raise Vaporware::Assembler::ELF::Error, "should be implementing #{self.class}")
def must_be_filled_section_fields = instance_variables.reject { |i| instance_variable_get(i) }
def num2bytes(val, bytes) = hexas(val, bytes).reverse
def check(val, bytes) = ((val.is_a?(Array) && val.all? { |v| v.is_a?(Integer) } && val.size == bytes) || (val.is_a?(Integer) && (hexas(val, bytes).size == bytes)))
Expand All @@ -18,6 +18,6 @@ def build_errors
return unless bytes.any?(&:nil?)
errors = []
bytes.each_with_index { |v, idx| errors << instance_variables[idx] if v.nil? }
raise Vaporware::Compiler::Assembler::ELF::Error, "unaccepted types: #{errors.join(",")}"
raise Vaporware::Assembler::ELF::Error, "unaccepted types: #{errors.join(",")}"
end
end
17 changes: 4 additions & 13 deletions lib/vaporware/compiler.rb
Original file line number Diff line number Diff line change
@@ -1,26 +1,17 @@
# frozen_string_literal: true

require_relative "compiler/generator"
require_relative "compiler/assembler"
require_relative "compiler/linker"

class Vaporware::Compiler
attr_reader *%i(generator assembler linker)

def self.compile(source, assembler: "as", linker: "ld", dest: "tmp", debug: false, compiler_options: ["-O0"], shared: false)
compiler = new(input: source, output: dest, debug:, shared:, linker:, assembler:)
def self.compile!(input:, output: "tmp.s", debug: false, compiler_options: ["-O0"], shared: false)
compiler = new(input:, output:, debug:, shared:,)
compiler.compile(compiler_options:)
compiler.assemble(input: dest.to_s + ".s", assembler:, debug:)
compiler.link
end

def initialize(input:, output: File.basename(input, ".*"), linker: "ld", assembler: "as", debug: false, shared: false)
@generator = Vaporware::Compiler::Generator.new(input:, output: output + ".s", debug:, shared:)
@assembler = Vaporware::Compiler::Assembler.new(input: @generator.precompile, output: output + ".o", assembler:, debug:)
@linker = Vaporware::Compiler::Linker.new(input: @assembler.obj_file, output:, linker:, debug:, shared:)
def initialize(input:, output:, debug: false, shared: false)
@generator = Vaporware::Compiler::Generator.new(input:, output:, debug:, shared:)
end

def assemble(input:, output: File.basename(input, ".*") + ".o", assembler: "as", assembler_options: [], debug: false) = @assembler.assemble(input:, output:, assembler:, assembler_options:, debug:)
def link = @linker.link
def compile(compiler_options: ["-O0"]) = @generator.compile
end
5 changes: 0 additions & 5 deletions lib/vaporware/compiler/assembler/elf/section/strtab.rb

This file was deleted.

19 changes: 0 additions & 19 deletions lib/vaporware/compiler/assembler/elf/sections.rb

This file was deleted.

4 changes: 2 additions & 2 deletions lib/vaporware/compiler/linker.rb → lib/vaporware/linker.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true
class Vaporware::Compiler::Linker
def self.link!(source, dest = "a.out", linker: "mold", options: []) = new(input: source, output: dest, linker:, options:).link
class Vaporware::Linker
def self.link!(input:, output: "a.out", linker: "mold", debug: false, shared: false) = new(input:, output:, linker:, debug:, shared:).link

def initialize(input:, output: "a.out", linker: "mold", linker_options: [], shared: false, debug: false)
@input, @output, @linker = input, output, linker
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use Vaporware::Compiler::Assembler::ELF
class Vaporware::Compiler::Assembler
use Vaporware::Assembler::ELF
class Vaporware::Assembler
@input: String
@output: String
@assembler: String
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use Vaporware::Compiler::Assembler::ELF::Header
use Vaporware::Compiler::Assembler::ELF::Section::Text
use Vaporware::Compiler::Assembler::ELF::Sections
use Vaporware::Assembler::ELF::Header
use Vaporware::Assembler::ELF::Section::Text
use Vaporware::Assembler::ELF::Sections

class Vaporware::Compiler::Assembler::ELF
class Vaporware::Assembler::ELF
Error: singleton(StandardError)

@input: String
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class Vaporware::Compiler::Assembler::ELF::Header
class Vaporware::Assembler::ELF::Header
IDENT: Array[Integer]
ELF_FILE_TYPE: Hash[Symbol, Integer]

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use Vaporware::Compiler::Assembler::ELF::SectionHeader
use Vaporware::Compiler::Assembler::ELF::Section::*
use Vaporware::Assembler::ELF::SectionHeader
use Vaporware::Assembler::ELF::Section::*

class Vaporware::Compiler::Assembler::ELF::Section
class Vaporware::Assembler::ELF::Section
attr_reader name: String
attr_reader header: SectionHeader
attr_reader body: Text | Null | Data | BSS | Symtab | Shstrtab | Strtab | Note
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class Vaporware::Compiler::Assembler::ELF::Section::BSS
class Vaporware::Assembler::ELF::Section::BSS
attr_reader size: Integer
attr_reader offset: Integer

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class Vaporware::Compiler::Assembler::ELF::Section::Data
class Vaporware::Assembler::ELF::Section::Data
PREFIX: Hash[Symbol, Integer]
REGISTER_CODE: Hash[Symbol, Integer]
OPECODE: Hash[Symbol, Integer]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class Vaporware::Compiler::Assembler::ELF::Section::Note
class Vaporware::Assembler::ELF::Section::Note
def self.gnu_property: () -> String

@nsize: Array[Integer]?
Expand Down
2 changes: 2 additions & 0 deletions sig/vaporware/assembler/elf/section/null.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class Vaporware::Assembler::ELF::Section::Null
end
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class Vaporware::Compiler::Assembler::ELF::Section::Shstrtab
class Vaporware::Assembler::ELF::Section::Shstrtab
@strtab: Array[Integer]
def initialize: () -> void
def build: () -> String
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class Vaporware::Compiler::Assembler::ELF::Section::Strtab
class Vaporware::Assembler::ELF::Section::Strtab
@name: String
def initialize: (String) -> void
def build: () -> String
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class Vaporware::Compiler::Assembler::ELF::Section::Symtab
class Vaporware::Assembler::ELF::Section::Symtab
@name: Array[Integer]?
@info: Array[Integer]
@other: Array[Integer]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class Vaporware::Compiler::Assembler::ELF::Section::Text
class Vaporware::Assembler::ELF::Section::Text
PREFIX: Hash[Symbol, Integer]
REGISTER_CODE: Hash[Symbol, Integer]
OPECODE: Hash[Symbol, Array[Integer]]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use Vaporware::Compiler::Assembler::ELF
use Vaporware::Assembler::ELF

class Vaporware::Compiler::Assembler::ELF::SectionHeader
class Vaporware::Assembler::ELF::SectionHeader
@name: Array[Integer]?
@type: Array[Integer]?
@flags: Array[Integer]?
Expand All @@ -13,7 +13,7 @@ class Vaporware::Compiler::Assembler::ELF::SectionHeader
@entsize: Array[Integer]?

def build: () -> String
def set!: (?name: Integer?, ?type: Integer?, ?flags: Integer?, ?addr: Integer?, ?offset: Integer?, ?size: Integer?, ?link: Integer?, ?info: Integer?, ?addralign: Integer?, ?entsize: Integer?) -> Vaporware::Compiler::Assembler::ELF::SectionHeader
def set!: (?name: Integer?, ?type: Integer?, ?flags: Integer?, ?addr: Integer?, ?offset: Integer?, ?size: Integer?, ?link: Integer?, ?info: Integer?, ?addralign: Integer?, ?entsize: Integer?) -> Vaporware::Assembler::ELF::SectionHeader
def null!: () -> ELF::SectionHeader
def text!: () -> ELF::SectionHeader
def note!: () -> ELF::SectionHeader
Expand Down
Loading