aboutsummaryrefslogtreecommitdiff
path: root/vendor/object/src/read/coff/import.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/object/src/read/coff/import.rs')
-rw-r--r--vendor/object/src/read/coff/import.rs220
1 files changed, 220 insertions, 0 deletions
diff --git a/vendor/object/src/read/coff/import.rs b/vendor/object/src/read/coff/import.rs
new file mode 100644
index 0000000..a296ac3
--- /dev/null
+++ b/vendor/object/src/read/coff/import.rs
@@ -0,0 +1,220 @@
+//! Support for reading short import files.
+//!
+//! These are used by some Windows linkers as a more compact way to describe
+//! dynamically imported symbols.
+
+use crate::read::{Architecture, Error, ReadError, ReadRef, Result};
+use crate::{pe, ByteString, Bytes, LittleEndian as LE, SubArchitecture};
+
+/// A Windows short form description of a symbol to import.
+///
+/// Used in Windows import libraries to provide a mapping from
+/// a symbol name to a DLL export. This is not an object file.
+///
+/// This is a file that starts with [`pe::ImportObjectHeader`], and corresponds
+/// to [`crate::FileKind::CoffImport`].
+#[derive(Debug, Clone)]
+pub struct ImportFile<'data> {
+ header: &'data pe::ImportObjectHeader,
+ kind: ImportType,
+ dll: ByteString<'data>,
+ symbol: ByteString<'data>,
+ import: Option<ByteString<'data>>,
+}
+
+impl<'data> ImportFile<'data> {
+ /// Parse it.
+ pub fn parse<R: ReadRef<'data>>(data: R) -> Result<Self> {
+ let mut offset = 0;
+ let header = pe::ImportObjectHeader::parse(data, &mut offset)?;
+ let data = header.parse_data(data, &mut offset)?;
+
+ // Unmangles a name by removing a `?`, `@` or `_` prefix.
+ fn strip_prefix(s: &[u8]) -> &[u8] {
+ match s.split_first() {
+ Some((b, rest)) if [b'?', b'@', b'_'].contains(b) => rest,
+ _ => s,
+ }
+ }
+ Ok(Self {
+ header,
+ dll: data.dll,
+ symbol: data.symbol,
+ kind: match header.import_type() {
+ pe::IMPORT_OBJECT_CODE => ImportType::Code,
+ pe::IMPORT_OBJECT_DATA => ImportType::Data,
+ pe::IMPORT_OBJECT_CONST => ImportType::Const,
+ _ => return Err(Error("Invalid COFF import library import type")),
+ },
+ import: match header.name_type() {
+ pe::IMPORT_OBJECT_ORDINAL => None,
+ pe::IMPORT_OBJECT_NAME => Some(data.symbol()),
+ pe::IMPORT_OBJECT_NAME_NO_PREFIX => Some(strip_prefix(data.symbol())),
+ pe::IMPORT_OBJECT_NAME_UNDECORATE => Some(
+ strip_prefix(data.symbol())
+ .split(|&b| b == b'@')
+ .next()
+ .unwrap(),
+ ),
+ pe::IMPORT_OBJECT_NAME_EXPORTAS => data.export(),
+ _ => return Err(Error("Unknown COFF import library name type")),
+ }
+ .map(ByteString),
+ })
+ }
+
+ /// Get the machine type.
+ pub fn architecture(&self) -> Architecture {
+ match self.header.machine.get(LE) {
+ pe::IMAGE_FILE_MACHINE_ARMNT => Architecture::Arm,
+ pe::IMAGE_FILE_MACHINE_ARM64 | pe::IMAGE_FILE_MACHINE_ARM64EC => Architecture::Aarch64,
+ pe::IMAGE_FILE_MACHINE_I386 => Architecture::I386,
+ pe::IMAGE_FILE_MACHINE_AMD64 => Architecture::X86_64,
+ _ => Architecture::Unknown,
+ }
+ }
+
+ /// Get the sub machine type, if available.
+ pub fn sub_architecture(&self) -> Option<SubArchitecture> {
+ match self.header.machine.get(LE) {
+ pe::IMAGE_FILE_MACHINE_ARM64EC => Some(SubArchitecture::Arm64EC),
+ _ => None,
+ }
+ }
+
+ /// The public symbol name.
+ pub fn symbol(&self) -> &'data [u8] {
+ self.symbol.0
+ }
+
+ /// The name of the DLL to import the symbol from.
+ pub fn dll(&self) -> &'data [u8] {
+ self.dll.0
+ }
+
+ /// The name exported from the DLL.
+ pub fn import(&self) -> ImportName<'data> {
+ match self.import {
+ Some(name) => ImportName::Name(name.0),
+ None => ImportName::Ordinal(self.header.ordinal_or_hint.get(LE)),
+ }
+ }
+
+ /// The type of import. Usually either a function or data.
+ pub fn import_type(&self) -> ImportType {
+ self.kind
+ }
+}
+
+/// The name or ordinal to import from a DLL.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum ImportName<'data> {
+ /// Import by ordinal. Ordinarily this is a 1-based index.
+ Ordinal(u16),
+ /// Import by name.
+ Name(&'data [u8]),
+}
+
+/// The kind of import symbol.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum ImportType {
+ /// An executable code symbol.
+ Code,
+ /// A data symbol.
+ Data,
+ /// A constant value.
+ Const,
+}
+
+impl pe::ImportObjectHeader {
+ /// Read the short import header.
+ ///
+ /// Also checks that the signature and version are valid.
+ /// Directly following this header will be the string data.
+ pub fn parse<'data, R: ReadRef<'data>>(data: R, offset: &mut u64) -> Result<&'data Self> {
+ let header = data
+ .read::<pe::ImportObjectHeader>(offset)
+ .read_error("Invalid COFF import library header size")?;
+ if header.sig1.get(LE) != 0 || header.sig2.get(LE) != pe::IMPORT_OBJECT_HDR_SIG2 {
+ Err(Error("Invalid COFF import library header"))
+ } else if header.version.get(LE) != 0 {
+ Err(Error("Unknown COFF import library header version"))
+ } else {
+ Ok(header)
+ }
+ }
+
+ /// Parse the data following the header.
+ pub fn parse_data<'data, R: ReadRef<'data>>(
+ &self,
+ data: R,
+ offset: &mut u64,
+ ) -> Result<ImportObjectData<'data>> {
+ let mut data = Bytes(
+ data.read_bytes(offset, u64::from(self.size_of_data.get(LE)))
+ .read_error("Invalid COFF import library data size")?,
+ );
+ let symbol = data
+ .read_string()
+ .map(ByteString)
+ .read_error("Could not read COFF import library symbol name")?;
+ let dll = data
+ .read_string()
+ .map(ByteString)
+ .read_error("Could not read COFF import library DLL name")?;
+ let export = if self.name_type() == pe::IMPORT_OBJECT_NAME_EXPORTAS {
+ data.read_string()
+ .map(ByteString)
+ .map(Some)
+ .read_error("Could not read COFF import library export name")?
+ } else {
+ None
+ };
+ Ok(ImportObjectData {
+ symbol,
+ dll,
+ export,
+ })
+ }
+
+ /// The type of import.
+ ///
+ /// This is one of the `IMPORT_OBJECT_*` constants.
+ pub fn import_type(&self) -> u16 {
+ self.name_type.get(LE) & pe::IMPORT_OBJECT_TYPE_MASK
+ }
+
+ /// The type of import name.
+ ///
+ /// This is one of the `IMPORT_OBJECT_*` constants.
+ pub fn name_type(&self) -> u16 {
+ (self.name_type.get(LE) >> pe::IMPORT_OBJECT_NAME_SHIFT) & pe::IMPORT_OBJECT_NAME_MASK
+ }
+}
+
+/// The data following [`pe::ImportObjectHeader`].
+#[derive(Debug, Clone)]
+pub struct ImportObjectData<'data> {
+ symbol: ByteString<'data>,
+ dll: ByteString<'data>,
+ export: Option<ByteString<'data>>,
+}
+
+impl<'data> ImportObjectData<'data> {
+ /// The public symbol name.
+ pub fn symbol(&self) -> &'data [u8] {
+ self.symbol.0
+ }
+
+ /// The name of the DLL to import the symbol from.
+ pub fn dll(&self) -> &'data [u8] {
+ self.dll.0
+ }
+
+ /// The name exported from the DLL.
+ ///
+ /// This is only set if the name is not derived from the symbol name.
+ pub fn export(&self) -> Option<&'data [u8]> {
+ self.export.map(|export| export.0)
+ }
+}