use std::borrow::Cow;
use std::io::{Error, ErrorKind, Result, Seek, Write};
use std::mem::{offset_of, size_of};
use std::path::PathBuf;
use std::str::from_utf8;
use object::pe::{
ImageAuxSymbolSection, ImageFileHeader, ImageImportDescriptor, ImageRelocation,
ImageSectionHeader, ImageSymbol, ImportObjectHeader, IMAGE_COMDAT_SELECT_ANY,
IMAGE_FILE_32BIT_MACHINE, IMAGE_REL_AMD64_ADDR32NB, IMAGE_REL_ARM64_ADDR32NB,
IMAGE_REL_ARM_ADDR32NB, IMAGE_REL_I386_DIR32NB, IMAGE_SCN_ALIGN_2BYTES, IMAGE_SCN_ALIGN_4BYTES,
IMAGE_SCN_ALIGN_8BYTES, IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT,
IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE,
IMAGE_SYM_CLASS_EXTERNAL, IMAGE_SYM_CLASS_NULL, IMAGE_SYM_CLASS_SECTION,
IMAGE_SYM_CLASS_STATIC, IMAGE_SYM_CLASS_WEAK_EXTERNAL, IMAGE_WEAK_EXTERN_SEARCH_ALIAS,
};
use object::pod::bytes_of;
use crate::coff::{is_arm64ec, ImportNameType, ImportType, MachineTypes};
use crate::mangler::{get_arm64ec_demangled_function_name, get_arm64ec_mangled_function_name};
use crate::{write_archive_to_stream, ArchiveKind, NewArchiveMember, DEFAULT_OBJECT_READER};
pub(crate) const IMPORT_DESCRIPTOR_PREFIX: &[u8] = b"__IMPORT_DESCRIPTOR_";
pub(crate) const NULL_IMPORT_DESCRIPTOR_SYMBOL_NAME: &[u8] = b"__NULL_IMPORT_DESCRIPTOR";
pub(crate) const NULL_THUNK_DATA_PREFIX: &[u8] = b"\x7f";
pub(crate) const NULL_THUNK_DATA_SUFFIX: &[u8] = b"_NULL_THUNK_DATA";
macro_rules! u16 {
($val:expr) => {
object::U16::new(object::LittleEndian, $val)
};
}
macro_rules! u32 {
($val:expr) => {
object::U32::new(object::LittleEndian, $val)
};
}
pub(crate) fn get_short_import_symbol(
buf: &[u8],
f: &mut dyn FnMut(&[u8]) -> Result<()>,
) -> Result<bool> {
let mut offset = 0;
let header = ImportObjectHeader::parse(buf, &mut offset).map_err(Error::other)?;
let data = header.parse_data(buf, &mut offset).map_err(Error::other)?;
let is_ec = header.machine.get(object::LittleEndian) == object::pe::IMAGE_FILE_MACHINE_ARM64EC;
let name = data.symbol();
let demangled_name = is_ec
.then(|| get_arm64ec_demangled_function_name(from_utf8(name).unwrap()))
.flatten()
.map_or_else(
|| Cow::Borrowed(name),
|demangled_name| Cow::Owned(demangled_name.into_bytes()),
);
const IMP_PREFIX: &[u8] = b"__imp_";
f(&IMP_PREFIX
.iter()
.chain(demangled_name.as_ref())
.copied()
.collect::<Vec<_>>())?;
if header.import_type() == ImportType::Data.into() {
return Ok(true);
}
f(demangled_name.as_ref())?;
if header.machine.get(object::LittleEndian) == object::pe::IMAGE_FILE_MACHINE_ARM64EC {
const IMP_PREFIX: &[u8] = b"__imp_aux_";
f(&IMP_PREFIX
.iter()
.chain(demangled_name.as_ref())
.copied()
.collect::<Vec<_>>())?;
f(name)?;
}
Ok(true)
}
const READER_FOR_SHORT_IMPORT: crate::ObjectReader = crate::ObjectReader {
get_symbols: get_short_import_symbol,
..crate::DEFAULT_OBJECT_READER
};
pub struct COFFShortExport {
pub name: String,
pub ext_name: Option<String>,
pub symbol_name: Option<String>,
pub alias_target: Option<String>,
pub ordinal: u16,
pub noname: bool,
pub data: bool,
pub private: bool,
pub constant: bool,
}
fn set_name_to_string_table_entry(symbol: &mut ImageSymbol, offset: usize) {
symbol.name[..4].copy_from_slice(&[0; 4]);
symbol.name[4..].copy_from_slice(&u32::try_from(offset).unwrap().to_le_bytes());
}
fn get_img_rel_relocation(machine: MachineTypes) -> object::U16<object::LittleEndian> {
u16!(match machine {
MachineTypes::AMD64 => IMAGE_REL_AMD64_ADDR32NB,
MachineTypes::ARMNT => IMAGE_REL_ARM_ADDR32NB,
MachineTypes::ARM64 | MachineTypes::ARM64EC | MachineTypes::ARM64X =>
IMAGE_REL_ARM64_ADDR32NB,
MachineTypes::I386 => IMAGE_REL_I386_DIR32NB,
})
}
fn write_string_table(b: &mut Vec<u8>, strings: &[&[u8]]) -> Result<()> {
let offset = b.len();
b.extend(0u32.to_le_bytes());
for s in strings {
b.write_all(s)?;
b.write_all(&[0])?;
}
let length: u32 = (b.len() - offset).try_into().unwrap();
b[offset..offset + size_of::<u32>()].copy_from_slice(&length.to_le_bytes());
Ok(())
}
fn get_name_type(sym: &str, ext_name: &str, machine: MachineTypes, mingw: bool) -> ImportNameType {
if ext_name.starts_with('_') && ext_name.contains('@') && !mingw {
ImportNameType::Name
} else if sym != ext_name {
ImportNameType::NameUndecorate
} else if machine == MachineTypes::I386 && sym.starts_with('_') {
ImportNameType::NameNoprefix
} else {
ImportNameType::Name
}
}
fn replace(s: &str, mut from: &str, mut to: &str) -> Result<String> {
if let Some((before, after)) = s.split_once(from) {
return Ok(format!("{before}{to}{after}"));
}
if from.starts_with('_') && to.starts_with('_') {
from = &from[1..];
to = &to[1..];
if let Some((before, after)) = s.split_once(from) {
return Ok(format!("{before}{to}{after}"));
}
}
Err(Error::other(format!(
"{s}: replacing '{from}' with '{to}' failed"
)))
}
struct ObjectFactory<'a> {
native_machine: MachineTypes,
import_name: &'a str,
import_descriptor_symbol_name: Vec<u8>,
null_thunk_symbol_name: Vec<u8>,
}
impl<'a> ObjectFactory<'a> {
fn new(s: &'a str, m: MachineTypes) -> Result<Self> {
let import_as_path = PathBuf::from(s);
let library = import_as_path
.file_stem()
.ok_or_else(|| {
Error::new(
ErrorKind::InvalidInput,
"Import name did not end with a file name",
)
})?
.to_str()
.ok_or_else(|| Error::new(ErrorKind::InvalidInput, "Import name is not valid UTF-8"))?;
let library = library.as_bytes();
Ok(Self {
native_machine: m,
import_name: s,
import_descriptor_symbol_name: IMPORT_DESCRIPTOR_PREFIX
.iter()
.chain(library)
.copied()
.collect(),
null_thunk_symbol_name: NULL_THUNK_DATA_PREFIX
.iter()
.chain(library)
.chain(NULL_THUNK_DATA_SUFFIX)
.copied()
.collect(),
})
}
fn is_64_bit(&self) -> bool {
crate::coff::is_64_bit(self.native_machine)
}
fn create_import_descriptor(&self) -> Result<NewArchiveMember<'_>> {
let mut buffer = Vec::new();
const NUMBER_OF_SECTIONS: usize = 2;
const NUMBER_OF_SYMBOLS: usize = 7;
const NUMBER_OF_RELOCATIONS: usize = 3;
let header = ImageFileHeader {
machine: u16!(self.native_machine.into()),
number_of_sections: u16!(NUMBER_OF_SECTIONS.try_into().unwrap()),
time_date_stamp: u32!(0),
pointer_to_symbol_table: u32!((size_of::<ImageFileHeader>() + (NUMBER_OF_SECTIONS * size_of::<ImageSectionHeader>()) +
size_of::<ImageImportDescriptor>() +
NUMBER_OF_RELOCATIONS * size_of::<ImageRelocation>() +
(self.import_name.len() + 1)).try_into().unwrap()),
number_of_symbols: u32!(NUMBER_OF_SYMBOLS.try_into().unwrap()),
size_of_optional_header: u16!(0),
characteristics: u16!(if self.is_64_bit() {
0
} else {
IMAGE_FILE_32BIT_MACHINE
}),
};
buffer.write_all(bytes_of(&header))?;
let section_table: [_; NUMBER_OF_SECTIONS] = [
ImageSectionHeader {
name: *b".idata$2",
virtual_size: u32!(0),
virtual_address: u32!(0),
size_of_raw_data: u32!(size_of::<ImageImportDescriptor>().try_into().unwrap()),
pointer_to_raw_data: u32!((size_of::<ImageFileHeader>()
+ NUMBER_OF_SECTIONS * size_of::<ImageSectionHeader>())
.try_into()
.unwrap()),
pointer_to_relocations: u32!((size_of::<ImageFileHeader>()
+ NUMBER_OF_SECTIONS * size_of::<ImageSectionHeader>()
+ size_of::<ImageImportDescriptor>())
.try_into()
.unwrap()),
pointer_to_linenumbers: u32!(0),
number_of_relocations: u16!(NUMBER_OF_RELOCATIONS.try_into().unwrap()),
number_of_linenumbers: u16!(0),
characteristics: u32!(
IMAGE_SCN_ALIGN_4BYTES
| IMAGE_SCN_CNT_INITIALIZED_DATA
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
),
},
ImageSectionHeader {
name: *b".idata$6",
virtual_size: u32!(0),
virtual_address: u32!(0),
size_of_raw_data: u32!((self.import_name.len() + 1).try_into().unwrap()),
pointer_to_raw_data: u32!((size_of::<ImageFileHeader>()
+ NUMBER_OF_SECTIONS * size_of::<ImageSectionHeader>()
+ size_of::<ImageImportDescriptor>()
+ NUMBER_OF_RELOCATIONS * size_of::<ImageRelocation>())
.try_into()
.unwrap()),
pointer_to_relocations: u32!(0),
pointer_to_linenumbers: u32!(0),
number_of_relocations: u16!(0),
number_of_linenumbers: u16!(0),
characteristics: u32!(
IMAGE_SCN_ALIGN_2BYTES
| IMAGE_SCN_CNT_INITIALIZED_DATA
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
),
},
];
buffer.write_all(bytes_of(§ion_table))?;
let import_descriptor = ImageImportDescriptor {
original_first_thunk: u32!(0),
time_date_stamp: u32!(0),
forwarder_chain: u32!(0),
name: u32!(0),
first_thunk: u32!(0),
};
buffer.write_all(bytes_of(&import_descriptor))?;
let relocation_table: [_; NUMBER_OF_RELOCATIONS] = [
ImageRelocation {
virtual_address: u32!((offset_of!(ImageImportDescriptor, name))
.try_into()
.unwrap()),
symbol_table_index: u32!(2),
typ: get_img_rel_relocation(self.native_machine),
},
ImageRelocation {
virtual_address: u32!(offset_of!(ImageImportDescriptor, original_first_thunk)
.try_into()
.unwrap()),
symbol_table_index: u32!(3),
typ: get_img_rel_relocation(self.native_machine),
},
ImageRelocation {
virtual_address: u32!(offset_of!(ImageImportDescriptor, first_thunk)
.try_into()
.unwrap()),
symbol_table_index: u32!(4),
typ: get_img_rel_relocation(self.native_machine),
},
];
buffer.write_all(bytes_of(&relocation_table))?;
buffer.write_all(self.import_name.as_bytes())?;
buffer.write_all(&[0])?;
let mut symbol_table: [_; NUMBER_OF_SYMBOLS] = [
ImageSymbol {
name: [0; 8],
value: u32!(0),
section_number: u16!(1),
typ: u16!(0),
storage_class: IMAGE_SYM_CLASS_EXTERNAL,
number_of_aux_symbols: 0,
},
ImageSymbol {
name: *b".idata$2",
value: u32!(0),
section_number: u16!(1),
typ: u16!(0),
storage_class: IMAGE_SYM_CLASS_SECTION,
number_of_aux_symbols: 0,
},
ImageSymbol {
name: *b".idata$6",
value: u32!(0),
section_number: u16!(2),
typ: u16!(0),
storage_class: IMAGE_SYM_CLASS_STATIC,
number_of_aux_symbols: 0,
},
ImageSymbol {
name: *b".idata$4",
value: u32!(0),
section_number: u16!(0),
typ: u16!(0),
storage_class: IMAGE_SYM_CLASS_SECTION,
number_of_aux_symbols: 0,
},
ImageSymbol {
name: *b".idata$5",
value: u32!(0),
section_number: u16!(0),
typ: u16!(0),
storage_class: IMAGE_SYM_CLASS_SECTION,
number_of_aux_symbols: 0,
},
ImageSymbol {
name: [0; 8],
value: u32!(0),
section_number: u16!(0),
typ: u16!(0),
storage_class: IMAGE_SYM_CLASS_EXTERNAL,
number_of_aux_symbols: 0,
},
ImageSymbol {
name: [0; 8],
value: u32!(0),
section_number: u16!(0),
typ: u16!(0),
storage_class: IMAGE_SYM_CLASS_EXTERNAL,
number_of_aux_symbols: 0,
},
];
set_name_to_string_table_entry(&mut symbol_table[0], size_of::<u32>());
set_name_to_string_table_entry(
&mut symbol_table[5],
size_of::<u32>() + self.import_descriptor_symbol_name.len() + 1,
);
set_name_to_string_table_entry(
&mut symbol_table[6],
size_of::<u32>()
+ self.import_descriptor_symbol_name.len()
+ 1
+ NULL_IMPORT_DESCRIPTOR_SYMBOL_NAME.len()
+ 1,
);
buffer.write_all(bytes_of(&symbol_table))?;
write_string_table(
&mut buffer,
&[
&self.import_descriptor_symbol_name,
NULL_IMPORT_DESCRIPTOR_SYMBOL_NAME,
&self.null_thunk_symbol_name,
],
)?;
Ok(NewArchiveMember::new(
buffer.into_boxed_slice(),
&DEFAULT_OBJECT_READER,
self.import_name.to_string(),
))
}
fn create_null_import_descriptor(&self, comdat: bool) -> Result<NewArchiveMember<'_>> {
let mut buffer = Vec::new();
const NUMBER_OF_SECTIONS: usize = 1;
let number_of_symbols = if comdat { 3 } else { 1 };
let header = ImageFileHeader {
machine: u16!(self.native_machine.into()),
number_of_sections: u16!(NUMBER_OF_SECTIONS.try_into().unwrap()),
time_date_stamp: u32!(0),
pointer_to_symbol_table: u32!((size_of::<ImageFileHeader>() + (NUMBER_OF_SECTIONS * size_of::<ImageSectionHeader>()) +
size_of::<ImageImportDescriptor>()).try_into().unwrap()),
number_of_symbols: u32!(number_of_symbols.try_into().unwrap()),
size_of_optional_header: u16!(0),
characteristics: u16!(if self.is_64_bit() {
0
} else {
IMAGE_FILE_32BIT_MACHINE
}),
};
buffer.write_all(bytes_of(&header))?;
let section_table: [_; NUMBER_OF_SECTIONS] = [ImageSectionHeader {
name: *b".idata$3",
virtual_size: u32!(0),
virtual_address: u32!(0),
size_of_raw_data: u32!(size_of::<ImageImportDescriptor>().try_into().unwrap()),
pointer_to_raw_data: u32!((size_of::<ImageFileHeader>()
+ NUMBER_OF_SECTIONS * size_of::<ImageSectionHeader>())
.try_into()
.unwrap()),
pointer_to_relocations: u32!(0),
pointer_to_linenumbers: u32!(0),
number_of_relocations: u16!(0),
number_of_linenumbers: u16!(0),
characteristics: u32!(
IMAGE_SCN_ALIGN_4BYTES
| IMAGE_SCN_CNT_INITIALIZED_DATA
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
| if comdat { IMAGE_SCN_LNK_COMDAT } else { 0 }
),
}];
buffer.write_all(bytes_of(§ion_table))?;
let import_descriptor = ImageImportDescriptor {
original_first_thunk: u32!(0),
time_date_stamp: u32!(0),
forwarder_chain: u32!(0),
name: u32!(0),
first_thunk: u32!(0),
};
buffer.write_all(bytes_of(&import_descriptor))?;
if comdat {
let symbol = ImageSymbol {
name: *b".idata$3",
value: u32!(0),
section_number: u16!(1),
typ: u16!(0),
storage_class: IMAGE_SYM_CLASS_STATIC,
number_of_aux_symbols: 1,
};
let aux = ImageAuxSymbolSection {
length: u32!(size_of::<ImageImportDescriptor>().try_into().unwrap()),
number_of_relocations: u16!(0),
number_of_linenumbers: u16!(0),
check_sum: u32!(0),
selection: IMAGE_COMDAT_SELECT_ANY,
number: u16!(0),
reserved: 0,
high_number: u16!(0),
};
buffer.write_all(bytes_of(&symbol))?;
buffer.write_all(bytes_of(&aux))?;
}
let mut null_descriptor_symbol = ImageSymbol {
name: [0; 8],
value: u32!(0),
section_number: u16!(1),
typ: u16!(0),
storage_class: IMAGE_SYM_CLASS_EXTERNAL,
number_of_aux_symbols: 0,
};
set_name_to_string_table_entry(&mut null_descriptor_symbol, size_of::<u32>());
buffer.write_all(bytes_of(&null_descriptor_symbol))?;
write_string_table(&mut buffer, &[NULL_IMPORT_DESCRIPTOR_SYMBOL_NAME])?;
Ok(NewArchiveMember::new(
buffer.into_boxed_slice(),
&DEFAULT_OBJECT_READER,
self.import_name.to_string(),
))
}
fn create_null_thunk(&self) -> Result<NewArchiveMember<'_>> {
let mut buffer = Vec::new();
const NUMBER_OF_SECTIONS: usize = 2;
const NUMBER_OF_SYMBOLS: usize = 1;
let va_size = if self.is_64_bit() { 8 } else { 4 };
let header = ImageFileHeader {
machine: u16!(self.native_machine.into()),
number_of_sections: u16!(NUMBER_OF_SECTIONS.try_into().unwrap()),
time_date_stamp: u32!(0),
pointer_to_symbol_table: u32!((size_of::<ImageFileHeader>() + (NUMBER_OF_SECTIONS * size_of::<ImageSectionHeader>()) +
va_size +
va_size).try_into().unwrap()),
number_of_symbols: u32!(NUMBER_OF_SYMBOLS.try_into().unwrap()),
size_of_optional_header: u16!(0),
characteristics: u16!(if self.is_64_bit() {
0
} else {
IMAGE_FILE_32BIT_MACHINE
}),
};
buffer.write_all(bytes_of(&header))?;
let alignment = if self.is_64_bit() {
IMAGE_SCN_ALIGN_8BYTES
} else {
IMAGE_SCN_ALIGN_4BYTES
};
let section_table: [_; NUMBER_OF_SECTIONS] = [
ImageSectionHeader {
name: *b".idata$5",
virtual_size: u32!(0),
virtual_address: u32!(0),
size_of_raw_data: u32!(va_size.try_into().unwrap()),
pointer_to_raw_data: u32!((size_of::<ImageFileHeader>()
+ NUMBER_OF_SECTIONS * size_of::<ImageSectionHeader>())
.try_into()
.unwrap()),
pointer_to_relocations: u32!(0),
pointer_to_linenumbers: u32!(0),
number_of_relocations: u16!(0),
number_of_linenumbers: u16!(0),
characteristics: u32!(
alignment
| IMAGE_SCN_CNT_INITIALIZED_DATA
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
),
},
ImageSectionHeader {
name: *b".idata$4",
virtual_size: u32!(0),
virtual_address: u32!(0),
size_of_raw_data: u32!(va_size.try_into().unwrap()),
pointer_to_raw_data: u32!((size_of::<ImageFileHeader>()
+ NUMBER_OF_SECTIONS * size_of::<ImageSectionHeader>()
+ va_size)
.try_into()
.unwrap()),
pointer_to_relocations: u32!(0),
pointer_to_linenumbers: u32!(0),
number_of_relocations: u16!(0),
number_of_linenumbers: u16!(0),
characteristics: u32!(
alignment
| IMAGE_SCN_CNT_INITIALIZED_DATA
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
),
},
];
buffer.write_all(bytes_of(§ion_table))?;
buffer.write_all(&vec![0; va_size])?;
buffer.write_all(&vec![0; va_size])?;
let mut symbol_table: [_; NUMBER_OF_SYMBOLS] = [ImageSymbol {
name: [0; 8],
value: u32!(0),
section_number: u16!(1),
typ: u16!(0),
storage_class: IMAGE_SYM_CLASS_EXTERNAL,
number_of_aux_symbols: 0,
}];
set_name_to_string_table_entry(&mut symbol_table[0], size_of::<u32>());
buffer.write_all(bytes_of(&symbol_table))?;
write_string_table(&mut buffer, &[&self.null_thunk_symbol_name])?;
Ok(NewArchiveMember::new(
buffer.into_boxed_slice(),
&DEFAULT_OBJECT_READER,
self.import_name.to_string(),
))
}
fn create_short_import(
&self,
sym: &str,
ordinal: u16,
import_type: ImportType,
name_type: ImportNameType,
export_name: Option<&str>,
machine: MachineTypes,
) -> Result<NewArchiveMember<'_>> {
let mut imp_size = self.import_name.len() + sym.len() + 2; if let Some(export_name) = export_name {
imp_size += export_name.len() + 1;
}
let size = size_of::<ImportObjectHeader>() + imp_size;
let mut buf = Vec::new();
buf.reserve_exact(size);
let imp = ImportObjectHeader {
sig1: u16!(0),
sig2: u16!(0xFFFF),
version: u16!(0),
machine: u16!(machine.into()),
time_date_stamp: u32!(0),
size_of_data: u32!(imp_size.try_into().unwrap()),
ordinal_or_hint: u16!(ordinal),
name_type: u16!((u16::from(name_type) << 2) | u16::from(import_type)),
};
buf.write_all(bytes_of(&imp))?;
buf.write_all(sym.as_bytes())?;
buf.write_all(&[0])?;
buf.write_all(self.import_name.as_bytes())?;
buf.write_all(&[0])?;
if let Some(export_name) = export_name {
buf.write_all(export_name.as_bytes())?;
buf.write_all(&[0])?;
}
Ok(NewArchiveMember::new(
buf.into_boxed_slice(),
&READER_FOR_SHORT_IMPORT,
self.import_name.to_string(),
))
}
fn create_weak_external(
&self,
sym: &str,
weak: &str,
imp: bool,
machine: MachineTypes,
) -> Result<NewArchiveMember<'_>> {
let mut buffer = Vec::new();
const NUMBER_OF_SECTIONS: usize = 1;
const NUMBER_OF_SYMBOLS: usize = 5;
let header = ImageFileHeader {
machine: u16!(machine.into()),
number_of_sections: u16!(NUMBER_OF_SECTIONS.try_into().unwrap()),
time_date_stamp: u32!(0),
pointer_to_symbol_table: u32!((size_of::<ImageFileHeader>()
+ (NUMBER_OF_SECTIONS * size_of::<ImageSectionHeader>()))
.try_into()
.unwrap()),
number_of_symbols: u32!(NUMBER_OF_SYMBOLS.try_into().unwrap()),
size_of_optional_header: u16!(0),
characteristics: u16!(0),
};
buffer.write_all(bytes_of(&header))?;
let section_table: [_; NUMBER_OF_SECTIONS] = [ImageSectionHeader {
name: *b".drectve",
virtual_size: u32!(0),
virtual_address: u32!(0),
size_of_raw_data: u32!(0),
pointer_to_raw_data: u32!(0),
pointer_to_relocations: u32!(0),
pointer_to_linenumbers: u32!(0),
number_of_relocations: u16!(0),
number_of_linenumbers: u16!(0),
characteristics: u32!(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE),
}];
buffer.write_all(bytes_of(§ion_table))?;
let mut symbol_table: [_; NUMBER_OF_SYMBOLS] = [
ImageSymbol {
name: *b"@comp.id",
value: u32!(0),
section_number: u16!(0xFFFF),
typ: u16!(0),
storage_class: IMAGE_SYM_CLASS_STATIC,
number_of_aux_symbols: 0,
},
ImageSymbol {
name: *b"@feat.00",
value: u32!(0),
section_number: u16!(0xFFFF),
typ: u16!(0),
storage_class: IMAGE_SYM_CLASS_STATIC,
number_of_aux_symbols: 0,
},
ImageSymbol {
name: [0; 8],
value: u32!(0),
section_number: u16!(0),
typ: u16!(0),
storage_class: IMAGE_SYM_CLASS_EXTERNAL,
number_of_aux_symbols: 0,
},
ImageSymbol {
name: [0; 8],
value: u32!(0),
section_number: u16!(0),
typ: u16!(0),
storage_class: IMAGE_SYM_CLASS_WEAK_EXTERNAL,
number_of_aux_symbols: 1,
},
ImageSymbol {
name: [2, 0, 0, 0, IMAGE_WEAK_EXTERN_SEARCH_ALIAS as u8, 0, 0, 0],
value: u32!(0),
section_number: u16!(0),
typ: u16!(0),
storage_class: IMAGE_SYM_CLASS_NULL,
number_of_aux_symbols: 0,
},
];
set_name_to_string_table_entry(&mut symbol_table[2], size_of::<u32>());
let prefix: &[u8] = if imp { b"__imp_" } else { b"" };
set_name_to_string_table_entry(
&mut symbol_table[3],
size_of::<u32>() + sym.len() + prefix.len() + 1,
);
buffer.write_all(bytes_of(&symbol_table))?;
write_string_table(
&mut buffer,
&[
&prefix
.iter()
.chain(sym.as_bytes())
.copied()
.collect::<Vec<_>>(),
&prefix
.iter()
.chain(weak.as_bytes())
.copied()
.collect::<Vec<_>>(),
],
)?;
Ok(NewArchiveMember::new(
buffer.into_boxed_slice(),
&DEFAULT_OBJECT_READER,
self.import_name.to_string(),
))
}
}
pub fn write_import_library<W: Write + Seek>(
w: &mut W,
import_name: &str,
exports: &[COFFShortExport],
machine: MachineTypes,
mingw: bool,
comdat: bool,
) -> Result<()> {
let native_machine = if machine == MachineTypes::ARM64EC {
MachineTypes::ARM64
} else {
machine
};
let of = ObjectFactory::new(import_name, native_machine)?;
let mut members = Vec::new();
members.push(of.create_import_descriptor()?);
members.push(of.create_null_import_descriptor(comdat)?);
members.push(of.create_null_thunk()?);
for e in exports {
if e.private {
continue;
}
let mut import_type = ImportType::Code;
if e.data {
import_type = ImportType::Data;
}
if e.constant {
import_type = ImportType::Const;
}
let symbol_name = if let Some(symbol_name) = e.symbol_name.as_ref() {
symbol_name
} else {
&e.name
};
let mut name: Cow<'_, str> = if let Some(ext_name) = e.ext_name.as_ref() {
Cow::Owned(replace(symbol_name, &e.name, ext_name)?)
} else {
Cow::Borrowed(symbol_name)
};
if let Some(alias_target) = e.alias_target.as_ref() {
if name.as_ref() != alias_target {
members.push(of.create_weak_external(alias_target, &name, false, machine)?);
members.push(of.create_weak_external(alias_target, &name, true, machine)?);
continue;
}
}
let mut name_type = if e.noname {
ImportNameType::Ordinal
} else {
get_name_type(symbol_name, &e.name, machine, mingw)
};
let export_name = if import_type == ImportType::Code && crate::coff::is_arm64ec(machine) {
if let Some(mangled_name) = get_arm64ec_mangled_function_name(&name) {
name_type = ImportNameType::NameExportas;
let export_name = name;
name = Cow::Owned(mangled_name);
Some(export_name)
} else {
name_type = ImportNameType::NameExportas;
get_arm64ec_demangled_function_name(&name).map(Cow::Owned)
}
} else {
None
};
members.push(of.create_short_import(
&name,
e.ordinal,
import_type,
name_type,
export_name.as_deref(),
machine,
)?);
}
write_archive_to_stream(
w,
&members,
if mingw {
ArchiveKind::Gnu
} else {
ArchiveKind::Coff
},
false,
is_arm64ec(machine),
)
}