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