Class: Rubycc::ObjFile::ArWriter
- Inherits:
-
Object
- Object
- Rubycc::ObjFile::ArWriter
- Defined in:
- lib/rubycc/objfile/ar_archive.rb
Overview
Builds a GNU-format ar archive. The counterpart of ArReader, mirroring
ELFWriter's builder taste: members are appended in order with #add_member
and the whole image is assembled by #to_binary.
Every archive is written with a classic ranlib symbol index as its first
/ member (always, even when empty), so output is a drop-in for ar rcs
and the linker can extract lazily. The index's symbols are gathered by
handing each member's bytes to ELFReader and taking its defined global and
weak symbols; a member ELFReader cannot parse (a non-ELF file) simply
contributes none. Long member names (over 15 characters, once the trailing
/ is counted) move to a // extended-name table and are referenced by a
/N byte offset; shorter names are stored inline as name/.
Output is fully deterministic (N4): mtime, uid and gid are pinned to 0 and
the mode to 0644 (the metadata GNU ar writes in deterministic mode), so
identical member bytes always produce a byte-identical archive.
Constant Summary collapse
- DETERMINISTIC_MTIME =
Pinned deterministic member metadata. The reserved
/and//members carry a 0 mode, matching GNU. "0"- DETERMINISTIC_UID =
"0"- DETERMINISTIC_GID =
"0"- REGULAR_MODE =
"644"- SPECIAL_MODE =
"0"- INLINE_NAME_CAPACITY =
A name plus its trailing-slash form fits inline when at most this many bytes; a longer name goes to the
//table. 16
Instance Method Summary collapse
-
#add_member(name, data) ⇒ Object
Appends a member with the given name and raw data.
-
#initialize ⇒ ArWriter
constructor
A new instance of ArWriter.
-
#to_binary ⇒ Object
Assembles and returns the archive as an ASCII-8BIT String.
-
#write(path) ⇒ Object
Convenience: assemble and write the archive to
path.
Constructor Details
#initialize ⇒ ArWriter
Returns a new instance of ArWriter.
287 288 289 |
# File 'lib/rubycc/objfile/ar_archive.rb', line 287 def initialize @members = [] end |
Instance Method Details
#add_member(name, data) ⇒ Object
Appends a member with the given name and raw data. Names are not de-duplicated here — replace-or-append is the CLI's job; the writer lays out exactly what it is given, in order.
294 295 296 297 |
# File 'lib/rubycc/objfile/ar_archive.rb', line 294 def add_member(name, data) @members << { name: name.to_s, data: data.b } self end |
#to_binary ⇒ Object
Assembles and returns the archive as an ASCII-8BIT String.
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 |
# File 'lib/rubycc/objfile/ar_archive.rb', line 300 def to_binary entries = @members.map { |m| { name: m[:name], data: m[:data], symbols: gather_symbols(m[:data]) } } name_table, name_field = build_name_table(entries) flat_symbols = flatten_symbols(entries) symtab_size = symtab_byte_size(flat_symbols) # The symbol index and the name table precede every regular member, so # each regular member's header offset — the value the index records — is # known once their spans are summed. The index's own size depends only on # the symbol count and names, not on the offsets it will hold, so there is # no circular dependency. base = AR_MAGIC.bytesize + member_span(symtab_size) base += member_span(name_table.bytesize) unless name_table.empty? offset = base entries.each do |entry| entry[:header_offset] = offset offset += member_span(entry[:data].bytesize) end symtab = build_symtab(flat_symbols, entries) out = +"".b out << AR_MAGIC emit_member(out, "/", symtab, SPECIAL_MODE) emit_member(out, "//", name_table, SPECIAL_MODE) unless name_table.empty? entries.each { |entry| emit_member(out, name_field[entry.object_id], entry[:data], REGULAR_MODE) } out end |
#write(path) ⇒ Object
Convenience: assemble and write the archive to path.
331 332 333 |
# File 'lib/rubycc/objfile/ar_archive.rb', line 331 def write(path) File.binwrite(path, to_binary) end |