1use alloc::vec::Vec;
2
3use crate::pe as coff;
4use crate::write::coff::writer;
5use crate::write::util::*;
6use crate::write::*;
7
8#[derive(Default, Clone, Copy)]
9struct SectionOffsets {
10 name: writer::Name,
11 offset: u32,
12 reloc_offset: u32,
13 selection: u8,
14 associative_section: u32,
15}
16
17#[derive(Default, Clone, Copy)]
18struct SymbolOffsets {
19 name: writer::Name,
20 index: u32,
21 aux_count: u8,
22}
23
24#[derive(Clone, Copy, Debug, PartialEq, Eq)]
27pub enum CoffExportStyle {
28 Msvc,
30 Gnu,
32}
33
34impl<'a> Object<'a> {
35 pub(crate) fn coff_section_info(
36 &self,
37 section: StandardSection,
38 ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) {
39 match section {
40 StandardSection::Text => (&[], &b".text"[..], SectionKind::Text, SectionFlags::None),
41 StandardSection::Data => (&[], &b".data"[..], SectionKind::Data, SectionFlags::None),
42 StandardSection::ReadOnlyData
43 | StandardSection::ReadOnlyDataWithRel
44 | StandardSection::ReadOnlyString => (
45 &[],
46 &b".rdata"[..],
47 SectionKind::ReadOnlyData,
48 SectionFlags::None,
49 ),
50 StandardSection::UninitializedData => (
51 &[],
52 &b".bss"[..],
53 SectionKind::UninitializedData,
54 SectionFlags::None,
55 ),
56 StandardSection::Tls => (&[], &b".tls$"[..], SectionKind::Data, SectionFlags::None),
58 StandardSection::UninitializedTls => {
59 (&[], &[], SectionKind::UninitializedTls, SectionFlags::None)
61 }
62 StandardSection::TlsVariables => {
63 (&[], &[], SectionKind::TlsVariables, SectionFlags::None)
65 }
66 StandardSection::Common => {
67 (&[], &[], SectionKind::Common, SectionFlags::None)
69 }
70 StandardSection::GnuProperty => {
71 (&[], &[], SectionKind::Note, SectionFlags::None)
73 }
74 }
75 }
76
77 pub(crate) fn coff_subsection_name(&self, section: &[u8], value: &[u8]) -> Vec<u8> {
78 let mut name = section.to_vec();
79 if !value.is_empty() {
80 name.push(b'$');
81 name.extend_from_slice(value);
82 }
83 name
84 }
85
86 pub(crate) fn coff_translate_relocation(&mut self, reloc: &mut Relocation) -> Result<()> {
87 use RelocationEncoding as E;
88 use RelocationKind as K;
89
90 let (mut kind, encoding, size) = if let RelocationFlags::Generic {
91 kind,
92 encoding,
93 size,
94 } = reloc.flags
95 {
96 (kind, encoding, size)
97 } else {
98 return Ok(());
99 };
100 if kind == K::GotRelative {
101 kind = K::Relative;
105 reloc.symbol = self.coff_add_stub_symbol(reloc.symbol)?;
106 } else if kind == K::PltRelative {
107 kind = K::Relative;
111 }
112
113 let unsupported_reloc = || Err(Error(format!("unimplemented relocation {:?}", reloc)));
114 let typ = match self.architecture {
115 Architecture::I386 => match (kind, size) {
116 (K::Absolute, 16) => coff::IMAGE_REL_I386_DIR16,
117 (K::Relative, 16) => coff::IMAGE_REL_I386_REL16,
118 (K::Absolute, 32) => coff::IMAGE_REL_I386_DIR32,
119 (K::ImageOffset, 32) => coff::IMAGE_REL_I386_DIR32NB,
120 (K::SectionIndex, 16) => coff::IMAGE_REL_I386_SECTION,
121 (K::SectionOffset, 32) => coff::IMAGE_REL_I386_SECREL,
122 (K::SectionOffset, 7) => coff::IMAGE_REL_I386_SECREL7,
123 (K::Relative, 32) => coff::IMAGE_REL_I386_REL32,
124 _ => return unsupported_reloc(),
125 },
126 Architecture::X86_64 => match (kind, size) {
127 (K::Absolute, 64) => coff::IMAGE_REL_AMD64_ADDR64,
128 (K::Absolute, 32) => coff::IMAGE_REL_AMD64_ADDR32,
129 (K::ImageOffset, 32) => coff::IMAGE_REL_AMD64_ADDR32NB,
130 (K::Relative, 32) => match reloc.addend {
131 -5 => coff::IMAGE_REL_AMD64_REL32_1,
132 -6 => coff::IMAGE_REL_AMD64_REL32_2,
133 -7 => coff::IMAGE_REL_AMD64_REL32_3,
134 -8 => coff::IMAGE_REL_AMD64_REL32_4,
135 -9 => coff::IMAGE_REL_AMD64_REL32_5,
136 _ => coff::IMAGE_REL_AMD64_REL32,
137 },
138 (K::SectionIndex, 16) => coff::IMAGE_REL_AMD64_SECTION,
139 (K::SectionOffset, 32) => coff::IMAGE_REL_AMD64_SECREL,
140 (K::SectionOffset, 7) => coff::IMAGE_REL_AMD64_SECREL7,
141 _ => return unsupported_reloc(),
142 },
143 Architecture::Arm => match (kind, size) {
144 (K::Absolute, 32) => coff::IMAGE_REL_ARM_ADDR32,
145 (K::ImageOffset, 32) => coff::IMAGE_REL_ARM_ADDR32NB,
146 (K::Relative, 32) => coff::IMAGE_REL_ARM_REL32,
147 (K::SectionIndex, 16) => coff::IMAGE_REL_ARM_SECTION,
148 (K::SectionOffset, 32) => coff::IMAGE_REL_ARM_SECREL,
149 _ => return unsupported_reloc(),
150 },
151 Architecture::Aarch64 => match (kind, encoding, size) {
152 (K::Absolute, _, 32) => coff::IMAGE_REL_ARM64_ADDR32,
153 (K::ImageOffset, _, 32) => coff::IMAGE_REL_ARM64_ADDR32NB,
154 (K::SectionIndex, _, 16) => coff::IMAGE_REL_ARM64_SECTION,
155 (K::SectionOffset, _, 32) => coff::IMAGE_REL_ARM64_SECREL,
156 (K::Absolute, _, 64) => coff::IMAGE_REL_ARM64_ADDR64,
157 (K::Relative, _, 32) => coff::IMAGE_REL_ARM64_REL32,
158 (K::Relative, E::AArch64Call, 26) => coff::IMAGE_REL_ARM64_BRANCH26,
159 _ => return unsupported_reloc(),
160 },
161 _ => {
162 return Err(Error(format!(
163 "unimplemented architecture {:?}",
164 self.architecture
165 )));
166 }
167 };
168 reloc.flags = RelocationFlags::Coff { typ };
169 Ok(())
170 }
171
172 pub(crate) fn coff_adjust_addend(&self, relocation: &mut Relocation) -> Result<bool> {
173 let typ = if let RelocationFlags::Coff { typ } = relocation.flags {
174 typ
175 } else {
176 return Err(Error(format!("invalid relocation flags {:?}", relocation)));
177 };
178 let offset = match self.architecture {
179 Architecture::Arm => {
180 if typ == coff::IMAGE_REL_ARM_REL32 {
181 4
182 } else {
183 0
184 }
185 }
186 Architecture::Aarch64 => {
187 if typ == coff::IMAGE_REL_ARM64_REL32 {
188 4
189 } else {
190 0
191 }
192 }
193 Architecture::I386 => {
194 if typ == coff::IMAGE_REL_I386_REL32 {
195 4
196 } else {
197 0
198 }
199 }
200 Architecture::X86_64 => match typ {
201 coff::IMAGE_REL_AMD64_REL32 => 4,
202 coff::IMAGE_REL_AMD64_REL32_1 => 5,
203 coff::IMAGE_REL_AMD64_REL32_2 => 6,
204 coff::IMAGE_REL_AMD64_REL32_3 => 7,
205 coff::IMAGE_REL_AMD64_REL32_4 => 8,
206 coff::IMAGE_REL_AMD64_REL32_5 => 9,
207 _ => 0,
208 },
209 _ => return Err(Error(format!("unimplemented relocation {:?}", relocation))),
210 };
211 relocation.addend += offset;
212 Ok(true)
213 }
214
215 pub(crate) fn coff_relocation_size(&self, reloc: &Relocation) -> Result<u8> {
216 let typ = if let RelocationFlags::Coff { typ } = reloc.flags {
217 typ
218 } else {
219 return Err(Error(format!("unexpected relocation for size {:?}", reloc)));
220 };
221 let size = match self.architecture {
222 Architecture::I386 => match typ {
223 coff::IMAGE_REL_I386_DIR16
224 | coff::IMAGE_REL_I386_REL16
225 | coff::IMAGE_REL_I386_SECTION => Some(16),
226 coff::IMAGE_REL_I386_DIR32
227 | coff::IMAGE_REL_I386_DIR32NB
228 | coff::IMAGE_REL_I386_SECREL
229 | coff::IMAGE_REL_I386_TOKEN
230 | coff::IMAGE_REL_I386_REL32 => Some(32),
231 _ => None,
232 },
233 Architecture::X86_64 => match typ {
234 coff::IMAGE_REL_AMD64_SECTION => Some(16),
235 coff::IMAGE_REL_AMD64_ADDR32
236 | coff::IMAGE_REL_AMD64_ADDR32NB
237 | coff::IMAGE_REL_AMD64_REL32
238 | coff::IMAGE_REL_AMD64_REL32_1
239 | coff::IMAGE_REL_AMD64_REL32_2
240 | coff::IMAGE_REL_AMD64_REL32_3
241 | coff::IMAGE_REL_AMD64_REL32_4
242 | coff::IMAGE_REL_AMD64_REL32_5
243 | coff::IMAGE_REL_AMD64_SECREL
244 | coff::IMAGE_REL_AMD64_TOKEN => Some(32),
245 coff::IMAGE_REL_AMD64_ADDR64 => Some(64),
246 _ => None,
247 },
248 Architecture::Arm => match typ {
249 coff::IMAGE_REL_ARM_SECTION => Some(16),
250 coff::IMAGE_REL_ARM_ADDR32
251 | coff::IMAGE_REL_ARM_ADDR32NB
252 | coff::IMAGE_REL_ARM_TOKEN
253 | coff::IMAGE_REL_ARM_REL32
254 | coff::IMAGE_REL_ARM_SECREL => Some(32),
255 _ => None,
256 },
257 Architecture::Aarch64 => match typ {
258 coff::IMAGE_REL_ARM64_SECTION => Some(16),
259 coff::IMAGE_REL_ARM64_ADDR32
260 | coff::IMAGE_REL_ARM64_ADDR32NB
261 | coff::IMAGE_REL_ARM64_SECREL
262 | coff::IMAGE_REL_ARM64_TOKEN
263 | coff::IMAGE_REL_ARM64_REL32 => Some(32),
264 coff::IMAGE_REL_ARM64_ADDR64 => Some(64),
265 _ => None,
266 },
267 _ => None,
268 };
269 size.ok_or_else(|| Error(format!("unsupported relocation for size {:?}", reloc)))
270 }
271
272 fn coff_add_stub_symbol(&mut self, symbol_id: SymbolId) -> Result<SymbolId> {
273 if let Some(stub_id) = self.stub_symbols.get(&symbol_id) {
274 return Ok(*stub_id);
275 }
276 let stub_size = self.architecture.address_size().unwrap().bytes();
277
278 let name = b".rdata$.refptr".to_vec();
279 let section_id = self.add_section(Vec::new(), name, SectionKind::ReadOnlyData);
280 let section = self.section_mut(section_id);
281 section.set_data(vec![0; stub_size as usize], u64::from(stub_size));
282 self.add_relocation(
283 section_id,
284 Relocation {
285 offset: 0,
286 symbol: symbol_id,
287 addend: 0,
288 flags: RelocationFlags::Generic {
289 kind: RelocationKind::Absolute,
290 encoding: RelocationEncoding::Generic,
291 size: stub_size * 8,
292 },
293 },
294 )?;
295
296 let mut name = b".refptr.".to_vec();
297 name.extend_from_slice(&self.symbol(symbol_id).name);
298 let stub_id = self.add_raw_symbol(Symbol {
299 name,
300 value: 0,
301 size: u64::from(stub_size),
302 kind: SymbolKind::Data,
303 scope: SymbolScope::Compilation,
304 weak: false,
305 section: SymbolSection::Section(section_id),
306 flags: SymbolFlags::None,
307 });
308 self.stub_symbols.insert(symbol_id, stub_id);
309
310 Ok(stub_id)
311 }
312
313 pub fn add_coff_exports(&mut self, style: CoffExportStyle) {
318 assert_eq!(self.format, BinaryFormat::Coff);
319
320 let mut directives = vec![];
321 for symbol in &self.symbols {
322 if symbol.scope == SymbolScope::Dynamic {
323 match style {
324 CoffExportStyle::Msvc => directives.extend(b" /EXPORT:\""),
325 CoffExportStyle::Gnu => directives.extend(b" -export:\""),
326 }
327 directives.extend(&symbol.name);
328 directives.extend(b"\"");
329 if symbol.kind != SymbolKind::Text {
330 match style {
331 CoffExportStyle::Msvc => directives.extend(b",DATA"),
332 CoffExportStyle::Gnu => directives.extend(b",data"),
333 }
334 }
335 }
336 }
337 let drectve = self.add_section(vec![], b".drectve".to_vec(), SectionKind::Linker);
338 self.append_section_data(drectve, &directives, 1);
339 }
340
341 pub(crate) fn coff_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> {
342 let mut writer = writer::Writer::new(buffer);
343
344 let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()];
346 for (index, section) in self.sections.iter().enumerate() {
347 section_offsets[index].name = writer.add_name(§ion.name);
348 }
349
350 for comdat in &self.comdats {
352 let symbol = &self.symbols[comdat.symbol.0];
353 let comdat_section = match symbol.section {
354 SymbolSection::Section(id) => id.0,
355 _ => {
356 return Err(Error(format!(
357 "unsupported COMDAT symbol `{}` section {:?}",
358 symbol.name().unwrap_or(""),
359 symbol.section
360 )));
361 }
362 };
363 section_offsets[comdat_section].selection = match comdat.kind {
364 ComdatKind::NoDuplicates => coff::IMAGE_COMDAT_SELECT_NODUPLICATES,
365 ComdatKind::Any => coff::IMAGE_COMDAT_SELECT_ANY,
366 ComdatKind::SameSize => coff::IMAGE_COMDAT_SELECT_SAME_SIZE,
367 ComdatKind::ExactMatch => coff::IMAGE_COMDAT_SELECT_EXACT_MATCH,
368 ComdatKind::Largest => coff::IMAGE_COMDAT_SELECT_LARGEST,
369 ComdatKind::Newest => coff::IMAGE_COMDAT_SELECT_NEWEST,
370 ComdatKind::Unknown => {
371 return Err(Error(format!(
372 "unsupported COMDAT symbol `{}` kind {:?}",
373 symbol.name().unwrap_or(""),
374 comdat.kind
375 )));
376 }
377 };
378 for id in &comdat.sections {
379 let section = &self.sections[id.0];
380 if section.symbol.is_none() {
381 return Err(Error(format!(
382 "missing symbol for COMDAT section `{}`",
383 section.name().unwrap_or(""),
384 )));
385 }
386 if id.0 != comdat_section {
387 section_offsets[id.0].selection = coff::IMAGE_COMDAT_SELECT_ASSOCIATIVE;
388 section_offsets[id.0].associative_section = comdat_section as u32 + 1;
389 }
390 }
391 }
392
393 let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()];
395 for (index, symbol) in self.symbols.iter().enumerate() {
396 symbol_offsets[index].index = writer.reserve_symbol_index();
397 let mut name = &*symbol.name;
398 match symbol.kind {
399 SymbolKind::File => {
400 symbol_offsets[index].aux_count = writer.reserve_aux_file_name(&symbol.name);
402 name = b".file";
403 }
404 SymbolKind::Section if symbol.section.id().is_some() => {
405 symbol_offsets[index].aux_count = writer.reserve_aux_section();
406 }
407 _ => {}
408 };
409 symbol_offsets[index].name = writer.add_name(name);
410 }
411
412 writer.reserve_file_header();
414 writer.reserve_section_headers(self.sections.len() as u16);
415 for (index, section) in self.sections.iter().enumerate() {
416 section_offsets[index].offset = writer.reserve_section(section.data.len());
417 section_offsets[index].reloc_offset =
418 writer.reserve_relocations(section.relocations.len());
419 }
420 writer.reserve_symtab_strtab();
421
422 writer.write_file_header(writer::FileHeader {
424 machine: match (self.architecture, self.sub_architecture) {
425 (Architecture::Arm, None) => coff::IMAGE_FILE_MACHINE_ARMNT,
426 (Architecture::Aarch64, None) => coff::IMAGE_FILE_MACHINE_ARM64,
427 (Architecture::Aarch64, Some(SubArchitecture::Arm64EC)) => {
428 coff::IMAGE_FILE_MACHINE_ARM64EC
429 }
430 (Architecture::I386, None) => coff::IMAGE_FILE_MACHINE_I386,
431 (Architecture::X86_64, None) => coff::IMAGE_FILE_MACHINE_AMD64,
432 _ => {
433 return Err(Error(format!(
434 "unimplemented architecture {:?} with sub-architecture {:?}",
435 self.architecture, self.sub_architecture
436 )));
437 }
438 },
439 time_date_stamp: 0,
440 characteristics: match self.flags {
441 FileFlags::Coff { characteristics } => characteristics,
442 _ => 0,
443 },
444 })?;
445
446 for (index, section) in self.sections.iter().enumerate() {
448 let mut characteristics = if let SectionFlags::Coff {
449 characteristics, ..
450 } = section.flags
451 {
452 characteristics
453 } else {
454 match section.kind {
455 SectionKind::Text => {
456 coff::IMAGE_SCN_CNT_CODE
457 | coff::IMAGE_SCN_MEM_EXECUTE
458 | coff::IMAGE_SCN_MEM_READ
459 }
460 SectionKind::Data => {
461 coff::IMAGE_SCN_CNT_INITIALIZED_DATA
462 | coff::IMAGE_SCN_MEM_READ
463 | coff::IMAGE_SCN_MEM_WRITE
464 }
465 SectionKind::UninitializedData => {
466 coff::IMAGE_SCN_CNT_UNINITIALIZED_DATA
467 | coff::IMAGE_SCN_MEM_READ
468 | coff::IMAGE_SCN_MEM_WRITE
469 }
470 SectionKind::ReadOnlyData
471 | SectionKind::ReadOnlyDataWithRel
472 | SectionKind::ReadOnlyString => {
473 coff::IMAGE_SCN_CNT_INITIALIZED_DATA | coff::IMAGE_SCN_MEM_READ
474 }
475 SectionKind::Debug
476 | SectionKind::DebugString
477 | SectionKind::Other
478 | SectionKind::OtherString => {
479 coff::IMAGE_SCN_CNT_INITIALIZED_DATA
480 | coff::IMAGE_SCN_MEM_READ
481 | coff::IMAGE_SCN_MEM_DISCARDABLE
482 }
483 SectionKind::Linker => coff::IMAGE_SCN_LNK_INFO | coff::IMAGE_SCN_LNK_REMOVE,
484 SectionKind::Common
485 | SectionKind::Tls
486 | SectionKind::UninitializedTls
487 | SectionKind::TlsVariables
488 | SectionKind::Note
489 | SectionKind::Unknown
490 | SectionKind::Metadata
491 | SectionKind::Elf(_) => {
492 return Err(Error(format!(
493 "unimplemented section `{}` kind {:?}",
494 section.name().unwrap_or(""),
495 section.kind
496 )));
497 }
498 }
499 };
500 if section_offsets[index].selection != 0 {
501 characteristics |= coff::IMAGE_SCN_LNK_COMDAT;
502 };
503 if section.relocations.len() > 0xffff {
504 characteristics |= coff::IMAGE_SCN_LNK_NRELOC_OVFL;
505 }
506 characteristics |= match section.align {
507 1 => coff::IMAGE_SCN_ALIGN_1BYTES,
508 2 => coff::IMAGE_SCN_ALIGN_2BYTES,
509 4 => coff::IMAGE_SCN_ALIGN_4BYTES,
510 8 => coff::IMAGE_SCN_ALIGN_8BYTES,
511 16 => coff::IMAGE_SCN_ALIGN_16BYTES,
512 32 => coff::IMAGE_SCN_ALIGN_32BYTES,
513 64 => coff::IMAGE_SCN_ALIGN_64BYTES,
514 128 => coff::IMAGE_SCN_ALIGN_128BYTES,
515 256 => coff::IMAGE_SCN_ALIGN_256BYTES,
516 512 => coff::IMAGE_SCN_ALIGN_512BYTES,
517 1024 => coff::IMAGE_SCN_ALIGN_1024BYTES,
518 2048 => coff::IMAGE_SCN_ALIGN_2048BYTES,
519 4096 => coff::IMAGE_SCN_ALIGN_4096BYTES,
520 8192 => coff::IMAGE_SCN_ALIGN_8192BYTES,
521 _ => {
522 return Err(Error(format!(
523 "unimplemented section `{}` align {}",
524 section.name().unwrap_or(""),
525 section.align
526 )));
527 }
528 };
529 writer.write_section_header(writer::SectionHeader {
530 name: section_offsets[index].name,
531 size_of_raw_data: section.size as u32,
532 pointer_to_raw_data: section_offsets[index].offset,
533 pointer_to_relocations: section_offsets[index].reloc_offset,
534 pointer_to_linenumbers: 0,
535 number_of_relocations: section.relocations.len() as u32,
536 number_of_linenumbers: 0,
537 characteristics,
538 });
539 }
540
541 for section in &self.sections {
543 writer.write_section(§ion.data);
544
545 if !section.relocations.is_empty() {
546 writer.write_relocations_count(section.relocations.len());
548 for reloc in §ion.relocations {
549 let typ = if let RelocationFlags::Coff { typ } = reloc.flags {
550 typ
551 } else {
552 return Err(Error("invalid relocation flags".into()));
553 };
554 writer.write_relocation(writer::Relocation {
555 virtual_address: reloc.offset as u32,
556 symbol: symbol_offsets[reloc.symbol.0].index,
557 typ,
558 });
559 }
560 }
561 }
562
563 for (index, symbol) in self.symbols.iter().enumerate() {
565 let section_number = match symbol.section {
566 SymbolSection::None => {
567 debug_assert_eq!(symbol.kind, SymbolKind::File);
568 coff::IMAGE_SYM_DEBUG as u16
569 }
570 SymbolSection::Undefined => coff::IMAGE_SYM_UNDEFINED as u16,
571 SymbolSection::Absolute => coff::IMAGE_SYM_ABSOLUTE as u16,
572 SymbolSection::Common => coff::IMAGE_SYM_UNDEFINED as u16,
573 SymbolSection::Section(id) => id.0 as u16 + 1,
574 };
575 let typ = if symbol.kind == SymbolKind::Text {
576 coff::IMAGE_SYM_DTYPE_FUNCTION << coff::IMAGE_SYM_DTYPE_SHIFT
577 } else {
578 coff::IMAGE_SYM_TYPE_NULL
579 };
580 let storage_class = match symbol.kind {
581 SymbolKind::File => coff::IMAGE_SYM_CLASS_FILE,
582 SymbolKind::Section => {
583 if symbol.section.id().is_some() {
584 coff::IMAGE_SYM_CLASS_STATIC
585 } else {
586 coff::IMAGE_SYM_CLASS_SECTION
587 }
588 }
589 SymbolKind::Label => coff::IMAGE_SYM_CLASS_LABEL,
590 SymbolKind::Text | SymbolKind::Data | SymbolKind::Tls => {
591 match symbol.section {
592 SymbolSection::None => {
593 return Err(Error(format!(
594 "missing section for symbol `{}`",
595 symbol.name().unwrap_or("")
596 )));
597 }
598 SymbolSection::Undefined | SymbolSection::Common => {
599 coff::IMAGE_SYM_CLASS_EXTERNAL
600 }
601 SymbolSection::Absolute | SymbolSection::Section(_) => {
602 match symbol.scope {
603 _ if symbol.weak => coff::IMAGE_SYM_CLASS_WEAK_EXTERNAL,
605 SymbolScope::Unknown => {
606 return Err(Error(format!(
607 "unimplemented symbol `{}` scope {:?}",
608 symbol.name().unwrap_or(""),
609 symbol.scope
610 )));
611 }
612 SymbolScope::Compilation => coff::IMAGE_SYM_CLASS_STATIC,
613 SymbolScope::Linkage | SymbolScope::Dynamic => {
614 coff::IMAGE_SYM_CLASS_EXTERNAL
615 }
616 }
617 }
618 }
619 }
620 SymbolKind::Unknown => {
621 return Err(Error(format!(
622 "unimplemented symbol `{}` kind {:?}",
623 symbol.name().unwrap_or(""),
624 symbol.kind
625 )));
626 }
627 };
628 let number_of_aux_symbols = symbol_offsets[index].aux_count;
629 let value = if symbol.section == SymbolSection::Common {
630 symbol.size as u32
631 } else {
632 symbol.value as u32
633 };
634 writer.write_symbol(writer::Symbol {
635 name: symbol_offsets[index].name,
636 value,
637 section_number,
638 typ,
639 storage_class,
640 number_of_aux_symbols,
641 });
642
643 match symbol.kind {
645 SymbolKind::File => {
646 writer.write_aux_file_name(&symbol.name, number_of_aux_symbols);
647 }
648 SymbolKind::Section if symbol.section.id().is_some() => {
649 debug_assert_eq!(number_of_aux_symbols, 1);
650 let section_index = symbol.section.id().unwrap().0;
651 let section = &self.sections[section_index];
652 writer.write_aux_section(writer::AuxSymbolSection {
653 length: section.size as u32,
654 number_of_relocations: section.relocations.len() as u32,
655 number_of_linenumbers: 0,
656 check_sum: if section.is_bss() {
657 0
658 } else {
659 checksum(section.data())
660 },
661 number: section_offsets[section_index].associative_section,
662 selection: section_offsets[section_index].selection,
663 });
664 }
665 _ => {
666 debug_assert_eq!(number_of_aux_symbols, 0);
667 }
668 }
669 }
670
671 writer.write_strtab();
672
673 debug_assert_eq!(writer.reserved_len(), writer.len());
674
675 Ok(())
676 }
677}
678
679fn checksum(data: &[u8]) -> u32 {
681 let mut hasher = crc32fast::Hasher::new_with_initial(0xffff_ffff);
682 hasher.update(data);
683 !hasher.finalize()
684}