From e34a9068b1207d1c300fd3bcb690931375135d6b Mon Sep 17 00:00:00 2001 From: "MATSUMOTO, Katsuyoshi" Date: Sun, 4 Jan 2026 08:55:21 +0900 Subject: [PATCH 01/32] migrate elf utils file --- lib/caotral/binary.rb | 4 ++++ lib/caotral/binary/elf.rb | 9 +++++++++ lib/caotral/binary/elf/error.rb | 8 ++++++++ lib/caotral/binary/elf/utils.rb | 31 +++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+) create mode 100644 lib/caotral/binary.rb create mode 100644 lib/caotral/binary/elf.rb create mode 100644 lib/caotral/binary/elf/error.rb create mode 100644 lib/caotral/binary/elf/utils.rb diff --git a/lib/caotral/binary.rb b/lib/caotral/binary.rb new file mode 100644 index 0000000..b2a4d20 --- /dev/null +++ b/lib/caotral/binary.rb @@ -0,0 +1,4 @@ +module Caotral + class Binary + end +end diff --git a/lib/caotral/binary/elf.rb b/lib/caotral/binary/elf.rb new file mode 100644 index 0000000..ca2ad89 --- /dev/null +++ b/lib/caotral/binary/elf.rb @@ -0,0 +1,9 @@ +require_relative "elf/utils" +require_relative "elf/error" + +module Caotral + class Binary + class ELF + end + end +end diff --git a/lib/caotral/binary/elf/error.rb b/lib/caotral/binary/elf/error.rb new file mode 100644 index 0000000..2370372 --- /dev/null +++ b/lib/caotral/binary/elf/error.rb @@ -0,0 +1,8 @@ +module Caotral + class Binary + class ELF + class Error < StandardError + end + end + end +end diff --git a/lib/caotral/binary/elf/utils.rb b/lib/caotral/binary/elf/utils.rb new file mode 100644 index 0000000..3cf83ab --- /dev/null +++ b/lib/caotral/binary/elf/utils.rb @@ -0,0 +1,31 @@ +require_relative "error" + +module Caotral + class Binary + class ELF + module Utils + def build = (build_errors; bytes.flatten.pack("C*")) + def size = build.bytesize + def set! = (raise Caotral::Binary::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 Caotral::Binary::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))) + def hexas(val, hex) = ("%0#{hex*2}x" % val).scan(/.{1,2}/).map { |v| v.to_i(16) }.then { |list| list.unshift(0) until list.size >= hex; list } + def build_errors + return unless bytes.any?(&:nil?) + errors = [] + bytes.each_with_index { |v, idx| errors << instance_variables[idx] if v.nil? } + raise Caotral::Binary::ELF::Error, "unaccepted types: #{errors.join(",")}" + end + end + end + end +end From 4a69e2ae48546bd146c19959c900c2836b9fc50e Mon Sep 17 00:00:00 2001 From: "MATSUMOTO, Katsuyoshi" Date: Sun, 4 Jan 2026 09:46:45 +0900 Subject: [PATCH 02/32] replace package name to Binary --- lib/caotral/assembler.rb | 1 - lib/caotral/assembler/elf/header.rb | 4 +++- lib/caotral/assembler/elf/section/bss.rb | 3 ++- lib/caotral/assembler/elf/section/data.rb | 3 ++- lib/caotral/assembler/elf/section/note.rb | 3 ++- lib/caotral/assembler/elf/section/null.rb | 3 ++- lib/caotral/assembler/elf/section/shstrtab.rb | 3 ++- lib/caotral/assembler/elf/section/strtab.rb | 3 ++- lib/caotral/assembler/elf/section/symtab.rb | 3 ++- lib/caotral/assembler/elf/section/text.rb | 7 +++--- lib/caotral/assembler/elf/section_header.rb | 4 +++- lib/caotral/assembler/elf/utils.rb | 23 ------------------- lib/caotral/linker/elf/header.rb | 3 ++- lib/caotral/linker/elf/program_header.rb | 4 +++- lib/caotral/linker/elf/section/rel.rb | 3 ++- lib/caotral/linker/elf/section/strtab.rb | 3 ++- lib/caotral/linker/elf/section/symtab.rb | 4 +++- lib/caotral/linker/elf/section_header.rb | 4 +++- lib/caotral/linker/writer.rb | 3 ++- 19 files changed, 41 insertions(+), 43 deletions(-) delete mode 100644 lib/caotral/assembler/elf/utils.rb diff --git a/lib/caotral/assembler.rb b/lib/caotral/assembler.rb index 89e0733..f31c012 100644 --- a/lib/caotral/assembler.rb +++ b/lib/caotral/assembler.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true require_relative "assembler/elf" -require_relative "assembler/elf/utils" require_relative "assembler/elf/header" require_relative "assembler/elf/sections" require_relative "assembler/elf/section_header" diff --git a/lib/caotral/assembler/elf/header.rb b/lib/caotral/assembler/elf/header.rb index aefd134..d9394e1 100644 --- a/lib/caotral/assembler/elf/header.rb +++ b/lib/caotral/assembler/elf/header.rb @@ -1,7 +1,9 @@ require_relative "../elf" +require_relative "../../binary/elf" + class Caotral::Assembler::ELF::Header - include Caotral::Assembler::ELF::Utils + include Caotral::Binary::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 diff --git a/lib/caotral/assembler/elf/section/bss.rb b/lib/caotral/assembler/elf/section/bss.rb index 87da36a..9a0f4ee 100644 --- a/lib/caotral/assembler/elf/section/bss.rb +++ b/lib/caotral/assembler/elf/section/bss.rb @@ -1,5 +1,6 @@ +require "caotral/binary/elf/utils" class Caotral::Assembler::ELF::Section::BSS - include Caotral::Assembler::ELF::Utils + include Caotral::Binary::ELF::Utils def initialize(**opts) = nil def build = bytes.flatten.pack("C*") def set! = self diff --git a/lib/caotral/assembler/elf/section/data.rb b/lib/caotral/assembler/elf/section/data.rb index ecf8d9a..4e88b2d 100644 --- a/lib/caotral/assembler/elf/section/data.rb +++ b/lib/caotral/assembler/elf/section/data.rb @@ -1,5 +1,6 @@ +require "caotral/binary/elf/utils" class Caotral::Assembler::ELF::Section::Data - include Caotral::Assembler::ELF::Utils + include Caotral::Binary::ELF::Utils def initialize(**opts) = nil def build = bytes.flatten.pack("C*") def set! = self diff --git a/lib/caotral/assembler/elf/section/note.rb b/lib/caotral/assembler/elf/section/note.rb index ece321c..ca5f6ac 100644 --- a/lib/caotral/assembler/elf/section/note.rb +++ b/lib/caotral/assembler/elf/section/note.rb @@ -1,5 +1,6 @@ +require "caotral/binary/elf/utils" class Caotral::Assembler::ELF::Section::Note - include Caotral::Assembler::ELF::Utils + include Caotral::Binary::ELF::Utils def self.gnu_property = new.gnu_property!.build def self.null = new.null!.build diff --git a/lib/caotral/assembler/elf/section/null.rb b/lib/caotral/assembler/elf/section/null.rb index e5dcb37..94fbf3a 100644 --- a/lib/caotral/assembler/elf/section/null.rb +++ b/lib/caotral/assembler/elf/section/null.rb @@ -1,5 +1,6 @@ +require "caotral/binary/elf/utils" class Caotral::Assembler::ELF::Section::Null - include Caotral::Assembler::ELF::Utils + include Caotral::Binary::ELF::Utils def initialize(**opts) = nil def build = bytes.flatten.pack("C*") def set! = self diff --git a/lib/caotral/assembler/elf/section/shstrtab.rb b/lib/caotral/assembler/elf/section/shstrtab.rb index 493a6d0..9aa224d 100644 --- a/lib/caotral/assembler/elf/section/shstrtab.rb +++ b/lib/caotral/assembler/elf/section/shstrtab.rb @@ -1,5 +1,6 @@ +require "caotral/binary/elf/utils" class Caotral::Assembler::ELF::Section::Shstrtab - include Caotral::Assembler::ELF::Utils + include Caotral::Binary::ELF::Utils def initialize(**opts) = @name = [] def build = bytes.flatten.pack("C*") def set!(name:) = (@name << name!(name); self) diff --git a/lib/caotral/assembler/elf/section/strtab.rb b/lib/caotral/assembler/elf/section/strtab.rb index 8984894..35a46d4 100644 --- a/lib/caotral/assembler/elf/section/strtab.rb +++ b/lib/caotral/assembler/elf/section/strtab.rb @@ -1,5 +1,6 @@ +require "caotral/binary/elf/utils" class Caotral::Assembler::ELF::Section::Strtab - include Caotral::Assembler::ELF::Utils + include Caotral::Binary::ELF::Utils def initialize(names = "\0main\0", **opts) = @names = names def build = @names.bytes.pack("C*") end diff --git a/lib/caotral/assembler/elf/section/symtab.rb b/lib/caotral/assembler/elf/section/symtab.rb index 215e8cc..de2235c 100644 --- a/lib/caotral/assembler/elf/section/symtab.rb +++ b/lib/caotral/assembler/elf/section/symtab.rb @@ -1,5 +1,6 @@ +require "caotral/binary/elf/utils" class Caotral::Assembler::ELF::Section::Symtab - include Caotral::Assembler::ELF::Utils + include Caotral::Binary::ELF::Utils def initialize(**opts) @entsize = [] @name = num2bytes(0, 4) diff --git a/lib/caotral/assembler/elf/section/text.rb b/lib/caotral/assembler/elf/section/text.rb index c82b012..6d9940b 100644 --- a/lib/caotral/assembler/elf/section/text.rb +++ b/lib/caotral/assembler/elf/section/text.rb @@ -1,3 +1,4 @@ +require "caotral/binary/elf" class Caotral::Assembler::ELF::Section::Text PREFIX = { REX_W: 0x48, @@ -115,14 +116,14 @@ def opecode(op, offset, *operands) when "ret" [0xc3] else - raise Caotral::Assembler::ELF::Error, "yet implemented operations: #{op}" + raise Caotral::Binary::ELF::Error, "yet implemented operations: #{op}" end end def jump(op, offset, *operands) label = operands.first target = @label_positions.fetch(label) do - raise Caotral::Compiler::Assembler::ELF::Error, "unknown label: #{label}" + raise Caotral::Binary::ELF::Error, "unknown label: #{label}" end size = instruction_size(op, label) rel = target - (offset + size) @@ -253,7 +254,7 @@ def reg(r) when /\d+/ r.to_i(16) else - raise Caotral::Assembler::ELF::Error, "yet implemented operand address: #{r}" + raise Caotral::Binary::ELF::Error, "yet implemented operand address: #{r}" end end def immediate(operand) = [operand.to_i(16)].pack("L").unpack("C*") diff --git a/lib/caotral/assembler/elf/section_header.rb b/lib/caotral/assembler/elf/section_header.rb index a0a9e34..dece655 100644 --- a/lib/caotral/assembler/elf/section_header.rb +++ b/lib/caotral/assembler/elf/section_header.rb @@ -1,5 +1,7 @@ +require "caotral/binary/elf" + class Caotral::Assembler::ELF::SectionHeader - include Caotral::Assembler::ELF::Utils + include Caotral::Binary::ELF::Utils def initialize @name = nil @type = nil diff --git a/lib/caotral/assembler/elf/utils.rb b/lib/caotral/assembler/elf/utils.rb deleted file mode 100644 index e10f46b..0000000 --- a/lib/caotral/assembler/elf/utils.rb +++ /dev/null @@ -1,23 +0,0 @@ -module Caotral::Assembler::ELF::Utils - def build = (build_errors; bytes.flatten.pack("C*")) - def size = build.bytesize - def set! = (raise Caotral::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 Caotral::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))) - def hexas(val, hex) = ("%0#{hex*2}x" % val).scan(/.{1,2}/).map { |v| v.to_i(16) }.then { |list| list.unshift(0) until list.size >= hex; list } - def build_errors - return unless bytes.any?(&:nil?) - errors = [] - bytes.each_with_index { |v, idx| errors << instance_variables[idx] if v.nil? } - raise Caotral::Assembler::ELF::Error, "unaccepted types: #{errors.join(",")}" - end -end diff --git a/lib/caotral/linker/elf/header.rb b/lib/caotral/linker/elf/header.rb index 5533506..4ffd20f 100644 --- a/lib/caotral/linker/elf/header.rb +++ b/lib/caotral/linker/elf/header.rb @@ -1,8 +1,9 @@ +require "caotral/binary/elf/utils" module Caotral class Linker class ELF class Header - include Caotral::Assembler::ELF::Utils + include Caotral::Binary::ELF::Utils attr_reader :entry, :phoffset, :shoffset, :shnum, :shstrndx IDENT = [0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00].freeze IDENT_STR = IDENT.pack("C*").freeze diff --git a/lib/caotral/linker/elf/program_header.rb b/lib/caotral/linker/elf/program_header.rb index a5177ec..a217b8f 100644 --- a/lib/caotral/linker/elf/program_header.rb +++ b/lib/caotral/linker/elf/program_header.rb @@ -1,8 +1,10 @@ +require "caotral/binary/elf/utils" + module Caotral class Linker class ELF class ProgramHeader - include Caotral::Assembler::ELF::Utils + include Caotral::Binary::ELF::Utils def initialize @type = num2bytes(0, 4) @flags = num2bytes(0, 4) diff --git a/lib/caotral/linker/elf/section/rel.rb b/lib/caotral/linker/elf/section/rel.rb index b6ecf62..3991ced 100644 --- a/lib/caotral/linker/elf/section/rel.rb +++ b/lib/caotral/linker/elf/section/rel.rb @@ -1,9 +1,10 @@ +require "caotral/binary/elf/utils" module Caotral class Linker class ELF class Section class Rel - include Caotral::Assembler::ELF::Utils + include Caotral::Binary::ELF::Utils def initialize(addend: true) @offset = num2bytes(0, 8) @info = num2bytes(0, 8) diff --git a/lib/caotral/linker/elf/section/strtab.rb b/lib/caotral/linker/elf/section/strtab.rb index 310e35a..fe07cfe 100644 --- a/lib/caotral/linker/elf/section/strtab.rb +++ b/lib/caotral/linker/elf/section/strtab.rb @@ -1,9 +1,10 @@ +require "caotral/binary/elf/utils" module Caotral class Linker class ELF class Section class Strtab - include Caotral::Assembler::ELF::Utils + include Caotral::Binary::ELF::Utils attr_reader :names def initialize(names = "\0main\0", **opts) = @names = names def build = @names.bytes.pack("C*") diff --git a/lib/caotral/linker/elf/section/symtab.rb b/lib/caotral/linker/elf/section/symtab.rb index a331418..2b95e7e 100644 --- a/lib/caotral/linker/elf/section/symtab.rb +++ b/lib/caotral/linker/elf/section/symtab.rb @@ -1,9 +1,11 @@ +require "caotral/binary/elf/utils" + module Caotral class Linker class ELF class Section class Symtab - include Caotral::Assembler::ELF::Utils + include Caotral::Binary::ELF::Utils attr_accessor :name_string def initialize(**opts) @entsize = [] diff --git a/lib/caotral/linker/elf/section_header.rb b/lib/caotral/linker/elf/section_header.rb index d3fcb04..fa5fc8d 100644 --- a/lib/caotral/linker/elf/section_header.rb +++ b/lib/caotral/linker/elf/section_header.rb @@ -1,7 +1,10 @@ +require "caotral/binary/elf/utils" + module Caotral class Linker class ELF class SectionHeader + include Caotral::Binary::ELF::Utils SHT = { null: 0, progbits: 1, @@ -17,7 +20,6 @@ class SectionHeader dynsym: 11, }.freeze SHT_BY_VALUE = SHT.invert.freeze - include Caotral::Assembler::ELF::Utils def initialize @name = nil @type = nil diff --git a/lib/caotral/linker/writer.rb b/lib/caotral/linker/writer.rb index 8ecddcc..acacb50 100644 --- a/lib/caotral/linker/writer.rb +++ b/lib/caotral/linker/writer.rb @@ -1,9 +1,10 @@ +require "caotral/binary/elf/utils" require_relative "elf/program_header" module Caotral class Linker class Writer - include Caotral::Assembler::ELF::Utils + include Caotral::Binary::ELF::Utils ALLOW_SECTIONS = %w(.text .strtab .shstrtab).freeze R_X86_64_PC32 = 2 R_X86_64_PLT32 = 4 From 3c68a1967debc064f3e288bdf9635f6278eea613 Mon Sep 17 00:00:00 2001 From: "MATSUMOTO, Katsuyoshi" Date: Sun, 4 Jan 2026 12:36:55 +0900 Subject: [PATCH 03/32] package restructuring section header --- lib/caotral/binary/elf/section_header.rb | 54 +++++++++++++++++ lib/caotral/linker/elf/section_header.rb | 74 +----------------------- 2 files changed, 56 insertions(+), 72 deletions(-) create mode 100644 lib/caotral/binary/elf/section_header.rb diff --git a/lib/caotral/binary/elf/section_header.rb b/lib/caotral/binary/elf/section_header.rb new file mode 100644 index 0000000..f161f1b --- /dev/null +++ b/lib/caotral/binary/elf/section_header.rb @@ -0,0 +1,54 @@ +require_relative "utils" + +module Caotral + class Binary + class ELF + class SectionHeader + include Caotral::Binary::ELF::Utils + SHT = { null: 0, progbits: 1, symtab: 2, strtab: 3, rela: 4, hash: 5, dynamic: 6, note: 7, nobits: 8, rel: 9, shlib: 10, dynsym: 11, }.freeze + SHT_BY_VALUE = SHT.invert.freeze + + def initialize + @name = num2bytes(0, 4) + @type = num2bytes(0, 4) + @flags = num2bytes(0, 8) + @addr = num2bytes(0, 8) + @offset = num2bytes(0, 8) + @size = num2bytes(0, 8) + @link = num2bytes(0, 4) + @info = num2bytes(0, 4) + @addralign = num2bytes(0, 8) + @entsize = num2bytes(0, 8) + end + + def build = bytes.flatten.pack("C*") + + def set!(name: nil, type: nil, flags: nil, addr: nil, + offset: nil, size: nil, link: nil, info: nil, + addralign: nil, entsize: nil) + @name = num2bytes(name, 4) if check(name, 4) + @type = num2bytes(type, 4) if check(type, 4) + @flags = num2bytes(flags, 8) if check(flags, 8) + @addr = num2bytes(addr, 8) if check(addr, 8) + @offset = num2bytes(offset, 8) if check(offset, 8) + @size = num2bytes(size, 8) if check(size, 8) + @link = num2bytes(link, 4) if check(link, 4) + @info = num2bytes(info, 4) if check(info, 4) + @addralign = num2bytes(addralign, 8) if check(addralign, 8) + @entsize = num2bytes(entsize, 8) if check(entsize, 8) + self + end + + def name = @name.pack("C*").unpack1("L<") + def offset = @offset.pack("C*").unpack1("Q<") + def entsize = @entsize.pack("C*").unpack1("Q<") + def size = @size.pack("C*").unpack1("Q<") + def type = SHT_BY_VALUE[@type.pack("C*").unpack1("L<")] + def info = @info.pack("C*").unpack1("L<") + def addr = @addr.pack("C*").unpack1("Q<") + + private def bytes = [@name, @type, @flags, @addr, @offset, @size, @link, @info, @addralign, @entsize] + end + end + end +end diff --git a/lib/caotral/linker/elf/section_header.rb b/lib/caotral/linker/elf/section_header.rb index fa5fc8d..107555f 100644 --- a/lib/caotral/linker/elf/section_header.rb +++ b/lib/caotral/linker/elf/section_header.rb @@ -1,79 +1,9 @@ -require "caotral/binary/elf/utils" +require "caotral/binary/elf/section_header" module Caotral class Linker class ELF - class SectionHeader - include Caotral::Binary::ELF::Utils - SHT = { - null: 0, - progbits: 1, - symtab: 2, - strtab: 3, - rela: 4, - hash: 5, - dynamic: 6, - note: 7, - nobits: 8, - rel: 9, - shlib: 10, - dynsym: 11, - }.freeze - SHT_BY_VALUE = SHT.invert.freeze - def initialize - @name = nil - @type = nil - @flags = nil - @addr = nil - @offset = nil - @size = nil - @link = nil - @info = nil - @addralign = nil - @entsize = nil - end - - def build = bytes.flatten.pack("C*") - - def set!(name: nil, type: nil, flags: nil, addr: nil, - offset: nil, size: nil, link: nil, info: nil, - addralign: nil, entsize: nil) - @name = num2bytes(name, 4) if check(name, 4) - @type = num2bytes(type, 4) if check(type, 4) - @flags = num2bytes(flags, 8) if check(flags, 8) - @addr = num2bytes(addr, 8) if check(addr, 8) - @offset = num2bytes(offset, 8) if check(offset, 8) - @size = num2bytes(size, 8) if check(size, 8) - @link = num2bytes(link, 4) if check(link, 4) - @info = num2bytes(info, 4) if check(info, 4) - @addralign = num2bytes(addralign, 8) if check(addralign, 8) - @entsize = num2bytes(entsize, 8) if check(entsize, 8) - self - end - - def null! = set!(name: 0, type: 0, flags: 0, addr: 0, offset: 0, size: 0, link: 0, info: 0, addralign: 0, entsize: 0) - def name = get(:name) - def offset = get(:offset) - def entsize = get(:entsize) - def size = get(:size) - def type = SHT_BY_VALUE[@type.pack("C*").unpack("L<").first] - def info = get(:info) - def addr = get(:addr) - LONG_TYPES = %w[flags addr offset size addralign entsize].freeze - INT_TYPES = %w[name type link info].freeze - - private_constant :LONG_TYPES, :INT_TYPES - - private def bytes = [@name, @type, @flags, @addr, @offset, @size, @link, @info, @addralign, @entsize] - private def get(type) - val = instance_variable_get("@#{type.to_s}").pack("C*") - case type.to_s - when *INT_TYPES; val.unpack("L<") - when *LONG_TYPES; val.unpack("Q<") - else - raise "not specified: #{type}" - end.first - end + class SectionHeader < Caotral::Binary::ELF::SectionHeader end end end From c60fd95abf7d87eea3c9b3ea398fd643b58aa25c Mon Sep 17 00:00:00 2001 From: "MATSUMOTO, Katsuyoshi" Date: Sun, 4 Jan 2026 14:59:55 +0900 Subject: [PATCH 04/32] migrate elf header description file --- lib/caotral/assembler/elf/header.rb | 62 +------------ lib/caotral/assembler/elf/section/text.rb | 6 +- lib/caotral/binary/elf/header.rb | 81 +++++++++++++++++ lib/caotral/linker.rb | 7 +- lib/caotral/linker/elf/header.rb | 93 +------------------- sig/caotral/assembler/elf/header.rbs | 30 +------ sig/caotral/assembler/elf/section_header.rbs | 32 ++----- sig/caotral/binary.rbs | 2 + sig/caotral/binary/elf.rbs | 2 + sig/caotral/binary/elf/header.rbs | 28 ++++++ sig/caotral/binary/elf/section_header.rbs | 27 ++++++ sig/caotral/linker/elf/header.rbs | 13 +-- sig/caotral/linker/elf/section_header.rbs | 27 +----- test/caotral/linker/reader_test.rb | 2 +- test/caotral/linker/writer_test.rb | 4 +- 15 files changed, 168 insertions(+), 248 deletions(-) create mode 100644 lib/caotral/binary/elf/header.rb create mode 100644 sig/caotral/binary.rbs create mode 100644 sig/caotral/binary/elf.rbs create mode 100644 sig/caotral/binary/elf/header.rbs create mode 100644 sig/caotral/binary/elf/section_header.rbs diff --git a/lib/caotral/assembler/elf/header.rb b/lib/caotral/assembler/elf/header.rb index d9394e1..75b752a 100644 --- a/lib/caotral/assembler/elf/header.rb +++ b/lib/caotral/assembler/elf/header.rb @@ -1,64 +1,6 @@ require_relative "../elf" -require_relative "../../binary/elf" +require "caotral/binary/elf/header" -class Caotral::Assembler::ELF::Header - include Caotral::Binary::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 - - def initialize(endian: :littel, type: :rel, arc: :amd64) - @ident = IDENT - @type = num2bytes(ELF_FILE_TYPE[elf(type)], 2) - @arch = arch(arc) - @version = num2bytes(1, 4) - @entry = num2bytes(0x00, 8) - @phoffset = num2bytes(0x00, 8) - @shoffset = num2bytes(0x00, 8) - @flags = num2bytes(0x00, 4) - @ehsize = num2bytes(0x40, 2) - @phsize = num2bytes(0x00, 2) - @phnum = num2bytes(0x00, 2) - @shentsize = num2bytes(0x40, 2) - @shnum = num2bytes(0x08, 2) - @shstrndx = num2bytes(0x07, 2) - end - - def build = bytes.flatten.pack("C*") - - def set!(entry: nil, phoffset: nil, shoffset: nil, shnum: nil, shstrndx: nil) - @entry = num2bytes(entry, 8) if check(entry, 8) - @phoffset = num2bytes(phoffset, 8) if check(phoffset, 8) - @shoffset = num2bytes(shoffset, 8) if check(shoffset, 8) - @shnum = num2bytes(shnum, 4) if check(shnum, 4) - @shstrndx = num2bytes(shstrndx, 4) if check(shstrndx, 4) - end - - private - - def bytes = [ - @ident, @type, @arch, @version, @entry, @phoffset, - @shoffset, @flags, @ehsize, @phsize, @phnum, @shentsize, - @shnum, @shstrndx - ] - - def arch(machine) - case machine.to_s - in "amd64" | "x86_64" | "x64" - [0x3e, 0x00] - end - end - - def elf(type) - case type.to_s - in "relocatable" | "rel" - :REL - in "exe" | "ex" | "exec" - :EXEC - in "shared" | "share" | "dynamic" | "dyn" - :DYN - else - :NONE - end - end +class Caotral::Assembler::ELF::Header < Caotral::Binary::ELF::Header end diff --git a/lib/caotral/assembler/elf/section/text.rb b/lib/caotral/assembler/elf/section/text.rb index 6d9940b..febbf0c 100644 --- a/lib/caotral/assembler/elf/section/text.rb +++ b/lib/caotral/assembler/elf/section/text.rb @@ -126,8 +126,8 @@ def jump(op, offset, *operands) raise Caotral::Binary::ELF::Error, "unknown label: #{label}" end size = instruction_size(op, label) - rel = target - (offset + size) - displacement = [rel].pack("l<").unpack("C*") + rel = Integer(target) - Integer(offset) - Integer(size) + displacement = [rel].pack("l<").bytes case op when "je" [0x0f, 0x84, *displacement] @@ -135,6 +135,8 @@ def jump(op, offset, *operands) [0xe9, *displacement] when "jne" [0x0f, 0x85, *displacement] + else + raise Caotral::Binary::ELF::Error, "unknown jump: #{op}" end end diff --git a/lib/caotral/binary/elf/header.rb b/lib/caotral/binary/elf/header.rb new file mode 100644 index 0000000..a41e404 --- /dev/null +++ b/lib/caotral/binary/elf/header.rb @@ -0,0 +1,81 @@ +require_relative "utils" +module Caotral + class Binary + class ELF + class Header + include Caotral::Binary::ELF::Utils + IDENT = [0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00].freeze + IDENT_STR = IDENT.pack("C*").freeze + ELF_FILE_TYPE = { NONE: 0, REL: 1, EXEC: 2, DYN: 3, CORE: 4 }.freeze + + def initialize(endian: :little, type: :rel, arc: :amd64) + @ident = IDENT + @type = num2bytes(ELF_FILE_TYPE[elf(type)], 2) + @arch = arch(arc) + @version = num2bytes(1, 4) + @entry = num2bytes(0x00, 8) + @phoffset = num2bytes(0x00, 8) + @shoffset = num2bytes(0x00, 8) + @flags = num2bytes(0x00, 4) + @ehsize = num2bytes(0x40, 2) + @phsize = num2bytes(0x00, 2) + @phnum = num2bytes(0x00, 2) + @shentsize = num2bytes(0x40, 2) + @shnum = num2bytes(0x08, 2) + @shstrndx = num2bytes(0x07, 2) + end + + def build = bytes.flatten.pack("C*") + + def set!(type: nil, entry: nil, phoffset: nil, shoffset: nil, shnum: nil, shstrndx: nil, phsize: nil, phnum: nil, ehsize: nil) + @type = num2bytes(type, 2) if check(type, 2) + @entry = num2bytes(entry, 8) if check(entry, 8) + @phoffset = num2bytes(phoffset, 8) if check(phoffset, 8) + @phsize = num2bytes(phsize, 2) if check(phsize, 2) + @phnum = num2bytes(phnum, 2) if check(phnum, 2) + @ehsize = num2bytes(ehsize, 2) if check(ehsize, 2) + @shoffset = num2bytes(shoffset, 8) if check(shoffset, 8) + @shnum = num2bytes(shnum, 2) if check(shnum, 2) + @shstrndx = num2bytes(shstrndx, 2) if check(shstrndx, 2) + self + end + + def entry = @entry.pack("C*").unpack1("Q<") + def ehsize = @ehsize.pack("C*").unpack1("S<") + def phsize = @phsize.pack("C*").unpack1("S<") + def phnum = @phnum.pack("C*").unpack1("S<") + def shentsize = @shentsize.pack("C*").unpack1("S<") + def shnum = @shnum.pack("C*").unpack1("S<") + def shstrndx = @shstrndx.pack("C*").unpack1("S<") + def shoffset = @shoffset.pack("C*").unpack1("Q<") + + private + def bytes = [ + @ident, @type, @arch, @version, @entry, @phoffset, + @shoffset, @flags, @ehsize, @phsize, @phnum, @shentsize, + @shnum, @shstrndx + ] + + def arch(machine) + case machine.to_s + in "amd64" | "x86_64" | "x64" + [0x3e, 0x00] + end + end + + def elf(type) + case type.to_s + in "relocatable" | "rel" + :REL + in "exe" | "ex" | "exec" + :EXEC + in "shared" | "share" | "dynamic" | "dyn" + :DYN + else + :NONE + end + end + end + end + end +end diff --git a/lib/caotral/linker.rb b/lib/caotral/linker.rb index 7521491..9a42f2c 100644 --- a/lib/caotral/linker.rb +++ b/lib/caotral/linker.rb @@ -12,11 +12,14 @@ def initialize(input:, output: "a.out", linker: "mold", linker_options: [], shar @debug, @shared = debug, shared end - def link(input: @input, output: @output, debug: @debug, shared: @shared) = IO.popen(link_command).close + def link(input: @input, output: @output, debug: @debug, shared: @shared) + return to_elf(input:, output:, debug:) if @linker == "self" + + IO.popen(link_command).close + end def link_command(input: @input, output: @output, debug: @debug, shared: @shared) ld_path = [] - return to_elf(input:, output:, debug:) if @linker == "self" if @shared ld_path << "--shared" diff --git a/lib/caotral/linker/elf/header.rb b/lib/caotral/linker/elf/header.rb index 4ffd20f..1d9fe4a 100644 --- a/lib/caotral/linker/elf/header.rb +++ b/lib/caotral/linker/elf/header.rb @@ -1,97 +1,8 @@ -require "caotral/binary/elf/utils" +require "caotral/binary/elf/header" module Caotral class Linker class ELF - class Header - include Caotral::Binary::ELF::Utils - attr_reader :entry, :phoffset, :shoffset, :shnum, :shstrndx - IDENT = [0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00].freeze - IDENT_STR = IDENT.pack("C*").freeze - ELF_FILE_TYPE = { NONE: 0, REL: 1, EXEC: 2, DYN: 3, CORE: 4 }.freeze - - def initialize(endian: :little, type: :rel, arc: :amd64) - @ident = IDENT - @type = num2bytes(ELF_FILE_TYPE[elf(type)], 2) - @arch = arch(arc) - @version = num2bytes(1, 4) - @entry = num2bytes(0x00, 8) - @phoffset = num2bytes(0x00, 8) - @shoffset = num2bytes(0x00, 8) - @flags = num2bytes(0x00, 4) - @ehsize = num2bytes(0x40, 2) - @phsize = num2bytes(0x00, 2) - @phnum = num2bytes(0x00, 2) - @shentsize = num2bytes(0x40, 2) - @shnum = num2bytes(0x08, 2) - @shstrndx = num2bytes(0x07, 2) - end - - def build = bytes.flatten.pack("C*") - - def set!(type: nil, entry: nil, phoffset: nil, shoffset: nil, shnum: nil, shstrndx: nil, phsize: nil, phnum: nil, ehsize: nil) - @type = num2bytes(type, 2) if check(type, 2) - @entry = num2bytes(entry, 8) if check(entry, 8) - @phoffset = num2bytes(phoffset, 8) if check(phoffset, 8) - @phsize = num2bytes(phsize, 2) if check(phsize, 2) - @phnum = num2bytes(phnum, 2) if check(phnum, 2) - @ehsize = num2bytes(ehsize, 2) if check(ehsize, 2) - @shoffset = num2bytes(shoffset, 8) if check(shoffset, 8) - @shnum = num2bytes(shnum, 2) if check(shnum, 2) - @shstrndx = num2bytes(shstrndx, 2) if check(shstrndx, 2) - self - end - - def ehsize = get(:ehsize) - def phsize = get(:phsize) - def phnum = get(:phnum) - def shentsize = get(:shentsize) - def shnum = get(:shnum) - def shstrndx = get(:shstrndx) - - LONG_TYPES = %w[entry phoffset shoffset].freeze - INT_TYPES = %w[type version].freeze - SHORT_TYPES = %w[ehsize phsize phnum shentsize shnum shstrndx].freeze - CHAR_TYPES = %w[arch flags].freeze - private_constant :LONG_TYPES, :INT_TYPES, :SHORT_TYPES, :CHAR_TYPES - - private - def bytes = [ - @ident, @type, @arch, @version, @entry, @phoffset, - @shoffset, @flags, @ehsize, @phsize, @phnum, @shentsize, - @shnum, @shstrndx - ] - - def arch(machine) - case machine.to_s - in "amd64" | "x86_64" | "x64" - [0x3e, 0x00] - end - end - - def elf(type) - case type.to_s - in "relocatable" | "rel" - :REL - in "exe" | "ex" | "exec" - :EXEC - in "shared" | "share" | "dynamic" | "dyn" - :DYN - else - :NONE - end - end - - def get(type) - val = instance_variable_get(:"@#{type.to_s}").pack("C*") - case type.to_s.downcase - when *LONG_TYPES; val.unpack("Q<") - when *INT_TYPES; val.unpack("L<") - when *SHORT_TYPES; val.unpack("S<") - when *CHAR_TYPES; val.unpack("C<") - else - raise "not specified: #{type}" - end.first - end + class Header < Caotral::Binary::ELF::Header end end end diff --git a/sig/caotral/assembler/elf/header.rbs b/sig/caotral/assembler/elf/header.rbs index 73939cc..27d7fa9 100644 --- a/sig/caotral/assembler/elf/header.rbs +++ b/sig/caotral/assembler/elf/header.rbs @@ -1,30 +1,2 @@ -class Caotral::Assembler::ELF::Header - IDENT: Array[Integer] - ELF_FILE_TYPE: Hash[Symbol, Integer] - - @e_ident: Array[Integer] - @type: Integer - @arch: Array[Integer] - @version: Array[Integer] - @entry: Array[Integer]? - @phoffset: Array[Integer]? - @shoffset: Array[Integer]? - @flags: Array[Integer] - @ehsize: Array[Integer] - @phsize: Array[Integer] - @ehnum: Array[Integer] - @shentsize: Array[Integer] - @shnum: Array[Integer]? - @shstrndx: Array[Integer]? - - def initialize: (?endian: Symbol, ?type: Symbol, ?arche: Symbol) -> void - def build: () -> String - def set!: (?entry: Integer?, ?phoffset: Integer?, ?shoffset: Integer?, ?shnum: Integer?, ?shstrndx: Integer?) -> void - - private - def check: (Array[Integer] | Integer, Integer) -> bool - def num2bytes: (Integer, Integer) -> Array[Integer] - def bytes: () -> Array[Array[Integer]] - def arch: (String | Symbol) -> Array[Integer] - def elf: (String | Symbol) -> Symbol +class Caotral::Assembler::ELF::Header < Caotral::Binary::ELF::Header end diff --git a/sig/caotral/assembler/elf/section_header.rbs b/sig/caotral/assembler/elf/section_header.rbs index 1fb5aab..837aea5 100644 --- a/sig/caotral/assembler/elf/section_header.rbs +++ b/sig/caotral/assembler/elf/section_header.rbs @@ -1,24 +1,10 @@ -use Caotral::Assembler::ELF - -class Caotral::Assembler::ELF::SectionHeader - @name: Array[Integer]? - @type: Array[Integer]? - @flags: Array[Integer]? - @addr: Array[Integer]? - @offset: Array[Integer]? - @size: Array[Integer]? - @link: Array[Integer]? - @info: Array[Integer]? - @addralign: Array[Integer]? - @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?) -> Caotral::Assembler::ELF::SectionHeader - def null!: () -> ELF::SectionHeader - def text!: () -> ELF::SectionHeader - def note!: () -> ELF::SectionHeader - - private def bytes: () -> Array[Array[Integer]?] - private def check: ((Array[Integer] | Integer)?, Integer) -> bool - private def num2bytes: (Integer?, Integer) -> Array[Integer] +class Caotral::Assembler::ELF::SectionHeader < Caotral::Binary::ELF::SectionHeader + def null!: () -> Caotral::Assembler::ELF::SectionHeader + def text!: () -> Caotral::Assembler::ELF::SectionHeader + def data!: () -> Caotral::Assembler::ELF::SectionHeader + def bss!: () -> Caotral::Assembler::ELF::SectionHeader + def note!: () -> Caotral::Assembler::ELF::SectionHeader + def symtab!: () -> Caotral::Assembler::ELF::SectionHeader + def strtab!: () -> Caotral::Assembler::ELF::SectionHeader + def shstrtab!: () -> Caotral::Assembler::ELF::SectionHeader end diff --git a/sig/caotral/binary.rbs b/sig/caotral/binary.rbs new file mode 100644 index 0000000..5554fd2 --- /dev/null +++ b/sig/caotral/binary.rbs @@ -0,0 +1,2 @@ +class Caotral::Binary +end diff --git a/sig/caotral/binary/elf.rbs b/sig/caotral/binary/elf.rbs new file mode 100644 index 0000000..0a18953 --- /dev/null +++ b/sig/caotral/binary/elf.rbs @@ -0,0 +1,2 @@ +class Caotral::Binary::ELF +end diff --git a/sig/caotral/binary/elf/header.rbs b/sig/caotral/binary/elf/header.rbs new file mode 100644 index 0000000..689e995 --- /dev/null +++ b/sig/caotral/binary/elf/header.rbs @@ -0,0 +1,28 @@ +class Caotral::Binary::ELF::Header + IDENT: Array[Integer] + IDENT_STR: String + ELF_FILE_TYPE: Hash[Symbol, Integer] + + def initialize: (?endian: Symbol, ?type: Symbol, ?arc: Symbol) -> void + def build: () -> String + def set!: ( + ?type: Integer?, + ?entry: Integer?, + ?phoffset: Integer?, + ?shoffset: Integer?, + ?shnum: Integer?, + ?shstrndx: Integer?, + ?phsize: Integer?, + ?phnum: Integer?, + ?ehsize: Integer? + ) -> self + + def entry: () -> Integer + def ehsize: () -> Integer + def phsize: () -> Integer + def phnum: () -> Integer + def shentsize: () -> Integer + def shnum: () -> Integer + def shstrndx: () -> Integer + def shoffset: () -> Integer +end diff --git a/sig/caotral/binary/elf/section_header.rbs b/sig/caotral/binary/elf/section_header.rbs new file mode 100644 index 0000000..8155d34 --- /dev/null +++ b/sig/caotral/binary/elf/section_header.rbs @@ -0,0 +1,27 @@ +class Caotral::Binary::ELF::SectionHeader + SHT: Hash[Symbol, Integer] + SHT_BY_VALUE: Hash[Integer, Symbol] + + def initialize: () -> void + 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? + ) -> self + + def name: () -> Integer + def offset: () -> Integer + def entsize: () -> Integer + def size: () -> Integer + def type: () -> Symbol? + def info: () -> Integer + def addr: () -> Integer +end diff --git a/sig/caotral/linker/elf/header.rbs b/sig/caotral/linker/elf/header.rbs index 1593ffc..fcda664 100644 --- a/sig/caotral/linker/elf/header.rbs +++ b/sig/caotral/linker/elf/header.rbs @@ -1,13 +1,2 @@ -class Caotral::Linker::ELF::Header - def set!: ( - ?type: Integer?, - ?entry: Integer?, - ?phoffset: Integer?, - ?shoffset: Integer?, - ?shnum: Integer?, - ?shstrndx: Integer?, - ?phsize: Integer?, - ?phnum: Integer?, - ?ehsize: Integer? - ) -> self +class Caotral::Linker::ELF::Header < Caotral::Binary::ELF::Header end diff --git a/sig/caotral/linker/elf/section_header.rbs b/sig/caotral/linker/elf/section_header.rbs index a6c9917..30a49e1 100644 --- a/sig/caotral/linker/elf/section_header.rbs +++ b/sig/caotral/linker/elf/section_header.rbs @@ -1,27 +1,2 @@ -class Caotral::Linker::ELF::SectionHeader - SHT: Hash[Symbol, Integer] - SHT_BY_VALUE: Hash[Integer, Symbol] - LONG_TYPES: Array[String] - INT_TYPES: Array[String] - - def initialize: () -> void - 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? - ) -> self - def null!: () -> self - def name: () -> Integer - def offset: () -> Integer - def entsize: () -> Integer - def size: () -> Integer - def info: () -> Integer +class Caotral::Linker::ELF::SectionHeader < Caotral::Binary::ELF::SectionHeader end diff --git a/test/caotral/linker/reader_test.rb b/test/caotral/linker/reader_test.rb index 9e02530..1b47618 100644 --- a/test/caotral/linker/reader_test.rb +++ b/test/caotral/linker/reader_test.rb @@ -5,7 +5,7 @@ def setup = Caotral.assemble(input: "sample/assembler/plus.s", output: "plus.o", def teardown = File.delete("plus.o") if File.exist?("plus.o") def test_read elf_obj = Caotral::Linker::Reader.read!(input: "plus.o", debug: false) - assert_equal elf_obj.header.shoffset.pack("C*").unpack("Q<").first, 264 + assert_equal elf_obj.header.shoffset, 264 assert_equal elf_obj.sections.size, 8 assert_equal elf_obj.sections[0].section_name, "null" shstrtab = elf_obj.sections[elf_obj.header.shstrndx] diff --git a/test/caotral/linker/writer_test.rb b/test/caotral/linker/writer_test.rb index 2c544bf..e9e872a 100644 --- a/test/caotral/linker/writer_test.rb +++ b/test/caotral/linker/writer_test.rb @@ -15,9 +15,9 @@ def teardown def test_write written_output = Caotral::Linker::Writer.write!(elf_obj: @elf_obj, output: "write.o", debug: false) read_written_elf = Caotral::Linker::Reader.read!(input: written_output, debug: false) - assert_equal @elf_obj.header.shoffset.pack("C*").unpack("Q<").first, read_written_elf.header.shoffset.pack("C*").unpack("Q<").first + assert_equal @elf_obj.header.shoffset, read_written_elf.header.shoffset assert_equal 4, read_written_elf.sections.size - assert_equal 0x401000, read_written_elf.header.entry.pack("C*").unpack("Q<").first + assert_equal 0x401000, read_written_elf.header.entry end def test_execute_written From 7bad6fee1b5bd1f8388ccfcbfd18a611588e765c Mon Sep 17 00:00:00 2001 From: "MATSUMOTO, Katsuyoshi" Date: Sun, 4 Jan 2026 15:02:12 +0900 Subject: [PATCH 05/32] remove unused file --- sig/caotral/assembler/elf/utils.rbs | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 sig/caotral/assembler/elf/utils.rbs diff --git a/sig/caotral/assembler/elf/utils.rbs b/sig/caotral/assembler/elf/utils.rbs deleted file mode 100644 index 2641788..0000000 --- a/sig/caotral/assembler/elf/utils.rbs +++ /dev/null @@ -1,13 +0,0 @@ -use Caotral::Assembler::ELF::Error - -module Caotral::Assembler::ELF::Utils - def build: () -> String - def size: () -> Integer - def empties: () -> Array[Symbol] - private def align: (Array[Integer], Integer) -> void - private def check: ((Array[Integer] | Integer)?, Integer) -> bool - private def num2bytes: (Integer, Integer) -> Array[Integer] - private def bytes: () -> Array[Array[Integer]?] - private def hexas: (Integer, Integer) -> Array[Integer] - private def must_be_filled_section_fields: () -> Array[Symbol] -end From e47df6f18f73d22be3a9d16a4aa27c8f5479f242 Mon Sep 17 00:00:00 2001 From: "MATSUMOTO, Katsuyoshi" Date: Tue, 6 Jan 2026 21:22:06 +0900 Subject: [PATCH 06/32] adjust elf section storage --- lib/caotral/binary/elf.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/caotral/binary/elf.rb b/lib/caotral/binary/elf.rb index ca2ad89..667886d 100644 --- a/lib/caotral/binary/elf.rb +++ b/lib/caotral/binary/elf.rb @@ -4,6 +4,15 @@ module Caotral class Binary class ELF + include Enumerable + attr_reader :sections, :header + def initialize + @sections = [] + @header = nil + end + def each(&block) = @sections.each(&block) + def [](idx) = @sections[idx] + def select_by_name(section_name) = @sections.select { [it.section_name, it.name].include?(section_name.to_s) } end end end From 566b494598041d71e13709c7c5364256adfc2320 Mon Sep 17 00:00:00 2001 From: "MATSUMOTO, Katsuyoshi" Date: Tue, 6 Jan 2026 21:37:53 +0900 Subject: [PATCH 07/32] simplify section --- lib/caotral/binary/elf/section.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 lib/caotral/binary/elf/section.rb diff --git a/lib/caotral/binary/elf/section.rb b/lib/caotral/binary/elf/section.rb new file mode 100644 index 0000000..d169ec8 --- /dev/null +++ b/lib/caotral/binary/elf/section.rb @@ -0,0 +1,14 @@ +module Caotral + class Binary + class ELF + class Section + attr_reader :header, :body, :section_name + def initialize(header:, body:, section_name:) + @header = header + @body = body + @section_name = section_name + end + end + end + end +end From 932266dae38fe47d3d8a90201b542069f9182245 Mon Sep 17 00:00:00 2001 From: "MATSUMOTO, Katsuyoshi" Date: Tue, 6 Jan 2026 22:51:28 +0900 Subject: [PATCH 08/32] replace linker elf with binary elf --- lib/caotral/binary/elf.rb | 13 +++++++-- lib/caotral/binary/elf/program_header.rb | 34 ++++++++++++++++++++++ lib/caotral/binary/elf/section.rb | 3 +- lib/caotral/binary/elf/section/rel.rb | 37 ++++++++++++++++++++++++ lib/caotral/binary/elf/section/strtab.rb | 28 ++++++++++++++++++ lib/caotral/binary/elf/section/symtab.rb | 37 ++++++++++++++++++++++++ lib/caotral/linker/elf.rb | 14 --------- lib/caotral/linker/reader.rb | 33 +++++++++------------ lib/caotral/linker/writer.rb | 17 +++++------ test/caotral/linker/reader_test.rb | 2 +- 10 files changed, 172 insertions(+), 46 deletions(-) create mode 100644 lib/caotral/binary/elf/program_header.rb create mode 100644 lib/caotral/binary/elf/section/rel.rb create mode 100644 lib/caotral/binary/elf/section/strtab.rb create mode 100644 lib/caotral/binary/elf/section/symtab.rb delete mode 100644 lib/caotral/linker/elf.rb diff --git a/lib/caotral/binary/elf.rb b/lib/caotral/binary/elf.rb index 667886d..85f5132 100644 --- a/lib/caotral/binary/elf.rb +++ b/lib/caotral/binary/elf.rb @@ -1,18 +1,27 @@ require_relative "elf/utils" require_relative "elf/error" +require_relative "elf/header" +require_relative "elf/program_header" +require_relative "elf/section" +require_relative "elf/section/rel" +require_relative "elf/section/strtab" +require_relative "elf/section/symtab" +require_relative "elf/section_header" module Caotral class Binary class ELF include Enumerable - attr_reader :sections, :header + attr_reader :sections + attr_accessor :header def initialize @sections = [] @header = nil end def each(&block) = @sections.each(&block) def [](idx) = @sections[idx] - def select_by_name(section_name) = @sections.select { [it.section_name, it.name].include?(section_name.to_s) } + def find_by_name(section_name) = @sections.find { section_name == it.section_name } + def select_by_name(section_name) = @sections.select { section_name == it.section_name } end end end diff --git a/lib/caotral/binary/elf/program_header.rb b/lib/caotral/binary/elf/program_header.rb new file mode 100644 index 0000000..8319a3f --- /dev/null +++ b/lib/caotral/binary/elf/program_header.rb @@ -0,0 +1,34 @@ +require "caotral/binary/elf/utils" + +module Caotral + class Binary + class ELF + class ProgramHeader + include Caotral::Binary::ELF::Utils + def initialize + @type = num2bytes(0, 4) + @flags = num2bytes(0, 4) + @offset = num2bytes(0, 8) + @vaddr = num2bytes(0, 8) + @paddr = num2bytes(0, 8) + @filesz = num2bytes(0, 8) + @memsz = num2bytes(0, 8) + @align = num2bytes(0, 8) + end + def build = bytes.flatten.pack("C*") + def set!(type: nil, flags: nil, offset: nil, vaddr: nil, paddr: nil, filesz: nil, memsz: nil, align: nil) + @type = num2bytes(type, 4) if check(type, 4) + @flags = num2bytes(flags, 4) if check(flags, 4) + @offset = num2bytes(offset, 8) if check(offset, 8) + @vaddr = num2bytes(vaddr, 8) if check(vaddr, 8) + @paddr = num2bytes(paddr, 8) if check(paddr, 8) + @filesz = num2bytes(filesz, 8) if check(filesz, 8) + @memsz = num2bytes(memsz, 8) if check(memsz, 8) + @align = num2bytes(align, 8) if check(align, 8) + self + end + private def bytes = [@type, @flags, @offset, @vaddr, @paddr, @filesz, @memsz, @align] + end + end + end +end diff --git a/lib/caotral/binary/elf/section.rb b/lib/caotral/binary/elf/section.rb index d169ec8..fc397a7 100644 --- a/lib/caotral/binary/elf/section.rb +++ b/lib/caotral/binary/elf/section.rb @@ -2,7 +2,8 @@ module Caotral class Binary class ELF class Section - attr_reader :header, :body, :section_name + attr_accessor :body, :section_name + attr_reader :header def initialize(header:, body:, section_name:) @header = header @body = body diff --git a/lib/caotral/binary/elf/section/rel.rb b/lib/caotral/binary/elf/section/rel.rb new file mode 100644 index 0000000..850871d --- /dev/null +++ b/lib/caotral/binary/elf/section/rel.rb @@ -0,0 +1,37 @@ +require "caotral/binary/elf/utils" +module Caotral + class Binary + class ELF + class Section + class Rel + include Caotral::Binary::ELF::Utils + def initialize(addend: true) + @offset = num2bytes(0, 8) + @info = num2bytes(0, 8) + @addend = addend ? num2bytes(0, 8) : false + end + + def set!(offset: nil, info: nil, addend: nil) + @offset = num2bytes(offset, 8) if check(offset, 8) + @info = num2bytes(info, 8) if check(info, 8) + @addend = num2bytes(addend, 8) if check(addend, 8) + self + end + + def build = bytes.flatten.pack("C*") + def offset = @offset.pack("C*").unpack1("Q<") + def info = @info.pack("C*").unpack1("Q<") + def addend + raise "No addend field in this REL entry" unless addend? + @addend.pack("C*").unpack1("Q<") + end + def sym = @info.pack("C*").unpack1("Q<") >> 32 + def type = @info.pack("C*").unpack1("Q<") & 0xffffffff + def addend? = !!@addend + + private def bytes = addend? ? [@offset, @info, @addend] : [@offset, @info] + end + end + end + end +end diff --git a/lib/caotral/binary/elf/section/strtab.rb b/lib/caotral/binary/elf/section/strtab.rb new file mode 100644 index 0000000..c7b1b2d --- /dev/null +++ b/lib/caotral/binary/elf/section/strtab.rb @@ -0,0 +1,28 @@ +require "caotral/binary/elf/utils" +module Caotral + class Binary + class ELF + class Section + class Strtab + include Caotral::Binary::ELF::Utils + attr_reader :names + def initialize(names = "\0main\0", **opts) = @names = names + def build = @names.bytes.pack("C*") + def offset_of(name) + offset = 0 + @names.split("\0").each do |n| + return offset if n == name + offset += n.bytesize + 1 + end + nil + end + + def lookup(offset) + return "" if offset == 0 + @names.byteslice(offset..).split("\0", 2).first + end + end + end + end + end +end diff --git a/lib/caotral/binary/elf/section/symtab.rb b/lib/caotral/binary/elf/section/symtab.rb new file mode 100644 index 0000000..a273a26 --- /dev/null +++ b/lib/caotral/binary/elf/section/symtab.rb @@ -0,0 +1,37 @@ +require "caotral/binary/elf/utils" + +module Caotral + class Binary + class ELF + class Section + class Symtab + include Caotral::Binary::ELF::Utils + attr_accessor :name_string + def initialize(**opts) + @entsize = [] + @name = num2bytes(0, 4) + @info = num2bytes(0, 1) + @other = num2bytes(0, 1) + @shndx = num2bytes(0, 2) + @value = num2bytes(0, 8) + @size = num2bytes(0, 8) + @name_string = "" + end + + def set!(name: nil, info: nil, other: nil, shndx: nil, value: nil, size: nil) + @name = num2bytes(name, 4) if check(name, 4) + @info = num2bytes(info, 1) if check(info, 1) + @other = num2bytes(other, 1) if check(other, 1) + @shndx = num2bytes(shndx, 2) if check(shndx, 2) + @value = num2bytes(value, 8) if check(value, 8) + @size = num2bytes(size, 8) if check(size, 8) + self + end + + def name_offset = @name.pack("C*").unpack1("L<") + def value = @value.pack("C*").unpack1("Q<") + end + end + end + end +end diff --git a/lib/caotral/linker/elf.rb b/lib/caotral/linker/elf.rb deleted file mode 100644 index 0635e21..0000000 --- a/lib/caotral/linker/elf.rb +++ /dev/null @@ -1,14 +0,0 @@ -require_relative "elf/header" -require_relative "elf/sections" - -module Caotral - class Linker - class ELF - attr_reader :sections, :header - def initialize - @sections = Caotral::Linker::ELF::Sections.new - @header = Caotral::Linker::ELF::Header.new - end - end - end -end diff --git a/lib/caotral/linker/reader.rb b/lib/caotral/linker/reader.rb index 1d6c7c1..e5d650a 100644 --- a/lib/caotral/linker/reader.rb +++ b/lib/caotral/linker/reader.rb @@ -1,10 +1,5 @@ require "stringio" -require_relative "elf" -require_relative "elf/section" -require_relative "elf/section_header" -require_relative "elf/section/strtab" -require_relative "elf/section/symtab" -require_relative "elf/section/rel" +require_relative "../binary/elf" module Caotral class Linker @@ -15,13 +10,14 @@ def self.read!(input:, debug: false, linker_options: []) = new(input:, debug:, l def initialize(input:, debug: false, linker_options: []) @input = decision(input) @bin = StringIO.new(@input.read) - @context = Caotral::Linker::ELF.new + @context = Caotral::Binary::ELF.new + @context.header = Caotral::Binary::ELF::Header.new end def read header = @bin.read(0x40) ident = header[0, 16] - raise "Not ELF file" unless ident == Caotral::Linker::ELF::Header::IDENT_STR + raise "Not ELF file" unless ident == Caotral::Binary::ELF::Header::IDENT_STR entry = header[24, 8].unpack("Q<").first phoffset = header[32, 8].unpack("Q<").first @@ -45,18 +41,17 @@ def read addralign = sh_entry[48, 8].unpack("Q<").first entsize = sh_entry[56, 8].unpack("Q<").first type_sym = type(type_val) - section_header = Caotral::Linker::ELF::SectionHeader.new + section_header = Caotral::Binary::ELF::SectionHeader.new section_header.set!(name:, type: type_val, flags:, addr:, offset:, size:, link:, info:, addralign:, entsize:) section_name = i == shstrndx ? ".shstrtab" : nil - args = { type: type_sym, section_name: }.compact - section = Caotral::Linker::ELF::Section.new(**args) - section.header = section_header - @context.sections.add(section) + section = Caotral::Binary::ELF::Section.new(header: section_header, section_name:, body: nil) + @context.sections.push(section) end + shstrtab = @context.sections[shstrndx].tap do |shstrtab| @bin.pos = shstrtab.header.offset names = @bin.read(shstrtab.header.size) - shstrtab.body = Caotral::Linker::ELF::Section::Strtab.new(names) + shstrtab.body = Caotral::Binary::ELF::Section::Strtab.new(names) shstrtab end @@ -71,7 +66,7 @@ def read body_bin = @bin.read(section.header.size) section.body = case type when :strtab - Caotral::Linker::ELF::Section::Strtab.new(body_bin) + Caotral::Binary::ELF::Section::Strtab.new(body_bin) when :symtab symtab_entsize = section.header.entsize count = body_bin.bytesize / symtab_entsize @@ -83,7 +78,7 @@ def read shndx = sym_bin[6, 2].unpack1("S<") value = sym_bin[8, 8].unpack1("Q<") size = sym_bin[16, 8].unpack1("Q<") - Caotral::Linker::ELF::Section::Symtab.new.set!(name:, info:, other:, shndx:, value:, size:) + Caotral::Binary::ELF::Section::Symtab.new.set!(name:, info:, other:, shndx:, value:, size:) end when :rel, :rela rela = type == :rela @@ -95,14 +90,14 @@ def read offset = rel_bin[0, 8].unpack1("Q<") info = rel_bin[8, 8].unpack1("Q<") addend = rela ? rel_bin[16, 8].unpack1("q<") : nil - Caotral::Linker::ELF::Section::Rel.new(addend: rela).set!(offset:, info:, addend:) + Caotral::Binary::ELF::Section::Rel.new(addend: rela).set!(offset:, info:, addend:) end when :progbits body_bin end end - strtab = @context.sections[".strtab"] + strtab = @context.find_by_name(".strtab") @context.sections.select { it.header.type == :symtab }.each do |symtab| symtab.body.each do |sym| name_offset = sym.name_offset @@ -125,7 +120,7 @@ def decision(input) end end - def type(num) = Caotral::Linker::ELF::SectionHeader::SHT_BY_VALUE.fetch(num, :unknown) + def type(num) = Caotral::Binary::ELF::SectionHeader::SHT_BY_VALUE.fetch(num, :unknown) end end end diff --git a/lib/caotral/linker/writer.rb b/lib/caotral/linker/writer.rb index acacb50..73ec3b3 100644 --- a/lib/caotral/linker/writer.rb +++ b/lib/caotral/linker/writer.rb @@ -1,5 +1,4 @@ -require "caotral/binary/elf/utils" -require_relative "elf/program_header" +require "caotral/binary/elf" module Caotral class Linker @@ -21,11 +20,11 @@ def write f = File.open(@output, "wb") phoffset, phnum, phsize, ehsize = 64, 1, 56, 64 header = @elf_obj.header.set!(type: 2, phoffset:, phnum:, phsize:, ehsize:) - ph = Caotral::Linker::ELF::ProgramHeader.new - text_section = @elf_obj.sections[".text"] + ph = Caotral::Binary::ELF::ProgramHeader.new + text_section = @elf_obj.find_by_name(".text") rel_sections = @elf_obj.sections.select { RELOCATION_SECTION_NAMES.include?(it.section_name) } start_bytes = [0xe8, *[0] * 4, 0x48, 0x89, 0xc7, 0x48, 0xc7, 0xc0, 0x3c, 0x00, 0x00, 0x00, 0x0f, 0x05] - symtab = @elf_obj.sections[".symtab"] + symtab = @elf_obj.find_by_name(".symtab") symtab_body = symtab.body old_text = text_section.body main_sym = symtab_body.find { |sym| sym.name_string == "main" } @@ -68,19 +67,19 @@ def write gap = [text_offset - f.pos, 0].max f.write("\0" * gap) f.write(text_section.body) - shstrtab = @elf_obj.sections[".shstrtab"] + shstrtab = @elf_obj.find_by_name(".shstrtab") shstrtab_offset = f.pos f.write(shstrtab.body.names) shstrtab.header.set!(offset: shstrtab_offset, size: shstrtab.body.names.bytesize) - write_sections = @elf_obj.sections.select { ALLOW_SECTIONS.include?(it.section_name) || it.name == "" } + write_sections = @elf_obj.sections.select { ALLOW_SECTIONS.include?(it.section_name) || it.section_name.nil? } shoffset = f.pos shstrndx = write_sections.index { it.section_name == ".shstrtab" } shnum = write_sections.size @elf_obj.header.set!(shoffset:, shnum:, shstrndx:) - names = @elf_obj.sections[".shstrtab"].body + names = @elf_obj.find_by_name(".shstrtab").body write_sections.each do |section| - lookup_name = section.name.sub(/\A\0/, "") + lookup_name = section.section_name name_offset = names.offset_of(lookup_name) section.header.set!(name: name_offset) if name_offset f.write(section.header.build) diff --git a/test/caotral/linker/reader_test.rb b/test/caotral/linker/reader_test.rb index 1b47618..c36b81d 100644 --- a/test/caotral/linker/reader_test.rb +++ b/test/caotral/linker/reader_test.rb @@ -7,7 +7,7 @@ def test_read elf_obj = Caotral::Linker::Reader.read!(input: "plus.o", debug: false) assert_equal elf_obj.header.shoffset, 264 assert_equal elf_obj.sections.size, 8 - assert_equal elf_obj.sections[0].section_name, "null" + assert_equal elf_obj.sections[0].section_name, nil shstrtab = elf_obj.sections[elf_obj.header.shstrndx] assert_equal shstrtab.section_name, ".shstrtab" assert_equal shstrtab.body.names, "\0.text\0.data\0.bss\0.note\0.symtab\0.strtab\0.shstrtab\0" From 393f6bdc384dcc5471af7c0d8fc771c7c637d9d2 Mon Sep 17 00:00:00 2001 From: "MATSUMOTO, Katsuyoshi" Date: Tue, 6 Jan 2026 22:55:48 +0900 Subject: [PATCH 09/32] remove unused files in linker --- lib/caotral/linker/elf/header.rb | 9 ------ lib/caotral/linker/elf/program_header.rb | 34 ---------------------- lib/caotral/linker/elf/section.rb | 15 ---------- lib/caotral/linker/elf/section/rel.rb | 37 ------------------------ lib/caotral/linker/elf/section/strtab.rb | 28 ------------------ lib/caotral/linker/elf/section/symtab.rb | 37 ------------------------ lib/caotral/linker/elf/section/text.rb | 4 --- lib/caotral/linker/elf/section_header.rb | 10 ------- lib/caotral/linker/elf/sections.rb | 37 ------------------------ 9 files changed, 211 deletions(-) delete mode 100644 lib/caotral/linker/elf/header.rb delete mode 100644 lib/caotral/linker/elf/program_header.rb delete mode 100644 lib/caotral/linker/elf/section.rb delete mode 100644 lib/caotral/linker/elf/section/rel.rb delete mode 100644 lib/caotral/linker/elf/section/strtab.rb delete mode 100644 lib/caotral/linker/elf/section/symtab.rb delete mode 100644 lib/caotral/linker/elf/section/text.rb delete mode 100644 lib/caotral/linker/elf/section_header.rb delete mode 100644 lib/caotral/linker/elf/sections.rb diff --git a/lib/caotral/linker/elf/header.rb b/lib/caotral/linker/elf/header.rb deleted file mode 100644 index 1d9fe4a..0000000 --- a/lib/caotral/linker/elf/header.rb +++ /dev/null @@ -1,9 +0,0 @@ -require "caotral/binary/elf/header" -module Caotral - class Linker - class ELF - class Header < Caotral::Binary::ELF::Header - end - end - end -end diff --git a/lib/caotral/linker/elf/program_header.rb b/lib/caotral/linker/elf/program_header.rb deleted file mode 100644 index a217b8f..0000000 --- a/lib/caotral/linker/elf/program_header.rb +++ /dev/null @@ -1,34 +0,0 @@ -require "caotral/binary/elf/utils" - -module Caotral - class Linker - class ELF - class ProgramHeader - include Caotral::Binary::ELF::Utils - def initialize - @type = num2bytes(0, 4) - @flags = num2bytes(0, 4) - @offset = num2bytes(0, 8) - @vaddr = num2bytes(0, 8) - @paddr = num2bytes(0, 8) - @filesz = num2bytes(0, 8) - @memsz = num2bytes(0, 8) - @align = num2bytes(0, 8) - end - def build = bytes.flatten.pack("C*") - def set!(type: nil, flags: nil, offset: nil, vaddr: nil, paddr: nil, filesz: nil, memsz: nil, align: nil) - @type = num2bytes(type, 4) if check(type, 4) - @flags = num2bytes(flags, 4) if check(flags, 4) - @offset = num2bytes(offset, 8) if check(offset, 8) - @vaddr = num2bytes(vaddr, 8) if check(vaddr, 8) - @paddr = num2bytes(paddr, 8) if check(paddr, 8) - @filesz = num2bytes(filesz, 8) if check(filesz, 8) - @memsz = num2bytes(memsz, 8) if check(memsz, 8) - @align = num2bytes(align, 8) if check(align, 8) - self - end - private def bytes = [@type, @flags, @offset, @vaddr, @paddr, @filesz, @memsz, @align] - end - end - end -end diff --git a/lib/caotral/linker/elf/section.rb b/lib/caotral/linker/elf/section.rb deleted file mode 100644 index 35249f7..0000000 --- a/lib/caotral/linker/elf/section.rb +++ /dev/null @@ -1,15 +0,0 @@ -class Caotral::Linker - class ELF - class Section - attr_accessor :header, :body, :section_name - def initialize(type:, section_name: nil, options: {}) - type_string = type.to_s.capitalize - type_string = type_string.upcase if type_string == "Bss" - @section_name = (section_name.nil? ? type_string : section_name).to_s.downcase - @header, @body = nil, nil - end - - def name = @section_name == "null" ? "" : "\0#{@section_name}" - end - end -end diff --git a/lib/caotral/linker/elf/section/rel.rb b/lib/caotral/linker/elf/section/rel.rb deleted file mode 100644 index 3991ced..0000000 --- a/lib/caotral/linker/elf/section/rel.rb +++ /dev/null @@ -1,37 +0,0 @@ -require "caotral/binary/elf/utils" -module Caotral - class Linker - class ELF - class Section - class Rel - include Caotral::Binary::ELF::Utils - def initialize(addend: true) - @offset = num2bytes(0, 8) - @info = num2bytes(0, 8) - @addend = addend ? num2bytes(0, 8) : false - end - - def set!(offset: nil, info: nil, addend: nil) - @offset = num2bytes(offset, 8) if check(offset, 8) - @info = num2bytes(info, 8) if check(info, 8) - @addend = num2bytes(addend, 8) if check(addend, 8) - self - end - - def build = bytes.flatten.pack("C*") - def offset = @offset.pack("C*").unpack1("Q<") - def info = @info.pack("C*").unpack1("Q<") - def addend - raise "No addend field in this REL entry" unless addend? - @addend.pack("C*").unpack1("Q<") - end - def sym = @info.pack("C*").unpack1("Q<") >> 32 - def type = @info.pack("C*").unpack1("Q<") & 0xffffffff - def addend? = !!@addend - - private def bytes = addend? ? [@offset, @info, @addend] : [@offset, @info] - end - end - end - end -end diff --git a/lib/caotral/linker/elf/section/strtab.rb b/lib/caotral/linker/elf/section/strtab.rb deleted file mode 100644 index fe07cfe..0000000 --- a/lib/caotral/linker/elf/section/strtab.rb +++ /dev/null @@ -1,28 +0,0 @@ -require "caotral/binary/elf/utils" -module Caotral - class Linker - class ELF - class Section - class Strtab - include Caotral::Binary::ELF::Utils - attr_reader :names - def initialize(names = "\0main\0", **opts) = @names = names - def build = @names.bytes.pack("C*") - def offset_of(name) - offset = 0 - @names.split("\0").each do |n| - return offset if n == name - offset += n.bytesize + 1 - end - nil - end - - def lookup(offset) - return "" if offset == 0 - @names.byteslice(offset..).split("\0", 2).first - end - end - end - end - end -end diff --git a/lib/caotral/linker/elf/section/symtab.rb b/lib/caotral/linker/elf/section/symtab.rb deleted file mode 100644 index 2b95e7e..0000000 --- a/lib/caotral/linker/elf/section/symtab.rb +++ /dev/null @@ -1,37 +0,0 @@ -require "caotral/binary/elf/utils" - -module Caotral - class Linker - class ELF - class Section - class Symtab - include Caotral::Binary::ELF::Utils - attr_accessor :name_string - def initialize(**opts) - @entsize = [] - @name = num2bytes(0, 4) - @info = num2bytes(0, 1) - @other = num2bytes(0, 1) - @shndx = num2bytes(0, 2) - @value = num2bytes(0, 8) - @size = num2bytes(0, 8) - @name_string = "" - end - - def set!(name: nil, info: nil, other: nil, shndx: nil, value: nil, size: nil) - @name = num2bytes(name, 4) if check(name, 4) - @info = num2bytes(info, 1) if check(info, 1) - @other = num2bytes(other, 1) if check(other, 1) - @shndx = num2bytes(shndx, 2) if check(shndx, 2) - @value = num2bytes(value, 8) if check(value, 8) - @size = num2bytes(size, 8) if check(size, 8) - self - end - - def name_offset = @name.pack("C*").unpack1("L<") - def value = @value.pack("C*").unpack1("Q<") - end - end - end - end -end diff --git a/lib/caotral/linker/elf/section/text.rb b/lib/caotral/linker/elf/section/text.rb deleted file mode 100644 index e3998f5..0000000 --- a/lib/caotral/linker/elf/section/text.rb +++ /dev/null @@ -1,4 +0,0 @@ -class Caotral::Linker::ELF::Section::Text - def initialize = @bytes = [] - def build = @bytes.flatten.pack("C*") -end diff --git a/lib/caotral/linker/elf/section_header.rb b/lib/caotral/linker/elf/section_header.rb deleted file mode 100644 index 107555f..0000000 --- a/lib/caotral/linker/elf/section_header.rb +++ /dev/null @@ -1,10 +0,0 @@ -require "caotral/binary/elf/section_header" - -module Caotral - class Linker - class ELF - class SectionHeader < Caotral::Binary::ELF::SectionHeader - end - end - end -end diff --git a/lib/caotral/linker/elf/sections.rb b/lib/caotral/linker/elf/sections.rb deleted file mode 100644 index ec8444f..0000000 --- a/lib/caotral/linker/elf/sections.rb +++ /dev/null @@ -1,37 +0,0 @@ -class Caotral::Linker::ELF::Sections - include Enumerable - - def initialize = @sections = [] - def each(&block) = @sections.each(&block) - def add(section) = @sections << section - alias << add - def size = @sections.size - alias length size - def empty? = @sections.empty? - def count(&block) - return @sections.count(&block) if block_given? - @sections.size - end - - def [](index) - case index - when Integer - @sections[index] - when String, Symbol - @sections.find { it.section_name == prepend_dot(index) } - else - raise ArgumentError, "Invalid index type: #{index.class}" - end - end - - def index(name) - name = prepend_dot(name) - @sections.each_with_index do |section, idx| - return idx if section.section_name == name - end - end - private def prepend_dot(name) - str = name.to_s - str.start_with?(".") ? str : ".#{str}" - end -end From 575cb4680d614c2d6bb6e1f1117ddee9e488b7bc Mon Sep 17 00:00:00 2001 From: "MATSUMOTO, Katsuyoshi" Date: Tue, 6 Jan 2026 23:09:15 +0900 Subject: [PATCH 10/32] update sig --- sig/caotral/binary/elf.rbs | 10 ++++++++++ .../{linker => binary}/elf/program_header.rbs | 2 +- sig/caotral/binary/elf/section.rbs | 11 +++++++++++ sig/caotral/binary/elf/section/rel.rbs | 11 +++++++++++ .../{linker => binary}/elf/section/strtab.rbs | 2 +- .../{linker => binary}/elf/section/symtab.rbs | 6 ++++-- sig/caotral/linker/elf.rbs | 3 --- sig/caotral/linker/elf/header.rbs | 2 -- sig/caotral/linker/elf/section.rbs | 8 -------- sig/caotral/linker/elf/section/rel.rbs | 12 ------------ sig/caotral/linker/elf/section_header.rbs | 2 -- sig/caotral/linker/reader.rbs | 4 ++-- sig/caotral/linker/writer.rbs | 4 ++-- 13 files changed, 42 insertions(+), 35 deletions(-) rename sig/caotral/{linker => binary}/elf/program_header.rbs (86%) create mode 100644 sig/caotral/binary/elf/section.rbs create mode 100644 sig/caotral/binary/elf/section/rel.rbs rename sig/caotral/{linker => binary}/elf/section/strtab.rbs (80%) rename sig/caotral/{linker => binary}/elf/section/symtab.rbs (67%) delete mode 100644 sig/caotral/linker/elf.rbs delete mode 100644 sig/caotral/linker/elf/header.rbs delete mode 100644 sig/caotral/linker/elf/section.rbs delete mode 100644 sig/caotral/linker/elf/section/rel.rbs delete mode 100644 sig/caotral/linker/elf/section_header.rbs diff --git a/sig/caotral/binary/elf.rbs b/sig/caotral/binary/elf.rbs index 0a18953..ba62e9e 100644 --- a/sig/caotral/binary/elf.rbs +++ b/sig/caotral/binary/elf.rbs @@ -1,2 +1,12 @@ class Caotral::Binary::ELF + include Enumerable[Caotral::Binary::ELF::Section] + + attr_reader sections: Array[Caotral::Binary::ELF::Section] + attr_accessor header: Caotral::Binary::ELF::Header? + + def initialize: () -> void + def each: () { (Caotral::Binary::ELF::Section) -> void } -> Array[Caotral::Binary::ELF::Section] + def []: (Integer) -> Caotral::Binary::ELF::Section? + def find_by_name: (String | Symbol) -> Caotral::Binary::ELF::Section? + def select_by_name: (String | Symbol) -> Array[Caotral::Binary::ELF::Section] end diff --git a/sig/caotral/linker/elf/program_header.rbs b/sig/caotral/binary/elf/program_header.rbs similarity index 86% rename from sig/caotral/linker/elf/program_header.rbs rename to sig/caotral/binary/elf/program_header.rbs index e8391bf..75b13a3 100644 --- a/sig/caotral/linker/elf/program_header.rbs +++ b/sig/caotral/binary/elf/program_header.rbs @@ -1,4 +1,4 @@ -class Caotral::Linker::ELF::ProgramHeader +class Caotral::Binary::ELF::ProgramHeader def initialize: () -> void def build: () -> String def set!: ( diff --git a/sig/caotral/binary/elf/section.rbs b/sig/caotral/binary/elf/section.rbs new file mode 100644 index 0000000..9933f46 --- /dev/null +++ b/sig/caotral/binary/elf/section.rbs @@ -0,0 +1,11 @@ +class Caotral::Binary::ELF::Section + attr_reader header: Caotral::Binary::ELF::SectionHeader + attr_accessor body: untyped + attr_accessor section_name: String? + + def initialize: ( + header: Caotral::Binary::ELF::SectionHeader, + body: untyped, + section_name: String? + ) -> void +end diff --git a/sig/caotral/binary/elf/section/rel.rbs b/sig/caotral/binary/elf/section/rel.rbs new file mode 100644 index 0000000..cc2e588 --- /dev/null +++ b/sig/caotral/binary/elf/section/rel.rbs @@ -0,0 +1,11 @@ +class Caotral::Binary::ELF::Section::Rel + def initialize: (?addend: bool) -> void + def set!: (?offset: Integer?, ?info: Integer?, ?addend: Integer?) -> self + def build: () -> String + def offset: () -> Integer + def info: () -> Integer + def addend: () -> Integer + def sym: () -> Integer + def type: () -> Integer + def addend?: () -> bool +end diff --git a/sig/caotral/linker/elf/section/strtab.rbs b/sig/caotral/binary/elf/section/strtab.rbs similarity index 80% rename from sig/caotral/linker/elf/section/strtab.rbs rename to sig/caotral/binary/elf/section/strtab.rbs index e5d3c8d..a602acb 100644 --- a/sig/caotral/linker/elf/section/strtab.rbs +++ b/sig/caotral/binary/elf/section/strtab.rbs @@ -1,4 +1,4 @@ -class Caotral::Linker::ELF::Section::Strtab +class Caotral::Binary::ELF::Section::Strtab attr_reader names: String def initialize: (?String, **untyped) -> void diff --git a/sig/caotral/linker/elf/section/symtab.rbs b/sig/caotral/binary/elf/section/symtab.rbs similarity index 67% rename from sig/caotral/linker/elf/section/symtab.rbs rename to sig/caotral/binary/elf/section/symtab.rbs index 3a8c272..a69110d 100644 --- a/sig/caotral/linker/elf/section/symtab.rbs +++ b/sig/caotral/binary/elf/section/symtab.rbs @@ -1,7 +1,7 @@ -class Caotral::Linker::ELF::Section::Symtab +class Caotral::Binary::ELF::Section::Symtab attr_accessor name_string: String - def initialize: (?opts: untyped) -> void + def initialize: (**untyped) -> void def set!: ( ?name: Integer?, ?info: Integer?, @@ -10,5 +10,7 @@ class Caotral::Linker::ELF::Section::Symtab ?value: Integer?, ?size: Integer? ) -> self + def name_offset: () -> Integer + def value: () -> Integer end diff --git a/sig/caotral/linker/elf.rbs b/sig/caotral/linker/elf.rbs deleted file mode 100644 index a295925..0000000 --- a/sig/caotral/linker/elf.rbs +++ /dev/null @@ -1,3 +0,0 @@ -class Caotral::Linker::ELF - def initialize: () -> void -end diff --git a/sig/caotral/linker/elf/header.rbs b/sig/caotral/linker/elf/header.rbs deleted file mode 100644 index fcda664..0000000 --- a/sig/caotral/linker/elf/header.rbs +++ /dev/null @@ -1,2 +0,0 @@ -class Caotral::Linker::ELF::Header < Caotral::Binary::ELF::Header -end diff --git a/sig/caotral/linker/elf/section.rbs b/sig/caotral/linker/elf/section.rbs deleted file mode 100644 index 2d7b111..0000000 --- a/sig/caotral/linker/elf/section.rbs +++ /dev/null @@ -1,8 +0,0 @@ -class Caotral::Linker::ELF::Section - attr_accessor header: untyped - attr_accessor body: untyped - attr_accessor section_name: String - - def initialize: (type: Symbol, ?section_name: String?, ?options: Hash[Symbol, untyped]) -> void - def name: () -> String -end diff --git a/sig/caotral/linker/elf/section/rel.rbs b/sig/caotral/linker/elf/section/rel.rbs deleted file mode 100644 index 6176c32..0000000 --- a/sig/caotral/linker/elf/section/rel.rbs +++ /dev/null @@ -1,12 +0,0 @@ -class Caotral::Linker::ELF::Section::Rel - def initialize: (?addend: bool) -> void - def set!: ( - ?offset: Integer?, - ?info: Integer?, - ?addend: Integer? - ) -> self - def build: () -> String - def offset: () -> Integer - def info: () -> Integer - def addend: () -> Integer -end diff --git a/sig/caotral/linker/elf/section_header.rbs b/sig/caotral/linker/elf/section_header.rbs deleted file mode 100644 index 30a49e1..0000000 --- a/sig/caotral/linker/elf/section_header.rbs +++ /dev/null @@ -1,2 +0,0 @@ -class Caotral::Linker::ELF::SectionHeader < Caotral::Binary::ELF::SectionHeader -end diff --git a/sig/caotral/linker/reader.rbs b/sig/caotral/linker/reader.rbs index 689f5e4..23a769c 100644 --- a/sig/caotral/linker/reader.rbs +++ b/sig/caotral/linker/reader.rbs @@ -1,5 +1,5 @@ class Caotral::Linker::Reader - def self.read!: (input: String, ?debug: bool, ?linker_options: Array[String]) -> Caotral::Linker::ELF + def self.read!: (input: String, ?debug: bool, ?linker_options: Array[String]) -> Caotral::Binary::ELF def initialize: (input: String, ?debug: bool, ?linker_options: Array[String]) -> void - def read: () -> Caotral::Linker::ELF + def read: () -> Caotral::Binary::ELF end diff --git a/sig/caotral/linker/writer.rbs b/sig/caotral/linker/writer.rbs index d4d5f9d..d47f1ef 100644 --- a/sig/caotral/linker/writer.rbs +++ b/sig/caotral/linker/writer.rbs @@ -1,5 +1,5 @@ class Caotral::Linker::Writer - def self.write!: (elf_obj: Caotral::Linker::ELF, output: String, ?entry: Integer, ?debug: bool) -> String - def initialize: (elf_obj: Caotral::Linker::ELF, output: String, ?entry: Integer, ?debug: bool) -> void + def self.write!: (elf_obj: Caotral::Binary::ELF, output: String, ?entry: Integer, ?debug: bool) -> String + def initialize: (elf_obj: Caotral::Binary::ELF, output: String, ?entry: Integer, ?debug: bool) -> void def write: () -> String end From 224c93a4cee0f424443453ade25e0d5000bac543 Mon Sep 17 00:00:00 2001 From: "MATSUMOTO, Katsuyoshi" Date: Wed, 7 Jan 2026 15:41:29 +0900 Subject: [PATCH 11/32] introduce reader for assembly file --- lib/caotral/assembler/reader.rb | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 lib/caotral/assembler/reader.rb diff --git a/lib/caotral/assembler/reader.rb b/lib/caotral/assembler/reader.rb new file mode 100644 index 0000000..60e127a --- /dev/null +++ b/lib/caotral/assembler/reader.rb @@ -0,0 +1,26 @@ +require "set" + +require "caotral/binary/elf" + +module Caotral + class Assembler + class Reader + def initialize(input:, debug: false) + @input, @debug = input, debug + @labels = Set.new + end + + def read + File.open(@input, "r") do |reader| + reader.each_line do |line| + if /^(?