Skip to content

Commit 044c459

Browse files
committed
Add ability to extract .gnu.version_d section data
1 parent d4b3e39 commit 044c459

File tree

4 files changed

+81
-0
lines changed

4 files changed

+81
-0
lines changed

src/ELF/ELF.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ include("ELFSegment.jl")
3030
include("ELFSymbol.jl")
3131
include("ELFDynEntry.jl")
3232
include("ELFDynamicLink.jl")
33+
include("ELFVersion.jl")
3334

3435
# Holdovers from ObjFileBase that I haven't cleaned up yet
3536
#include("ELFRelocation.jl")

src/ELF/ELFVersion.jl

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
export ELFVersionData
2+
3+
# Special ELF version data structures
4+
@io struct ELFVerDef{H <: ELFHandle}
5+
vd_version::UInt16
6+
vd_flags::UInt16
7+
vd_ndx::UInt16
8+
vd_cnt::UInt16
9+
vd_hash::UInt32
10+
vd_aux::UInt32
11+
vd_next::UInt32
12+
end
13+
14+
@io struct ELFVerdAux{H <: ELFHandle}
15+
vda_name::UInt32
16+
vda_next::UInt32
17+
end
18+
19+
@io struct ELFVerNeed{H <: ELFHandle}
20+
vn_version::UInt16
21+
vn_cnt::UInt16
22+
vn_file::UInt16
23+
vn_aux::UInt32
24+
vn_next::UInt32
25+
end
26+
27+
struct ELFVersionEntry{H <: ELFHandle}
28+
ver_def::ELFVerDef{H}
29+
names::Vector{String}
30+
end
31+
32+
function ELFVersionData(oh::H) where {H <: ELFHandle}
33+
s = findfirst(Sections(oh), ".gnu.version_d")
34+
strtab = StrTab(findfirst(Sections(oh), ".dynstr"))
35+
36+
# Queue oh up to the beginning of this section
37+
seek(oh, section_offset(s))
38+
39+
# Read out ALL OF THE version definitions
40+
version_defs = ELFVersionEntry[]
41+
while true
42+
vd_pos = position(oh)
43+
vd = unpack(oh, ELFVerDef{H})
44+
45+
# Find aux names and resolve immediately to strings
46+
auxes = String[]
47+
aux_offset = 0
48+
for aux_idx in 1:vd.vd_cnt
49+
seek(oh, vd_pos + vd.vd_aux + aux_offset)
50+
aux = unpack(oh, ELFVerdAux{H})
51+
name = strtab_lookup(strtab, aux.vda_name)
52+
push!(auxes, name)
53+
aux_offset += aux.vda_next
54+
end
55+
56+
push!(version_defs, ELFVersionEntry(vd, auxes))
57+
58+
if vd.vd_next == 0
59+
break
60+
end
61+
seek(oh, vd_pos + vd.vd_next)
62+
end
63+
64+
return version_defs
65+
end

test/linux64/libstdc++.so.6

1.49 MB
Binary file not shown.

test/runtests.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,18 @@ end
162162
# Run COFF tests
163163
test_libfoo_and_fooifier("./win32/fooifier.exe", "./win32/libfoo.dll")
164164
test_libfoo_and_fooifier("./win64/fooifier.exe", "./win64/libfoo.dll")
165+
166+
167+
# Ensure that ELF version stuff works
168+
@testset "ELF Version Info Parsing" begin
169+
libstdcxx_path = "./linux64/libstdc++.so.6"
170+
171+
# Extract all pieces of `.gnu.version_d` from libstdc++.so, find the `GLIBCXX_*`
172+
# symbols, and use the maximum version of that to find the GLIBCXX ABI version number
173+
version_symbols = readmeta(libstdcxx_path) do oh
174+
unique(vcat((x -> x.names).(ObjectFile.ELF.ELFVersionData(oh))...))
175+
end
176+
version_symbols = filter(x -> startswith(x, "GLIBCXX_"), version_symbols)
177+
max_version = maximum([VersionNumber(split(v, "_")[2]) for v in version_symbols])
178+
@test max_version == v"3.4.25"
179+
end

0 commit comments

Comments
 (0)