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::BytesMut;
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 }
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 Object {
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(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(&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(&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) -> Result<Vec<u8>>140     pub(crate) fn coff_write(&self) -> Result<Vec<u8>> {
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         // Calculate size of symbols and add symbol strings to strtab.
177         let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()];
178         let mut symtab_count = 0;
179         for (index, symbol) in self.symbols.iter().enumerate() {
180             symbol_offsets[index].index = symtab_count;
181             symtab_count += 1;
182             match symbol.kind {
183                 SymbolKind::File => {
184                     // Name goes in auxilary symbol records.
185                     let aux_count = (symbol.name.len() + coff::IMAGE_SIZEOF_SYMBOL - 1)
186                         / coff::IMAGE_SIZEOF_SYMBOL;
187                     symbol_offsets[index].aux_count = aux_count as u8;
188                     symtab_count += aux_count;
189                     // Don't add name to strtab.
190                     continue;
191                 }
192                 SymbolKind::Section => {
193                     symbol_offsets[index].aux_count = 1;
194                     symtab_count += 1;
195                 }
196                 _ => {}
197             }
198             if symbol.name.len() > 8 {
199                 symbol_offsets[index].str_id = Some(strtab.add(&symbol.name));
200             }
201         }
202 
203         // Calculate size of symtab.
204         let symtab_offset = offset;
205         let symtab_len = symtab_count * coff::IMAGE_SIZEOF_SYMBOL;
206         offset += symtab_len;
207 
208         // Calculate size of strtab.
209         let strtab_offset = offset;
210         let mut strtab_data = Vec::new();
211         // First 4 bytes of strtab are the length.
212         strtab.write(4, &mut strtab_data);
213         let strtab_len = strtab_data.len() + 4;
214         offset += strtab_len;
215 
216         // Start writing.
217         let mut buffer = BytesMut(Vec::with_capacity(offset));
218 
219         // Write file header.
220         let header = coff::ImageFileHeader {
221             machine: U16::new(
222                 LE,
223                 match self.architecture {
224                     Architecture::I386 => coff::IMAGE_FILE_MACHINE_I386,
225                     Architecture::X86_64 => coff::IMAGE_FILE_MACHINE_AMD64,
226                     _ => {
227                         return Err(Error(format!(
228                             "unimplemented architecture {:?}",
229                             self.architecture
230                         )));
231                     }
232                 },
233             ),
234             number_of_sections: U16::new(LE, self.sections.len() as u16),
235             time_date_stamp: U32::default(),
236             pointer_to_symbol_table: U32::new(LE, symtab_offset as u32),
237             number_of_symbols: U32::new(LE, symtab_count as u32),
238             size_of_optional_header: U16::default(),
239             characteristics: match self.flags {
240                 FileFlags::Coff { characteristics } => U16::new(LE, characteristics),
241                 _ => U16::default(),
242             },
243         };
244         buffer.write(&header);
245 
246         // Write section headers.
247         for (index, section) in self.sections.iter().enumerate() {
248             // TODO: IMAGE_SCN_LNK_COMDAT
249             let characteristics = match section.flags {
250                 SectionFlags::Coff {
251                     characteristics, ..
252                 } => characteristics,
253                 _ => 0,
254             } | match section.kind {
255                 SectionKind::Text => {
256                     coff::IMAGE_SCN_CNT_CODE
257                         | coff::IMAGE_SCN_MEM_EXECUTE
258                         | coff::IMAGE_SCN_MEM_READ
259                 }
260                 SectionKind::Data => {
261                     coff::IMAGE_SCN_CNT_INITIALIZED_DATA
262                         | coff::IMAGE_SCN_MEM_READ
263                         | coff::IMAGE_SCN_MEM_WRITE
264                 }
265                 SectionKind::UninitializedData => {
266                     coff::IMAGE_SCN_CNT_UNINITIALIZED_DATA
267                         | coff::IMAGE_SCN_MEM_READ
268                         | coff::IMAGE_SCN_MEM_WRITE
269                 }
270                 SectionKind::ReadOnlyData | SectionKind::ReadOnlyString => {
271                     coff::IMAGE_SCN_CNT_INITIALIZED_DATA | coff::IMAGE_SCN_MEM_READ
272                 }
273                 SectionKind::Debug | SectionKind::Other | SectionKind::OtherString => {
274                     coff::IMAGE_SCN_CNT_INITIALIZED_DATA
275                         | coff::IMAGE_SCN_MEM_READ
276                         | coff::IMAGE_SCN_MEM_DISCARDABLE
277                 }
278                 SectionKind::Linker => coff::IMAGE_SCN_LNK_INFO | coff::IMAGE_SCN_LNK_REMOVE,
279                 SectionKind::Common
280                 | SectionKind::Tls
281                 | SectionKind::UninitializedTls
282                 | SectionKind::TlsVariables
283                 | SectionKind::Note
284                 | SectionKind::Unknown
285                 | SectionKind::Metadata => {
286                     return Err(Error(format!(
287                         "unimplemented section `{}` kind {:?}",
288                         section.name().unwrap_or(""),
289                         section.kind
290                     )));
291                 }
292             } | match section.align {
293                 1 => coff::IMAGE_SCN_ALIGN_1BYTES,
294                 2 => coff::IMAGE_SCN_ALIGN_2BYTES,
295                 4 => coff::IMAGE_SCN_ALIGN_4BYTES,
296                 8 => coff::IMAGE_SCN_ALIGN_8BYTES,
297                 16 => coff::IMAGE_SCN_ALIGN_16BYTES,
298                 32 => coff::IMAGE_SCN_ALIGN_32BYTES,
299                 64 => coff::IMAGE_SCN_ALIGN_64BYTES,
300                 128 => coff::IMAGE_SCN_ALIGN_128BYTES,
301                 256 => coff::IMAGE_SCN_ALIGN_256BYTES,
302                 512 => coff::IMAGE_SCN_ALIGN_512BYTES,
303                 1024 => coff::IMAGE_SCN_ALIGN_1024BYTES,
304                 2048 => coff::IMAGE_SCN_ALIGN_2048BYTES,
305                 4096 => coff::IMAGE_SCN_ALIGN_4096BYTES,
306                 8192 => coff::IMAGE_SCN_ALIGN_8192BYTES,
307                 _ => {
308                     return Err(Error(format!(
309                         "unimplemented section `{}` align {}",
310                         section.name().unwrap_or(""),
311                         section.align
312                     )));
313                 }
314             };
315             let mut coff_section = coff::ImageSectionHeader {
316                 name: [0; 8],
317                 virtual_size: U32::default(),
318                 virtual_address: U32::default(),
319                 size_of_raw_data: U32::new(LE, section.size as u32),
320                 pointer_to_raw_data: U32::new(LE, section_offsets[index].offset as u32),
321                 pointer_to_relocations: U32::new(LE, section_offsets[index].reloc_offset as u32),
322                 pointer_to_linenumbers: U32::default(),
323                 number_of_relocations: U16::new(LE, section.relocations.len() as u16),
324                 number_of_linenumbers: U16::default(),
325                 characteristics: U32::new(LE, characteristics),
326             };
327             if section.name.len() <= 8 {
328                 coff_section.name[..section.name.len()].copy_from_slice(&section.name);
329             } else {
330                 let mut str_offset = strtab.get_offset(section_offsets[index].str_id.unwrap());
331                 if str_offset <= 9_999_999 {
332                     let mut name = [0; 7];
333                     let mut len = 0;
334                     if str_offset == 0 {
335                         name[6] = b'0';
336                         len = 1;
337                     } else {
338                         while str_offset != 0 {
339                             let rem = (str_offset % 10) as u8;
340                             str_offset /= 10;
341                             name[6 - len] = b'0' + rem;
342                             len += 1;
343                         }
344                     }
345                     coff_section.name = [0; 8];
346                     coff_section.name[0] = b'/';
347                     coff_section.name[1..][..len].copy_from_slice(&name[7 - len..]);
348                 } else if str_offset as u64 <= 0xfff_fff_fff {
349                     coff_section.name[0] = b'/';
350                     coff_section.name[1] = b'/';
351                     for i in 0..6 {
352                         let rem = (str_offset % 64) as u8;
353                         str_offset /= 64;
354                         let c = match rem {
355                             0..=25 => b'A' + rem,
356                             26..=51 => b'a' + rem - 26,
357                             52..=61 => b'0' + rem - 52,
358                             62 => b'+',
359                             63 => b'/',
360                             _ => unreachable!(),
361                         };
362                         coff_section.name[7 - i] = c;
363                     }
364                 } else {
365                     return Err(Error(format!("invalid section name offset {}", str_offset)));
366                 }
367             }
368             buffer.write(&coff_section);
369         }
370 
371         // Write section data and relocations.
372         for (index, section) in self.sections.iter().enumerate() {
373             let len = section.data.len();
374             if len != 0 {
375                 write_align(&mut buffer, 4);
376                 debug_assert_eq!(section_offsets[index].offset, buffer.len());
377                 buffer.write_bytes(&section.data);
378             }
379 
380             if !section.relocations.is_empty() {
381                 debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len());
382                 for reloc in &section.relocations {
383                     //assert!(reloc.implicit_addend);
384                     let typ = match self.architecture {
385                         Architecture::I386 => match (reloc.kind, reloc.size, reloc.addend) {
386                             (RelocationKind::Absolute, 16, 0) => coff::IMAGE_REL_I386_DIR16,
387                             (RelocationKind::Relative, 16, 0) => coff::IMAGE_REL_I386_REL16,
388                             (RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_I386_DIR32,
389                             (RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_I386_DIR32NB,
390                             (RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_I386_SECTION,
391                             (RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_I386_SECREL,
392                             (RelocationKind::SectionOffset, 7, 0) => coff::IMAGE_REL_I386_SECREL7,
393                             (RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_I386_REL32,
394                             (RelocationKind::Coff(x), _, _) => x,
395                             _ => {
396                                 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
397                             }
398                         },
399                         Architecture::X86_64 => match (reloc.kind, reloc.size, reloc.addend) {
400                             (RelocationKind::Absolute, 64, 0) => coff::IMAGE_REL_AMD64_ADDR64,
401                             (RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_AMD64_ADDR32,
402                             (RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_AMD64_ADDR32NB,
403                             (RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_AMD64_REL32,
404                             (RelocationKind::Relative, 32, -5) => coff::IMAGE_REL_AMD64_REL32_1,
405                             (RelocationKind::Relative, 32, -6) => coff::IMAGE_REL_AMD64_REL32_2,
406                             (RelocationKind::Relative, 32, -7) => coff::IMAGE_REL_AMD64_REL32_3,
407                             (RelocationKind::Relative, 32, -8) => coff::IMAGE_REL_AMD64_REL32_4,
408                             (RelocationKind::Relative, 32, -9) => coff::IMAGE_REL_AMD64_REL32_5,
409                             (RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_AMD64_SECTION,
410                             (RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_AMD64_SECREL,
411                             (RelocationKind::SectionOffset, 7, 0) => coff::IMAGE_REL_AMD64_SECREL7,
412                             (RelocationKind::Coff(x), _, _) => x,
413                             _ => {
414                                 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
415                             }
416                         },
417                         _ => {
418                             return Err(Error(format!(
419                                 "unimplemented architecture {:?}",
420                                 self.architecture
421                             )));
422                         }
423                     };
424                     let coff_relocation = coff::ImageRelocation {
425                         virtual_address: U32Bytes::new(LE, reloc.offset as u32),
426                         symbol_table_index: U32Bytes::new(
427                             LE,
428                             symbol_offsets[reloc.symbol.0].index as u32,
429                         ),
430                         typ: U16Bytes::new(LE, typ),
431                     };
432                     buffer.write(&coff_relocation);
433                 }
434             }
435         }
436 
437         // Write symbols.
438         debug_assert_eq!(symtab_offset, buffer.len());
439         for (index, symbol) in self.symbols.iter().enumerate() {
440             let mut name = &symbol.name[..];
441             let section_number = match symbol.section {
442                 SymbolSection::None => {
443                     debug_assert_eq!(symbol.kind, SymbolKind::File);
444                     coff::IMAGE_SYM_DEBUG
445                 }
446                 SymbolSection::Undefined => coff::IMAGE_SYM_UNDEFINED,
447                 SymbolSection::Absolute => coff::IMAGE_SYM_ABSOLUTE,
448                 SymbolSection::Common => coff::IMAGE_SYM_UNDEFINED,
449                 SymbolSection::Section(id) => id.0 as u16 + 1,
450             };
451             let typ = if symbol.kind == SymbolKind::Text {
452                 coff::IMAGE_SYM_DTYPE_FUNCTION << coff::IMAGE_SYM_DTYPE_SHIFT
453             } else {
454                 coff::IMAGE_SYM_TYPE_NULL
455             };
456             let storage_class = match symbol.kind {
457                 SymbolKind::File => {
458                     // Name goes in auxilary symbol records.
459                     name = b".file";
460                     coff::IMAGE_SYM_CLASS_FILE
461                 }
462                 SymbolKind::Section => coff::IMAGE_SYM_CLASS_STATIC,
463                 SymbolKind::Label => coff::IMAGE_SYM_CLASS_LABEL,
464                 SymbolKind::Text | SymbolKind::Data | SymbolKind::Tls => {
465                     match symbol.section {
466                         SymbolSection::None => {
467                             return Err(Error(format!(
468                                 "missing section for symbol `{}`",
469                                 symbol.name().unwrap_or("")
470                             )));
471                         }
472                         SymbolSection::Undefined | SymbolSection::Common => {
473                             coff::IMAGE_SYM_CLASS_EXTERNAL
474                         }
475                         SymbolSection::Absolute | SymbolSection::Section(_) => {
476                             match symbol.scope {
477                                 // TODO: does this need aux symbol records too?
478                                 _ if symbol.weak => coff::IMAGE_SYM_CLASS_WEAK_EXTERNAL,
479                                 SymbolScope::Unknown => {
480                                     return Err(Error(format!(
481                                         "unimplemented symbol `{}` scope {:?}",
482                                         symbol.name().unwrap_or(""),
483                                         symbol.scope
484                                     )));
485                                 }
486                                 SymbolScope::Compilation => coff::IMAGE_SYM_CLASS_STATIC,
487                                 SymbolScope::Linkage | SymbolScope::Dynamic => {
488                                     coff::IMAGE_SYM_CLASS_EXTERNAL
489                                 }
490                             }
491                         }
492                     }
493                 }
494                 SymbolKind::Unknown | SymbolKind::Null => {
495                     return Err(Error(format!(
496                         "unimplemented symbol `{}` kind {:?}",
497                         symbol.name().unwrap_or(""),
498                         symbol.kind
499                     )));
500                 }
501             };
502             let number_of_aux_symbols = symbol_offsets[index].aux_count;
503             let value = if symbol.section == SymbolSection::Common {
504                 symbol.size as u32
505             } else {
506                 symbol.value as u32
507             };
508             let mut coff_symbol = coff::ImageSymbol {
509                 name: [0; 8],
510                 value: U32Bytes::new(LE, value),
511                 section_number: U16Bytes::new(LE, section_number as u16),
512                 typ: U16Bytes::new(LE, typ),
513                 storage_class,
514                 number_of_aux_symbols,
515             };
516             if name.len() <= 8 {
517                 coff_symbol.name[..name.len()].copy_from_slice(name);
518             } else {
519                 let str_offset = strtab.get_offset(symbol_offsets[index].str_id.unwrap());
520                 coff_symbol.name[4..8].copy_from_slice(&u32::to_le_bytes(str_offset as u32));
521             }
522             buffer.write(&coff_symbol);
523 
524             // Write auxiliary symbols.
525             match symbol.kind {
526                 SymbolKind::File => {
527                     let aux_len = number_of_aux_symbols as usize * coff::IMAGE_SIZEOF_SYMBOL;
528                     debug_assert!(aux_len >= symbol.name.len());
529                     let old_len = buffer.len();
530                     buffer.extend(&symbol.name);
531                     buffer.resize(old_len + aux_len, 0);
532                 }
533                 SymbolKind::Section => {
534                     debug_assert_eq!(number_of_aux_symbols, 1);
535                     let section = &self.sections[symbol.section.id().unwrap().0];
536                     let (selection, number) = match symbol.flags {
537                         SymbolFlags::CoffSection {
538                             selection,
539                             associative_section,
540                         } => (selection, associative_section.0 as u16),
541                         _ => (0, 0),
542                     };
543                     let aux = coff::ImageAuxSymbolSection {
544                         length: U32Bytes::new(LE, section.size as u32),
545                         number_of_relocations: U16Bytes::new(LE, section.relocations.len() as u16),
546                         number_of_linenumbers: U16Bytes::default(),
547                         check_sum: U32Bytes::new(LE, checksum(&section.data.0)),
548                         number: U16Bytes::new(LE, number),
549                         selection,
550                         reserved: 0,
551                         // TODO: bigobj
552                         high_number: U16Bytes::default(),
553                     };
554                     buffer.write(&aux);
555                 }
556                 _ => {
557                     debug_assert_eq!(number_of_aux_symbols, 0);
558                 }
559             }
560         }
561 
562         // Write strtab section.
563         debug_assert_eq!(strtab_offset, buffer.len());
564         buffer.extend(&u32::to_le_bytes(strtab_len as u32));
565         buffer.extend(&strtab_data);
566 
567         Ok(buffer.0)
568     }
569 }
570 
571 // JamCRC
checksum(data: &[u8]) -> u32572 fn checksum(data: &[u8]) -> u32 {
573     let mut hasher = crc32fast::Hasher::new_with_initial(0xffff_ffff);
574     hasher.update(data);
575     !hasher.finalize()
576 }
577