Repository: gimli-rs/object
Pull request #693 (2024-06-07 09:00:43)

elf: parse library from symbol versioning table
This change parses the library name for a dynamic symbol from the ELF symbol versioning table and removes a // TODO

robbje: Thanks for the reviews.

Patch:
diff --git a/src/read/elf/file.rs b/src/read/elf/file.rs
index ca4e3ef..01615e1 100644
--- a/src/read/elf/file.rs
+++ b/src/read/elf/file.rs
@@ -334,15 +334,23 @@ where
     }
 
     fn imports(&self) -> read::Result<Vec<Import<'data>>> {
+        let versions = self.sections.versions(self.endian, self.data)?;
+
         let mut imports = Vec::new();
-        for symbol in self.dynamic_symbols.iter() {
+        for (index, symbol) in self.dynamic_symbols.enumerate() {
             if symbol.is_undefined(self.endian) {
                 let name = symbol.name(self.endian, self.dynamic_symbols.strings())?;
                 if !name.is_empty() {
-                    // TODO: use symbol versioning to determine library
+                    let library = if let Some(svt) = versions.as_ref() {
+                        let vi = svt.version_index(self.endian, index);
+                        svt.version(vi)?.and_then(|v| v.file())
+                    } else {
+                        None
+                    }
+                    .unwrap_or(&[]);
                     imports.push(Import {
                         name: ByteString(name),
-                        library: ByteString(&[]),
+                        library: ByteString(library),
                     });
                 }
             }
diff --git a/src/read/elf/version.rs b/src/read/elf/version.rs
index ae3f005..d0bd504 100644
--- a/src/read/elf/version.rs
+++ b/src/read/elf/version.rs
@@ -40,6 +40,7 @@ pub struct Version<'data> {
     hash: u32,
     // Used to keep track of valid indices in `VersionTable`.
     valid: bool,
+    file: Option<&'data [u8]>,
 }
 
 impl<'data> Version<'data> {
@@ -52,6 +53,14 @@ impl<'data> Version<'data> {
     pub fn hash(&self) -> u32 {
         self.hash
     }
+
+    /// Return the filename of the library containing this version.
+    ///
+    /// This is the `vn_file` field of the associated entry in [`elf::SHT_GNU_VERNEED`].
+    /// or `None` if the version info was parsed from a [`elf::SHT_GNU_VERDEF`] section.
+    pub fn file(&self) -> Option<&'data [u8]> {
+        self.file
+    }
 }
 
 /// A table of version definitions and requirements.
@@ -128,12 +137,13 @@ impl<'data, Elf: FileHeader> VersionTable<'data, Elf> {
                         name: verdaux.name(endian, strings)?,
                         hash: verdef.vd_hash.get(endian),
                         valid: true,
+                        file: None,
                     };
                 }
             }
         }
         if let Some(mut verneeds) = verneeds {
-            while let Some((_, mut vernauxs)) = verneeds.next()? {
+            while let Some((verneed, mut vernauxs)) = verneeds.next()? {
                 while let Some(vernaux) = vernauxs.next()? {
                     let index = vernaux.vna_other.get(endian) & elf::VERSYM_VERSION;
                     if index <= elf::VER_NDX_GLOBAL {
@@ -144,6 +154,7 @@ impl<'data, Elf: FileHeader> VersionTable<'data, Elf> {
                         name: vernaux.name(endian, strings)?,
                         hash: vernaux.vna_hash.get(endian),
                         valid: true,
+                        file: Some(verneed.file(endian, strings)?),
                     };
                 }
             }


Test patch:
diff --git a/crates/examples/testfiles/elf/base-aarch64.objdump b/crates/examples/testfiles/elf/base-aarch64.objdump
index 2c73255..242a2cc 100644
--- a/crates/examples/testfiles/elf/base-aarch64.objdump
+++ b/crates/examples/testfiles/elf/base-aarch64.objdump
@@ -152,12 +152,12 @@ Dynamic relocations
 (10fb8, Relocation { kind: Unknown, encoding: Generic, size: 0, target: Symbol(SymbolIndex(9)), addend: 0, implicit_addend: false, flags: Elf { r_type: 402 } })
 
 Import { library: "", name: "_ITM_deregisterTMCloneTable" }
-Import { library: "", name: "__cxa_finalize" }
-Import { library: "", name: "__libc_start_main" }
+Import { library: "libc.so.6", name: "__cxa_finalize" }
+Import { library: "libc.so.6", name: "__libc_start_main" }
 Import { library: "", name: "__gmon_start__" }
-Import { library: "", name: "abort" }
+Import { library: "libc.so.6", name: "abort" }
 Import { library: "", name: "_ITM_registerTMCloneTable" }
-Import { library: "", name: "printf" }
+Import { library: "libc.so.6", name: "printf" }
 
 Symbol map
 0x598 "_init"
diff --git a/crates/examples/testfiles/elf/base.objdump b/crates/examples/testfiles/elf/base.objdump
index 74d86f6..484db5c 100644
--- a/crates/examples/testfiles/elf/base.objdump
+++ b/crates/examples/testfiles/elf/base.objdump
@@ -122,11 +122,11 @@ Dynamic relocations
 (200fd0, Relocation { kind: Unknown, encoding: Generic, size: 0, target: Symbol(SymbolIndex(2)), addend: 0, implicit_addend: false, flags: Elf { r_type: 7 } })
 
 Import { library: "", name: "_ITM_deregisterTMCloneTable" }
-Import { library: "", name: "printf" }
-Import { library: "", name: "__libc_start_main" }
+Import { library: "libc.so.6", name: "printf" }
+Import { library: "libc.so.6", name: "__libc_start_main" }
 Import { library: "", name: "__gmon_start__" }
 Import { library: "", name: "_ITM_registerTMCloneTable" }
-Import { library: "", name: "__cxa_finalize" }
+Import { library: "libc.so.6", name: "__cxa_finalize" }
 
 Symbol map
 0x520 "_init"