Class: Rubycc::ObjFile::ArReader
- Inherits:
-
Object
- Object
- Rubycc::ObjFile::ArReader
- Defined in:
- lib/rubycc/objfile/ar_archive.rb
Overview
Reads a GNU-format ar archive into its members and (when present) its
symbol index. BSD archives are out of scope; only !<arch>\n is accepted.
The model mirrors ELFReader's load-then-query taste: read/read_file
walk the whole image once into #members (in file order) and, if the
archive carries one, a symbol name -> member map. That map is exactly what
the linker's lazy-extraction driver queries ("which member defines this
still-undefined symbol?"), so it is exposed both as the raw ordered
#symbols list and the first-wins #symbol_index hash.
Three reserved member names are understood: / is the classic ranlib
symbol table (big-endian uint32 count, that many big-endian uint32
member-header offsets, then NUL-terminated symbol names); // is the
extended-name table holding long member names each terminated by /\n; and
/N in a member's name field is a decimal byte offset into that // table.
A short name is stored as name/, the trailing slash marking its end so a
name may keep trailing spaces. Archives written without a symbol index
(plain ar qc) are tolerated: #symbols is then empty.
Constant Summary collapse
- HEADER_SIZE =
60- NAME_OFF =
Field offsets and widths within a 60-byte member header. The five ASCII fields are space-padded; only
size(decimal) is needed to walk the archive, the rest are decoded for the member's metadata. 0- NAME_LEN =
16- MTIME_OFF =
16- MTIME_LEN =
12- UID_OFF =
28- UID_LEN =
6- GID_OFF =
34- GID_LEN =
6- MODE_OFF =
40- MODE_LEN =
8- SIZE_OFF =
48- SIZE_LEN =
10- MAGIC_OFF =
58- HEADER_MAGIC =
"\x60\x0a".b
Instance Attribute Summary collapse
-
#members ⇒ Object
readonly
Returns the value of attribute members.
-
#name_table ⇒ Object
readonly
Returns the value of attribute name_table.
-
#symbols ⇒ Object
readonly
Returns the value of attribute symbols.
Class Method Summary collapse
-
.read(bytes) ⇒ Object
Parses an in-memory archive (an ASCII-8BIT String) into a ready-to-query reader.
-
.read_file(path) ⇒ Object
Reads an archive file from disk and parses it.
Instance Method Summary collapse
-
#initialize(bytes) ⇒ ArReader
constructor
A new instance of ArReader.
-
#member(name) ⇒ Object
The member with the given name, or nil.
-
#member_defining(symbol_name) ⇒ Object
The member that defines
symbol_name, or nil — the query the lazy linker asks for each still-undefined reference. - #parse! ⇒ Object
-
#symbol_index ⇒ Object
symbol name -> defining member, first definition winning when a symbol is exported by more than one member (the order the linker resolves in).
Constructor Details
#initialize(bytes) ⇒ ArReader
Returns a new instance of ArReader.
84 85 86 87 88 89 90 |
# File 'lib/rubycc/objfile/ar_archive.rb', line 84 def initialize(bytes) @data = bytes.b @members = [] @symbols = [] @name_table = nil @symtab_raw = nil end |
Instance Attribute Details
#members ⇒ Object (readonly)
Returns the value of attribute members.
82 83 84 |
# File 'lib/rubycc/objfile/ar_archive.rb', line 82 def members @members end |
#name_table ⇒ Object (readonly)
Returns the value of attribute name_table.
82 83 84 |
# File 'lib/rubycc/objfile/ar_archive.rb', line 82 def name_table @name_table end |
#symbols ⇒ Object (readonly)
Returns the value of attribute symbols.
82 83 84 |
# File 'lib/rubycc/objfile/ar_archive.rb', line 82 def symbols @symbols end |
Class Method Details
.read(bytes) ⇒ Object
Parses an in-memory archive (an ASCII-8BIT String) into a ready-to-query reader.
72 73 74 |
# File 'lib/rubycc/objfile/ar_archive.rb', line 72 def read(bytes) new(bytes).tap(&:parse!) end |
.read_file(path) ⇒ Object
Reads an archive file from disk and parses it.
77 78 79 |
# File 'lib/rubycc/objfile/ar_archive.rb', line 77 def read_file(path) read(File.binread(path)) end |
Instance Method Details
#member(name) ⇒ Object
The member with the given name, or nil. Regular members only — the /
and // metadata members never carry a user-facing name.
110 111 112 |
# File 'lib/rubycc/objfile/ar_archive.rb', line 110 def member(name) @members.find { |m| !m.special? && m.name == name } end |
#member_defining(symbol_name) ⇒ Object
The member that defines symbol_name, or nil — the query the lazy linker
asks for each still-undefined reference.
124 125 126 |
# File 'lib/rubycc/objfile/ar_archive.rb', line 124 def member_defining(symbol_name) symbol_index[symbol_name] end |
#parse! ⇒ Object
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/rubycc/objfile/ar_archive.rb', line 92 def parse! unless @data.byteslice(0, AR_MAGIC.bytesize) == AR_MAGIC raise ArFormatError, "not an ar archive (bad global magic)" end pos = AR_MAGIC.bytesize # This loop always terminates: parse_member advances pos by at least the # 60-byte header plus a non-negative member size (a size field that is not # a non-negative decimal is rejected outright), so pos strictly increases # by >= 60 each turn and reaches @data.bytesize in a bounded number of # steps — a malformed archive cannot make it stall or loop. pos = parse_member(pos) while pos < @data.bytesize resolve_symbol_index self end |
#symbol_index ⇒ Object
symbol name -> defining member, first definition winning when a symbol is exported by more than one member (the order the linker resolves in).
116 117 118 119 120 |
# File 'lib/rubycc/objfile/ar_archive.rb', line 116 def symbol_index @symbol_index ||= @symbols.each_with_object({}) do |entry, map| map[entry[:name]] ||= entry[:member] end end |