1
- export ELFVersionData
1
+ export ELFVersionData, ELFVersionNeededData, ELFHash
2
2
3
3
# Special ELF version data structures
4
4
@io struct ELFVerDef{H <: ELFHandle }
24
24
vn_next:: UInt32
25
25
end
26
26
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
+
27
35
struct ELFVersionEntry{H <: ELFHandle }
28
36
ver_def:: ELFVerDef{H}
29
37
names:: Vector{String}
30
38
end
31
39
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
+ """
32
54
function ELFVersionData (oh:: H ) where {H <: ELFHandle }
33
55
s = findfirst (Sections (oh), " .gnu.version_d" )
34
56
strtab = StrTab (findfirst (Sections (oh), " .dynstr" ))
57
+ (isnothing (s) || isnothing (strtab)) && return ELFVersionEntry[]
35
58
36
59
# Queue oh up to the beginning of this section
37
60
seek (oh, section_offset (s))
@@ -62,4 +85,62 @@ function ELFVersionData(oh::H) where {H <: ELFHandle}
62
85
end
63
86
64
87
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