Skip to content

Commit d8167f3

Browse files
committed
add linker elf stubs
1 parent e7e111e commit d8167f3

File tree

16 files changed

+236
-0
lines changed

16 files changed

+236
-0
lines changed

lib/caotral/linker.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ def link(input: @input, output: @output, debug: @debug, shared: @shared) = IO.po
1212

1313
def link_command(input: @input, output: @output, debug: @debug, shared: @shared)
1414
ld_path = []
15+
return to_elf(input:, output:, debug:) if @linker == "self"
16+
1517
if @shared
1618
ld_path << "--shared"
1719
ld_path << "#{libpath}/crti.o"
@@ -36,4 +38,9 @@ def link_command(input: @input, output: @output, debug: @debug, shared: @shared)
3638

3739
def libpath = @libpath ||= File.dirname(Dir.glob("/usr/lib*/**/crti.o").last)
3840
def gcc_libpath = @gcc_libpath ||= File.dirname(Dir.glob("/usr/lib/gcc/x86_64-*/*/crtbegin.o").last)
41+
42+
def to_elf(input: @input, output: @output, debug: @debug)
43+
elf_obj = Caotral::Linker::Reader.new(input:, debug:).read
44+
Caotral::Linker::Writer.new(elf_obj:, output:, debug:).write
45+
end
3946
end

lib/caotral/linker/elf.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class Caotral::Linker::ELF
2+
attr_reader :sections, :header
3+
def initialize
4+
@sections = Caotral::Linker::ELF::Sections.new
5+
@header = Caotral::Linker::ELF::Header.new
6+
end
7+
end

lib/caotral/linker/elf/header.rb

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
class Caotral::Linker::ELF::Header
2+
include Caotral::Assembler::ELF::Utils
3+
IDENT = [0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00].freeze
4+
ELF_FILE_TYPE = { NONE: 0, REL: 1, EXEC: 2, DYN: 3, CORE: 4 }.freeze
5+
6+
def initialize(endian: :little, type: :rel, arc: :amd64)
7+
@ident = IDENT
8+
@type = num2bytes(ELF_FILE_TYPE[elf(type)], 2)
9+
@arch = arch(arc)
10+
@version = num2bytes(1, 4)
11+
@entry = num2bytes(0x00, 8)
12+
@phoffset = num2bytes(0x00, 8)
13+
@shoffset = num2bytes(0x00, 8)
14+
@flags = num2bytes(0x00, 4)
15+
@ehsize = num2bytes(0x40, 2)
16+
@phsize = num2bytes(0x00, 2)
17+
@phnum = num2bytes(0x00, 2)
18+
@shentsize = num2bytes(0x40, 2)
19+
@shnum = num2bytes(0x08, 2)
20+
@shstrndx = num2bytes(0x07, 2)
21+
end
22+
23+
def build = bytes.flatten.pack("C*")
24+
25+
def set!(entry: nil, phoffset: nil, shoffset: nil, shnum: nil, shstrndx: nil)
26+
@entry = num2bytes(entry, 8) if check(entry, 8)
27+
@phoffset = num2bytes(phoffset, 8) if check(phoffset, 8)
28+
@shoffset = num2bytes(shoffset, 8) if check(shoffset, 8)
29+
@shnum = num2bytes(shnum, 2) if check(shnum, 2)
30+
@shstrndx = num2bytes(shstrndx, 2) if check(shstrndx, 2)
31+
end
32+
33+
private
34+
35+
def bytes = [
36+
@ident, @type, @arch, @version, @entry, @phoffset,
37+
@shoffset, @flags, @ehsize, @phsize, @phnum, @shentsize,
38+
@shnum, @shstrndx
39+
]
40+
41+
def arch(machine)
42+
case machine.to_s
43+
in "amd64" | "x86_64" | "x64"
44+
[0x3e, 0x00]
45+
end
46+
end
47+
48+
def elf(type)
49+
case type.to_s
50+
in "relocatable" | "rel"
51+
:REL
52+
in "exe" | "ex" | "exec"
53+
:EXEC
54+
in "shared" | "share" | "dynamic" | "dyn"
55+
:DYN
56+
else
57+
:NONE
58+
end
59+
end
60+
end

lib/caotral/linker/elf/section.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
class Caotral::Linker::ELF::Section
2+
attr_accessor :name
3+
attr_reader :section_name, :header, :body
4+
def initialize(type:, options: {})
5+
type_string = type.to_s.capitalize
6+
type_string = type_string.upcase if type_string == "Bss"
7+
# section_name is extra information about section type
8+
@section_name = type_string.downcase
9+
# name is used in section header string table in elf file
10+
@name = section_name == "null" ? "" : "\0.#{section_name}"
11+
@header, @body = nil, nil
12+
end
13+
end
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class Caotral::Linker::ELF::Section::Shstrtab
2+
include Caotral::Assembler::ELF::Utils
3+
def initialize(**opts) = @name = []
4+
def build = bytes.flatten.pack("C*")
5+
def set!(name:) = (@name << name!(name); self)
6+
end
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class Caotral::Linker::ELF::Section::Strtab
2+
include Caotral::Assembler::ELF::Utils
3+
def initialize(names = "\0main\0", **opts) = @names = names
4+
def build = @names.bytes.pack("C*")
5+
end
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
class Caotral::Linker::ELF::Section::Symtab
2+
include Caotral::Assembler::ELF::Utils
3+
def initialize(**opts)
4+
@entsize = []
5+
@name = num2bytes(0, 4)
6+
@info = num2bytes(0, 1)
7+
@other = num2bytes(0, 1)
8+
@shndx = num2bytes(0, 2)
9+
@value = num2bytes(0, 8)
10+
@size = num2bytes(0, 8)
11+
end
12+
end
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
class Caotral::Linker::ELF::Section::Text
2+
def initialize = @bytes = []
3+
def build = @bytes.flatten.pack("C*")
4+
end
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
class Caotral::Linker::ELF::SectionHeader
2+
include Caotral::Assembler::ELF::Utils
3+
def initialize
4+
@name = nil
5+
@type = nil
6+
@flags = nil
7+
@addr = nil
8+
@offset = nil
9+
@size = nil
10+
@link = nil
11+
@info = nil
12+
@addralign = nil
13+
@entsize = nil
14+
end
15+
16+
def build = bytes.flatten.pack("C*")
17+
18+
def set!(name: nil, type: nil, flags: nil, addr: nil,
19+
offset: nil, size: nil, link: nil, info: nil,
20+
addralign: nil, entsize: nil)
21+
@name = num2bytes(name, 4) if check(name, 4)
22+
@type = num2bytes(type, 4) if check(type, 4)
23+
@flags = num2bytes(flags, 8) if check(flags, 8)
24+
@addr = num2bytes(addr, 8) if check(addr, 8)
25+
@offset = num2bytes(offset, 8) if check(offset, 8)
26+
@size = num2bytes(size, 8) if check(size, 8)
27+
@link = num2bytes(link, 4) if check(link, 4)
28+
@info = num2bytes(info, 4) if check(info, 4)
29+
@addralign = num2bytes(addralign, 8) if check(addralign, 8)
30+
@entsize = num2bytes(entsize, 8) if check(entsize, 8)
31+
self
32+
end
33+
34+
def null! = set!(name: 0, type: 0, flags: 0, addr: 0, offset: 0, size: 0, link: 0, info: 0, addralign: 0, entsize: 0)
35+
36+
private def bytes = [@name, @type, @flags, @addr, @offset, @size, @link, @info, @addralign, @entsize]
37+
end

lib/caotral/linker/elf/sections.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
class Caotral::Linker::ELF::Sections
2+
include Enumerable
3+
4+
def initialize = @sections = []
5+
def each(&block) = @sections.each(&block)
6+
def add(section) = @sections << section
7+
alias << add
8+
def [](index)
9+
case index
10+
when Integer
11+
@sections[index]
12+
when String, Symbol
13+
@sections.find { _1.section_name.to_s == index.to_s }
14+
else
15+
raise ArgumentError, "Invalid index type: #{index.class}"
16+
end
17+
end
18+
end

0 commit comments

Comments
 (0)