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