1 use std::mem;
2 use std::vec::Vec;
3 
4 use crate::endian::{LittleEndian as LE, U16Bytes, U32Bytes, U16, U32};
5 use crate::pe as coff;
6 use crate::write::string::*;
7 use crate::write::util::*;
8 use crate::write::*;
9 
10 #[derive(Default, Clone, Copy)]
11 struct SectionOffsets {
12     offset: usize,
13     str_id: Option<StringId>,
14     reloc_offset: usize,
15     selection: u8,
16     associative_section: u16,
17 }
18 
19 #[derive(Default, Clone, Copy)]
20 struct SymbolOffsets {
21     index: usize,
22     str_id: Option<StringId>,
23     aux_count: u8,
24 }
25 
26 impl<'a> Object<'a> {
coff_section_info( &self, section: StandardSection, ) -> (&'static [u8], &'static [u8], SectionKind)27     pub(crate) fn coff_section_info(
28         &self,
29         section: StandardSection,
30     ) -> (&'static [u8], &'static [u8], SectionKind) {
31         match section {
32             StandardSection::Text => (&[], &b".text"[..], SectionKind::Text),
33             StandardSection::Data => (&[], &b".data"[..], SectionKind::Data),
34             StandardSection::ReadOnlyData
35             | StandardSection::ReadOnlyDataWithRel
36             | StandardSection::ReadOnlyString => (&[], &b".rdata"[..], SectionKind::ReadOnlyData),
37             StandardSection::UninitializedData => {
38                 (&[], &b".bss"[..], SectionKind::UninitializedData)
39             }
40             // TLS sections are data sections with a special name.
41             StandardSection::Tls => (&[], &b".tls$"[..], SectionKind::Data),
42             StandardSection::UninitializedTls => {
43                 // Unsupported section.
44                 (&[], &[], SectionKind::UninitializedTls)
45             }
46             StandardSection::TlsVariables => {
47                 // Unsupported section.
48                 (&[], &[], SectionKind::TlsVariables)
49             }
50             StandardSection::Common => {
51                 // Unsupported section.
52                 (&[], &[], SectionKind::Common)
53             }
54         }
55     }
56 
coff_subsection_name(&self, section: &[u8], value: &[u8]) -> Vec<u8>57     pub(crate) fn coff_subsection_name(&self, section: &[u8], value: &[u8]) -> Vec<u8> {
58         let mut name = section.to_vec();
59         name.push(b'$');
60         name.extend_from_slice(value);
61         name
62     }
63 
coff_fixup_relocation(&mut self, mut relocation: &mut Relocation) -> i6464     pub(crate) fn coff_fixup_relocation(&mut self, mut relocation: &mut Relocation) -> i64 {
65         if relocation.kind == RelocationKind::GotRelative {
66             // Use a stub symbol for the relocation instead.
67             // This isn't really a GOT, but it's a similar purpose.
68             // TODO: need to handle DLL imports differently?
69             relocation.kind = RelocationKind::Relative;
70             relocation.symbol = self.coff_add_stub_symbol(relocation.symbol);
71         } else if relocation.kind == RelocationKind::PltRelative {
72             // Windows doesn't need a separate relocation type for
73             // references to functions in import libraries.
74             // For convenience, treat this the same as Relative.
75             relocation.kind = RelocationKind::Relative;
76         }
77 
78         let constant = match self.architecture {
79             Architecture::I386 => match relocation.kind {
80                 RelocationKind::Relative => {
81                     // IMAGE_REL_I386_REL32
82                     relocation.addend + 4
83                 }
84                 _ => relocation.addend,
85             },
86             Architecture::X86_64 => match relocation.kind {
87                 RelocationKind::Relative => {
88                     // IMAGE_REL_AMD64_REL32 through to IMAGE_REL_AMD64_REL32_5
89                     if relocation.addend <= -4 && relocation.addend >= -9 {
90                         0
91                     } else {
92                         relocation.addend + 4
93                     }
94                 }
95                 _ => relocation.addend,
96             },
97             _ => unimplemented!(),
98         };
99         relocation.addend -= constant;
100         constant
101     }
102 
coff_add_stub_symbol(&mut self, symbol_id: SymbolId) -> SymbolId103     fn coff_add_stub_symbol(&mut self, symbol_id: SymbolId) -> SymbolId {
104         if let Some(stub_id) = self.stub_symbols.get(&symbol_id) {
105             return *stub_id;
106         }
107         let stub_size = self.architecture.address_size().unwrap().bytes();
108 
109         let mut name = b".rdata$.refptr.".to_vec();
110         name.extend_from_slice(&self.symbols[symbol_id.0].name);
111         let section_id = self.add_section(Vec::new(), name, SectionKind::ReadOnlyData);
112         let section = self.section_mut(section_id);
113         section.set_data(vec![0; stub_size as usize], u64::from(stub_size));
114         section.relocations = vec![Relocation {
115             offset: 0,
116             size: stub_size * 8,
117             kind: RelocationKind::Absolute,
118             encoding: RelocationEncoding::Generic,
119             symbol: symbol_id,
120             addend: 0,
121         }];
122 
123         let mut name = b".refptr.".to_vec();
124         name.extend_from_slice(&self.symbol(symbol_id).name);
125         let stub_id = self.add_raw_symbol(Symbol {
126             name,
127             value: 0,
128             size: u64::from(stub_size),
129             kind: SymbolKind::Data,
130             scope: SymbolScope::Compilation,
131             weak: false,
132             section: SymbolSection::Section(section_id),
133             flags: SymbolFlags::None,
134         });
135         self.stub_symbols.insert(symbol_id, stub_id);
136 
137         stub_id
138     }
139 
coff_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()>140     pub(crate) fn coff_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> {
141         // Calculate offsets of everything, and build strtab.
142         let mut offset = 0;
143         let mut strtab = StringTable::default();
144 
145         // COFF header.
146         offset += mem::size_of::<coff::ImageFileHeader>();
147 
148         // Section headers.
149         offset += self.sections.len() * mem::size_of::<coff::ImageSectionHeader>();
150 
151         // Calculate size of section data and add section strings to strtab.
152         let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()];
153         for (index, section) in self.sections.iter().enumerate() {
154             if section.name.len() > 8 {
155                 section_offsets[index].str_id = Some(strtab.add(&section.name));
156             }
157 
158             let len = section.data.len();
159             if len != 0 {
160                 // TODO: not sure what alignment is required here, but this seems to match LLVM
161                 offset = align(offset, 4);
162                 section_offsets[index].offset = offset;
163                 offset += len;
164             } else {
165                 section_offsets[index].offset = 0;
166             }
167 
168             // Calculate size of relocations.
169             let count = section.relocations.len();
170             if count != 0 {
171                 section_offsets[index].reloc_offset = offset;
172                 offset += count * mem::size_of::<coff::ImageRelocation>();
173             }
174         }
175 
176         // Set COMDAT flags.
177         for comdat in &self.comdats {
178             let symbol = &self.symbols[comdat.symbol.0];
179             let comdat_section = match symbol.section {
180                 SymbolSection::Section(id) => id.0,
181                 _ => {
182                     return Err(Error(format!(
183                         "unsupported COMDAT symbol `{}` section {:?}",
184                         symbol.name().unwrap_or(""),
185                         symbol.section
186                     )));
187                 }
188             };
189             section_offsets[comdat_section].selection = match comdat.kind {
190                 ComdatKind::NoDuplicates => coff::IMAGE_COMDAT_SELECT_NODUPLICATES,
191                 ComdatKind::Any => coff::IMAGE_COMDAT_SELECT_ANY,
192                 ComdatKind::SameSize => coff::IMAGE_COMDAT_SELECT_SAME_SIZE,
193                 ComdatKind::ExactMatch => coff::IMAGE_COMDAT_SELECT_EXACT_MATCH,
194                 ComdatKind::Largest => coff::IMAGE_COMDAT_SELECT_LARGEST,
195                 ComdatKind::Newest => coff::IMAGE_COMDAT_SELECT_NEWEST,
196                 ComdatKind::Unknown => {
197                     return Err(Error(format!(
198                         "unsupported COMDAT symbol `{}` kind {:?}",
199                         symbol.name().unwrap_or(""),
200                         comdat.kind
201                     )));
202                 }
203             };
204             for id in &comdat.sections {
205                 let section = &self.sections[id.0];
206                 if section.symbol.is_none() {
207                     return Err(Error(format!(
208                         "missing symbol for COMDAT section `{}`",
209                         section.name().unwrap_or(""),
210                     )));
211                 }
212                 if id.0 != comdat_section {
213                     section_offsets[id.0].selection = coff::IMAGE_COMDAT_SELECT_ASSOCIATIVE;
214                     section_offsets[id.0].associative_section = comdat_section as u16 + 1;
215                 }
216             }
217         }
218 
219         // Calculate size of symbols and add symbol strings to strtab.
220         let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()];
221         let mut symtab_count = 0;
222         for (index, symbol) in self.symbols.iter().enumerate() {
223             symbol_offsets[index].index = symtab_count;
224             symtab_count += 1;
225             match symbol.kind {
226                 SymbolKind::File => {
227                     // Name goes in auxilary symbol records.
228                     let aux_count = (symbol.name.len() + coff::IMAGE_SIZEOF_SYMBOL - 1)
229                         / coff::IMAGE_SIZEOF_SYMBOL;
230                     symbol_offsets[index].aux_count = aux_count as u8;
231                     symtab_count += aux_count;
232                     // Don't add name to strtab.
233                     continue;
234                 }
235                 SymbolKind::Section => {
236                     symbol_offsets[index].aux_count = 1;
237                     symtab_count += 1;
238                 }
239                 _ => {}
240             }
241             if symbol.name.len() > 8 {
242                 symbol_offsets[index].str_id = Some(strtab.add(&symbol.name));
243             }
244         }
245 
246         // Calculate size of symtab.
247         let symtab_offset = offset;
248         let symtab_len = symtab_count * coff::IMAGE_SIZEOF_SYMBOL;
249         offset += symtab_len;
250 
251         // Calculate size of strtab.
252         let strtab_offset = offset;
253         let mut strtab_data = Vec::new();
254         // First 4 bytes of strtab are the length.
255         strtab.write(4, &mut strtab_data);
256         let strtab_len = strtab_data.len() + 4;
257         offset += strtab_len;
258 
259         // Start writing.
260         buffer
261             .reserve(offset)
262             .map_err(|_| Error(String::from("Cannot allocate buffer")))?;
263 
264         // Write file header.
265         let header = coff::ImageFileHeader {
266             machine: U16::new(
267                 LE,
268                 match self.architecture {
269                     Architecture::Arm => coff::IMAGE_FILE_MACHINE_ARMNT,
270                     Architecture::Aarch64 => coff::IMAGE_FILE_MACHINE_ARM64,
271                     Architecture::I386 => coff::IMAGE_FILE_MACHINE_I386,
272                     Architecture::X86_64 => coff::IMAGE_FILE_MACHINE_AMD64,
273                     _ => {
274                         return Err(Error(format!(
275                             "unimplemented architecture {:?}",
276                             self.architecture
277                         )));
278                     }
279                 },
280             ),
281             number_of_sections: U16::new(LE, self.sections.len() as u16),
282             time_date_stamp: U32::default(),
283             pointer_to_symbol_table: U32::new(LE, symtab_offset as u32),
284             number_of_symbols: U32::new(LE, symtab_count as u32),
285             size_of_optional_header: U16::default(),
286             characteristics: match self.flags {
287                 FileFlags::Coff { characteristics } => U16::new(LE, characteristics),
288                 _ => U16::default(),
289             },
290         };
291         buffer.write(&header);
292 
293         // Write section headers.
294         for (index, section) in self.sections.iter().enumerate() {
295             let mut characteristics = match section.flags {
296                 SectionFlags::Coff {
297                     characteristics, ..
298                 } => characteristics,
299                 _ => 0,
300             };
301             if section_offsets[index].selection != 0 {
302                 characteristics |= coff::IMAGE_SCN_LNK_COMDAT;
303             };
304             characteristics |= match section.kind {
305                 SectionKind::Text => {
306                     coff::IMAGE_SCN_CNT_CODE
307                         | coff::IMAGE_SCN_MEM_EXECUTE
308                         | coff::IMAGE_SCN_MEM_READ
309                 }
310                 SectionKind::Data => {
311                     coff::IMAGE_SCN_CNT_INITIALIZED_DATA
312                         | coff::IMAGE_SCN_MEM_READ
313                         | coff::IMAGE_SCN_MEM_WRITE
314                 }
315                 SectionKind::UninitializedData => {
316                     coff::IMAGE_SCN_CNT_UNINITIALIZED_DATA
317                         | coff::IMAGE_SCN_MEM_READ
318                         | coff::IMAGE_SCN_MEM_WRITE
319                 }
320                 SectionKind::ReadOnlyData | SectionKind::ReadOnlyString => {
321                     coff::IMAGE_SCN_CNT_INITIALIZED_DATA | coff::IMAGE_SCN_MEM_READ
322                 }
323                 SectionKind::Debug | SectionKind::Other | SectionKind::OtherString => {
324                     coff::IMAGE_SCN_CNT_INITIALIZED_DATA
325                         | coff::IMAGE_SCN_MEM_READ
326                         | coff::IMAGE_SCN_MEM_DISCARDABLE
327                 }
328                 SectionKind::Linker => coff::IMAGE_SCN_LNK_INFO | coff::IMAGE_SCN_LNK_REMOVE,
329                 SectionKind::Common
330                 | SectionKind::Tls
331                 | SectionKind::UninitializedTls
332                 | SectionKind::TlsVariables
333                 | SectionKind::Note
334                 | SectionKind::Unknown
335                 | SectionKind::Metadata
336                 | SectionKind::Elf(_) => {
337                     return Err(Error(format!(
338                         "unimplemented section `{}` kind {:?}",
339                         section.name().unwrap_or(""),
340                         section.kind
341                     )));
342                 }
343             } | match section.align {
344                 1 => coff::IMAGE_SCN_ALIGN_1BYTES,
345                 2 => coff::IMAGE_SCN_ALIGN_2BYTES,
346                 4 => coff::IMAGE_SCN_ALIGN_4BYTES,
347                 8 => coff::IMAGE_SCN_ALIGN_8BYTES,
348                 16 => coff::IMAGE_SCN_ALIGN_16BYTES,
349                 32 => coff::IMAGE_SCN_ALIGN_32BYTES,
350                 64 => coff::IMAGE_SCN_ALIGN_64BYTES,
351                 128 => coff::IMAGE_SCN_ALIGN_128BYTES,
352                 256 => coff::IMAGE_SCN_ALIGN_256BYTES,
353                 512 => coff::IMAGE_SCN_ALIGN_512BYTES,
354                 1024 => coff::IMAGE_SCN_ALIGN_1024BYTES,
355                 2048 => coff::IMAGE_SCN_ALIGN_2048BYTES,
356                 4096 => coff::IMAGE_SCN_ALIGN_4096BYTES,
357                 8192 => coff::IMAGE_SCN_ALIGN_8192BYTES,
358                 _ => {
359                     return Err(Error(format!(
360                         "unimplemented section `{}` align {}",
361                         section.name().unwrap_or(""),
362                         section.align
363                     )));
364                 }
365             };
366             let mut coff_section = coff::ImageSectionHeader {
367                 name: [0; 8],
368                 virtual_size: U32::default(),
369                 virtual_address: U32::default(),
370                 size_of_raw_data: U32::new(LE, section.size as u32),
371                 pointer_to_raw_data: U32::new(LE, section_offsets[index].offset as u32),
372                 pointer_to_relocations: U32::new(LE, section_offsets[index].reloc_offset as u32),
373                 pointer_to_linenumbers: U32::default(),
374                 number_of_relocations: U16::new(LE, section.relocations.len() as u16),
375                 number_of_linenumbers: U16::default(),
376                 characteristics: U32::new(LE, characteristics),
377             };
378             if section.name.len() <= 8 {
379                 coff_section.name[..section.name.len()].copy_from_slice(&section.name);
380             } else {
381                 let mut str_offset = strtab.get_offset(section_offsets[index].str_id.unwrap());
382                 if str_offset <= 9_999_999 {
383                     let mut name = [0; 7];
384                     let mut len = 0;
385                     if str_offset == 0 {
386                         name[6] = b'0';
387                         len = 1;
388                     } else {
389                         while str_offset != 0 {
390                             let rem = (str_offset % 10) as u8;
391                             str_offset /= 10;
392                             name[6 - len] = b'0' + rem;
393                             len += 1;
394                         }
395                     }
396                     coff_section.name = [0; 8];
397                     coff_section.name[0] = b'/';
398                     coff_section.name[1..][..len].copy_from_slice(&name[7 - len..]);
399                 } else if str_offset as u64 <= 0xf_ffff_ffff {
400                     coff_section.name[0] = b'/';
401                     coff_section.name[1] = b'/';
402                     for i in 0..6 {
403                         let rem = (str_offset % 64) as u8;
404                         str_offset /= 64;
405                         let c = match rem {
406                             0..=25 => b'A' + rem,
407                             26..=51 => b'a' + rem - 26,
408                             52..=61 => b'0' + rem - 52,
409                             62 => b'+',
410                             63 => b'/',
411                             _ => unreachable!(),
412                         };
413                         coff_section.name[7 - i] = c;
414                     }
415                 } else {
416                     return Err(Error(format!("invalid section name offset {}", str_offset)));
417                 }
418             }
419             buffer.write(&coff_section);
420         }
421 
422         // Write section data and relocations.
423         for (index, section) in self.sections.iter().enumerate() {
424             let len = section.data.len();
425             if len != 0 {
426                 write_align(buffer, 4);
427                 debug_assert_eq!(section_offsets[index].offset, buffer.len());
428                 buffer.write_bytes(&section.data);
429             }
430 
431             if !section.relocations.is_empty() {
432                 debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len());
433                 for reloc in &section.relocations {
434                     //assert!(reloc.implicit_addend);
435                     let typ = match self.architecture {
436                         Architecture::I386 => match (reloc.kind, reloc.size, reloc.addend) {
437                             (RelocationKind::Absolute, 16, 0) => coff::IMAGE_REL_I386_DIR16,
438                             (RelocationKind::Relative, 16, 0) => coff::IMAGE_REL_I386_REL16,
439                             (RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_I386_DIR32,
440                             (RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_I386_DIR32NB,
441                             (RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_I386_SECTION,
442                             (RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_I386_SECREL,
443                             (RelocationKind::SectionOffset, 7, 0) => coff::IMAGE_REL_I386_SECREL7,
444                             (RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_I386_REL32,
445                             (RelocationKind::Coff(x), _, _) => x,
446                             _ => {
447                                 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
448                             }
449                         },
450                         Architecture::X86_64 => match (reloc.kind, reloc.size, reloc.addend) {
451                             (RelocationKind::Absolute, 64, 0) => coff::IMAGE_REL_AMD64_ADDR64,
452                             (RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_AMD64_ADDR32,
453                             (RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_AMD64_ADDR32NB,
454                             (RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_AMD64_REL32,
455                             (RelocationKind::Relative, 32, -5) => coff::IMAGE_REL_AMD64_REL32_1,
456                             (RelocationKind::Relative, 32, -6) => coff::IMAGE_REL_AMD64_REL32_2,
457                             (RelocationKind::Relative, 32, -7) => coff::IMAGE_REL_AMD64_REL32_3,
458                             (RelocationKind::Relative, 32, -8) => coff::IMAGE_REL_AMD64_REL32_4,
459                             (RelocationKind::Relative, 32, -9) => coff::IMAGE_REL_AMD64_REL32_5,
460                             (RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_AMD64_SECTION,
461                             (RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_AMD64_SECREL,
462                             (RelocationKind::SectionOffset, 7, 0) => coff::IMAGE_REL_AMD64_SECREL7,
463                             (RelocationKind::Coff(x), _, _) => x,
464                             _ => {
465                                 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
466                             }
467                         },
468                         _ => {
469                             return Err(Error(format!(
470                                 "unimplemented architecture {:?}",
471                                 self.architecture
472                             )));
473                         }
474                     };
475                     let coff_relocation = coff::ImageRelocation {
476                         virtual_address: U32Bytes::new(LE, reloc.offset as u32),
477                         symbol_table_index: U32Bytes::new(
478                             LE,
479                             symbol_offsets[reloc.symbol.0].index as u32,
480                         ),
481                         typ: U16Bytes::new(LE, typ),
482                     };
483                     buffer.write(&coff_relocation);
484                 }
485             }
486         }
487 
488         // Write symbols.
489         debug_assert_eq!(symtab_offset, buffer.len());
490         for (index, symbol) in self.symbols.iter().enumerate() {
491             let mut name = &symbol.name[..];
492             let section_number = match symbol.section {
493                 SymbolSection::None => {
494                     debug_assert_eq!(symbol.kind, SymbolKind::File);
495                     coff::IMAGE_SYM_DEBUG
496                 }
497                 SymbolSection::Undefined => coff::IMAGE_SYM_UNDEFINED,
498                 SymbolSection::Absolute => coff::IMAGE_SYM_ABSOLUTE,
499                 SymbolSection::Common => coff::IMAGE_SYM_UNDEFINED,
500                 SymbolSection::Section(id) => id.0 as u16 + 1,
501             };
502             let typ = if symbol.kind == SymbolKind::Text {
503                 coff::IMAGE_SYM_DTYPE_FUNCTION << coff::IMAGE_SYM_DTYPE_SHIFT
504             } else {
505                 coff::IMAGE_SYM_TYPE_NULL
506             };
507             let storage_class = match symbol.kind {
508                 SymbolKind::File => {
509                     // Name goes in auxilary symbol records.
510                     name = b".file";
511                     coff::IMAGE_SYM_CLASS_FILE
512                 }
513                 SymbolKind::Section => coff::IMAGE_SYM_CLASS_STATIC,
514                 SymbolKind::Label => coff::IMAGE_SYM_CLASS_LABEL,
515                 SymbolKind::Text | SymbolKind::Data | SymbolKind::Tls => {
516                     match symbol.section {
517                         SymbolSection::None => {
518                             return Err(Error(format!(
519                                 "missing section for symbol `{}`",
520                                 symbol.name().unwrap_or("")
521                             )));
522                         }
523                         SymbolSection::Undefined | SymbolSection::Common => {
524                             coff::IMAGE_SYM_CLASS_EXTERNAL
525                         }
526                         SymbolSection::Absolute | SymbolSection::Section(_) => {
527                             match symbol.scope {
528                                 // TODO: does this need aux symbol records too?
529                                 _ if symbol.weak => coff::IMAGE_SYM_CLASS_WEAK_EXTERNAL,
530                                 SymbolScope::Unknown => {
531                                     return Err(Error(format!(
532                                         "unimplemented symbol `{}` scope {:?}",
533                                         symbol.name().unwrap_or(""),
534                                         symbol.scope
535                                     )));
536                                 }
537                                 SymbolScope::Compilation => coff::IMAGE_SYM_CLASS_STATIC,
538                                 SymbolScope::Linkage | SymbolScope::Dynamic => {
539                                     coff::IMAGE_SYM_CLASS_EXTERNAL
540                                 }
541                             }
542                         }
543                     }
544                 }
545                 SymbolKind::Unknown | SymbolKind::Null => {
546                     return Err(Error(format!(
547                         "unimplemented symbol `{}` kind {:?}",
548                         symbol.name().unwrap_or(""),
549                         symbol.kind
550                     )));
551                 }
552             };
553             let number_of_aux_symbols = symbol_offsets[index].aux_count;
554             let value = if symbol.section == SymbolSection::Common {
555                 symbol.size as u32
556             } else {
557                 symbol.value as u32
558             };
559             let mut coff_symbol = coff::ImageSymbol {
560                 name: [0; 8],
561                 value: U32Bytes::new(LE, value),
562                 section_number: U16Bytes::new(LE, section_number as u16),
563                 typ: U16Bytes::new(LE, typ),
564                 storage_class,
565                 number_of_aux_symbols,
566             };
567             if name.len() <= 8 {
568                 coff_symbol.name[..name.len()].copy_from_slice(name);
569             } else {
570                 let str_offset = strtab.get_offset(symbol_offsets[index].str_id.unwrap());
571                 coff_symbol.name[4..8].copy_from_slice(&u32::to_le_bytes(str_offset as u32));
572             }
573             buffer.write(&coff_symbol);
574 
575             // Write auxiliary symbols.
576             match symbol.kind {
577                 SymbolKind::File => {
578                     let aux_len = number_of_aux_symbols as usize * coff::IMAGE_SIZEOF_SYMBOL;
579                     debug_assert!(aux_len >= symbol.name.len());
580                     let old_len = buffer.len();
581                     buffer.write_bytes(&symbol.name);
582                     buffer.resize(old_len + aux_len);
583                 }
584                 SymbolKind::Section => {
585                     debug_assert_eq!(number_of_aux_symbols, 1);
586                     let section_index = symbol.section.id().unwrap().0;
587                     let section = &self.sections[section_index];
588                     let aux = coff::ImageAuxSymbolSection {
589                         length: U32Bytes::new(LE, section.size as u32),
590                         number_of_relocations: U16Bytes::new(LE, section.relocations.len() as u16),
591                         number_of_linenumbers: U16Bytes::default(),
592                         check_sum: U32Bytes::new(LE, checksum(section.data())),
593                         number: U16Bytes::new(
594                             LE,
595                             section_offsets[section_index].associative_section,
596                         ),
597                         selection: section_offsets[section_index].selection,
598                         reserved: 0,
599                         // TODO: bigobj
600                         high_number: U16Bytes::default(),
601                     };
602                     buffer.write(&aux);
603                 }
604                 _ => {
605                     debug_assert_eq!(number_of_aux_symbols, 0);
606                 }
607             }
608         }
609 
610         // Write strtab section.
611         debug_assert_eq!(strtab_offset, buffer.len());
612         buffer.write_bytes(&u32::to_le_bytes(strtab_len as u32));
613         buffer.write_bytes(&strtab_data);
614 
615         debug_assert_eq!(offset, buffer.len());
616 
617         Ok(())
618     }
619 }
620 
621 // JamCRC
checksum(data: &[u8]) -> u32622 fn checksum(data: &[u8]) -> u32 {
623     let mut hasher = crc32fast::Hasher::new_with_initial(0xffff_ffff);
624     hasher.update(data);
625     !hasher.finalize()
626 }
627