|
1 |
| -export ELFVersionData |
| 1 | +export ELFVersionData, ELFVersionNeededData, ELFHash |
2 | 2 |
|
3 | 3 | # Special ELF version data structures
|
4 | 4 | @io struct ELFVerDef{H <: ELFHandle}
|
@@ -37,6 +37,20 @@ struct ELFVersionEntry{H <: ELFHandle}
|
37 | 37 | names::Vector{String}
|
38 | 38 | end
|
39 | 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 | +""" |
40 | 54 | function ELFVersionData(oh::H) where {H <: ELFHandle}
|
41 | 55 | s = findfirst(Sections(oh), ".gnu.version_d")
|
42 | 56 | strtab = StrTab(findfirst(Sections(oh), ".dynstr"))
|
@@ -74,11 +88,53 @@ function ELFVersionData(oh::H) where {H <: ELFHandle}
|
74 | 88 | end
|
75 | 89 |
|
76 | 90 | """
|
77 |
| -Hash function used to create vd_hash from vda_name, or vna_hash from vna_name |
| 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. |
78 | 133 | """
|
79 | 134 | function ELFHash(v::Vector{UInt8})
|
80 | 135 | h = UInt32(0)
|
81 | 136 | for b in v
|
| 137 | + (b == 0) && break; |
82 | 138 | h = (h << 4) + b
|
83 | 139 | hi = h & 0xf0000000
|
84 | 140 | if (hi != 0)
|
|
0 commit comments