From 3294c2480abb9d3d2ea5b256e1febcfc43c351e8 Mon Sep 17 00:00:00 2001 From: "MATSUMOTO, Katsuyoshi" Date: Sat, 23 Sep 2023 11:15:15 +0900 Subject: [PATCH] replace utils for common methods --- lib/vaporware/compiler/assembler.rb | 41 ++++++++++++------- lib/vaporware/compiler/assembler/elf.rb | 3 ++ .../compiler/assembler/elf/section.rb | 13 +++--- .../compiler/assembler/elf/section/bss.rb | 9 ++-- .../compiler/assembler/elf/section/data.rb | 4 +- .../compiler/assembler/elf/section/note.rb | 11 ++--- .../compiler/assembler/elf/section/null.rb | 7 ++++ .../assembler/elf/section/shstrtab.rb | 8 ++-- .../compiler/assembler/elf/section/strtab.rb | 1 + .../compiler/assembler/elf/section/symtab.rb | 6 +-- .../compiler/assembler/elf/section/text.rb | 15 ++----- .../compiler/assembler/elf/section_header.rb | 8 +--- .../compiler/assembler/elf/sections.rb | 18 +++++++- lib/vaporware/compiler/assembler/elf/utils.rb | 11 +++++ .../compiler/assembler/elf/section/null.rbs | 2 + .../compiler/assembler/elf/utils.rbs | 7 ++++ 16 files changed, 104 insertions(+), 60 deletions(-) create mode 100644 lib/vaporware/compiler/assembler/elf/section/null.rb create mode 100644 lib/vaporware/compiler/assembler/elf/utils.rb create mode 100644 sig/vaporware/compiler/assembler/elf/section/null.rbs create mode 100644 sig/vaporware/compiler/assembler/elf/utils.rbs diff --git a/lib/vaporware/compiler/assembler.rb b/lib/vaporware/compiler/assembler.rb index 7078af7..253683f 100644 --- a/lib/vaporware/compiler/assembler.rb +++ b/lib/vaporware/compiler/assembler.rb @@ -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 @@ -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 diff --git a/lib/vaporware/compiler/assembler/elf.rb b/lib/vaporware/compiler/assembler/elf.rb index c2c77ca..4dfe014 100644 --- a/lib/vaporware/compiler/assembler/elf.rb +++ b/lib/vaporware/compiler/assembler/elf.rb @@ -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 diff --git a/lib/vaporware/compiler/assembler/elf/section.rb b/lib/vaporware/compiler/assembler/elf/section.rb index e75f12a..10e3fb1 100644 --- a/lib/vaporware/compiler/assembler/elf/section.rb +++ b/lib/vaporware/compiler/assembler/elf/section.rb @@ -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 diff --git a/lib/vaporware/compiler/assembler/elf/section/bss.rb b/lib/vaporware/compiler/assembler/elf/section/bss.rb index 5550a4d..942ce1b 100644 --- a/lib/vaporware/compiler/assembler/elf/section/bss.rb +++ b/lib/vaporware/compiler/assembler/elf/section/bss.rb @@ -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 diff --git a/lib/vaporware/compiler/assembler/elf/section/data.rb b/lib/vaporware/compiler/assembler/elf/section/data.rb index 7b99987..fe6ad04 100644 --- a/lib/vaporware/compiler/assembler/elf/section/data.rb +++ b/lib/vaporware/compiler/assembler/elf/section/data.rb @@ -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 diff --git a/lib/vaporware/compiler/assembler/elf/section/note.rb b/lib/vaporware/compiler/assembler/elf/section/note.rb index ea83ceb..e7d54fc 100644 --- a/lib/vaporware/compiler/assembler/elf/section/note.rb +++ b/lib/vaporware/compiler/assembler/elf/section/note.rb @@ -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 @@ -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 diff --git a/lib/vaporware/compiler/assembler/elf/section/null.rb b/lib/vaporware/compiler/assembler/elf/section/null.rb new file mode 100644 index 0000000..ea49ce3 --- /dev/null +++ b/lib/vaporware/compiler/assembler/elf/section/null.rb @@ -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 diff --git a/lib/vaporware/compiler/assembler/elf/section/shstrtab.rb b/lib/vaporware/compiler/assembler/elf/section/shstrtab.rb index c7f75e4..a4d5700 100644 --- a/lib/vaporware/compiler/assembler/elf/section/shstrtab.rb +++ b/lib/vaporware/compiler/assembler/elf/section/shstrtab.rb @@ -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 diff --git a/lib/vaporware/compiler/assembler/elf/section/strtab.rb b/lib/vaporware/compiler/assembler/elf/section/strtab.rb index 61c0d0a..8253008 100644 --- a/lib/vaporware/compiler/assembler/elf/section/strtab.rb +++ b/lib/vaporware/compiler/assembler/elf/section/strtab.rb @@ -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 diff --git a/lib/vaporware/compiler/assembler/elf/section/symtab.rb b/lib/vaporware/compiler/assembler/elf/section/symtab.rb index 6414755..d06f41f 100644 --- a/lib/vaporware/compiler/assembler/elf/section/symtab.rb +++ b/lib/vaporware/compiler/assembler/elf/section/symtab.rb @@ -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) @@ -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 diff --git a/lib/vaporware/compiler/assembler/elf/section/text.rb b/lib/vaporware/compiler/assembler/elf/section/text.rb index 7fb713d..63a6d22 100644 --- a/lib/vaporware/compiler/assembler/elf/section/text.rb +++ b/lib/vaporware/compiler/assembler/elf/section/text.rb @@ -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 diff --git a/lib/vaporware/compiler/assembler/elf/section_header.rb b/lib/vaporware/compiler/assembler/elf/section_header.rb index e0a4c78..727dce8 100644 --- a/lib/vaporware/compiler/assembler/elf/section_header.rb +++ b/lib/vaporware/compiler/assembler/elf/section_header.rb @@ -1,4 +1,5 @@ class Vaporware::Compiler::Assembler::ELF::SectionHeader + include Vaporware::Compiler::Assembler::ELF::Utils def initialize @name = nil @type = nil @@ -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 diff --git a/lib/vaporware/compiler/assembler/elf/sections.rb b/lib/vaporware/compiler/assembler/elf/sections.rb index 00686a8..293f93e 100644 --- a/lib/vaporware/compiler/assembler/elf/sections.rb +++ b/lib/vaporware/compiler/assembler/elf/sections.rb @@ -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 diff --git a/lib/vaporware/compiler/assembler/elf/utils.rb b/lib/vaporware/compiler/assembler/elf/utils.rb new file mode 100644 index 0000000..d02afd3 --- /dev/null +++ b/lib/vaporware/compiler/assembler/elf/utils.rb @@ -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 diff --git a/sig/vaporware/compiler/assembler/elf/section/null.rbs b/sig/vaporware/compiler/assembler/elf/section/null.rbs new file mode 100644 index 0000000..0bf63b3 --- /dev/null +++ b/sig/vaporware/compiler/assembler/elf/section/null.rbs @@ -0,0 +1,2 @@ +class Vaporware::Compiler::Assembler::ELF::Section::Null +end diff --git a/sig/vaporware/compiler/assembler/elf/utils.rbs b/sig/vaporware/compiler/assembler/elf/utils.rbs new file mode 100644 index 0000000..bb49b94 --- /dev/null +++ b/sig/vaporware/compiler/assembler/elf/utils.rbs @@ -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