1 | use alloc::vec::Vec; |
2 | |
3 | use crate::pe as coff; |
4 | use crate::write::coff::writer; |
5 | use crate::write::util::*; |
6 | use crate::write::*; |
7 | |
8 | #[derive (Default, Clone, Copy)] |
9 | struct 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)] |
18 | struct SymbolOffsets { |
19 | name: writer::Name, |
20 | index: u32, |
21 | aux_count: u8, |
22 | } |
23 | |
24 | /// Internal format to use for the `.drectve` section containing linker |
25 | /// directives for symbol exports. |
26 | #[derive (Clone, Copy, Debug, PartialEq, Eq)] |
27 | pub enum CoffExportStyle { |
28 | /// MSVC format supported by link.exe and LLD. |
29 | Msvc, |
30 | /// Gnu format supported by GNU LD and LLD. |
31 | Gnu, |
32 | } |
33 | |
34 | impl<'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 | // TLS sections are data sections with a special name. |
57 | StandardSection::Tls => (&[], &b".tls$" [..], SectionKind::Data, SectionFlags::None), |
58 | StandardSection::UninitializedTls => { |
59 | // Unsupported section. |
60 | (&[], &[], SectionKind::UninitializedTls, SectionFlags::None) |
61 | } |
62 | StandardSection::TlsVariables => { |
63 | // Unsupported section. |
64 | (&[], &[], SectionKind::TlsVariables, SectionFlags::None) |
65 | } |
66 | StandardSection::Common => { |
67 | // Unsupported section. |
68 | (&[], &[], SectionKind::Common, SectionFlags::None) |
69 | } |
70 | StandardSection::GnuProperty => { |
71 | // Unsupported section. |
72 | (&[], &[], 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 | // Use a stub symbol for the relocation instead. |
102 | // This isn't really a GOT, but it's a similar purpose. |
103 | // TODO: need to handle DLL imports differently? |
104 | kind = K::Relative; |
105 | reloc.symbol = self.coff_add_stub_symbol(reloc.symbol)?; |
106 | } else if kind == K::PltRelative { |
107 | // Windows doesn't need a separate relocation type for |
108 | // references to functions in import libraries. |
109 | // For convenience, treat this the same as Relative. |
110 | 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 | /// Appends linker directives to the `.drectve` section to tell the linker |
314 | /// to export all symbols with `SymbolScope::Dynamic`. |
315 | /// |
316 | /// This must be called after all symbols have been defined. |
317 | 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 | // Add section strings to strtab. |
345 | 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 | // Set COMDAT flags. |
351 | 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 | // Reserve symbol indices and add symbol strings to strtab. |
394 | 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 | // Name goes in auxiliary symbol records. |
401 | 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 | // Reserve file ranges. |
413 | 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 | // Start writing. |
423 | 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 | // Write section headers. |
447 | 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 | // Write section data and relocations. |
542 | for section in &self.sections { |
543 | writer.write_section(§ion.data); |
544 | |
545 | if !section.relocations.is_empty() { |
546 | //debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len()); |
547 | 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 | // Write symbols. |
564 | 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 | // TODO: does this need aux symbol records too? |
604 | _ 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 | // Write auxiliary symbols. |
644 | 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 | |
679 | // JamCRC |
680 | fn checksum(data: &[u8]) -> u32 { |
681 | let mut hasher: Hasher = crc32fast::Hasher::new_with_initial(init:0xffff_ffff); |
682 | hasher.update(buf:data); |
683 | !hasher.finalize() |
684 | } |
685 | |