1use alloc::vec::Vec;
2
3use crate::endian::*;
4use crate::pe as coff;
5use crate::write::coff::writer;
6use crate::write::util::*;
7use crate::write::*;
8
9#[derive(Default, Clone, Copy)]
10struct SectionOffsets {
11 name: writer::Name,
12 offset: u32,
13 reloc_offset: u32,
14 selection: u8,
15 associative_section: u32,
16}
17
18#[derive(Default, Clone, Copy)]
19struct SymbolOffsets {
20 name: writer::Name,
21 index: u32,
22 aux_count: u8,
23}
24
25#[derive(Clone, Copy, Debug, PartialEq, Eq)]
28pub enum CoffExportStyle {
29 Msvc,
31 Gnu,
33}
34
35impl<'a> Object<'a> {
36 pub(crate) fn coff_section_info(
37 &self,
38 section: StandardSection,
39 ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) {
40 match section {
41 StandardSection::Text => (&[], &b".text"[..], SectionKind::Text, SectionFlags::None),
42 StandardSection::Data => (&[], &b".data"[..], SectionKind::Data, SectionFlags::None),
43 StandardSection::ReadOnlyData
44 | StandardSection::ReadOnlyDataWithRel
45 | StandardSection::ReadOnlyString => (
46 &[],
47 &b".rdata"[..],
48 SectionKind::ReadOnlyData,
49 SectionFlags::None,
50 ),
51 StandardSection::UninitializedData => (
52 &[],
53 &b".bss"[..],
54 SectionKind::UninitializedData,
55 SectionFlags::None,
56 ),
57 StandardSection::Tls => (&[], &b".tls$"[..], SectionKind::Data, SectionFlags::None),
59 StandardSection::UninitializedTls => {
60 (&[], &[], SectionKind::UninitializedTls, SectionFlags::None)
62 }
63 StandardSection::TlsVariables => {
64 (&[], &[], SectionKind::TlsVariables, SectionFlags::None)
66 }
67 StandardSection::Common => {
68 (&[], &[], SectionKind::Common, SectionFlags::None)
70 }
71 StandardSection::GnuProperty => {
72 (&[], &[], SectionKind::Note, SectionFlags::None)
74 }
75 StandardSection::EhFrame => (
76 &[],
77 &b".eh_frame"[..],
78 SectionKind::ReadOnlyData,
79 SectionFlags::None,
80 ),
81 }
82 }
83
84 pub(crate) fn coff_subsection_name(&self, section: &[u8], value: &[u8]) -> Vec<u8> {
85 let mut name = section.to_vec();
86 if !value.is_empty() {
87 name.push(b'$');
88 name.extend_from_slice(value);
89 }
90 name
91 }
92
93 pub(crate) fn coff_section_flags(&self, section: &Section<'_>) -> SectionFlags {
94 let characteristics = match section.kind {
95 SectionKind::Text => {
96 coff::IMAGE_SCN_CNT_CODE | coff::IMAGE_SCN_MEM_EXECUTE | coff::IMAGE_SCN_MEM_READ
97 }
98 SectionKind::Data => {
99 coff::IMAGE_SCN_CNT_INITIALIZED_DATA
100 | coff::IMAGE_SCN_MEM_READ
101 | coff::IMAGE_SCN_MEM_WRITE
102 }
103 SectionKind::UninitializedData => {
104 coff::IMAGE_SCN_CNT_UNINITIALIZED_DATA
105 | coff::IMAGE_SCN_MEM_READ
106 | coff::IMAGE_SCN_MEM_WRITE
107 }
108 SectionKind::ReadOnlyData
109 | SectionKind::ReadOnlyDataWithRel
110 | SectionKind::ReadOnlyString => {
111 coff::IMAGE_SCN_CNT_INITIALIZED_DATA | coff::IMAGE_SCN_MEM_READ
112 }
113 SectionKind::Debug
114 | SectionKind::DebugString
115 | SectionKind::Other
116 | SectionKind::OtherString => {
117 coff::IMAGE_SCN_CNT_INITIALIZED_DATA
118 | coff::IMAGE_SCN_MEM_READ
119 | coff::IMAGE_SCN_MEM_DISCARDABLE
120 }
121 SectionKind::Linker => coff::IMAGE_SCN_LNK_INFO | coff::IMAGE_SCN_LNK_REMOVE,
122 SectionKind::Common
123 | SectionKind::Tls
124 | SectionKind::UninitializedTls
125 | SectionKind::TlsVariables
126 | SectionKind::Note
127 | SectionKind::Unknown
128 | SectionKind::Metadata
129 | SectionKind::Elf(_) => {
130 return SectionFlags::None;
131 }
132 };
133 SectionFlags::Coff { characteristics }
134 }
135
136 pub(crate) fn coff_symbol_flags(&self, _symbol: &Symbol) -> SymbolFlags<SectionId, SymbolId> {
137 SymbolFlags::None
139 }
140
141 pub(crate) fn coff_translate_relocation(
142 &mut self,
143 reloc: &mut RelocationInternal,
144 ) -> Result<()> {
145 use RelocationEncoding as E;
146 use RelocationKind as K;
147
148 let (mut kind, encoding, size) = if let RelocationFlags::Generic {
149 kind,
150 encoding,
151 size,
152 } = reloc.flags
153 {
154 (kind, encoding, size)
155 } else {
156 return Ok(());
157 };
158 if kind == K::GotRelative {
159 kind = K::Relative;
163 reloc.symbol = self.coff_add_stub_symbol(reloc.symbol)?;
164 } else if kind == K::PltRelative {
165 kind = K::Relative;
169 }
170
171 let unsupported_reloc = || Err(Error(format!("unimplemented relocation {:?}", reloc)));
172 let typ = match self.architecture {
173 Architecture::I386 => match (kind, size) {
174 (K::Absolute, 16) => coff::IMAGE_REL_I386_DIR16,
175 (K::Relative, 16) => coff::IMAGE_REL_I386_REL16,
176 (K::Absolute, 32) => coff::IMAGE_REL_I386_DIR32,
177 (K::ImageOffset, 32) => coff::IMAGE_REL_I386_DIR32NB,
178 (K::SectionIndex, 16) => coff::IMAGE_REL_I386_SECTION,
179 (K::SectionOffset, 32) => coff::IMAGE_REL_I386_SECREL,
180 (K::SectionOffset, 7) => coff::IMAGE_REL_I386_SECREL7,
181 (K::Relative, 32) => coff::IMAGE_REL_I386_REL32,
182 _ => return unsupported_reloc(),
183 },
184 Architecture::X86_64 => match (kind, size) {
185 (K::Absolute, 64) => coff::IMAGE_REL_AMD64_ADDR64,
186 (K::Absolute, 32) => coff::IMAGE_REL_AMD64_ADDR32,
187 (K::ImageOffset, 32) => coff::IMAGE_REL_AMD64_ADDR32NB,
188 (K::Relative, 32) => match reloc.addend {
189 -5 => coff::IMAGE_REL_AMD64_REL32_1,
190 -6 => coff::IMAGE_REL_AMD64_REL32_2,
191 -7 => coff::IMAGE_REL_AMD64_REL32_3,
192 -8 => coff::IMAGE_REL_AMD64_REL32_4,
193 -9 => coff::IMAGE_REL_AMD64_REL32_5,
194 _ => coff::IMAGE_REL_AMD64_REL32,
195 },
196 (K::SectionIndex, 16) => coff::IMAGE_REL_AMD64_SECTION,
197 (K::SectionOffset, 32) => coff::IMAGE_REL_AMD64_SECREL,
198 (K::SectionOffset, 7) => coff::IMAGE_REL_AMD64_SECREL7,
199 _ => return unsupported_reloc(),
200 },
201 Architecture::Arm => match (kind, size) {
202 (K::Absolute, 32) => coff::IMAGE_REL_ARM_ADDR32,
203 (K::ImageOffset, 32) => coff::IMAGE_REL_ARM_ADDR32NB,
204 (K::Relative, 32) => coff::IMAGE_REL_ARM_REL32,
205 (K::SectionIndex, 16) => coff::IMAGE_REL_ARM_SECTION,
206 (K::SectionOffset, 32) => coff::IMAGE_REL_ARM_SECREL,
207 _ => return unsupported_reloc(),
208 },
209 Architecture::Aarch64 => match (kind, encoding, size) {
210 (K::Absolute, _, 32) => coff::IMAGE_REL_ARM64_ADDR32,
211 (K::ImageOffset, _, 32) => coff::IMAGE_REL_ARM64_ADDR32NB,
212 (K::SectionIndex, _, 16) => coff::IMAGE_REL_ARM64_SECTION,
213 (K::SectionOffset, _, 32) => coff::IMAGE_REL_ARM64_SECREL,
214 (K::Absolute, _, 64) => coff::IMAGE_REL_ARM64_ADDR64,
215 (K::Relative, _, 32) => coff::IMAGE_REL_ARM64_REL32,
216 (K::Relative, E::AArch64Call, 26) => coff::IMAGE_REL_ARM64_BRANCH26,
217 _ => return unsupported_reloc(),
218 },
219 _ => {
220 return Err(Error(format!(
221 "unimplemented architecture {:?}",
222 self.architecture
223 )));
224 }
225 };
226 reloc.flags = RelocationFlags::Coff { typ };
227 Ok(())
228 }
229
230 pub(crate) fn coff_adjust_addend(&self, relocation: &mut RelocationInternal) -> Result<bool> {
231 let typ = if let RelocationFlags::Coff { typ } = relocation.flags {
232 typ
233 } else {
234 return Err(Error(format!("invalid relocation flags {:?}", relocation)));
235 };
236 let offset = match self.architecture {
237 Architecture::Arm => {
238 if typ == coff::IMAGE_REL_ARM_REL32 {
239 4
240 } else {
241 0
242 }
243 }
244 Architecture::Aarch64 => {
245 if typ == coff::IMAGE_REL_ARM64_REL32 {
246 4
247 } else {
248 0
249 }
250 }
251 Architecture::I386 => {
252 if typ == coff::IMAGE_REL_I386_REL32 {
253 4
254 } else {
255 0
256 }
257 }
258 Architecture::X86_64 => match typ {
259 coff::IMAGE_REL_AMD64_REL32 => 4,
260 coff::IMAGE_REL_AMD64_REL32_1 => 5,
261 coff::IMAGE_REL_AMD64_REL32_2 => 6,
262 coff::IMAGE_REL_AMD64_REL32_3 => 7,
263 coff::IMAGE_REL_AMD64_REL32_4 => 8,
264 coff::IMAGE_REL_AMD64_REL32_5 => 9,
265 _ => 0,
266 },
267 Architecture::PowerPc | Architecture::PowerPc64 => 0,
268 _ => return Err(Error(format!("unimplemented relocation {:?}", relocation))),
269 };
270 relocation.addend += offset;
271 Ok(true)
272 }
273
274 pub(crate) fn coff_relocation_size(&self, reloc: &RelocationInternal) -> Result<u8> {
275 let typ = if let RelocationFlags::Coff { typ } = reloc.flags {
276 typ
277 } else {
278 return Err(Error(format!("unexpected relocation for size {:?}", reloc)));
279 };
280 let size = match self.architecture {
281 Architecture::I386 => match typ {
282 coff::IMAGE_REL_I386_DIR16
283 | coff::IMAGE_REL_I386_REL16
284 | coff::IMAGE_REL_I386_SECTION => Some(16),
285 coff::IMAGE_REL_I386_DIR32
286 | coff::IMAGE_REL_I386_DIR32NB
287 | coff::IMAGE_REL_I386_SECREL
288 | coff::IMAGE_REL_I386_TOKEN
289 | coff::IMAGE_REL_I386_REL32 => Some(32),
290 _ => None,
291 },
292 Architecture::X86_64 => match typ {
293 coff::IMAGE_REL_AMD64_SECTION => Some(16),
294 coff::IMAGE_REL_AMD64_ADDR32
295 | coff::IMAGE_REL_AMD64_ADDR32NB
296 | coff::IMAGE_REL_AMD64_REL32
297 | coff::IMAGE_REL_AMD64_REL32_1
298 | coff::IMAGE_REL_AMD64_REL32_2
299 | coff::IMAGE_REL_AMD64_REL32_3
300 | coff::IMAGE_REL_AMD64_REL32_4
301 | coff::IMAGE_REL_AMD64_REL32_5
302 | coff::IMAGE_REL_AMD64_SECREL
303 | coff::IMAGE_REL_AMD64_TOKEN => Some(32),
304 coff::IMAGE_REL_AMD64_ADDR64 => Some(64),
305 _ => None,
306 },
307 Architecture::Arm => match typ {
308 coff::IMAGE_REL_ARM_SECTION => Some(16),
309 coff::IMAGE_REL_ARM_ADDR32
310 | coff::IMAGE_REL_ARM_ADDR32NB
311 | coff::IMAGE_REL_ARM_TOKEN
312 | coff::IMAGE_REL_ARM_REL32
313 | coff::IMAGE_REL_ARM_SECREL => Some(32),
314 _ => None,
315 },
316 Architecture::Aarch64 => match typ {
317 coff::IMAGE_REL_ARM64_SECTION => Some(16),
318 coff::IMAGE_REL_ARM64_ADDR32
319 | coff::IMAGE_REL_ARM64_ADDR32NB
320 | coff::IMAGE_REL_ARM64_SECREL
321 | coff::IMAGE_REL_ARM64_TOKEN
322 | coff::IMAGE_REL_ARM64_REL32 => Some(32),
323 coff::IMAGE_REL_ARM64_ADDR64 => Some(64),
324 _ => None,
325 },
326 _ => None,
327 };
328 size.ok_or_else(|| Error(format!("unsupported relocation for size {:?}", reloc)))
329 }
330
331 fn coff_add_stub_symbol(&mut self, symbol_id: SymbolId) -> Result<SymbolId> {
332 if let Some(stub_id) = self.stub_symbols.get(&symbol_id) {
333 return Ok(*stub_id);
334 }
335 let stub_size = self.architecture.address_size().unwrap().bytes();
336
337 let name = b".rdata$.refptr".to_vec();
338 let section_id = self.add_section(Vec::new(), name, SectionKind::ReadOnlyData);
339 let section = self.section_mut(section_id);
340 section.set_data(vec![0; stub_size as usize], u64::from(stub_size));
341 self.add_relocation(
342 section_id,
343 Relocation {
344 offset: 0,
345 symbol: symbol_id,
346 addend: 0,
347 flags: RelocationFlags::Generic {
348 kind: RelocationKind::Absolute,
349 encoding: RelocationEncoding::Generic,
350 size: stub_size * 8,
351 },
352 },
353 )?;
354
355 let mut name = b".refptr.".to_vec();
356 name.extend_from_slice(&self.symbol(symbol_id).name);
357 let stub_id = self.add_raw_symbol(Symbol {
358 name,
359 value: 0,
360 size: u64::from(stub_size),
361 kind: SymbolKind::Data,
362 scope: SymbolScope::Compilation,
363 weak: false,
364 section: SymbolSection::Section(section_id),
365 flags: SymbolFlags::None,
366 });
367 self.stub_symbols.insert(symbol_id, stub_id);
368
369 Ok(stub_id)
370 }
371
372 pub fn add_coff_exports(&mut self, style: CoffExportStyle) {
377 assert_eq!(self.format, BinaryFormat::Coff);
378
379 let mut directives = vec![];
380 for symbol in &self.symbols {
381 if symbol.scope == SymbolScope::Dynamic {
382 match style {
383 CoffExportStyle::Msvc => directives.extend(b" /EXPORT:\""),
384 CoffExportStyle::Gnu => directives.extend(b" -export:\""),
385 }
386 directives.extend(&symbol.name);
387 directives.extend(b"\"");
388 if symbol.kind != SymbolKind::Text {
389 match style {
390 CoffExportStyle::Msvc => directives.extend(b",DATA"),
391 CoffExportStyle::Gnu => directives.extend(b",data"),
392 }
393 }
394 }
395 }
396 let drectve = self.add_section(vec![], b".drectve".to_vec(), SectionKind::Linker);
397 self.append_section_data(drectve, &directives, 1);
398 }
399
400 pub(crate) fn coff_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> {
401 let mut writer = writer::Writer::new(buffer);
402
403 let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()];
405 for (index, section) in self.sections.iter().enumerate() {
406 section_offsets[index].name = writer.add_name(§ion.name);
407 }
408
409 for comdat in &self.comdats {
411 let symbol = &self.symbols[comdat.symbol.0];
412 let comdat_section = match symbol.section {
413 SymbolSection::Section(id) => id.0,
414 _ => {
415 return Err(Error(format!(
416 "unsupported COMDAT symbol `{}` section {:?}",
417 symbol.name().unwrap_or(""),
418 symbol.section
419 )));
420 }
421 };
422 section_offsets[comdat_section].selection = match comdat.kind {
423 ComdatKind::NoDuplicates => coff::IMAGE_COMDAT_SELECT_NODUPLICATES,
424 ComdatKind::Any => coff::IMAGE_COMDAT_SELECT_ANY,
425 ComdatKind::SameSize => coff::IMAGE_COMDAT_SELECT_SAME_SIZE,
426 ComdatKind::ExactMatch => coff::IMAGE_COMDAT_SELECT_EXACT_MATCH,
427 ComdatKind::Largest => coff::IMAGE_COMDAT_SELECT_LARGEST,
428 ComdatKind::Newest => coff::IMAGE_COMDAT_SELECT_NEWEST,
429 ComdatKind::Unknown => {
430 return Err(Error(format!(
431 "unsupported COMDAT symbol `{}` kind {:?}",
432 symbol.name().unwrap_or(""),
433 comdat.kind
434 )));
435 }
436 };
437 for id in &comdat.sections {
438 let section = &self.sections[id.0];
439 if section.symbol.is_none() {
440 return Err(Error(format!(
441 "missing symbol for COMDAT section `{}`",
442 section.name().unwrap_or(""),
443 )));
444 }
445 if id.0 != comdat_section {
446 section_offsets[id.0].selection = coff::IMAGE_COMDAT_SELECT_ASSOCIATIVE;
447 section_offsets[id.0].associative_section = comdat_section as u32 + 1;
448 }
449 }
450 }
451
452 let weak_symbol_count = self.symbols.iter().filter(|symbol| symbol.weak).count();
454 let mut weak_default_names = HashMap::new();
455 let mut weak_default_offsets = HashMap::new();
456
457 if weak_symbol_count > 0 {
458 weak_default_names.reserve(weak_symbol_count);
459 weak_default_offsets.reserve(weak_symbol_count);
460
461 let defined_external_symbol = |symbol: &&Symbol| -> bool {
462 !symbol.weak
463 && (symbol.scope == SymbolScope::Linkage
464 || symbol.scope == SymbolScope::Dynamic)
465 && (matches!(symbol.section, SymbolSection::Section(_))
466 || matches!(symbol.section, SymbolSection::Absolute))
467 };
468
469 let mut weak_default_unique_name = Default::default();
470
471 for symbol in self.symbols.iter().filter(defined_external_symbol) {
474 let SymbolSection::Section(section_id) = symbol.section else {
475 weak_default_unique_name = &*symbol.name;
476 break;
477 };
478
479 if !self
480 .comdats
481 .iter()
482 .flat_map(|comdat| comdat.sections.iter())
483 .any(|comdat_section| *comdat_section == section_id)
484 {
485 weak_default_unique_name = &*symbol.name;
486 break;
487 }
488 }
489
490 if weak_default_unique_name.is_empty() {
492 for symbol in self.symbols.iter().filter(defined_external_symbol) {
493 if matches!(symbol.section, SymbolSection::Section(_)) {
494 weak_default_unique_name = &*symbol.name;
495 break;
496 }
497 }
498 }
499
500 for (index, symbol) in self
502 .symbols
503 .iter()
504 .enumerate()
505 .filter(|(_, symbol)| symbol.weak)
506 {
507 let mut weak_default_name = [b".weak.", symbol.name.as_slice()].concat();
508 if !weak_default_unique_name.is_empty() {
509 weak_default_name.push(b'.');
510 weak_default_name.extend(weak_default_unique_name);
511 }
512
513 weak_default_names.insert(index, weak_default_name);
514 }
515 }
516
517 let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()];
519 for (index, symbol) in self.symbols.iter().enumerate() {
520 if symbol.weak {
521 let weak_default_name = weak_default_names.get(&index).unwrap_or_else(|| {
523 unreachable!("weak default symbol name should have been created")
524 });
525
526 weak_default_offsets.insert(
527 index,
528 SymbolOffsets {
529 name: writer.add_name(weak_default_name.as_slice()),
530 index: writer.reserve_symbol_index(),
531 aux_count: 0,
532 },
533 );
534 }
535
536 symbol_offsets[index].index = writer.reserve_symbol_index();
537 let mut name = &*symbol.name;
538 match symbol.kind {
539 _ if symbol.weak => {
540 symbol_offsets[index].aux_count = writer.reserve_aux_weak_external();
541 }
542 SymbolKind::File => {
543 symbol_offsets[index].aux_count = writer.reserve_aux_file_name(&symbol.name);
545 name = b".file";
546 }
547 SymbolKind::Section if symbol.section.id().is_some() => {
548 symbol_offsets[index].aux_count = writer.reserve_aux_section();
549 }
550 _ => {}
551 };
552 symbol_offsets[index].name = writer.add_name(name);
553 }
554
555 writer.reserve_file_header();
557 writer.reserve_section_headers(self.sections.len() as u16);
558 for (index, section) in self.sections.iter().enumerate() {
559 section_offsets[index].offset = writer.reserve_section(section.data.len());
560 section_offsets[index].reloc_offset =
561 writer.reserve_relocations(section.relocations.len());
562 }
563 writer.reserve_symtab_strtab();
564
565 writer.write_file_header(writer::FileHeader {
567 machine: match (self.architecture, self.sub_architecture, self.endian) {
568 (Architecture::Arm, None, _) => coff::IMAGE_FILE_MACHINE_ARMNT,
569 (Architecture::Aarch64, None, _) => coff::IMAGE_FILE_MACHINE_ARM64,
570 (Architecture::Aarch64, Some(SubArchitecture::Arm64EC), _) => {
571 coff::IMAGE_FILE_MACHINE_ARM64EC
572 }
573 (Architecture::I386, None, _) => coff::IMAGE_FILE_MACHINE_I386,
574 (Architecture::X86_64, None, _) => coff::IMAGE_FILE_MACHINE_AMD64,
575 (Architecture::PowerPc | Architecture::PowerPc64, None, Endianness::Little) => {
576 coff::IMAGE_FILE_MACHINE_POWERPC
577 }
578 (Architecture::PowerPc | Architecture::PowerPc64, None, Endianness::Big) => {
579 coff::IMAGE_FILE_MACHINE_POWERPCBE
580 }
581 _ => {
582 return Err(Error(format!(
583 "unimplemented architecture {:?} with sub-architecture {:?}",
584 self.architecture, self.sub_architecture
585 )));
586 }
587 },
588 time_date_stamp: 0,
589 characteristics: match self.flags {
590 FileFlags::Coff { characteristics } => characteristics,
591 _ => 0,
592 },
593 })?;
594
595 for (index, section) in self.sections.iter().enumerate() {
597 let SectionFlags::Coff {
598 mut characteristics,
599 ..
600 } = self.section_flags(section)
601 else {
602 return Err(Error(format!(
603 "unimplemented section `{}` kind {:?}",
604 section.name().unwrap_or(""),
605 section.kind
606 )));
607 };
608 if section_offsets[index].selection != 0 {
609 characteristics |= coff::IMAGE_SCN_LNK_COMDAT;
610 };
611 if section.relocations.len() > 0xffff {
612 characteristics |= coff::IMAGE_SCN_LNK_NRELOC_OVFL;
613 }
614 characteristics |= match section.align {
615 1 => coff::IMAGE_SCN_ALIGN_1BYTES,
616 2 => coff::IMAGE_SCN_ALIGN_2BYTES,
617 4 => coff::IMAGE_SCN_ALIGN_4BYTES,
618 8 => coff::IMAGE_SCN_ALIGN_8BYTES,
619 16 => coff::IMAGE_SCN_ALIGN_16BYTES,
620 32 => coff::IMAGE_SCN_ALIGN_32BYTES,
621 64 => coff::IMAGE_SCN_ALIGN_64BYTES,
622 128 => coff::IMAGE_SCN_ALIGN_128BYTES,
623 256 => coff::IMAGE_SCN_ALIGN_256BYTES,
624 512 => coff::IMAGE_SCN_ALIGN_512BYTES,
625 1024 => coff::IMAGE_SCN_ALIGN_1024BYTES,
626 2048 => coff::IMAGE_SCN_ALIGN_2048BYTES,
627 4096 => coff::IMAGE_SCN_ALIGN_4096BYTES,
628 8192 => coff::IMAGE_SCN_ALIGN_8192BYTES,
629 _ => {
630 return Err(Error(format!(
631 "unimplemented section `{}` align {}",
632 section.name().unwrap_or(""),
633 section.align
634 )));
635 }
636 };
637 writer.write_section_header(writer::SectionHeader {
638 name: section_offsets[index].name,
639 size_of_raw_data: section.size as u32,
640 pointer_to_raw_data: section_offsets[index].offset,
641 pointer_to_relocations: section_offsets[index].reloc_offset,
642 pointer_to_linenumbers: 0,
643 number_of_relocations: section.relocations.len() as u32,
644 number_of_linenumbers: 0,
645 characteristics,
646 });
647 }
648
649 for section in &self.sections {
651 writer.write_section(§ion.data);
652
653 if !section.relocations.is_empty() {
654 writer.write_relocations_count(section.relocations.len());
656 for reloc in §ion.relocations {
657 let typ = if let RelocationFlags::Coff { typ } = reloc.flags {
658 typ
659 } else {
660 return Err(Error("invalid relocation flags".into()));
661 };
662 writer.write_relocation(writer::Relocation {
663 virtual_address: reloc.offset as u32,
664 symbol: symbol_offsets[reloc.symbol.0].index,
665 typ,
666 });
667 }
668 }
669 }
670
671 for (index, symbol) in self.symbols.iter().enumerate() {
673 let SymbolFlags::None = symbol.flags else {
674 return Err(Error(format!(
675 "unimplemented symbol `{}` kind {:?}",
676 symbol.name().unwrap_or(""),
677 symbol.kind
678 )));
679 };
680 let section_number = match symbol.section {
681 _ if symbol.weak => coff::IMAGE_SYM_UNDEFINED as u16,
683 SymbolSection::None => {
684 debug_assert_eq!(symbol.kind, SymbolKind::File);
685 coff::IMAGE_SYM_DEBUG as u16
686 }
687 SymbolSection::Undefined => coff::IMAGE_SYM_UNDEFINED as u16,
688 SymbolSection::Absolute => coff::IMAGE_SYM_ABSOLUTE as u16,
689 SymbolSection::Common => coff::IMAGE_SYM_UNDEFINED as u16,
690 SymbolSection::Section(id) => id.0 as u16 + 1,
691 };
692 let typ = if symbol.kind == SymbolKind::Text {
693 coff::IMAGE_SYM_DTYPE_FUNCTION << coff::IMAGE_SYM_DTYPE_SHIFT
694 } else {
695 coff::IMAGE_SYM_TYPE_NULL
696 };
697 let storage_class = match symbol.kind {
698 _ if symbol.weak => coff::IMAGE_SYM_CLASS_WEAK_EXTERNAL,
699 SymbolKind::File => coff::IMAGE_SYM_CLASS_FILE,
700 SymbolKind::Section => {
701 if symbol.section.id().is_some() {
702 coff::IMAGE_SYM_CLASS_STATIC
703 } else {
704 coff::IMAGE_SYM_CLASS_SECTION
705 }
706 }
707 SymbolKind::Label => coff::IMAGE_SYM_CLASS_LABEL,
708 SymbolKind::Text | SymbolKind::Data | SymbolKind::Tls => match symbol.section {
709 SymbolSection::None => {
710 return Err(Error(format!(
711 "missing section for symbol `{}`",
712 symbol.name().unwrap_or("")
713 )));
714 }
715 SymbolSection::Undefined | SymbolSection::Common => {
716 coff::IMAGE_SYM_CLASS_EXTERNAL
717 }
718 SymbolSection::Absolute | SymbolSection::Section(_) => match symbol.scope {
719 SymbolScope::Unknown => {
720 return Err(Error(format!(
721 "unimplemented symbol `{}` scope {:?}",
722 symbol.name().unwrap_or(""),
723 symbol.scope
724 )));
725 }
726 SymbolScope::Compilation => coff::IMAGE_SYM_CLASS_STATIC,
727 SymbolScope::Linkage | SymbolScope::Dynamic => {
728 coff::IMAGE_SYM_CLASS_EXTERNAL
729 }
730 },
731 },
732 SymbolKind::Unknown => match symbol.section {
733 SymbolSection::Undefined => coff::IMAGE_SYM_CLASS_EXTERNAL,
734 _ => {
735 return Err(Error(format!(
736 "unimplemented symbol `{}` kind {:?}",
737 symbol.name().unwrap_or(""),
738 symbol.kind
739 )))
740 }
741 },
742 };
743 let number_of_aux_symbols = symbol_offsets[index].aux_count;
744 let value = if symbol.weak {
745 0
747 } else if symbol.section == SymbolSection::Common {
748 symbol.size as u32
749 } else {
750 symbol.value as u32
751 };
752
753 if symbol.weak {
755 let weak_default_symbol = weak_default_offsets.get(&index).unwrap_or_else(|| {
756 unreachable!("weak symbol should have a weak default offset")
757 });
758
759 writer.write_symbol(writer::Symbol {
760 name: weak_default_symbol.name,
761 value: symbol.value as u32,
762 section_number: match symbol.section {
763 SymbolSection::Section(id) => id.0 as u16 + 1,
764 SymbolSection::Undefined => coff::IMAGE_SYM_ABSOLUTE as u16,
765 o => {
766 return Err(Error(format!(
767 "invalid symbol section for weak external `{}` section {o:?}",
768 symbol.name().unwrap_or("")
769 )));
770 }
771 },
772 number_of_aux_symbols: 0,
773 typ: 0,
774 storage_class: coff::IMAGE_SYM_CLASS_EXTERNAL,
775 });
776 }
777
778 writer.write_symbol(writer::Symbol {
779 name: symbol_offsets[index].name,
780 value,
781 section_number,
782 typ,
783 storage_class,
784 number_of_aux_symbols,
785 });
786
787 match symbol.kind {
789 _ if symbol.weak => {
790 let weak_default_offset =
791 weak_default_offsets.get(&index).unwrap_or_else(|| {
792 unreachable!("weak symbol should have a weak default offset")
793 });
794
795 let weak_default_sym_index = weak_default_offset.index;
796 writer.write_aux_weak_external(writer::AuxSymbolWeak {
797 weak_default_sym_index,
798 weak_search_type: coff::IMAGE_WEAK_EXTERN_SEARCH_ALIAS,
799 });
800 }
801 SymbolKind::File => {
802 writer.write_aux_file_name(&symbol.name, number_of_aux_symbols);
803 }
804 SymbolKind::Section if symbol.section.id().is_some() => {
805 debug_assert_eq!(number_of_aux_symbols, 1);
806 let section_index = symbol.section.id().unwrap().0;
807 let section = &self.sections[section_index];
808 writer.write_aux_section(writer::AuxSymbolSection {
809 length: section.size as u32,
810 number_of_relocations: section.relocations.len() as u32,
811 number_of_linenumbers: 0,
812 check_sum: if section.is_bss() {
813 0
814 } else {
815 checksum(section.data())
816 },
817 number: section_offsets[section_index].associative_section,
818 selection: section_offsets[section_index].selection,
819 });
820 }
821 _ => {
822 debug_assert_eq!(number_of_aux_symbols, 0);
823 }
824 }
825 }
826
827 writer.write_strtab();
828
829 debug_assert_eq!(writer.reserved_len(), writer.len());
830
831 Ok(())
832 }
833}
834
835fn checksum(data: &[u8]) -> u32 {
837 let mut hasher = crc32fast::Hasher::new_with_initial(0xffff_ffff);
838 hasher.update(data);
839 !hasher.finalize()
840}