Skip to content

Commit b54f093

Browse files
authored
Merge pull request #23 from ChrisDenton/rename
Make the null import descriptor name unique to the import library
2 parents c61dc95 + 870962c commit b54f093

File tree

3 files changed

+63
-77
lines changed

3 files changed

+63
-77
lines changed

src/archive_writer.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,7 @@ fn write_ec_symbols<W: Write + Seek>(w: &mut W, sym_map: &SymMap) -> io::Result<
542542

543543
fn is_import_descriptor(name: &[u8]) -> bool {
544544
name.starts_with(coff_import_file::IMPORT_DESCRIPTOR_PREFIX)
545-
|| name == coff_import_file::NULL_IMPORT_DESCRIPTOR_SYMBOL_NAME
545+
|| name.starts_with(coff_import_file::NULL_IMPORT_DESCRIPTOR_SYMBOL_NAME)
546546
|| (name.starts_with(coff_import_file::NULL_THUNK_DATA_PREFIX)
547547
&& name.ends_with(coff_import_file::NULL_THUNK_DATA_SUFFIX))
548548
}

src/coff_import_file.rs

+31-47
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,12 @@ use std::path::PathBuf;
1010
use std::str::from_utf8;
1111

1212
use object::pe::{
13-
ImageAuxSymbolSection, ImageFileHeader, ImageImportDescriptor, ImageRelocation,
14-
ImageSectionHeader, ImageSymbol, ImportObjectHeader, IMAGE_COMDAT_SELECT_ANY,
15-
IMAGE_FILE_32BIT_MACHINE, IMAGE_REL_AMD64_ADDR32NB, IMAGE_REL_ARM64_ADDR32NB,
16-
IMAGE_REL_ARM_ADDR32NB, IMAGE_REL_I386_DIR32NB, IMAGE_SCN_ALIGN_2BYTES, IMAGE_SCN_ALIGN_4BYTES,
17-
IMAGE_SCN_ALIGN_8BYTES, IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT,
18-
IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE,
19-
IMAGE_SYM_CLASS_EXTERNAL, IMAGE_SYM_CLASS_NULL, IMAGE_SYM_CLASS_SECTION,
13+
ImageFileHeader, ImageImportDescriptor, ImageRelocation, ImageSectionHeader, ImageSymbol,
14+
ImportObjectHeader, IMAGE_FILE_32BIT_MACHINE, IMAGE_REL_AMD64_ADDR32NB,
15+
IMAGE_REL_ARM64_ADDR32NB, IMAGE_REL_ARM_ADDR32NB, IMAGE_REL_I386_DIR32NB,
16+
IMAGE_SCN_ALIGN_2BYTES, IMAGE_SCN_ALIGN_4BYTES, IMAGE_SCN_ALIGN_8BYTES,
17+
IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE, IMAGE_SCN_MEM_READ,
18+
IMAGE_SCN_MEM_WRITE, IMAGE_SYM_CLASS_EXTERNAL, IMAGE_SYM_CLASS_NULL, IMAGE_SYM_CLASS_SECTION,
2019
IMAGE_SYM_CLASS_STATIC, IMAGE_SYM_CLASS_WEAK_EXTERNAL, IMAGE_WEAK_EXTERN_SEARCH_ALIAS,
2120
};
2221
use object::pod::bytes_of;
@@ -27,6 +26,7 @@ use crate::{write_archive_to_stream, ArchiveKind, NewArchiveMember, DEFAULT_OBJE
2726

2827
pub(crate) const IMPORT_DESCRIPTOR_PREFIX: &[u8] = b"__IMPORT_DESCRIPTOR_";
2928
pub(crate) const NULL_IMPORT_DESCRIPTOR_SYMBOL_NAME: &[u8] = b"__NULL_IMPORT_DESCRIPTOR";
29+
pub(crate) const NULL_IMPORT_DESCRIPTOR_SYMBOL_NAME_PREFIX: &[u8] = b"__NULL_IMPORT_DESCRIPTOR_";
3030
pub(crate) const NULL_THUNK_DATA_PREFIX: &[u8] = b"\x7f";
3131
pub(crate) const NULL_THUNK_DATA_SUFFIX: &[u8] = b"_NULL_THUNK_DATA";
3232

@@ -209,10 +209,11 @@ struct ObjectFactory<'a> {
209209
import_name: &'a str,
210210
import_descriptor_symbol_name: Vec<u8>,
211211
null_thunk_symbol_name: Vec<u8>,
212+
null_import_descriptor_symbol_name: Vec<u8>,
212213
}
213214

214215
impl<'a> ObjectFactory<'a> {
215-
fn new(s: &'a str, m: MachineTypes) -> Result<Self> {
216+
fn new(s: &'a str, m: MachineTypes, whole_archive_compat: bool) -> Result<Self> {
216217
let import_as_path = PathBuf::from(s);
217218
let library = import_as_path
218219
.file_stem()
@@ -239,6 +240,15 @@ impl<'a> ObjectFactory<'a> {
239240
.chain(NULL_THUNK_DATA_SUFFIX)
240241
.copied()
241242
.collect(),
243+
null_import_descriptor_symbol_name: if whole_archive_compat {
244+
NULL_IMPORT_DESCRIPTOR_SYMBOL_NAME_PREFIX
245+
.iter()
246+
.chain(library)
247+
.copied()
248+
.collect()
249+
} else {
250+
NULL_IMPORT_DESCRIPTOR_SYMBOL_NAME.into()
251+
},
242252
})
243253
}
244254

@@ -439,7 +449,7 @@ impl<'a> ObjectFactory<'a> {
439449
size_of::<u32>()
440450
+ self.import_descriptor_symbol_name.len()
441451
+ 1
442-
+ NULL_IMPORT_DESCRIPTOR_SYMBOL_NAME.len()
452+
+ self.null_import_descriptor_symbol_name.len()
443453
+ 1,
444454
);
445455
buffer.write_all(bytes_of(&symbol_table))?;
@@ -449,7 +459,7 @@ impl<'a> ObjectFactory<'a> {
449459
&mut buffer,
450460
&[
451461
&self.import_descriptor_symbol_name,
452-
NULL_IMPORT_DESCRIPTOR_SYMBOL_NAME,
462+
&self.null_import_descriptor_symbol_name,
453463
&self.null_thunk_symbol_name,
454464
],
455465
)?;
@@ -464,14 +474,11 @@ impl<'a> ObjectFactory<'a> {
464474
/// Creates a NULL import descriptor. This is a small object file whcih
465475
/// contains a NULL import descriptor. It is used to terminate the imports
466476
/// from a specific DLL.
467-
///
468-
/// If `comdat` is set to true, the NULL import descriptor's section (`.idata$3`) will be
469-
/// turned into a COMDAT section.
470-
fn create_null_import_descriptor(&self, comdat: bool) -> Result<NewArchiveMember<'_>> {
477+
fn create_null_import_descriptor(&self) -> Result<NewArchiveMember<'_>> {
471478
let mut buffer = Vec::new();
472479

473480
const NUMBER_OF_SECTIONS: usize = 1;
474-
let number_of_symbols = if comdat { 3 } else { 1 };
481+
const NUMBER_OF_SYMBOLS: usize = 1;
475482

476483
// COFF Header
477484
let header = ImageFileHeader {
@@ -481,7 +488,7 @@ impl<'a> ObjectFactory<'a> {
481488
pointer_to_symbol_table: u32!((size_of::<ImageFileHeader>() + (NUMBER_OF_SECTIONS * size_of::<ImageSectionHeader>()) +
482489
// .idata$3
483490
size_of::<ImageImportDescriptor>()).try_into().unwrap()),
484-
number_of_symbols: u32!(number_of_symbols.try_into().unwrap()),
491+
number_of_symbols: u32!(NUMBER_OF_SYMBOLS.try_into().unwrap()),
485492
size_of_optional_header: u16!(0),
486493
characteristics: u16!(if self.is_64_bit() {
487494
0
@@ -510,7 +517,6 @@ impl<'a> ObjectFactory<'a> {
510517
| IMAGE_SCN_CNT_INITIALIZED_DATA
511518
| IMAGE_SCN_MEM_READ
512519
| IMAGE_SCN_MEM_WRITE
513-
| if comdat { IMAGE_SCN_LNK_COMDAT } else { 0 }
514520
),
515521
}];
516522
buffer.write_all(bytes_of(&section_table))?;
@@ -526,41 +532,19 @@ impl<'a> ObjectFactory<'a> {
526532
buffer.write_all(bytes_of(&import_descriptor))?;
527533

528534
// Symbol Table
529-
if comdat {
530-
let symbol = ImageSymbol {
531-
name: *b".idata$3",
532-
value: u32!(0),
533-
section_number: u16!(1),
534-
typ: u16!(0),
535-
storage_class: IMAGE_SYM_CLASS_STATIC,
536-
number_of_aux_symbols: 1,
537-
};
538-
let aux = ImageAuxSymbolSection {
539-
length: u32!(size_of::<ImageImportDescriptor>().try_into().unwrap()),
540-
number_of_relocations: u16!(0),
541-
number_of_linenumbers: u16!(0),
542-
check_sum: u32!(0),
543-
selection: IMAGE_COMDAT_SELECT_ANY,
544-
number: u16!(0),
545-
reserved: 0,
546-
high_number: u16!(0),
547-
};
548-
buffer.write_all(bytes_of(&symbol))?;
549-
buffer.write_all(bytes_of(&aux))?;
550-
}
551-
let mut null_descriptor_symbol = ImageSymbol {
535+
let mut symbol_table: [_; NUMBER_OF_SYMBOLS] = [ImageSymbol {
552536
name: [0; 8],
553537
value: u32!(0),
554538
section_number: u16!(1),
555539
typ: u16!(0),
556540
storage_class: IMAGE_SYM_CLASS_EXTERNAL,
557541
number_of_aux_symbols: 0,
558-
};
559-
set_name_to_string_table_entry(&mut null_descriptor_symbol, size_of::<u32>());
560-
buffer.write_all(bytes_of(&null_descriptor_symbol))?;
542+
}];
543+
set_name_to_string_table_entry(&mut symbol_table[0], size_of::<u32>());
544+
buffer.write_all(bytes_of(&symbol_table))?;
561545

562546
// String Table
563-
write_string_table(&mut buffer, &[NULL_IMPORT_DESCRIPTOR_SYMBOL_NAME])?;
547+
write_string_table(&mut buffer, &[&self.null_import_descriptor_symbol_name])?;
564548

565549
Ok(NewArchiveMember::new(
566550
buffer.into_boxed_slice(),
@@ -853,20 +837,20 @@ pub fn write_import_library<W: Write + Seek>(
853837
exports: &[COFFShortExport],
854838
machine: MachineTypes,
855839
mingw: bool,
856-
comdat: bool,
840+
whole_archive_compat: bool,
857841
) -> Result<()> {
858842
let native_machine = if machine == MachineTypes::ARM64EC {
859843
MachineTypes::ARM64
860844
} else {
861845
machine
862846
};
863847

864-
let of = ObjectFactory::new(import_name, native_machine)?;
848+
let of = ObjectFactory::new(import_name, native_machine, whole_archive_compat)?;
865849
let mut members = Vec::new();
866850

867851
members.push(of.create_import_descriptor()?);
868852

869-
members.push(of.create_null_import_descriptor(comdat)?);
853+
members.push(of.create_null_import_descriptor()?);
870854

871855
members.push(of.create_null_thunk()?);
872856

tests/import_library.rs

+31-29
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ use std::process::Command;
55

66
use ar_archive_writer::{ArchiveKind, COFFShortExport, MachineTypes};
77
use common::{create_archive_with_ar_archive_writer, create_archive_with_llvm_ar};
8-
use object::coff::CoffHeader;
8+
use object::coff::CoffFile;
99
use object::pe::ImageFileHeader;
1010
use object::read::archive::ArchiveFile;
11-
use object::{bytes_of, Architecture, Object, SubArchitecture, U32Bytes};
11+
use object::{bytes_of, Architecture, Object, ObjectSection, ObjectSymbol, SubArchitecture};
1212
use pretty_assertions::assert_eq;
1313

1414
mod common;
@@ -305,43 +305,45 @@ fn compare_comdat(archive_writer_bytes: &[u8], llvm_bytes: &[u8]) {
305305
let archive_member = archive_member.unwrap();
306306
let llvm_member = llvm_member.unwrap();
307307

308+
// skip the EC symbols table.
309+
if archive_member.name() == b"/<ECSYMBOLS>/" {
310+
continue;
311+
}
312+
308313
if archive_member.size() != llvm_member.size() {
309314
// Ensure that the member header is the same except for the file size.
310315
let mut llvm_file_header = *llvm_member.header().unwrap();
311-
llvm_file_header.size = *b"163 ";
316+
llvm_file_header.size = archive_member.header().unwrap().size;
312317
assert_eq!(
313318
bytes_of(archive_member.header().unwrap()),
314319
bytes_of(&llvm_file_header)
315320
);
316321

317-
// Ensure that the LLVM generated object contains .idata$3
318-
object::File::parse(llvm_member.data(llvm_bytes).unwrap())
319-
.unwrap()
320-
.section_by_name_bytes(b".idata$3")
321-
.unwrap();
322-
323-
// Ensure the COFF file headers are the same except for the symbol count.
324-
let llvm_data = llvm_member.data(llvm_bytes).unwrap();
322+
// Make sure they are both COFF files with the same sections and symbols,
323+
// except for the different naming for the null import descriptor.
325324
let archive_data = archive_member.data(archive_writer_bytes).unwrap();
326-
let mut offset = 0;
327-
let mut header = *ImageFileHeader::parse(llvm_data, &mut offset).unwrap();
328-
header.number_of_symbols = U32Bytes::from_bytes(3_u32.to_le_bytes());
329-
assert_eq!(
330-
&archive_data[..size_of::<ImageFileHeader>()],
331-
bytes_of(&header)
332-
);
325+
let llvm_data = llvm_member.data(llvm_bytes).unwrap();
326+
let archive_file = CoffFile::<_, ImageFileHeader>::parse(archive_data).unwrap();
327+
let llvm_file = CoffFile::<_, ImageFileHeader>::parse(llvm_data).unwrap();
333328

334-
// The rest of the object file will always be the same as `expected`
335-
// for all import files no matter the platform.
336-
let expected = [
337-
46, 105, 100, 97, 116, 97, 36, 51, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 60, 0, 0,
338-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 16, 48, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0,
339-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 105, 100, 97, 116, 97, 36, 51, 0, 0, 0, 0, 1,
340-
0, 0, 0, 3, 1, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
341-
4, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 29, 0, 0, 0, 95, 95, 78, 85, 76, 76, 95,
342-
73, 77, 80, 79, 82, 84, 95, 68, 69, 83, 67, 82, 73, 80, 84, 79, 82, 0,
343-
];
344-
assert_eq!(&archive_data[size_of::<ImageFileHeader>()..], &expected);
329+
for (archive_section, llvm_section) in archive_file.sections().zip(llvm_file.sections())
330+
{
331+
assert_eq!(archive_section.data(), llvm_section.data());
332+
}
333+
for (archive_symbol, llvm_symbol) in archive_file.symbols().zip(llvm_file.symbols()) {
334+
if llvm_symbol.name().unwrap() == "__NULL_IMPORT_DESCRIPTOR" {
335+
assert!(archive_symbol
336+
.name()
337+
.unwrap()
338+
.starts_with("__NULL_IMPORT_DESCRIPTOR_"));
339+
} else {
340+
assert_eq!(archive_symbol.name(), llvm_symbol.name());
341+
}
342+
let archive_coff_symbol = archive_symbol.coff_symbol();
343+
let mut llvm_coff_symbol = *llvm_symbol.coff_symbol();
344+
llvm_coff_symbol.name = archive_coff_symbol.name;
345+
assert_eq!(bytes_of(archive_coff_symbol), bytes_of(&llvm_coff_symbol));
346+
}
345347
} else {
346348
assert_eq!(
347349
bytes_of(archive_member.header().unwrap()),

0 commit comments

Comments
 (0)