]> git.proxmox.com Git - rustc.git/blob - vendor/object/src/write/coff.rs
New upstream version 1.71.1+dfsg1
[rustc.git] / vendor / object / src / write / coff.rs
1 use alloc::vec::Vec;
2 use core::mem;
3
4 use crate::endian::{LittleEndian as LE, U16Bytes, U32Bytes, U16, U32};
5 use crate::pe as coff;
6 use crate::write::string::*;
7 use crate::write::util::*;
8 use crate::write::*;
9
10 #[derive(Default, Clone, Copy)]
11 struct SectionOffsets {
12 offset: usize,
13 str_id: Option<StringId>,
14 reloc_offset: usize,
15 selection: u8,
16 associative_section: u16,
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 /// Internal format to use for the `.drectve` section containing linker
27 /// directives for symbol exports.
28 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
29 pub enum CoffExportStyle {
30 /// MSVC format supported by link.exe and LLD.
31 Msvc,
32 /// Gnu format supported by GNU LD and LLD.
33 Gnu,
34 }
35
36 impl<'a> Object<'a> {
37 pub(crate) fn coff_section_info(
38 &self,
39 section: StandardSection,
40 ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) {
41 match section {
42 StandardSection::Text => (&[], &b".text"[..], SectionKind::Text, SectionFlags::None),
43 StandardSection::Data => (&[], &b".data"[..], SectionKind::Data, SectionFlags::None),
44 StandardSection::ReadOnlyData
45 | StandardSection::ReadOnlyDataWithRel
46 | StandardSection::ReadOnlyString => (
47 &[],
48 &b".rdata"[..],
49 SectionKind::ReadOnlyData,
50 SectionFlags::None,
51 ),
52 StandardSection::UninitializedData => (
53 &[],
54 &b".bss"[..],
55 SectionKind::UninitializedData,
56 SectionFlags::None,
57 ),
58 // TLS sections are data sections with a special name.
59 StandardSection::Tls => (&[], &b".tls$"[..], SectionKind::Data, SectionFlags::None),
60 StandardSection::UninitializedTls => {
61 // Unsupported section.
62 (&[], &[], SectionKind::UninitializedTls, SectionFlags::None)
63 }
64 StandardSection::TlsVariables => {
65 // Unsupported section.
66 (&[], &[], SectionKind::TlsVariables, SectionFlags::None)
67 }
68 StandardSection::Common => {
69 // Unsupported section.
70 (&[], &[], SectionKind::Common, SectionFlags::None)
71 }
72 StandardSection::GnuProperty => {
73 // Unsupported section.
74 (&[], &[], SectionKind::Note, SectionFlags::None)
75 }
76 }
77 }
78
79 pub(crate) fn coff_subsection_name(&self, section: &[u8], value: &[u8]) -> Vec<u8> {
80 let mut name = section.to_vec();
81 name.push(b'$');
82 name.extend_from_slice(value);
83 name
84 }
85
86 pub(crate) fn coff_fixup_relocation(&mut self, mut relocation: &mut Relocation) -> i64 {
87 if relocation.kind == RelocationKind::GotRelative {
88 // Use a stub symbol for the relocation instead.
89 // This isn't really a GOT, but it's a similar purpose.
90 // TODO: need to handle DLL imports differently?
91 relocation.kind = RelocationKind::Relative;
92 relocation.symbol = self.coff_add_stub_symbol(relocation.symbol);
93 } else if relocation.kind == RelocationKind::PltRelative {
94 // Windows doesn't need a separate relocation type for
95 // references to functions in import libraries.
96 // For convenience, treat this the same as Relative.
97 relocation.kind = RelocationKind::Relative;
98 }
99
100 let constant = match self.architecture {
101 Architecture::I386 | Architecture::Arm | Architecture::Aarch64 => match relocation.kind
102 {
103 RelocationKind::Relative => {
104 // IMAGE_REL_I386_REL32, IMAGE_REL_ARM_REL32, IMAGE_REL_ARM64_REL32
105 relocation.addend + 4
106 }
107 _ => relocation.addend,
108 },
109 Architecture::X86_64 => match relocation.kind {
110 RelocationKind::Relative => {
111 // IMAGE_REL_AMD64_REL32 through to IMAGE_REL_AMD64_REL32_5
112 if relocation.addend <= -4 && relocation.addend >= -9 {
113 0
114 } else {
115 relocation.addend + 4
116 }
117 }
118 _ => relocation.addend,
119 },
120 _ => unimplemented!(),
121 };
122 relocation.addend -= constant;
123 constant
124 }
125
126 fn coff_add_stub_symbol(&mut self, symbol_id: SymbolId) -> SymbolId {
127 if let Some(stub_id) = self.stub_symbols.get(&symbol_id) {
128 return *stub_id;
129 }
130 let stub_size = self.architecture.address_size().unwrap().bytes();
131
132 let name = b".rdata$.refptr".to_vec();
133 let section_id = self.add_section(Vec::new(), name, SectionKind::ReadOnlyData);
134 let section = self.section_mut(section_id);
135 section.set_data(vec![0; stub_size as usize], u64::from(stub_size));
136 section.relocations = vec![Relocation {
137 offset: 0,
138 size: stub_size * 8,
139 kind: RelocationKind::Absolute,
140 encoding: RelocationEncoding::Generic,
141 symbol: symbol_id,
142 addend: 0,
143 }];
144
145 let mut name = b".refptr.".to_vec();
146 name.extend_from_slice(&self.symbol(symbol_id).name);
147 let stub_id = self.add_raw_symbol(Symbol {
148 name,
149 value: 0,
150 size: u64::from(stub_size),
151 kind: SymbolKind::Data,
152 scope: SymbolScope::Compilation,
153 weak: false,
154 section: SymbolSection::Section(section_id),
155 flags: SymbolFlags::None,
156 });
157 self.stub_symbols.insert(symbol_id, stub_id);
158
159 stub_id
160 }
161
162 /// Appends linker directives to the `.drectve` section to tell the linker
163 /// to export all symbols with `SymbolScope::Dynamic`.
164 ///
165 /// This must be called after all symbols have been defined.
166 pub fn add_coff_exports(&mut self, style: CoffExportStyle) {
167 assert_eq!(self.format, BinaryFormat::Coff);
168
169 let mut directives = vec![];
170 for symbol in &self.symbols {
171 if symbol.scope == SymbolScope::Dynamic {
172 match style {
173 CoffExportStyle::Msvc => directives.extend(b" /EXPORT:\""),
174 CoffExportStyle::Gnu => directives.extend(b" -export:\""),
175 }
176 directives.extend(&symbol.name);
177 directives.extend(b"\"");
178 if symbol.kind != SymbolKind::Text {
179 match style {
180 CoffExportStyle::Msvc => directives.extend(b",DATA"),
181 CoffExportStyle::Gnu => directives.extend(b",data"),
182 }
183 }
184 }
185 }
186 let drectve = self.add_section(vec![], b".drectve".to_vec(), SectionKind::Linker);
187 self.append_section_data(drectve, &directives, 1);
188 }
189
190 pub(crate) fn coff_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> {
191 // Calculate offsets of everything, and build strtab.
192 let mut offset = 0;
193 let mut strtab = StringTable::default();
194
195 // COFF header.
196 offset += mem::size_of::<coff::ImageFileHeader>();
197
198 // Section headers.
199 offset += self.sections.len() * mem::size_of::<coff::ImageSectionHeader>();
200
201 // Calculate size of section data and add section strings to strtab.
202 let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()];
203 for (index, section) in self.sections.iter().enumerate() {
204 if section.name.len() > 8 {
205 section_offsets[index].str_id = Some(strtab.add(&section.name));
206 }
207
208 let len = section.data.len();
209 if len != 0 {
210 // TODO: not sure what alignment is required here, but this seems to match LLVM
211 offset = align(offset, 4);
212 section_offsets[index].offset = offset;
213 offset += len;
214 } else {
215 section_offsets[index].offset = 0;
216 }
217
218 // Calculate size of relocations.
219 let mut count = section.relocations.len();
220 if count != 0 {
221 section_offsets[index].reloc_offset = offset;
222 if count > 0xffff {
223 count += 1;
224 }
225 offset += count * mem::size_of::<coff::ImageRelocation>();
226 }
227 }
228
229 // Set COMDAT flags.
230 for comdat in &self.comdats {
231 let symbol = &self.symbols[comdat.symbol.0];
232 let comdat_section = match symbol.section {
233 SymbolSection::Section(id) => id.0,
234 _ => {
235 return Err(Error(format!(
236 "unsupported COMDAT symbol `{}` section {:?}",
237 symbol.name().unwrap_or(""),
238 symbol.section
239 )));
240 }
241 };
242 section_offsets[comdat_section].selection = match comdat.kind {
243 ComdatKind::NoDuplicates => coff::IMAGE_COMDAT_SELECT_NODUPLICATES,
244 ComdatKind::Any => coff::IMAGE_COMDAT_SELECT_ANY,
245 ComdatKind::SameSize => coff::IMAGE_COMDAT_SELECT_SAME_SIZE,
246 ComdatKind::ExactMatch => coff::IMAGE_COMDAT_SELECT_EXACT_MATCH,
247 ComdatKind::Largest => coff::IMAGE_COMDAT_SELECT_LARGEST,
248 ComdatKind::Newest => coff::IMAGE_COMDAT_SELECT_NEWEST,
249 ComdatKind::Unknown => {
250 return Err(Error(format!(
251 "unsupported COMDAT symbol `{}` kind {:?}",
252 symbol.name().unwrap_or(""),
253 comdat.kind
254 )));
255 }
256 };
257 for id in &comdat.sections {
258 let section = &self.sections[id.0];
259 if section.symbol.is_none() {
260 return Err(Error(format!(
261 "missing symbol for COMDAT section `{}`",
262 section.name().unwrap_or(""),
263 )));
264 }
265 if id.0 != comdat_section {
266 section_offsets[id.0].selection = coff::IMAGE_COMDAT_SELECT_ASSOCIATIVE;
267 section_offsets[id.0].associative_section = comdat_section as u16 + 1;
268 }
269 }
270 }
271
272 // Calculate size of symbols and add symbol strings to strtab.
273 let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()];
274 let mut symtab_count = 0;
275 for (index, symbol) in self.symbols.iter().enumerate() {
276 symbol_offsets[index].index = symtab_count;
277 symtab_count += 1;
278 match symbol.kind {
279 SymbolKind::File => {
280 // Name goes in auxiliary symbol records.
281 let aux_count = (symbol.name.len() + coff::IMAGE_SIZEOF_SYMBOL - 1)
282 / coff::IMAGE_SIZEOF_SYMBOL;
283 symbol_offsets[index].aux_count = aux_count as u8;
284 symtab_count += aux_count;
285 // Don't add name to strtab.
286 continue;
287 }
288 SymbolKind::Section => {
289 symbol_offsets[index].aux_count = 1;
290 symtab_count += 1;
291 }
292 _ => {}
293 }
294 if symbol.name.len() > 8 {
295 symbol_offsets[index].str_id = Some(strtab.add(&symbol.name));
296 }
297 }
298
299 // Calculate size of symtab.
300 let symtab_offset = offset;
301 let symtab_len = symtab_count * coff::IMAGE_SIZEOF_SYMBOL;
302 offset += symtab_len;
303
304 // Calculate size of strtab.
305 let strtab_offset = offset;
306 let mut strtab_data = Vec::new();
307 // First 4 bytes of strtab are the length.
308 strtab.write(4, &mut strtab_data);
309 let strtab_len = strtab_data.len() + 4;
310 offset += strtab_len;
311
312 // Start writing.
313 buffer
314 .reserve(offset)
315 .map_err(|_| Error(String::from("Cannot allocate buffer")))?;
316
317 // Write file header.
318 let header = coff::ImageFileHeader {
319 machine: U16::new(
320 LE,
321 match self.architecture {
322 Architecture::Arm => coff::IMAGE_FILE_MACHINE_ARMNT,
323 Architecture::Aarch64 => coff::IMAGE_FILE_MACHINE_ARM64,
324 Architecture::I386 => coff::IMAGE_FILE_MACHINE_I386,
325 Architecture::X86_64 => coff::IMAGE_FILE_MACHINE_AMD64,
326 _ => {
327 return Err(Error(format!(
328 "unimplemented architecture {:?}",
329 self.architecture
330 )));
331 }
332 },
333 ),
334 number_of_sections: U16::new(LE, self.sections.len() as u16),
335 time_date_stamp: U32::default(),
336 pointer_to_symbol_table: U32::new(LE, symtab_offset as u32),
337 number_of_symbols: U32::new(LE, symtab_count as u32),
338 size_of_optional_header: U16::default(),
339 characteristics: match self.flags {
340 FileFlags::Coff { characteristics } => U16::new(LE, characteristics),
341 _ => U16::default(),
342 },
343 };
344 buffer.write(&header);
345
346 // Write section headers.
347 for (index, section) in self.sections.iter().enumerate() {
348 let mut characteristics = if let SectionFlags::Coff {
349 characteristics, ..
350 } = section.flags
351 {
352 characteristics
353 } else {
354 match section.kind {
355 SectionKind::Text => {
356 coff::IMAGE_SCN_CNT_CODE
357 | coff::IMAGE_SCN_MEM_EXECUTE
358 | coff::IMAGE_SCN_MEM_READ
359 }
360 SectionKind::Data => {
361 coff::IMAGE_SCN_CNT_INITIALIZED_DATA
362 | coff::IMAGE_SCN_MEM_READ
363 | coff::IMAGE_SCN_MEM_WRITE
364 }
365 SectionKind::UninitializedData => {
366 coff::IMAGE_SCN_CNT_UNINITIALIZED_DATA
367 | coff::IMAGE_SCN_MEM_READ
368 | coff::IMAGE_SCN_MEM_WRITE
369 }
370 SectionKind::ReadOnlyData
371 | SectionKind::ReadOnlyDataWithRel
372 | SectionKind::ReadOnlyString => {
373 coff::IMAGE_SCN_CNT_INITIALIZED_DATA | coff::IMAGE_SCN_MEM_READ
374 }
375 SectionKind::Debug | SectionKind::Other | SectionKind::OtherString => {
376 coff::IMAGE_SCN_CNT_INITIALIZED_DATA
377 | coff::IMAGE_SCN_MEM_READ
378 | coff::IMAGE_SCN_MEM_DISCARDABLE
379 }
380 SectionKind::Linker => coff::IMAGE_SCN_LNK_INFO | coff::IMAGE_SCN_LNK_REMOVE,
381 SectionKind::Common
382 | SectionKind::Tls
383 | SectionKind::UninitializedTls
384 | SectionKind::TlsVariables
385 | SectionKind::Note
386 | SectionKind::Unknown
387 | SectionKind::Metadata
388 | SectionKind::Elf(_) => {
389 return Err(Error(format!(
390 "unimplemented section `{}` kind {:?}",
391 section.name().unwrap_or(""),
392 section.kind
393 )));
394 }
395 }
396 };
397 if section_offsets[index].selection != 0 {
398 characteristics |= coff::IMAGE_SCN_LNK_COMDAT;
399 };
400 if section.relocations.len() > 0xffff {
401 characteristics |= coff::IMAGE_SCN_LNK_NRELOC_OVFL;
402 }
403 characteristics |= match section.align {
404 1 => coff::IMAGE_SCN_ALIGN_1BYTES,
405 2 => coff::IMAGE_SCN_ALIGN_2BYTES,
406 4 => coff::IMAGE_SCN_ALIGN_4BYTES,
407 8 => coff::IMAGE_SCN_ALIGN_8BYTES,
408 16 => coff::IMAGE_SCN_ALIGN_16BYTES,
409 32 => coff::IMAGE_SCN_ALIGN_32BYTES,
410 64 => coff::IMAGE_SCN_ALIGN_64BYTES,
411 128 => coff::IMAGE_SCN_ALIGN_128BYTES,
412 256 => coff::IMAGE_SCN_ALIGN_256BYTES,
413 512 => coff::IMAGE_SCN_ALIGN_512BYTES,
414 1024 => coff::IMAGE_SCN_ALIGN_1024BYTES,
415 2048 => coff::IMAGE_SCN_ALIGN_2048BYTES,
416 4096 => coff::IMAGE_SCN_ALIGN_4096BYTES,
417 8192 => coff::IMAGE_SCN_ALIGN_8192BYTES,
418 _ => {
419 return Err(Error(format!(
420 "unimplemented section `{}` align {}",
421 section.name().unwrap_or(""),
422 section.align
423 )));
424 }
425 };
426 let mut coff_section = coff::ImageSectionHeader {
427 name: [0; 8],
428 virtual_size: U32::default(),
429 virtual_address: U32::default(),
430 size_of_raw_data: U32::new(LE, section.size as u32),
431 pointer_to_raw_data: U32::new(LE, section_offsets[index].offset as u32),
432 pointer_to_relocations: U32::new(LE, section_offsets[index].reloc_offset as u32),
433 pointer_to_linenumbers: U32::default(),
434 number_of_relocations: if section.relocations.len() > 0xffff {
435 U16::new(LE, 0xffff)
436 } else {
437 U16::new(LE, section.relocations.len() as u16)
438 },
439 number_of_linenumbers: U16::default(),
440 characteristics: U32::new(LE, characteristics),
441 };
442 if section.name.len() <= 8 {
443 coff_section.name[..section.name.len()].copy_from_slice(&section.name);
444 } else {
445 let mut str_offset = strtab.get_offset(section_offsets[index].str_id.unwrap());
446 if str_offset <= 9_999_999 {
447 let mut name = [0; 7];
448 let mut len = 0;
449 if str_offset == 0 {
450 name[6] = b'0';
451 len = 1;
452 } else {
453 while str_offset != 0 {
454 let rem = (str_offset % 10) as u8;
455 str_offset /= 10;
456 name[6 - len] = b'0' + rem;
457 len += 1;
458 }
459 }
460 coff_section.name = [0; 8];
461 coff_section.name[0] = b'/';
462 coff_section.name[1..][..len].copy_from_slice(&name[7 - len..]);
463 } else if str_offset as u64 <= 0xf_ffff_ffff {
464 coff_section.name[0] = b'/';
465 coff_section.name[1] = b'/';
466 for i in 0..6 {
467 let rem = (str_offset % 64) as u8;
468 str_offset /= 64;
469 let c = match rem {
470 0..=25 => b'A' + rem,
471 26..=51 => b'a' + rem - 26,
472 52..=61 => b'0' + rem - 52,
473 62 => b'+',
474 63 => b'/',
475 _ => unreachable!(),
476 };
477 coff_section.name[7 - i] = c;
478 }
479 } else {
480 return Err(Error(format!("invalid section name offset {}", str_offset)));
481 }
482 }
483 buffer.write(&coff_section);
484 }
485
486 // Write section data and relocations.
487 for (index, section) in self.sections.iter().enumerate() {
488 let len = section.data.len();
489 if len != 0 {
490 write_align(buffer, 4);
491 debug_assert_eq!(section_offsets[index].offset, buffer.len());
492 buffer.write_bytes(&section.data);
493 }
494
495 if !section.relocations.is_empty() {
496 debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len());
497 if section.relocations.len() > 0xffff {
498 let coff_relocation = coff::ImageRelocation {
499 virtual_address: U32Bytes::new(LE, section.relocations.len() as u32 + 1),
500 symbol_table_index: U32Bytes::new(LE, 0),
501 typ: U16Bytes::new(LE, 0),
502 };
503 buffer.write(&coff_relocation);
504 }
505 for reloc in &section.relocations {
506 //assert!(reloc.implicit_addend);
507 let typ = match self.architecture {
508 Architecture::I386 => match (reloc.kind, reloc.size, reloc.addend) {
509 (RelocationKind::Absolute, 16, 0) => coff::IMAGE_REL_I386_DIR16,
510 (RelocationKind::Relative, 16, 0) => coff::IMAGE_REL_I386_REL16,
511 (RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_I386_DIR32,
512 (RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_I386_DIR32NB,
513 (RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_I386_SECTION,
514 (RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_I386_SECREL,
515 (RelocationKind::SectionOffset, 7, 0) => coff::IMAGE_REL_I386_SECREL7,
516 (RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_I386_REL32,
517 (RelocationKind::Coff(x), _, _) => x,
518 _ => {
519 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
520 }
521 },
522 Architecture::X86_64 => match (reloc.kind, reloc.size, reloc.addend) {
523 (RelocationKind::Absolute, 64, 0) => coff::IMAGE_REL_AMD64_ADDR64,
524 (RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_AMD64_ADDR32,
525 (RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_AMD64_ADDR32NB,
526 (RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_AMD64_REL32,
527 (RelocationKind::Relative, 32, -5) => coff::IMAGE_REL_AMD64_REL32_1,
528 (RelocationKind::Relative, 32, -6) => coff::IMAGE_REL_AMD64_REL32_2,
529 (RelocationKind::Relative, 32, -7) => coff::IMAGE_REL_AMD64_REL32_3,
530 (RelocationKind::Relative, 32, -8) => coff::IMAGE_REL_AMD64_REL32_4,
531 (RelocationKind::Relative, 32, -9) => coff::IMAGE_REL_AMD64_REL32_5,
532 (RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_AMD64_SECTION,
533 (RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_AMD64_SECREL,
534 (RelocationKind::SectionOffset, 7, 0) => coff::IMAGE_REL_AMD64_SECREL7,
535 (RelocationKind::Coff(x), _, _) => x,
536 _ => {
537 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
538 }
539 },
540 Architecture::Arm => match (reloc.kind, reloc.size, reloc.addend) {
541 (RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_ARM_ADDR32,
542 (RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_ARM_ADDR32NB,
543 (RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_ARM_REL32,
544 (RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_ARM_SECTION,
545 (RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_ARM_SECREL,
546 (RelocationKind::Coff(x), _, _) => x,
547 _ => {
548 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
549 }
550 },
551 Architecture::Aarch64 => match (reloc.kind, reloc.size, reloc.addend) {
552 (RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_ARM64_ADDR32,
553 (RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_ARM64_ADDR32NB,
554 (RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_ARM64_SECTION,
555 (RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_ARM64_SECREL,
556 (RelocationKind::Absolute, 64, 0) => coff::IMAGE_REL_ARM64_ADDR64,
557 (RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_ARM64_REL32,
558 (RelocationKind::Coff(x), _, _) => x,
559 _ => {
560 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
561 }
562 },
563 _ => {
564 return Err(Error(format!(
565 "unimplemented architecture {:?}",
566 self.architecture
567 )));
568 }
569 };
570 let coff_relocation = coff::ImageRelocation {
571 virtual_address: U32Bytes::new(LE, reloc.offset as u32),
572 symbol_table_index: U32Bytes::new(
573 LE,
574 symbol_offsets[reloc.symbol.0].index as u32,
575 ),
576 typ: U16Bytes::new(LE, typ),
577 };
578 buffer.write(&coff_relocation);
579 }
580 }
581 }
582
583 // Write symbols.
584 debug_assert_eq!(symtab_offset, buffer.len());
585 for (index, symbol) in self.symbols.iter().enumerate() {
586 let mut name = &symbol.name[..];
587 let section_number = match symbol.section {
588 SymbolSection::None => {
589 debug_assert_eq!(symbol.kind, SymbolKind::File);
590 coff::IMAGE_SYM_DEBUG as u16
591 }
592 SymbolSection::Undefined => coff::IMAGE_SYM_UNDEFINED as u16,
593 SymbolSection::Absolute => coff::IMAGE_SYM_ABSOLUTE as u16,
594 SymbolSection::Common => coff::IMAGE_SYM_UNDEFINED as u16,
595 SymbolSection::Section(id) => id.0 as u16 + 1,
596 };
597 let typ = if symbol.kind == SymbolKind::Text {
598 coff::IMAGE_SYM_DTYPE_FUNCTION << coff::IMAGE_SYM_DTYPE_SHIFT
599 } else {
600 coff::IMAGE_SYM_TYPE_NULL
601 };
602 let storage_class = match symbol.kind {
603 SymbolKind::File => {
604 // Name goes in auxiliary symbol records.
605 name = b".file";
606 coff::IMAGE_SYM_CLASS_FILE
607 }
608 SymbolKind::Section => coff::IMAGE_SYM_CLASS_STATIC,
609 SymbolKind::Label => coff::IMAGE_SYM_CLASS_LABEL,
610 SymbolKind::Text | SymbolKind::Data | SymbolKind::Tls => {
611 match symbol.section {
612 SymbolSection::None => {
613 return Err(Error(format!(
614 "missing section for symbol `{}`",
615 symbol.name().unwrap_or("")
616 )));
617 }
618 SymbolSection::Undefined | SymbolSection::Common => {
619 coff::IMAGE_SYM_CLASS_EXTERNAL
620 }
621 SymbolSection::Absolute | SymbolSection::Section(_) => {
622 match symbol.scope {
623 // TODO: does this need aux symbol records too?
624 _ if symbol.weak => coff::IMAGE_SYM_CLASS_WEAK_EXTERNAL,
625 SymbolScope::Unknown => {
626 return Err(Error(format!(
627 "unimplemented symbol `{}` scope {:?}",
628 symbol.name().unwrap_or(""),
629 symbol.scope
630 )));
631 }
632 SymbolScope::Compilation => coff::IMAGE_SYM_CLASS_STATIC,
633 SymbolScope::Linkage | SymbolScope::Dynamic => {
634 coff::IMAGE_SYM_CLASS_EXTERNAL
635 }
636 }
637 }
638 }
639 }
640 SymbolKind::Unknown | SymbolKind::Null => {
641 return Err(Error(format!(
642 "unimplemented symbol `{}` kind {:?}",
643 symbol.name().unwrap_or(""),
644 symbol.kind
645 )));
646 }
647 };
648 let number_of_aux_symbols = symbol_offsets[index].aux_count;
649 let value = if symbol.section == SymbolSection::Common {
650 symbol.size as u32
651 } else {
652 symbol.value as u32
653 };
654 let mut coff_symbol = coff::ImageSymbol {
655 name: [0; 8],
656 value: U32Bytes::new(LE, value),
657 section_number: U16Bytes::new(LE, section_number),
658 typ: U16Bytes::new(LE, typ),
659 storage_class,
660 number_of_aux_symbols,
661 };
662 if name.len() <= 8 {
663 coff_symbol.name[..name.len()].copy_from_slice(name);
664 } else {
665 let str_offset = strtab.get_offset(symbol_offsets[index].str_id.unwrap());
666 coff_symbol.name[4..8].copy_from_slice(&u32::to_le_bytes(str_offset as u32));
667 }
668 buffer.write(&coff_symbol);
669
670 // Write auxiliary symbols.
671 match symbol.kind {
672 SymbolKind::File => {
673 let aux_len = number_of_aux_symbols as usize * coff::IMAGE_SIZEOF_SYMBOL;
674 debug_assert!(aux_len >= symbol.name.len());
675 let old_len = buffer.len();
676 buffer.write_bytes(&symbol.name);
677 buffer.resize(old_len + aux_len);
678 }
679 SymbolKind::Section => {
680 debug_assert_eq!(number_of_aux_symbols, 1);
681 let section_index = symbol.section.id().unwrap().0;
682 let section = &self.sections[section_index];
683 let aux = coff::ImageAuxSymbolSection {
684 length: U32Bytes::new(LE, section.size as u32),
685 number_of_relocations: if section.relocations.len() > 0xffff {
686 U16Bytes::new(LE, 0xffff)
687 } else {
688 U16Bytes::new(LE, section.relocations.len() as u16)
689 },
690 number_of_linenumbers: U16Bytes::default(),
691 check_sum: U32Bytes::new(LE, checksum(section.data())),
692 number: U16Bytes::new(
693 LE,
694 section_offsets[section_index].associative_section,
695 ),
696 selection: section_offsets[section_index].selection,
697 reserved: 0,
698 // TODO: bigobj
699 high_number: U16Bytes::default(),
700 };
701 buffer.write(&aux);
702 }
703 _ => {
704 debug_assert_eq!(number_of_aux_symbols, 0);
705 }
706 }
707 }
708
709 // Write strtab section.
710 debug_assert_eq!(strtab_offset, buffer.len());
711 buffer.write_bytes(&u32::to_le_bytes(strtab_len as u32));
712 buffer.write_bytes(&strtab_data);
713
714 debug_assert_eq!(offset, buffer.len());
715
716 Ok(())
717 }
718 }
719
720 // JamCRC
721 fn checksum(data: &[u8]) -> u32 {
722 let mut hasher = crc32fast::Hasher::new_with_initial(0xffff_ffff);
723 hasher.update(data);
724 !hasher.finalize()
725 }