Skip to content

Commit

Permalink
replace utils for common methods
Browse files Browse the repository at this point in the history
  • Loading branch information
katsyoshi committed Sep 23, 2023
1 parent 71abafa commit 3294c24
Show file tree
Hide file tree
Showing 16 changed files with 104 additions and 60 deletions.
41 changes: 27 additions & 14 deletions lib/vaporware/compiler/assembler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def initialize(input:, output: File.basename(input, ".*") + ".o", assembler: "as
@input, @output = input, output
@elf_header = ELF::Header.new(type:)
@assembler = assembler
@sections = Vaporware::Compiler::Assembler::ELF::Sections.new
@sections = ELF::Sections.new
@debug = debug
end

Expand All @@ -26,26 +26,39 @@ def assemble(assembler: @assembler, assembler_options: [], input: @input, output
def obj_file = @output

def to_elf(input: @input, output: @output, debug: false)
program_size = 0
read(input:)
header = @elf_header.build

offset = 0
section_headers = []
name = []
bins = []
@sections.each do |section|
name << section.name
bin = section.body.build
size = bin.bytesize
offset += size
section.body.align(bin, 8)
bins << bin
header = section.header
header.set!(offset:)
section_headers << header.build
end
f = File.open(output, "wb")
ensure
f.close
f.path
end

def read(input: @input)
read = { main: false }
program_size = 0
text = @sections[:text][:body]
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)
text.assemble!(line)
@sections.text.assemble!(line)
end
end
f.write(@elf_header.build)
bins = []
section_headers = []
@sections.values.map do |section|
bins << section[:body].build
section_headers << section[:header].build
end

f.close
f.path
end
end
3 changes: 3 additions & 0 deletions lib/vaporware/compiler/assembler/elf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ class Compiler
class Assembler
class ELF
class ERROR < StandardError; end
class Section; end
class SectionHeader; end
module Utils; end
end
end
end
Expand Down
13 changes: 7 additions & 6 deletions lib/vaporware/compiler/assembler/elf/section.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@
require_relative "section/bss"
require_relative "section/data"
require_relative "section/note"
require_relative "section/null"
require_relative "section/symtab"
require_relative "section/strtab"
require_relative "section/shsymtab"
require_relative "section/shstrtab"
require_relative "section_headers"
require_relative "section_header"

class Vaporware::Compiler::Assembler::ELF::Section
attr_reader :header, :body, :name
def initialize(type:)
type_string = type.to_s.capitalize
type_string = type_string.upcase if type_string == "Bss"
@header = Vaporware::Compiler::Assembler::ELF::SectionHeader.new.send("#{type_string.downcase}!")
base = "Vaporware::Compiler::Assembler::ELF::Section"
eval_string = type_string == "Null" ? "#{base}.new" : "#{base}::#{type_string}.new"
@body = eval(eval_string)
section_name = type_string.downcase
@name = "\0.#{section_name}\0"
@header = Vaporware::Compiler::Assembler::ELF::SectionHeader.new.send("#{section_name}!")
@body = Module.const_get("Vaporware::Compiler::Assembler::ELF::Section::#{type_string}").new
end
end
9 changes: 4 additions & 5 deletions lib/vaporware/compiler/assembler/elf/section/bss.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
class Vaporware::Compiler::Assembler::ELF::Section::BSS
def initialize
end
include Vaporware::Compiler::Assembler::ELF::Utils
def initialize = nil
def build = bytes.flatten.pack("C*")
def set!()
self
end
def set! = self

private
def bytes = []
def check(val, bytes) = false
Expand Down
4 changes: 3 additions & 1 deletion lib/vaporware/compiler/assembler/elf/section/data.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
class Vaporware::Compiler::Assembler::ELF::Section::Data

include Vaporware::Compiler::Assembler::ELF::Utils
def initialize = nil
def build = bytes.flatten.pack("C*")
def set! = self
private
def bytes = []
end
11 changes: 4 additions & 7 deletions lib/vaporware/compiler/assembler/elf/section/note.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
class Vaporware::Compiler::Assembler::ELF::Section::Note
include Vaporware::Compiler::Assembler::ELF::Utils
def self.gnu_property
note = new
note.gnu_property!
note.build
end

def initialize
@nsize = nil
@dsize = nil
Expand All @@ -22,14 +24,9 @@ def set!(nsize: nil, dsize: nil, type: nil, name: nil, desc: nil)

def gnu_property! = set!(nsize: 0x04, dsize: 0x20, type: 0x05, name: "GNU", desc: %w(02 00 01 c0 04 00 00 00 00 00 00 00 00 00 00 00 01 00 01 c0 04 00 00 00 01 00 00 00 00 00 00 00).map { |val| val.to_i(16) })

def build = bytes.flatten.pack("C*")

private
def name!(name) = align!(@name = name.bytes, 4)
def desc!(desc) = align!(@desc = desc.is_a?(Array) ? desc : desc.bytes, 4)

def name!(name) = align(@name = name.bytes, 4)
def desc!(desc) = align(@desc = desc.is_a?(Array) ? desc : desc.bytes, 4)
def bytes = [@nsize, @dsize, @type, @name, @desc]
def align!(val, bytes) = (val << 0 until val.size % bytes == 0)
def num2bytes(val, bytes) = ("%0#{bytes}x" % val).scan(/.{1,2}/).map { |v| v.to_i(16) }.reverse
def check(val, bytes) = (val.is_a?(Array) && val.all? { |v| v.is_a?(Integer) } && val.size == bytes) || val.is_a?(Integer)
end
7 changes: 7 additions & 0 deletions lib/vaporware/compiler/assembler/elf/section/null.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class Vaporware::Compiler::Assembler::ELF::Section::Null
include Vaporware::Compiler::Assembler::ELF::Utils
def initialize = nil
def build = bytes.flatten.pack("C*")
def set! = self
private def bytes = []
end
8 changes: 5 additions & 3 deletions lib/vaporware/compiler/assembler/elf/section/shstrtab.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
class Vaporware::Compiler::Assembler::ELF::Section::Strtab

class Vaporware::Compiler::Assembler::ELF::Section::Shstrtab
include Vaporware::Compiler::Assembler::ELF::Utils
def initialize = @strtab = []
def build = bytes.flatten.pack("C*")
def set!(name:) = @strtab << name
private
def bytes = []
def bytes = [@strtab]
end
1 change: 1 addition & 0 deletions lib/vaporware/compiler/assembler/elf/section/strtab.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
class Vaporware::Compiler::Assembler::ELF::Section::Strtab
include Vaporware::Compiler::Assembler::ELF::Utils
def initialize(names = "\0main\0") = @names = names
def build = @names.bytes.pack("C*")
end
6 changes: 1 addition & 5 deletions lib/vaporware/compiler/assembler/elf/section/symtab.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
class Vaporware::Compiler::Assembler::ELF::Section::Symtab
include Vaporware::Compiler::Assembler::ELF::Utils
def initialize(name: 0, info: 0, other: 0, shndx: 0, value: 0, size: 0)
@name = num2bytes(name, 4)
@info = num2bytes(info, 1)
Expand All @@ -18,9 +19,4 @@ def set!(name: nil, info: nil, other: nil, shndx: nil, value: nil, size: nil)
@value = num2bytes(value, 8) if check(value, 8)
@size = num2bytes(size, 8) if check(size, 8)
end

private
def bytes = [@name, @info, @other, @shndx, @value, @size]
def num2bytes(val, bytes) = ("%0#{bytes}x" % val).scan(/.{1,2}/).map { |v| v.to_i(16) }.reverse
def check(val, bytes) = (val.is_a?(Array) && val.all? { |v| v.is_a?(Integer) } && val.size == bytes) || val.is_a?(Integer)
end
15 changes: 4 additions & 11 deletions lib/vaporware/compiler/assembler/elf/section/text.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,16 @@ class Vaporware::Compiler::Assembler::ELF::Section::Text
SUB: 0x83,
}.freeze

attr_reader :bytes, :size, :offset

def initialize
@bytes = []
@size = 0
@offset = 0
end
def initialize = @bytes = []

def assemble!(line)
op, *operands = line.split(/\s+/).reject { |o| o.empty? }.map { |op| op.gsub(/,/, "") }
@bytes << opecode(op, *operands)
@size += @bytes.last.bytesize
end

def align!(bytes)
@bytes << [0x00] until @bytes.map(:bytesize).sum % bytes == 0
end
def build = @bytes.flatten.pack("C*")
def size = build.bytesize
def align(val, bytes) = (val << [0] until @bytes.map(:bytesize).sum % bytes == 0)

private

Expand Down
8 changes: 2 additions & 6 deletions lib/vaporware/compiler/assembler/elf/section_header.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
class Vaporware::Compiler::Assembler::ELF::SectionHeader
include Vaporware::Compiler::Assembler::ELF::Utils
def initialize
@name = nil
@type = nil
Expand Down Expand Up @@ -33,14 +34,9 @@ def set!(name: nil, type: nil, flags: nil, addr: nil,
def null! = set!(name: 0, type: 0, flags: 0, addr: 0, offset: 0, size: 0, link: 0, info: 0, addralign: 0, entsize: 0)
def text! = set!(flags: 0x06, addralign: 0x01)
def note! = set!(type: 0x07, flags: 0x02, size: 0x30, addralign: 0x08)
def data! = set!
def data! = set!()
def symtab! = set!
def strtab! = set!
def bss! = set!
def shsymtab! = set!

private
def bytes = [@name, @type, @flags, @addr, @offset, @size, @link, @info, @addralign, @entsize,].then { |v| v.compact.size == v.size ? v : raise Vaporware::Error, "must be to fill all attributes" }
def check(val, bytes) = (val.is_a?(Array) && val.all? { |v| v.is_a?(Integer) } && val.size == bytes) || val.is_a?(Integer)
def num2bytes(val, bytes) = ("%0#{bytes}x" % val).scan(/.{1,2}/).map { |x| x.to_i(16) }.reverse
end
18 changes: 16 additions & 2 deletions lib/vaporware/compiler/assembler/elf/sections.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
require_relative "section"

class Vaporware::Compiler::Assembler::ELF::Sections
attr_reader %i|null text data bss note symtab strtab shsymtab|
ATTRIBUTES = %i|null text data bss note symtab strtab shstrtab|
attr_reader *ATTRIBUTES
def initialize
@null, @text, @data, @bss, @note, @symtab, @strtab, @shsymtab = %i|null text data bss note symtab strtab shsymtab|.map { |cn| Section.new(type: cn) }
@null = Section.new(type: :null)
@text = Section.new(type: :text)
@data = Section.new(type: :data)
@bss = Section.new(type: :bss)
@note = Section.new(type: :note)
@symtab = Section.new(type: :symtab)
@strtab = Section.new(type: :strtab)
@shstrtab = Section.new(type: :shstrtab)
end

def each(&block)
ATTRIBUTES.each do |t|
yield t
end
end
end
11 changes: 11 additions & 0 deletions lib/vaporware/compiler/assembler/elf/utils.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module Vaporware::Compiler::Assembler::ELF::Utils
def build = bytes.flatten.pack("C*")
def size = build.bytesize

private

def align(val, bytes) = (val << 0 until val.size % bytes == 0)
def bytes = (raise Vaporware::Error, "should be implement this class")
def num2bytes(val, bytes) = ("%0#{bytes}x" % val).scan(/.{1,2}/).map { |v| v.to_i(16) }.reverse
def check(val, bytes) = (val.is_a?(Array) && val.all? { |v| v.is_a?(Integer) } && val.size == bytes) || val.is_a?(Integer)
end
2 changes: 2 additions & 0 deletions sig/vaporware/compiler/assembler/elf/section/null.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class Vaporware::Compiler::Assembler::ELF::Section::Null
end
7 changes: 7 additions & 0 deletions sig/vaporware/compiler/assembler/elf/utils.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module Vaporware::Utils
def build: () -> String
private def align: (Array[Integer], Integer) -> void
private def check: (Array[Integer]?, Integer) -> bool
private def num2bytes: (Integer?, Integer) -> Array[Integer]
private def bytes: () -> Array[Array[Integer]?]
end

0 comments on commit 3294c24

Please sign in to comment.