1- export ELFVersionData
1+ export ELFVersionData, ELFVersionNeededData, ELFHash
22
33# Special ELF version data structures
44@io struct ELFVerDef{H <: ELFHandle }
2424 vn_next:: UInt32
2525end
2626
27+ @io struct ELFVernAux{H <: ELFHandle }
28+ vna_hash:: UInt32
29+ vna_flags:: UInt16
30+ vna_other:: UInt16
31+ vna_name:: UInt32
32+ vna_next:: UInt32
33+ end
34+
2735struct ELFVersionEntry{H <: ELFHandle }
2836 ver_def:: ELFVerDef{H}
2937 names:: Vector{String}
3038end
3139
40+ struct ELFVersionNeededEntry{H <: ELFHandle }
41+ ver_need:: ELFVerNeed{H}
42+ auxes:: Vector{ELFVernAux}
43+ names:: Vector{String}
44+ end
45+
46+ """
47+ Collect all version definitions from .gnu.version_d. This section contains a
48+ sequence of verdef structs `vd`, each of which owns exactly `vd.vd_cnt` verdaux
49+ structs which we convert to names. The first name is generally the only
50+ important one to the given `vd`; it is the version being defined, and
51+ corresponds to `vd.vd_hash`. If present, a second verdaux usually notes the
52+ parent version (e.g. `names = ["GLIBCXX_3.4.7", "GLIBCXX_3.4.6"]`)
53+ """
3254function ELFVersionData (oh:: H ) where {H <: ELFHandle }
3355 s = findfirst (Sections (oh), " .gnu.version_d" )
3456 strtab = StrTab (findfirst (Sections (oh), " .dynstr" ))
57+ (isnothing (s) || isnothing (strtab)) && return ELFVersionEntry[]
3558
3659 # Queue oh up to the beginning of this section
3760 seek (oh, section_offset (s))
@@ -62,4 +85,62 @@ function ELFVersionData(oh::H) where {H <: ELFHandle}
6285 end
6386
6487 return version_defs
65- end
88+ end
89+
90+ """
91+ Collect all version requirements from .gnu.version_r. This section is
92+ structurally similar to the version definition section, but the primary
93+ "verneed" struct corresponds to one shared library, and the auxiliary struct
94+ corresponds to a version.
95+ """
96+ function ELFVersionNeededData (oh:: H ) where {H <: ELFHandle }
97+ s = findfirst (Sections (oh), " .gnu.version_r" )
98+ strtab = StrTab (findfirst (Sections (oh), " .dynstr" ))
99+ (isnothing (s) || isnothing (strtab)) && return ELFVersionNeededEntry[]
100+
101+ seek (oh, section_offset (s))
102+ verneeds = ELFVersionNeededEntry[]
103+ while true
104+ vn_pos = position (oh)
105+ vn = unpack (oh, ELFVerNeed{H})
106+ auxes = ELFVernAux[]
107+ names = String[]
108+ aux_offset = 0
109+ for aux_idx in 1 : vn. vn_cnt
110+ seek (oh, vn_pos + vn. vn_aux + aux_offset)
111+ aux = unpack (oh, ELFVernAux{H})
112+ name = strtab_lookup (strtab, aux. vna_name)
113+ push! (auxes, aux)
114+ push! (names, name)
115+ aux_offset += aux. vna_next
116+ end
117+ push! (verneeds, ELFVersionNeededEntry (vn, auxes, names))
118+
119+ if vn. vn_next == 0
120+ break
121+ end
122+ seek (oh, vn_pos + vn. vn_next)
123+ end
124+
125+ return verneeds
126+ end
127+
128+ """
129+ See https://en.wikipedia.org/wiki/PJW_hash_function
130+
131+ Hash function used to create vd_hash from vda_name, or vna_hash from vna_name.
132+ Stops at the first null byte.
133+ """
134+ function ELFHash (v:: Vector{UInt8} )
135+ h = UInt32 (0 )
136+ for b in v
137+ (b == 0 ) && break ;
138+ h = (h << 4 ) + b
139+ hi = h & 0xf0000000
140+ if (hi != 0 )
141+ h ⊻= (hi >> 24 )
142+ end
143+ h &= ~ hi
144+ end
145+ return h
146+ end
0 commit comments