the COFF archive file format maybe used in .lib files (they hold binary import information for libraries) used for unix .a static library files (with no 2nd linker and newline-separated longnames)
# File metasm/exe_format/coff_decode.rb, line 918 def decode @encoded.ptr = 0 @signature = @encoded.read(8) raise InvalidExeFormat, "Invalid COFF Archive signature #{@signature.inspect}" if @signature != "!<arch>\n" @members = [] while @encoded.ptr < @encoded.virtsize @members << Member.decode(self) end @members.each { |m| case m.name when '/'; @first_linker ? decode_second_linker(m) : decode_first_linker(m) when '//'; decode_longnames(m) else break end } fixup_names end
# File metasm/exe_format/coff_decode.rb, line 866 def decode_first_linker(m) offsets = [] names = [] m.encoded.ptr = 0 numsym = m.decode_word numsym.times { offsets << m.decode_word } numsym.times { names << decode_strz(m.encoded) } # names[42] is found in object at file offset offsets[42] # offsets are sorted by object index (all syms from 1st object, then 2nd etc) @first_linker = names.zip(offsets) #.inject({}) { |h, (n, o)| h.update n => o } end
# File metasm/exe_format/coff_decode.rb, line 859 def decode_half(edata = @encoded) ; edata.decode_imm(:u16, :little) end
# File metasm/exe_format/coff_decode.rb, line 899 def decode_longnames(m) @longnames = m.encoded end
# File metasm/exe_format/coff_decode.rb, line 880 def decode_second_linker(m) names = [] mboffsets = [] indices = [] m = @members[1] m.encoded.ptr = 0 nummb = decode_word(m.encoded) nummb.times { mboffsets << decode_word(m.encoded) } numsym = decode_word(m.encoded) numsym.times { indices << decode_half(m.encoded) } numsym.times { names << decode_strz(m.encoded) } # names[42] is found in object at file offset mboffsets[indices[42]] # symbols sorted by symbol name (supposed to be more efficient, but no index into string table...) #names.zip(indices).inject({}) { |h, (n, i)| h.update n => mboffsets[i] } @second_linker = [names, mboffsets, indices] end
# File metasm/exe_format/coff_decode.rb, line 861 def decode_strz(edata = @encoded) i = edata.data.index(\0, edata.ptr) || edata.data.index(\n, edata.ptr) || (edata.length+1) edata.read(i+1-edata.ptr).chop end
# File metasm/exe_format/coff_decode.rb, line 860 def decode_word(edata = @encoded) ; edata.decode_imm(:u32, :little) end
set real name to archive members look it up in the name table member if needed, or just remove the trailing /
# File metasm/exe_format/coff_decode.rb, line 905 def fixup_names @members.each { |m| case m.name when '/' when '//' when /^\/(\d+)/ @longnames.ptr = $1.to_i m.name = decode_strz(@longnames).chomp("/") else m.name.chomp! "/" end } end
return the 1st member whose name is name
# File metasm/exe_format/coff.rb, line 455 def member(name) @members.find { |m| m.name == name } end
# File metasm/exe_format/coff.rb, line 459 def sizeof_half ; 2 ; end
# File metasm/exe_format/coff.rb, line 460 def sizeof_word ; 4 ; end