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