Skip to content

Commit 4a41f78

Browse files
authored
Merge pull request #35 from katsyoshi/shared-dyn-sections
Shared dyn sections
2 parents 2e34465 + 93e6f5c commit 4a41f78

5 files changed

Lines changed: 107 additions & 4 deletions

File tree

lib/caotral/binary/elf.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
require_relative "elf/header"
44
require_relative "elf/program_header"
55
require_relative "elf/section"
6+
require_relative "elf/section/dynamic"
67
require_relative "elf/section/rel"
78
require_relative "elf/section/strtab"
89
require_relative "elf/section/symtab"
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
require "caotral/binary/elf/utils"
2+
module Caotral
3+
module Binary
4+
class ELF
5+
class Section
6+
class Dynamic
7+
include Caotral::Binary::ELF::Utils
8+
TAG_TYPES = { NULL: 0 }.freeze
9+
10+
def initialize
11+
@tag = num2bytes(0, 8)
12+
# d_un is a C union. Depending on d_tag, interpret this 8-byte field as either
13+
# a pointer (d_ptr) or an integer value (d_val).
14+
@un = num2bytes(0, 8)
15+
end
16+
17+
def set!(tag: nil, un: nil)
18+
@tag = num2bytes(tag, 8) if check(tag, 8)
19+
@un = num2bytes(un, 8) if check(un, 8)
20+
self
21+
end
22+
23+
def tag = @tag.pack("C*").unpack1("Q<")
24+
def null? = tag == TAG_TYPES[:NULL]
25+
26+
private def bytes = [@tag, @un]
27+
end
28+
end
29+
end
30+
end
31+
end

lib/caotral/linker/builder.rb

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ class Builder
1111
BIND_BY_VALUE = SYMTAB_BIND.invert.freeze
1212
RELOCATION_SECTION_NAMES = [".rela.text", ".rel.text"].freeze
1313
ALLOW_RELOCATION_TYPES = [R_X86_64_PC32, R_X86_64_PLT32].freeze
14+
GENERATED_SECTION_NAMES = [".text", ".strtab", ".symtab", ".shstrtab", /\.rela?\./, ".dynstr", ".dynsym", ".dynamic"].freeze
1415

1516
attr_reader :symbols
1617

@@ -50,6 +51,7 @@ def build
5051
section_name: ".shstrtab",
5152
header: Caotral::Binary::ELF::SectionHeader.new
5253
)
54+
5355
start_bytes = [0xe8, *[0] * 4, 0x48, 0x89, 0xc7, 0x48, 0xc7, 0xc0, 0x3c, 0x00, 0x00, 0x00, 0x0f, 0x05]
5456
exec_text_offset = 0x1000
5557
base_addr = 0x400000
@@ -150,6 +152,7 @@ def build
150152
entsize: 24
151153
)
152154

155+
sections += build_shared_dynamic_sections(sections:, symtab_section:, strtab_section:, text_section:) if @shared
153156
sections << symtab_section
154157

155158
rel_sections.each { |s| sections << s.dup }
@@ -161,7 +164,7 @@ def build
161164
entsize: 0
162165
)
163166

164-
@elf_objs.first.without_sections([".text", ".strtab", ".symtab", ".shstrtab", /\.rela?\./]).each do |section|
167+
@elf_objs.first.without_sections(GENERATED_SECTION_NAMES).each do |section|
165168
sections << section.dup
166169
end
167170

@@ -254,6 +257,35 @@ def resolve_symbols
254257
end
255258

256259
private
260+
def build_shared_dynamic_sections(sections:, symtab_section:, strtab_section:, text_section:)
261+
sht = Caotral::Binary::ELF::SectionHeader::SHT
262+
dynstr_section = Caotral::Binary::ELF::Section.new(
263+
body: Caotral::Binary::ELF::Section::Strtab.new("\0".b),
264+
section_name: ".dynstr",
265+
header: Caotral::Binary::ELF::SectionHeader.new
266+
)
267+
268+
dynstr_section.header.set!(type: sht[:strtab], flags: 0, addralign: 1, entsize: 0)
269+
270+
dynsym_section = Caotral::Binary::ELF::Section.new(
271+
body: [Caotral::Binary::ELF::Section::Symtab.new],
272+
section_name: ".dynsym",
273+
header: Caotral::Binary::ELF::SectionHeader.new
274+
)
275+
276+
dynsym_section.header.set!(type: sht[:dynsym], flags: 0, addralign: 8, entsize: 24)
277+
278+
dynamic_section = Caotral::Binary::ELF::Section.new(
279+
body: [Caotral::Binary::ELF::Section::Dynamic.new],
280+
section_name: ".dynamic",
281+
header: Caotral::Binary::ELF::SectionHeader.new
282+
)
283+
284+
dynamic_section.header.set!(type: sht[:dynamic], flags: 0, addralign: 8, entsize: 16)
285+
286+
[dynstr_section, dynsym_section, dynamic_section]
287+
end
288+
257289
def ref_index(sections, section_name)
258290
raise Caotral::Binary::ELF::Error, "invalid section name: #{section_name}" if section_name.nil?
259291
ref_names = "." + section_name.split(".").filter { |sn| !sn.empty? && sn != "rel" && sn != "rela" }.join(".")

lib/caotral/linker/writer.rb

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ def write
4141
gap = [text_offset - f.pos, 0].max
4242
f.write("\0" * gap)
4343
f.write(text_section.body)
44+
write_shared_dynamic_sections(file: f) if @shared
4445
symtab_offset = f.pos
4546
symtab_section.body.each { |sym| f.write(sym.build) }
4647
symtab_entsize = symtab_section.body.first&.build&.bytesize.to_i
@@ -67,7 +68,6 @@ def write
6768
f.write(shstrtab_section.body.names)
6869
shoffset = f.pos
6970
shstrndx = write_section_index(".shstrtab")
70-
strtabndx = write_section_index(".strtab")
7171
symtabndx = write_section_index(".symtab")
7272
shnum = @write_sections.size
7373
@elf_obj.header.set!(shoffset:, shnum:, shstrndx:)
@@ -78,8 +78,8 @@ def write
7878
lookup_name = section.section_name
7979
name_offset = names.offset_of(lookup_name)
8080
name, info, entsize = (name_offset.nil? ? 0 : name_offset), header.info, header.entsize
81-
link = header.link
82-
link = strtabndx if section.section_name == ".symtab"
81+
link = link_index(section.section_name)
82+
link = header.link if link.nil?
8383
if [:rel, :rela].include?(header.type)
8484
link = symtabndx
8585
info = ref_index(section.section_name)
@@ -100,13 +100,34 @@ def write_order_sections
100100
write_order = []
101101
write_order << @elf_obj.sections.find { |s| s.section_name.nil? }
102102
write_order << @elf_obj.find_by_name(".text")
103+
write_order << @elf_obj.find_by_name(".dynstr")
104+
write_order << @elf_obj.find_by_name(".dynsym")
105+
write_order << @elf_obj.find_by_name(".dynamic")
103106
write_order << @elf_obj.find_by_name(".symtab")
104107
write_order << @elf_obj.find_by_name(".strtab")
105108
write_order.concat(@elf_obj.select_by_names(RELOCATION_SECTION_NAMES))
106109
write_order << @elf_obj.find_by_name(".shstrtab")
107110
write_order.compact
108111
end
109112
def write_section_index(section_name) = @write_sections.index { it.section_name == section_name }
113+
114+
def write_shared_dynamic_sections(file:)
115+
dynstr_offset = file.pos
116+
file.write(dynstr_section.body.build)
117+
size = file.pos - dynstr_offset
118+
dynstr_section.header.set!(offset: dynstr_offset, size:)
119+
120+
dynsym_offset = file.pos
121+
dynsym_section.body.each { |dynsym| file.write(dynsym.build) }
122+
size = file.pos - dynsym_offset
123+
dynsym_section.header.set!(offset: dynsym_offset, size:)
124+
125+
dynamic_offset = file.pos
126+
dynamic_section.body.each { |dynamic| file.write(dynamic.build) }
127+
size = file.pos - dynamic_offset
128+
dynamic_section.header.set!(offset: dynamic_offset, size:)
129+
end
130+
110131
def ref_index(section_name)
111132
ref_name = section_name.split(".").filter { |sn| !sn.empty? && sn != "rel" && sn != "rela" }
112133
ref_name = "." + ref_name.join(".")
@@ -115,11 +136,25 @@ def ref_index(section_name)
115136
write_section_index(ref.section_name)
116137
end
117138

139+
def link_index(section_name)
140+
case section_name
141+
when ".symtab"
142+
write_section_index(".strtab")
143+
when ".dynsym", ".dynamic"
144+
write_section_index(".dynstr")
145+
else
146+
nil
147+
end
148+
end
149+
118150
def text_section = @text_section ||= @write_sections.find { |s| ".text" === s.section_name.to_s }
119151
def rel_sections = @rel_sections ||= @write_sections.select { RELOCATION_SECTION_NAMES.include?(it.section_name) }
120152
def symtab_section = @symtab_section ||= @write_sections.find { |s| ".symtab" === s.section_name.to_s }
121153
def strtab_section = @strtab_section ||= @write_sections.find { |s| ".strtab" === s.section_name.to_s }
122154
def shstrtab_section = @shstrtab_section ||= @write_sections.find { |s| ".shstrtab" === s.section_name.to_s }
155+
def dynstr_section = @dynstr_section ||= @write_sections.find { |s| ".dynstr" === s.section_name.to_s }
156+
def dynsym_section = @dynsym_section ||= @write_sections.find { |s| ".dynsym" === s.section_name.to_s }
157+
def dynamic_section = @dynamic_section ||= @write_sections.find { |s| ".dynamic" === s.section_name.to_s }
123158
end
124159
end
125160
end

test/caotral/linker/shared-object_test.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ def teardown
1717
def test_link_shared_object
1818
Caotral::Linker.link!(inputs: @inputs, output: @output, linker: "self", shared: true, executable: false)
1919
elf = Caotral::Binary::ELF::Reader.read!(input: @output, debug: false)
20+
section_names = elf.sections.map(&:section_name)
21+
assert_include(section_names, ".dynstr")
22+
assert_include(section_names, ".dynsym")
23+
assert_include(section_names, ".dynamic")
2024
assert_equal(:DYN, elf.header.type)
2125
assert_equal(:AMD64, elf.header.arch)
2226
end

0 commit comments

Comments
 (0)