@@ -6,6 +6,7 @@ class Linker
66 class Builder
77 include Caotral ::Binary ::ELF ::Utils
88 REL_TYPES = Caotral ::Binary ::ELF ::Section ::Rel ::TYPES
9+ DYNAMIC_TAGS = Caotral ::Binary ::ELF ::Section ::Dynamic ::TAG_TYPES
910 SYMTAB_BIND = { locals : 0 , globals : 1 , weaks : 2 , } . freeze
1011 BIND_BY_VALUE = SYMTAB_BIND . invert . freeze
1112 RELOCATION_SECTION_NAMES = [ ".rela.text" , ".rel.text" , ".rela.data" , ".rel.data" ] . freeze
@@ -18,6 +19,11 @@ class Builder
1819 REL_TYPES [ :AMD64_GOTPCRELX ] ,
1920 REL_TYPES [ :AMD64_REX_GOTPCRELX ] ,
2021 ] . freeze
22+ REJECT_DYNAMIC_TAGS = [
23+ DYNAMIC_TAGS [ :PLTRELSZ ] ,
24+ DYNAMIC_TAGS [ :PLTREL ] ,
25+ DYNAMIC_TAGS [ :JMPREL ] ,
26+ ] . freeze
2127
2228 attr_reader :symbols
2329
@@ -176,22 +182,22 @@ def build
176182 first_insertion = got_plt_offsets [ sym ] . nil?
177183 got_plt_offsets [ sym ] ||= got_plt_offset . tap { got_plt_offset += 8 }
178184 if dynamic? && undefined && first_insertion
179- got_plt_section . body << [ 0 ] . pack ( "Q<" )
180- rps = Caotral ::Binary ::ELF ::Section ::Rel . new . set! (
181- offset : got_plt_offsets [ sym ] ,
182- info : ( ( sym ) << 32 ) | REL_TYPES [ :AMD64_JUMP_SLOT ]
185+ got_plt_section . body << [ 0 ] . pack ( "Q<" )
186+ rps = Caotral ::Binary ::ELF ::Section ::Rel . new . set! (
187+ offset : got_plt_offsets [ sym ] ,
188+ info : ( ( sym ) << 32 ) | REL_TYPES [ :AMD64_JUMP_SLOT ]
189+ )
190+ name = symtab_section . body [ sym ] . name_string
191+ dynstr_index = dynstr . body . offset_of ( name )
192+ if dynstr_index . nil?
193+ dynstr . body . names += name + "\0 "
194+ dynsym . body << Caotral ::Binary ::ELF ::Section ::Symtab . new . set! (
195+ name : dynstr . body . offset_of ( name ) ,
196+ info : ( 1 << 4 ) | 2 ,
183197 )
184- name = symtab_section . body [ sym ] . name_string
185- dynstr_index = dynstr . body . offset_of ( name )
186- if dynstr_index . nil?
187- dynstr . body . names += name + "\0 "
188- dynsym . body << Caotral ::Binary ::ELF ::Section ::Symtab . new . set! (
189- name : dynstr . body . offset_of ( name ) ,
190- info : ( 1 << 4 ) | 2 ,
191- )
192- end
193- rela_plt_section . body << rps
194- next
198+ end
199+ rela_plt_section . body << rps
200+ next
195201 end
196202 elsif UNSUPPORTED_REL_TYPES . include? ( rel . type )
197203 raise Caotral ::Binary ::ELF ::Error , "unsupported relocation type: #{ rel . type_name } "
@@ -260,13 +266,40 @@ def build
260266 if dynamic?
261267 sections << dynstr
262268 sections << dynsym
263- sections << build_hash_section if @pie
269+ hash_section = build_hash_section
270+ sections << hash_section
264271 sections << rela_dyn_section
265272 sections << rela_plt_section
266273 sym = sections . index ( dynsym )
267274 rela_dyn_section . header . set! ( link : sym , type : rel_type ( rela_dyn_section ) , entsize : rel_entsize ( rela_dyn_section ) )
268275 rela_plt_section . header . set! ( link : sym , type : rel_type ( rela_plt_section ) , info : ref_index ( sections , got_plt_section . section_name ) )
269- sections << build_dynamic_section
276+ symtab_section . body . each do |sym |
277+ next unless [ SYMTAB_BIND [ :globals ] , SYMTAB_BIND [ :weaks ] ] . include? ( sym . bind )
278+ next if sym . shndx == 0
279+ copy_sym = sym . dup
280+ shndx = copy_sym . shndx
281+ name = dynstr . body . offset_of ( sym . name_string )
282+ if name . nil?
283+ dynstr . body . names += copy_sym . name_string + "\0 "
284+ name = dynstr . body . offset_of ( copy_sym . name_string )
285+ end
286+ copy_sym . name_string = sym . name_string
287+ dynsym . body << copy_sym . set! ( name :, shndx :, value : sym . value )
288+ end
289+ hash = Caotral ::Binary ::ELF ::Section ::Hash . new ( nchain : dynsym . body . size )
290+ hash . bucket [ 0 ] = num2bytes ( 1 , 4 ) if dynsym . body . size > 1
291+ dynsym . body . each_with_index do |sym , i |
292+ next if i == 0
293+ hash . chain [ i ] = num2bytes ( 0 , 4 )
294+ end
295+ hash_section . body = hash
296+ dynamic_section = build_dynamic_section
297+ if rela_plt_section . body . size == 0 && dynamic?
298+ bodies = dynamic_section . body . reject { |ent | REJECT_DYNAMIC_TAGS . include? ( ent . tag ) }
299+ dynamic_section . body = bodies
300+ end
301+
302+ sections << dynamic_section
270303 end
271304 sections << symtab_section
272305
0 commit comments