11require_relative "elf/program_header"
2+
23module Caotral
34 class Linker
45 class Writer
6+ include Caotral ::Assembler ::ELF ::Utils
57 ALLOW_SECTIONS = %w( .text .strtab .shstrtab ) . freeze
68 R_X86_64_PC32 = 2
9+ R_X86_64_PLT32 = 4
10+ ALLOW_RELOCATION_TYPES = [ R_X86_64_PC32 , R_X86_64_PLT32 ] . freeze
711 RELOCATION_SECTION_NAMES = [ ".rela.text" , ".rel.text" ] . freeze
812 attr_reader :elf_obj , :output , :entry , :debug
913 def self . write! ( elf_obj :, output :, entry : nil , debug : false )
@@ -19,33 +23,45 @@ def write
1923 ph = Caotral ::Linker ::ELF ::ProgramHeader . new
2024 text_section = @elf_obj . sections [ ".text" ]
2125 rel_sections = @elf_obj . sections . select { RELOCATION_SECTION_NAMES . include? ( it . section_name ) }
26+ start_bytes = [ 0xe8 , *[ 0 ] * 4 , 0x48 , 0x89 , 0xc7 , 0x48 , 0xc7 , 0xc0 , 0x3c , 0x00 , 0x00 , 0x00 , 0x0f , 0x05 ]
2227 symtab = @elf_obj . sections [ ".symtab" ]
2328 symtab_body = symtab . body
29+ old_text = text_section . body
30+ main_sym = symtab_body . find { |sym | sym . name_string == "main" }
31+ text_offset = 0x1000
32+ base_addr = 0x400000
33+ align = 0x1000
34+ vaddr = base_addr + text_offset
35+ paddr = base_addr + text_offset
36+ start_len = start_bytes . length
37+ start_addr = base_addr + text_offset
38+ main_offset = main_sym . value + start_len
39+ start_bytes [ 1 , 4 ] = num2bytes ( ( main_offset - 5 ) , 4 )
40+ start_bytestring = start_bytes . pack ( "C*" )
41+ text_section . body = start_bytestring + old_text
42+ type , flags = 1 , 5
43+ filesz = text_section . body . bytesize
44+ memsz = filesz
45+
2446 rel_sections . each do |rel |
2547 target = @elf_obj . sections [ rel . header . info ]
2648 bytes = target . body . dup
2749 rel . body . each do |entry |
28- next unless entry . type == R_X86_64_PC32
50+ next unless ALLOW_RELOCATION_TYPES . include? ( entry . type )
51+ a = entry . type == R_X86_64_PC32 ? 4 : 0
2952 sym = symtab_body [ entry . sym ]
30- sym_addr = sym . value + target . header . addr
31- offset = entry . offset
32- addend = entry . addend? ? entry . addend : bytes [ offset , 4 ] . unpack1 ( "l<" )
33- value = sym_addr + addend - ( target . header . addr + offset )
34- bytes [ offset , 4 ] = [ value ] . pack ( "l<" )
53+ target_addr = target == text_section ? vaddr : target . header . addr
54+ sym_addr = sym . value + target_addr + ( target == text_section ? start_len : 0 )
55+ sym_offset = entry . offset + ( target == text_section ? start_len : 0 )
56+ sym_addend = entry . addend? ? entry . addend : bytes [ sym_offset , 4 ] . unpack1 ( "l<" )
57+ value = sym_addr + sym_addend - ( target_addr + sym_offset + a )
58+ bytes [ sym_offset , 4 ] = [ value ] . pack ( "l<" )
3559 end
3660 target . body = bytes
3761 end
38- filesz = text_section . header . size
39- memsz = filesz
40- offset = text_offset = 0x1000
41- base_addr = 0x400000
42- align = 0x1000
43- vaddr = base_addr + text_offset
44- paddr = base_addr + text_offset
45- type , flags = 1 , 5
4662 header . set! ( entry : @entry || base_addr + text_offset )
47- ph . set! ( type :, offset :, vaddr :, paddr :, filesz :, memsz :, flags :, align :)
48- text_section . header . set! ( addr : vaddr , offset : text_offset )
63+ ph . set! ( type :, offset : text_offset , vaddr :, paddr :, filesz :, memsz :, flags :, align :)
64+ text_section . header . set! ( size : text_section . body . bytesize , addr : vaddr , offset : text_offset )
4965 f . write ( @elf_obj . header . build )
5066 f . write ( ph . build )
5167 gap = [ text_offset - f . pos , 0 ] . max
0 commit comments