diff options
Diffstat (limited to 'vendor/windows-metadata/src/writer/imp/file.rs')
-rw-r--r-- | vendor/windows-metadata/src/writer/imp/file.rs | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/vendor/windows-metadata/src/writer/imp/file.rs b/vendor/windows-metadata/src/writer/imp/file.rs new file mode 100644 index 000000000..2f25f942b --- /dev/null +++ b/vendor/windows-metadata/src/writer/imp/file.rs @@ -0,0 +1,138 @@ +use super::*; +use std::mem::*; + +pub fn write(tables: Tables, strings: StagedStrings, blobs: StagedBlobs) -> Vec<u8> { + unsafe { + let mut tables = tables.stream(); + let mut strings = strings.stream(); + let mut blobs = blobs.stream(); + let mut guids = vec![0; 16]; // zero guid + let size_of_streams = tables.len() + guids.len() + strings.len() + blobs.len(); + + let mut dos: IMAGE_DOS_HEADER = zeroed(); + dos.e_magic = IMAGE_DOS_SIGNATURE as _; + dos.e_lfarlc = 64; + dos.e_lfanew = size_of::<IMAGE_DOS_HEADER>() as _; + + let mut file: IMAGE_FILE_HEADER = zeroed(); + file.Machine = IMAGE_FILE_MACHINE_I386; + file.NumberOfSections = 1; + file.SizeOfOptionalHeader = size_of::<IMAGE_OPTIONAL_HEADER32>() as _; + file.Characteristics = IMAGE_FILE_DLL | IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_EXECUTABLE_IMAGE; + + let mut optional: IMAGE_OPTIONAL_HEADER32 = zeroed(); + optional.Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC; + optional.MajorLinkerVersion = 11; + optional.SizeOfInitializedData = 1024; + optional.ImageBase = 0x400000; + optional.SectionAlignment = SECTION_ALIGNMENT; + optional.FileAlignment = 512; + optional.MajorOperatingSystemVersion = 6; + optional.MinorOperatingSystemVersion = 2; + optional.MajorSubsystemVersion = 6; + optional.MinorSubsystemVersion = 2; + optional.SizeOfHeaders = 512; + optional.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI; + optional.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_NO_SEH | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE; + optional.SizeOfStackReserve = 0x100000; + optional.SizeOfHeapReserve = 4096; + optional.LoaderFlags = 0x100000; + optional.NumberOfRvaAndSizes = 16; + + let mut section: IMAGE_SECTION_HEADER = zeroed(); + section.Name = *b".text\0\0\0"; + section.Characteristics = 0x4000_0020; + section.VirtualAddress = SECTION_ALIGNMENT; + + let mut clr: IMAGE_COR20_HEADER = zeroed(); + clr.cb = size_of::<IMAGE_COR20_HEADER>() as _; + clr.MajorRuntimeVersion = 2; + clr.MinorRuntimeVersion = 5; + clr.Flags = 1; + + let metadata = METADATA_HEADER { + signature: METADATA_SIGNATURE, + major_version: 1, + minor_version: 1, + length: 20, + version: *b"WindowsRuntime\0\0\0\0\0\0", + streams: 4, + ..Default::default() + }; + + type TablesHeader = StreamHeader<4>; + type StringsHeader = StreamHeader<12>; + type GuidsHeader = StreamHeader<8>; + type BlobsHeader = StreamHeader<8>; + + let size_of_stream_headers = size_of::<TablesHeader>() + size_of::<StringsHeader>() + size_of::<GuidsHeader>() + size_of::<BlobsHeader>(); + let size_of_image = optional.FileAlignment as usize + size_of::<IMAGE_COR20_HEADER>() + size_of::<METADATA_HEADER>() + size_of_stream_headers + size_of_streams; + + optional.SizeOfImage = round(size_of_image, optional.SectionAlignment as _) as _; + section.Misc.VirtualSize = size_of_image as u32 - optional.FileAlignment; + section.SizeOfRawData = round(section.Misc.VirtualSize as _, optional.FileAlignment as _) as _; + + optional.DataDirectory[14] = IMAGE_DATA_DIRECTORY { VirtualAddress: SECTION_ALIGNMENT, Size: size_of::<IMAGE_COR20_HEADER>() as _ }; + section.PointerToRawData = optional.FileAlignment; + clr.MetaData.VirtualAddress = SECTION_ALIGNMENT + size_of::<IMAGE_COR20_HEADER>() as u32; + clr.MetaData.Size = section.Misc.VirtualSize - size_of::<IMAGE_COR20_HEADER>() as u32; + + let mut buffer = Vec::<u8>::new(); + + buffer.write_header(&dos); + buffer.write_u32(IMAGE_NT_SIGNATURE); + buffer.write_header(&file); + buffer.write_header(&optional); + buffer.write_header(§ion); + debug_assert!(buffer.len() < optional.FileAlignment as _); + buffer.resize(optional.FileAlignment as _, 0); + buffer.write_header(&clr); + let metadata_offset = buffer.len(); + buffer.write_header(&metadata); + + let stream_offset = buffer.len() - metadata_offset + size_of_stream_headers; + let tables_header = TablesHeader::new(stream_offset as _, tables.len() as _, b"#~\0\0"); + let strings_header = StringsHeader::new(tables_header.next_offset(), strings.len() as _, b"#Strings\0\0\0\0"); + let guids_header = GuidsHeader::new(strings_header.next_offset(), guids.len() as _, b"#GUID\0\0\0"); + let blobs_header = BlobsHeader::new(guids_header.next_offset(), blobs.len() as _, b"#Blob\0\0\0"); + + buffer.write_header(&tables_header); + buffer.write_header(&strings_header); + buffer.write_header(&guids_header); + buffer.write_header(&blobs_header); + + buffer.append(&mut tables); + buffer.append(&mut strings); + buffer.append(&mut guids); + buffer.append(&mut blobs); + + assert_eq!(clr.MetaData.Size as usize, buffer.len() - metadata_offset); + assert_eq!(size_of_image, buffer.len()); + + buffer + } +} + +const SECTION_ALIGNMENT: u32 = 4096; + +#[repr(C)] +struct StreamHeader<const LEN: usize> { + offset: u32, + size: u32, + name: [u8; LEN], +} + +impl<const LEN: usize> StreamHeader<LEN> { + fn new(offset: u32, size: u32, name: &[u8; LEN]) -> Self { + Self { offset, size, name: *name } + } + fn next_offset(&self) -> u32 { + self.offset + self.size + } +} + +fn guid_stream() -> Vec<u8> { + let mut buffer = Vec::new(); + buffer.resize(16, 0); // zero guid + buffer +} |