Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions lib/caotral/binary/elf/section.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,18 @@ def build
end

def layout!(offset:)
size = build.bytesize
size = file_size
align = [@header.addralign.to_i, 1].max
offset = (offset + align - 1) / align * align
@header.set!(offset:, size:)

offset + size
if header.nobits?
header.set!(offset:)
Comment thread
katsyoshi marked this conversation as resolved.
else
header.set!(offset:, size:)
end
offset + file_size
end
def file_size = header.nobits? ? 0 : build.bytesize
def memory_size = header.nobits? ? header.size : build.bytesize
end
end
end
Expand Down
1 change: 1 addition & 0 deletions lib/caotral/binary/elf/section_header.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def addralign = @addralign.pack("C*").unpack1("Q<")
def allocated? = (@flags.pack("C*").unpack1("Q<") & SHF[:ALLOC]) != 0
def writable? = (@flags.pack("C*").unpack1("Q<") & SHF[:WRITE]) != 0
def execinstr? = (@flags.pack("C*").unpack1("Q<") & SHF[:EXECINSTR]) != 0
def nobits? = type == :nobits

private def bytes = [@name, @type, @flags, @addr, @offset, @size, @link, @info, @addralign, @entsize]
end
Expand Down
33 changes: 30 additions & 3 deletions lib/caotral/linker/builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ def build
section_name: ".strtab",
header: Caotral::Binary::ELF::SectionHeader.new
)
bss_section = Caotral::Binary::ELF::Section.new(
body: nil,
section_name: ".bss",
header: Caotral::Binary::ELF::SectionHeader.new
.set!(type: SHT[:nobits], flags: SHF[:ALLOC] | SHF[:WRITE], addralign: 8)
)
symtab_section = Caotral::Binary::ELF::Section.new(
body: [],
section_name: ".symtab",
Expand Down Expand Up @@ -119,14 +125,19 @@ def build
rel_sections = []
rel_texts = []
pending_relative_relocations = []
dynamic_symbol_pairs = []
elf.header = elf_obj.header.dup
strtab_names = []
text_offsets = {}
rodata_offsets = {}
bss_offsets = {}
data_offsets = {}
got_plt_offsets = {}
text_offset = 0
rodata_offset = 0
bss_offset = 0
bss_present = false
bss_addralign = 1
data_offset = 0
got_plt_offset = 24
sym_by_elf = Hash.new { |h, k| h[k] = [] }
Expand Down Expand Up @@ -154,13 +165,23 @@ def build
data_offsets[elf_obj.object_id] = data_offset
data_offset += data.body.bytesize
end
bss = elf_obj.find_by_name(".bss")
unless bss.nil?
bss_present = true
alignment = [bss.header.addralign, 1].max
bss_offset = align_up(bss_offset, alignment)
bss_addralign = [bss_addralign, alignment].compact.max
bss_offsets[elf_obj.object_id] = bss_offset
bss_offset += bss.memory_size
Comment thread
katsyoshi marked this conversation as resolved.
end
strtab = elf_obj.find_by_name(".strtab")
strtab.body.names.split("\0").each { |name| strtab_names << name } unless strtab.nil?
symtab = elf_obj.find_by_name(".symtab")
base_index = nil
unless symtab.nil?
base_index = symtab_section.body.size
text_index = elf_obj.sections.index(text) unless text.nil?
bss_index = elf_obj.sections.index(bss) unless bss.nil?
data_index = elf_obj.sections.index(data) unless data.nil?
rodata_index = elf_obj.sections.index(rodata) unless rodata.nil?

Expand All @@ -169,6 +190,7 @@ def build
name, info, other, shndx, value, size = st.build.unpack("L<CCS<Q<Q<")
sym_by_elf[elf_obj] << sym
value += text_offsets.fetch(elf_obj.object_id, 0) if shndx == text_index
value += bss_offsets.fetch(elf_obj.object_id, 0) if shndx == bss_index
value += data_offsets.fetch(elf_obj.object_id, 0) if shndx == data_index
value += rodata_offsets.fetch(elf_obj.object_id, 0) if shndx == rodata_index
sym.set!(name:, info:, other:, shndx:, value:, size:)
Expand Down Expand Up @@ -278,7 +300,6 @@ def build
sections << plt_section
sections << got_plt_section
end
sections << strtab_section
text_index = sections.index(text_section)
symtab_section.body.each do |sym|
next if sym.shndx == 0
Expand All @@ -297,12 +318,10 @@ def build
symtab_section.header.set!(
type: 2,
flags: 0,
link: elf.sections.index(strtab_section),
info: local_count,
addralign: 8,
entsize: 24
)

sections += build_pie_sections if @pie
if dynamic?
@needed.each { |lib| dynstr.body.names += lib + "\0" if dynstr.body.offset_of(lib).nil? }
Expand All @@ -326,6 +345,7 @@ def build
name = dynstr.body.offset_of(copy_sym.name_string)
end
copy_sym.name_string = sym.name_string
dynamic_symbol_pairs << [copy_sym, sym]
dynsym.body << copy_sym.set!(name:, shndx:, value: sym.value)
end
hash = Caotral::Binary::ELF::Section::Hash.new(nchain: dynsym.body.size)
Expand All @@ -344,7 +364,9 @@ def build

sections << dynamic_section
end
sections << bss_section if bss_present
sections << symtab_section
sections << strtab_section

rel_sections.each { |s| sections << s.dup }

Expand All @@ -357,6 +379,8 @@ def build

sections << shstrtab_section

bss_section.header.set!(size: bss_offset, addralign: bss_addralign)

shstrtab_section_names = [*sections.map(&:section_name), "\0"].join("\0")
shstrtab_section.body.names = shstrtab_section_names

Expand All @@ -376,6 +400,8 @@ def build
end
end

dynamic_symbol_pairs.each { |copy_sym, sym| copy_sym.set!(shndx: sym.shndx) }

defined_global_index = {}
symtab_section.body.each_with_index do |sym, index|
next unless sym.bind == SYMTAB_BIND[:globals]
Expand Down Expand Up @@ -535,6 +561,7 @@ def ref_index(sections, section_name)

def rel_type(section) = section.section_name&.start_with?(".rela.") ? 4 : 9
def rel_entsize(section) = section.section_name&.start_with?(".rela.") ? 24 : 16
def align_up(val, align) = (val + align - 1) / align * align

def dynamic? = @shared || @pie
end
Expand Down
16 changes: 12 additions & 4 deletions lib/caotral/linker/layout.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,15 +118,23 @@ def finalize_program_headers!
when :LOAD
allocated_sections = @load_sections[ph.flags]

section_end = allocated_sections.map { |s| s.header.offset + s.header.size }.max
memory_end = allocated_sections.map { |s| s.header.offset + s.memory_size }.max
file_end = allocated_sections
.reject { |s| s.header.nobits? }
.map { |s| s.header.offset + s.file_size }.max
segment_start = ph.flags == :R ? 0 : allocated_sections.map { |s| s.header.offset }.min
segment_end = ph.flags == :R ? [header_end, section_end].compact.max : section_end
if ph.flags == :R
memory_end = [header_end, memory_end].compact.max
file_end = [header_end, file_end].compact.max
end
memory_end ||= segment_start
file_end ||= segment_start

offset = segment_start
vaddr = @load_bias + offset
paddr = vaddr
filesz = segment_end - segment_start
memsz = filesz
filesz = file_end - segment_start
memsz = memory_end - segment_start
flags = PF[ph.flags]
align = LOAD_ALIGNMENT
when :INTERP
Expand Down
16 changes: 16 additions & 0 deletions sample/assembler/bss.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.section .bss
.balign 8
.globl value
.type value, @object
.size value, 8
value:
.zero 8

.text
.globl _start
.type _start, @function
_start:
movq $42, value(%rip)
movq value(%rip), %rdi
movq $60, %rax
syscall
27 changes: 27 additions & 0 deletions sample/assembler/bss_initialize_zero.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.section .bss
.balign 8
.zero 24

.globl value
.type value, @object
.size value, 8
value:
.zero 8

.text
.globl _start
.type _start, @function
_start:
cmpq $0, value(%rip)
jne .Lnot_zero

movq $42, value(%rip)
movq value(%rip), %rdi
jmp .Lexit

.Lnot_zero:
movq $1, %rdi

.Lexit:
movq $60, %rax
syscall
15 changes: 15 additions & 0 deletions sample/assembler/empty_bss.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.section .bss
.balign 8
.globl value
.type value, @object
.size value, 0
value:

.text
.globl _start
.type _start, @function
_start:
movq $42, value(%rip)
movq value(%rip), %rdi
movq $60, %rax
syscall
7 changes: 7 additions & 0 deletions sample/assembler/two_bss_sections.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.section .bss
.balign 16
.globl aligned_value
.type aligned_value, @object
.size aligned_value, 16
aligned_value:
.zero 16
3 changes: 3 additions & 0 deletions sig/caotral/binary/elf/section.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@ class Caotral::Binary::ELF::Section
body: untyped,
section_name: String?
) -> void

def file_size: () -> Integer
def memory_size: () -> Integer
end
1 change: 1 addition & 0 deletions sig/caotral/binary/elf/section_header.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ class Caotral::Binary::ELF::SectionHeader
def addr: () -> Integer
def writable?: () -> bool
def execinstr?: () -> bool
def nobits?: () -> bool
end
Loading
Loading