]>
Commit | Line | Data |
---|---|---|
f035d41b XL |
1 | use crc32fast; |
2 | use std::mem; | |
3 | use std::vec::Vec; | |
4 | ||
5 | use crate::endian::{LittleEndian as LE, U16Bytes, U32Bytes, U16, U32}; | |
6 | use crate::pe as coff; | |
7 | use crate::pod::BytesMut; | |
8 | use crate::write::string::*; | |
9 | use crate::write::util::*; | |
10 | use crate::write::*; | |
11 | ||
12 | #[derive(Default, Clone, Copy)] | |
13 | struct SectionOffsets { | |
14 | offset: usize, | |
15 | str_id: Option<StringId>, | |
16 | reloc_offset: usize, | |
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 | impl Object { | |
27 | pub(crate) fn coff_section_info( | |
28 | &self, | |
29 | section: StandardSection, | |
30 | ) -> (&'static [u8], &'static [u8], SectionKind) { | |
31 | match section { | |
32 | StandardSection::Text => (&[], &b".text"[..], SectionKind::Text), | |
33 | StandardSection::Data => (&[], &b".data"[..], SectionKind::Data), | |
34 | StandardSection::ReadOnlyData | |
35 | | StandardSection::ReadOnlyDataWithRel | |
36 | | StandardSection::ReadOnlyString => (&[], &b".rdata"[..], SectionKind::ReadOnlyData), | |
37 | StandardSection::UninitializedData => { | |
38 | (&[], &b".bss"[..], SectionKind::UninitializedData) | |
39 | } | |
40 | // TLS sections are data sections with a special name. | |
41 | StandardSection::Tls => (&[], &b".tls$"[..], SectionKind::Data), | |
42 | StandardSection::UninitializedTls => { | |
43 | // Unsupported section. | |
44 | (&[], &[], SectionKind::UninitializedTls) | |
45 | } | |
46 | StandardSection::TlsVariables => { | |
47 | // Unsupported section. | |
48 | (&[], &[], SectionKind::TlsVariables) | |
49 | } | |
50 | StandardSection::Common => { | |
51 | // Unsupported section. | |
52 | (&[], &[], SectionKind::Common) | |
53 | } | |
54 | } | |
55 | } | |
56 | ||
57 | pub(crate) fn coff_subsection_name(&self, section: &[u8], value: &[u8]) -> Vec<u8> { | |
58 | let mut name = section.to_vec(); | |
59 | name.push(b'$'); | |
60 | name.extend(value); | |
61 | name | |
62 | } | |
63 | ||
64 | pub(crate) fn coff_fixup_relocation(&mut self, mut relocation: &mut Relocation) -> i64 { | |
65 | if relocation.kind == RelocationKind::GotRelative { | |
66 | // Use a stub symbol for the relocation instead. | |
67 | // This isn't really a GOT, but it's a similar purpose. | |
68 | // TODO: need to handle DLL imports differently? | |
69 | relocation.kind = RelocationKind::Relative; | |
70 | relocation.symbol = self.coff_add_stub_symbol(relocation.symbol); | |
71 | } else if relocation.kind == RelocationKind::PltRelative { | |
72 | // Windows doesn't need a separate relocation type for | |
73 | // references to functions in import libraries. | |
74 | // For convenience, treat this the same as Relative. | |
75 | relocation.kind = RelocationKind::Relative; | |
76 | } | |
77 | ||
78 | let constant = match self.architecture { | |
79 | Architecture::I386 => match relocation.kind { | |
80 | RelocationKind::Relative => { | |
81 | // IMAGE_REL_I386_REL32 | |
82 | relocation.addend + 4 | |
83 | } | |
84 | _ => relocation.addend, | |
85 | }, | |
86 | Architecture::X86_64 => match relocation.kind { | |
87 | RelocationKind::Relative => { | |
88 | // IMAGE_REL_AMD64_REL32 through to IMAGE_REL_AMD64_REL32_5 | |
89 | if relocation.addend <= -4 && relocation.addend >= -9 { | |
90 | 0 | |
91 | } else { | |
92 | relocation.addend + 4 | |
93 | } | |
94 | } | |
95 | _ => relocation.addend, | |
96 | }, | |
97 | _ => unimplemented!(), | |
98 | }; | |
99 | relocation.addend -= constant; | |
100 | constant | |
101 | } | |
102 | ||
103 | fn coff_add_stub_symbol(&mut self, symbol_id: SymbolId) -> SymbolId { | |
104 | if let Some(stub_id) = self.stub_symbols.get(&symbol_id) { | |
105 | return *stub_id; | |
106 | } | |
107 | let stub_size = self.architecture.address_size().unwrap().bytes(); | |
108 | ||
109 | let mut name = b".rdata$.refptr.".to_vec(); | |
110 | name.extend(&self.symbols[symbol_id.0].name); | |
111 | let section_id = self.add_section(Vec::new(), name, SectionKind::ReadOnlyData); | |
112 | let section = self.section_mut(section_id); | |
113 | section.set_data(vec![0; stub_size as usize], u64::from(stub_size)); | |
114 | section.relocations = vec![Relocation { | |
115 | offset: 0, | |
116 | size: stub_size * 8, | |
117 | kind: RelocationKind::Absolute, | |
118 | encoding: RelocationEncoding::Generic, | |
119 | symbol: symbol_id, | |
120 | addend: 0, | |
121 | }]; | |
122 | ||
123 | let mut name = b".refptr.".to_vec(); | |
124 | name.extend(&self.symbol(symbol_id).name); | |
125 | let stub_id = self.add_raw_symbol(Symbol { | |
126 | name, | |
127 | value: 0, | |
128 | size: u64::from(stub_size), | |
129 | kind: SymbolKind::Data, | |
130 | scope: SymbolScope::Compilation, | |
131 | weak: false, | |
132 | section: SymbolSection::Section(section_id), | |
133 | flags: SymbolFlags::None, | |
134 | }); | |
135 | self.stub_symbols.insert(symbol_id, stub_id); | |
136 | ||
137 | stub_id | |
138 | } | |
139 | ||
140 | pub(crate) fn coff_write(&self) -> Result<Vec<u8>> { | |
141 | // Calculate offsets of everything, and build strtab. | |
142 | let mut offset = 0; | |
143 | let mut strtab = StringTable::default(); | |
144 | ||
145 | // COFF header. | |
146 | offset += mem::size_of::<coff::ImageFileHeader>(); | |
147 | ||
148 | // Section headers. | |
149 | offset += self.sections.len() * mem::size_of::<coff::ImageSectionHeader>(); | |
150 | ||
151 | // Calculate size of section data and add section strings to strtab. | |
152 | let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()]; | |
153 | for (index, section) in self.sections.iter().enumerate() { | |
154 | if section.name.len() > 8 { | |
155 | section_offsets[index].str_id = Some(strtab.add(§ion.name)); | |
156 | } | |
157 | ||
158 | let len = section.data.len(); | |
159 | if len != 0 { | |
160 | // TODO: not sure what alignment is required here, but this seems to match LLVM | |
161 | offset = align(offset, 4); | |
162 | section_offsets[index].offset = offset; | |
163 | offset += len; | |
164 | } else { | |
165 | section_offsets[index].offset = 0; | |
166 | } | |
167 | ||
168 | // Calculate size of relocations. | |
169 | let count = section.relocations.len(); | |
170 | if count != 0 { | |
171 | section_offsets[index].reloc_offset = offset; | |
172 | offset += count * mem::size_of::<coff::ImageRelocation>(); | |
173 | } | |
174 | } | |
175 | ||
176 | // Calculate size of symbols and add symbol strings to strtab. | |
177 | let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()]; | |
178 | let mut symtab_count = 0; | |
179 | for (index, symbol) in self.symbols.iter().enumerate() { | |
180 | symbol_offsets[index].index = symtab_count; | |
181 | symtab_count += 1; | |
182 | match symbol.kind { | |
183 | SymbolKind::File => { | |
184 | // Name goes in auxilary symbol records. | |
185 | let aux_count = (symbol.name.len() + coff::IMAGE_SIZEOF_SYMBOL - 1) | |
186 | / coff::IMAGE_SIZEOF_SYMBOL; | |
187 | symbol_offsets[index].aux_count = aux_count as u8; | |
188 | symtab_count += aux_count; | |
189 | // Don't add name to strtab. | |
190 | continue; | |
191 | } | |
192 | SymbolKind::Section => { | |
193 | symbol_offsets[index].aux_count = 1; | |
194 | symtab_count += 1; | |
195 | } | |
196 | _ => {} | |
197 | } | |
198 | if symbol.name.len() > 8 { | |
199 | symbol_offsets[index].str_id = Some(strtab.add(&symbol.name)); | |
200 | } | |
201 | } | |
202 | ||
203 | // Calculate size of symtab. | |
204 | let symtab_offset = offset; | |
205 | let symtab_len = symtab_count * coff::IMAGE_SIZEOF_SYMBOL; | |
206 | offset += symtab_len; | |
207 | ||
208 | // Calculate size of strtab. | |
209 | let strtab_offset = offset; | |
210 | let mut strtab_data = Vec::new(); | |
211 | // First 4 bytes of strtab are the length. | |
212 | strtab.write(4, &mut strtab_data); | |
213 | let strtab_len = strtab_data.len() + 4; | |
214 | offset += strtab_len; | |
215 | ||
216 | // Start writing. | |
217 | let mut buffer = BytesMut(Vec::with_capacity(offset)); | |
218 | ||
219 | // Write file header. | |
220 | let header = coff::ImageFileHeader { | |
221 | machine: U16::new( | |
222 | LE, | |
223 | match self.architecture { | |
224 | Architecture::I386 => coff::IMAGE_FILE_MACHINE_I386, | |
225 | Architecture::X86_64 => coff::IMAGE_FILE_MACHINE_AMD64, | |
226 | _ => { | |
227 | return Err(Error(format!( | |
228 | "unimplemented architecture {:?}", | |
229 | self.architecture | |
230 | ))); | |
231 | } | |
232 | }, | |
233 | ), | |
234 | number_of_sections: U16::new(LE, self.sections.len() as u16), | |
235 | time_date_stamp: U32::default(), | |
236 | pointer_to_symbol_table: U32::new(LE, symtab_offset as u32), | |
237 | number_of_symbols: U32::new(LE, symtab_count as u32), | |
238 | size_of_optional_header: U16::default(), | |
239 | characteristics: match self.flags { | |
240 | FileFlags::Coff { characteristics } => U16::new(LE, characteristics), | |
241 | _ => U16::default(), | |
242 | }, | |
243 | }; | |
244 | buffer.write(&header); | |
245 | ||
246 | // Write section headers. | |
247 | for (index, section) in self.sections.iter().enumerate() { | |
248 | // TODO: IMAGE_SCN_LNK_COMDAT | |
249 | let characteristics = match section.flags { | |
250 | SectionFlags::Coff { | |
251 | characteristics, .. | |
252 | } => characteristics, | |
253 | _ => 0, | |
254 | } | match section.kind { | |
255 | SectionKind::Text => { | |
256 | coff::IMAGE_SCN_CNT_CODE | |
257 | | coff::IMAGE_SCN_MEM_EXECUTE | |
258 | | coff::IMAGE_SCN_MEM_READ | |
259 | } | |
260 | SectionKind::Data => { | |
261 | coff::IMAGE_SCN_CNT_INITIALIZED_DATA | |
262 | | coff::IMAGE_SCN_MEM_READ | |
263 | | coff::IMAGE_SCN_MEM_WRITE | |
264 | } | |
265 | SectionKind::UninitializedData => { | |
266 | coff::IMAGE_SCN_CNT_UNINITIALIZED_DATA | |
267 | | coff::IMAGE_SCN_MEM_READ | |
268 | | coff::IMAGE_SCN_MEM_WRITE | |
269 | } | |
270 | SectionKind::ReadOnlyData | SectionKind::ReadOnlyString => { | |
271 | coff::IMAGE_SCN_CNT_INITIALIZED_DATA | coff::IMAGE_SCN_MEM_READ | |
272 | } | |
273 | SectionKind::Debug | SectionKind::Other | SectionKind::OtherString => { | |
274 | coff::IMAGE_SCN_CNT_INITIALIZED_DATA | |
275 | | coff::IMAGE_SCN_MEM_READ | |
276 | | coff::IMAGE_SCN_MEM_DISCARDABLE | |
277 | } | |
278 | SectionKind::Linker => coff::IMAGE_SCN_LNK_INFO | coff::IMAGE_SCN_LNK_REMOVE, | |
279 | SectionKind::Common | |
280 | | SectionKind::Tls | |
281 | | SectionKind::UninitializedTls | |
282 | | SectionKind::TlsVariables | |
283 | | SectionKind::Note | |
284 | | SectionKind::Unknown | |
285 | | SectionKind::Metadata => { | |
286 | return Err(Error(format!( | |
287 | "unimplemented section `{}` kind {:?}", | |
288 | section.name().unwrap_or(""), | |
289 | section.kind | |
290 | ))); | |
291 | } | |
292 | } | match section.align { | |
293 | 1 => coff::IMAGE_SCN_ALIGN_1BYTES, | |
294 | 2 => coff::IMAGE_SCN_ALIGN_2BYTES, | |
295 | 4 => coff::IMAGE_SCN_ALIGN_4BYTES, | |
296 | 8 => coff::IMAGE_SCN_ALIGN_8BYTES, | |
297 | 16 => coff::IMAGE_SCN_ALIGN_16BYTES, | |
298 | 32 => coff::IMAGE_SCN_ALIGN_32BYTES, | |
299 | 64 => coff::IMAGE_SCN_ALIGN_64BYTES, | |
300 | 128 => coff::IMAGE_SCN_ALIGN_128BYTES, | |
301 | 256 => coff::IMAGE_SCN_ALIGN_256BYTES, | |
302 | 512 => coff::IMAGE_SCN_ALIGN_512BYTES, | |
303 | 1024 => coff::IMAGE_SCN_ALIGN_1024BYTES, | |
304 | 2048 => coff::IMAGE_SCN_ALIGN_2048BYTES, | |
305 | 4096 => coff::IMAGE_SCN_ALIGN_4096BYTES, | |
306 | 8192 => coff::IMAGE_SCN_ALIGN_8192BYTES, | |
307 | _ => { | |
308 | return Err(Error(format!( | |
309 | "unimplemented section `{}` align {}", | |
310 | section.name().unwrap_or(""), | |
311 | section.align | |
312 | ))); | |
313 | } | |
314 | }; | |
315 | let mut coff_section = coff::ImageSectionHeader { | |
316 | name: [0; 8], | |
317 | virtual_size: U32::default(), | |
318 | virtual_address: U32::default(), | |
319 | size_of_raw_data: U32::new(LE, section.size as u32), | |
320 | pointer_to_raw_data: U32::new(LE, section_offsets[index].offset as u32), | |
321 | pointer_to_relocations: U32::new(LE, section_offsets[index].reloc_offset as u32), | |
322 | pointer_to_linenumbers: U32::default(), | |
323 | number_of_relocations: U16::new(LE, section.relocations.len() as u16), | |
324 | number_of_linenumbers: U16::default(), | |
325 | characteristics: U32::new(LE, characteristics), | |
326 | }; | |
327 | if section.name.len() <= 8 { | |
328 | coff_section.name[..section.name.len()].copy_from_slice(§ion.name); | |
329 | } else { | |
330 | let mut str_offset = strtab.get_offset(section_offsets[index].str_id.unwrap()); | |
331 | if str_offset <= 9_999_999 { | |
332 | let mut name = [0; 7]; | |
333 | let mut len = 0; | |
334 | if str_offset == 0 { | |
335 | name[6] = b'0'; | |
336 | len = 1; | |
337 | } else { | |
338 | while str_offset != 0 { | |
339 | let rem = (str_offset % 10) as u8; | |
340 | str_offset /= 10; | |
341 | name[6 - len] = b'0' + rem; | |
342 | len += 1; | |
343 | } | |
344 | } | |
345 | coff_section.name = [0; 8]; | |
346 | coff_section.name[0] = b'/'; | |
347 | coff_section.name[1..][..len].copy_from_slice(&name[7 - len..]); | |
348 | } else if str_offset as u64 <= 0xfff_fff_fff { | |
349 | coff_section.name[0] = b'/'; | |
350 | coff_section.name[1] = b'/'; | |
351 | for i in 0..6 { | |
352 | let rem = (str_offset % 64) as u8; | |
353 | str_offset /= 64; | |
354 | let c = match rem { | |
355 | 0..=25 => b'A' + rem, | |
356 | 26..=51 => b'a' + rem - 26, | |
357 | 52..=61 => b'0' + rem - 52, | |
358 | 62 => b'+', | |
359 | 63 => b'/', | |
360 | _ => unreachable!(), | |
361 | }; | |
362 | coff_section.name[7 - i] = c; | |
363 | } | |
364 | } else { | |
365 | return Err(Error(format!("invalid section name offset {}", str_offset))); | |
366 | } | |
367 | } | |
368 | buffer.write(&coff_section); | |
369 | } | |
370 | ||
371 | // Write section data and relocations. | |
372 | for (index, section) in self.sections.iter().enumerate() { | |
373 | let len = section.data.len(); | |
374 | if len != 0 { | |
375 | write_align(&mut buffer, 4); | |
376 | debug_assert_eq!(section_offsets[index].offset, buffer.len()); | |
377 | buffer.write_bytes(§ion.data); | |
378 | } | |
379 | ||
380 | if !section.relocations.is_empty() { | |
381 | debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len()); | |
382 | for reloc in §ion.relocations { | |
383 | //assert!(reloc.implicit_addend); | |
384 | let typ = match self.architecture { | |
385 | Architecture::I386 => match (reloc.kind, reloc.size, reloc.addend) { | |
386 | (RelocationKind::Absolute, 16, 0) => coff::IMAGE_REL_I386_DIR16, | |
387 | (RelocationKind::Relative, 16, 0) => coff::IMAGE_REL_I386_REL16, | |
388 | (RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_I386_DIR32, | |
389 | (RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_I386_DIR32NB, | |
390 | (RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_I386_SECTION, | |
391 | (RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_I386_SECREL, | |
392 | (RelocationKind::SectionOffset, 7, 0) => coff::IMAGE_REL_I386_SECREL7, | |
393 | (RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_I386_REL32, | |
394 | (RelocationKind::Coff(x), _, _) => x, | |
395 | _ => { | |
396 | return Err(Error(format!("unimplemented relocation {:?}", reloc))); | |
397 | } | |
398 | }, | |
399 | Architecture::X86_64 => match (reloc.kind, reloc.size, reloc.addend) { | |
400 | (RelocationKind::Absolute, 64, 0) => coff::IMAGE_REL_AMD64_ADDR64, | |
401 | (RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_AMD64_ADDR32, | |
402 | (RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_AMD64_ADDR32NB, | |
403 | (RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_AMD64_REL32, | |
404 | (RelocationKind::Relative, 32, -5) => coff::IMAGE_REL_AMD64_REL32_1, | |
405 | (RelocationKind::Relative, 32, -6) => coff::IMAGE_REL_AMD64_REL32_2, | |
406 | (RelocationKind::Relative, 32, -7) => coff::IMAGE_REL_AMD64_REL32_3, | |
407 | (RelocationKind::Relative, 32, -8) => coff::IMAGE_REL_AMD64_REL32_4, | |
408 | (RelocationKind::Relative, 32, -9) => coff::IMAGE_REL_AMD64_REL32_5, | |
409 | (RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_AMD64_SECTION, | |
410 | (RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_AMD64_SECREL, | |
411 | (RelocationKind::SectionOffset, 7, 0) => coff::IMAGE_REL_AMD64_SECREL7, | |
412 | (RelocationKind::Coff(x), _, _) => x, | |
413 | _ => { | |
414 | return Err(Error(format!("unimplemented relocation {:?}", reloc))); | |
415 | } | |
416 | }, | |
417 | _ => { | |
418 | return Err(Error(format!( | |
419 | "unimplemented architecture {:?}", | |
420 | self.architecture | |
421 | ))); | |
422 | } | |
423 | }; | |
424 | let coff_relocation = coff::ImageRelocation { | |
425 | virtual_address: U32Bytes::new(LE, reloc.offset as u32), | |
426 | symbol_table_index: U32Bytes::new( | |
427 | LE, | |
428 | symbol_offsets[reloc.symbol.0].index as u32, | |
429 | ), | |
430 | typ: U16Bytes::new(LE, typ), | |
431 | }; | |
432 | buffer.write(&coff_relocation); | |
433 | } | |
434 | } | |
435 | } | |
436 | ||
437 | // Write symbols. | |
438 | debug_assert_eq!(symtab_offset, buffer.len()); | |
439 | for (index, symbol) in self.symbols.iter().enumerate() { | |
440 | let mut name = &symbol.name[..]; | |
441 | let section_number = match symbol.section { | |
442 | SymbolSection::None => { | |
443 | debug_assert_eq!(symbol.kind, SymbolKind::File); | |
444 | coff::IMAGE_SYM_DEBUG | |
445 | } | |
446 | SymbolSection::Undefined => coff::IMAGE_SYM_UNDEFINED, | |
447 | SymbolSection::Absolute => coff::IMAGE_SYM_ABSOLUTE, | |
448 | SymbolSection::Common => coff::IMAGE_SYM_UNDEFINED, | |
449 | SymbolSection::Section(id) => id.0 as u16 + 1, | |
450 | }; | |
451 | let typ = if symbol.kind == SymbolKind::Text { | |
452 | coff::IMAGE_SYM_DTYPE_FUNCTION << coff::IMAGE_SYM_DTYPE_SHIFT | |
453 | } else { | |
454 | coff::IMAGE_SYM_TYPE_NULL | |
455 | }; | |
456 | let storage_class = match symbol.kind { | |
457 | SymbolKind::File => { | |
458 | // Name goes in auxilary symbol records. | |
459 | name = b".file"; | |
460 | coff::IMAGE_SYM_CLASS_FILE | |
461 | } | |
462 | SymbolKind::Section => coff::IMAGE_SYM_CLASS_STATIC, | |
463 | SymbolKind::Label => coff::IMAGE_SYM_CLASS_LABEL, | |
464 | SymbolKind::Text | SymbolKind::Data | SymbolKind::Tls => { | |
465 | match symbol.section { | |
466 | SymbolSection::None => { | |
467 | return Err(Error(format!( | |
468 | "missing section for symbol `{}`", | |
469 | symbol.name().unwrap_or("") | |
470 | ))); | |
471 | } | |
472 | SymbolSection::Undefined | SymbolSection::Common => { | |
473 | coff::IMAGE_SYM_CLASS_EXTERNAL | |
474 | } | |
475 | SymbolSection::Absolute | SymbolSection::Section(_) => { | |
476 | match symbol.scope { | |
477 | // TODO: does this need aux symbol records too? | |
478 | _ if symbol.weak => coff::IMAGE_SYM_CLASS_WEAK_EXTERNAL, | |
479 | SymbolScope::Unknown => { | |
480 | return Err(Error(format!( | |
481 | "unimplemented symbol `{}` scope {:?}", | |
482 | symbol.name().unwrap_or(""), | |
483 | symbol.scope | |
484 | ))); | |
485 | } | |
486 | SymbolScope::Compilation => coff::IMAGE_SYM_CLASS_STATIC, | |
487 | SymbolScope::Linkage | SymbolScope::Dynamic => { | |
488 | coff::IMAGE_SYM_CLASS_EXTERNAL | |
489 | } | |
490 | } | |
491 | } | |
492 | } | |
493 | } | |
494 | SymbolKind::Unknown | SymbolKind::Null => { | |
495 | return Err(Error(format!( | |
496 | "unimplemented symbol `{}` kind {:?}", | |
497 | symbol.name().unwrap_or(""), | |
498 | symbol.kind | |
499 | ))); | |
500 | } | |
501 | }; | |
502 | let number_of_aux_symbols = symbol_offsets[index].aux_count; | |
503 | let value = if symbol.section == SymbolSection::Common { | |
504 | symbol.size as u32 | |
505 | } else { | |
506 | symbol.value as u32 | |
507 | }; | |
508 | let mut coff_symbol = coff::ImageSymbol { | |
509 | name: [0; 8], | |
510 | value: U32Bytes::new(LE, value), | |
511 | section_number: U16Bytes::new(LE, section_number as u16), | |
512 | typ: U16Bytes::new(LE, typ), | |
513 | storage_class, | |
514 | number_of_aux_symbols, | |
515 | }; | |
516 | if name.len() <= 8 { | |
517 | coff_symbol.name[..name.len()].copy_from_slice(name); | |
518 | } else { | |
519 | let str_offset = strtab.get_offset(symbol_offsets[index].str_id.unwrap()); | |
520 | coff_symbol.name[4..8].copy_from_slice(&u32::to_le_bytes(str_offset as u32)); | |
521 | } | |
522 | buffer.write(&coff_symbol); | |
523 | ||
524 | // Write auxiliary symbols. | |
525 | match symbol.kind { | |
526 | SymbolKind::File => { | |
527 | let aux_len = number_of_aux_symbols as usize * coff::IMAGE_SIZEOF_SYMBOL; | |
528 | debug_assert!(aux_len >= symbol.name.len()); | |
529 | let old_len = buffer.len(); | |
530 | buffer.extend(&symbol.name); | |
531 | buffer.resize(old_len + aux_len, 0); | |
532 | } | |
533 | SymbolKind::Section => { | |
534 | debug_assert_eq!(number_of_aux_symbols, 1); | |
535 | let section = &self.sections[symbol.section.id().unwrap().0]; | |
536 | let (selection, number) = match symbol.flags { | |
537 | SymbolFlags::CoffSection { | |
538 | selection, | |
539 | associative_section, | |
540 | } => (selection, associative_section.0 as u16), | |
541 | _ => (0, 0), | |
542 | }; | |
543 | let aux = coff::ImageAuxSymbolSection { | |
544 | length: U32Bytes::new(LE, section.size as u32), | |
545 | number_of_relocations: U16Bytes::new(LE, section.relocations.len() as u16), | |
546 | number_of_linenumbers: U16Bytes::default(), | |
547 | check_sum: U32Bytes::new(LE, checksum(§ion.data.0)), | |
548 | number: U16Bytes::new(LE, number), | |
549 | selection, | |
550 | reserved: 0, | |
551 | // TODO: bigobj | |
552 | high_number: U16Bytes::default(), | |
553 | }; | |
554 | buffer.write(&aux); | |
555 | } | |
556 | _ => { | |
557 | debug_assert_eq!(number_of_aux_symbols, 0); | |
558 | } | |
559 | } | |
560 | } | |
561 | ||
562 | // Write strtab section. | |
563 | debug_assert_eq!(strtab_offset, buffer.len()); | |
564 | buffer.extend(&u32::to_le_bytes(strtab_len as u32)); | |
565 | buffer.extend(&strtab_data); | |
566 | ||
567 | Ok(buffer.0) | |
568 | } | |
569 | } | |
570 | ||
571 | // JamCRC | |
572 | fn checksum(data: &[u8]) -> u32 { | |
573 | let mut hasher = crc32fast::Hasher::new_with_initial(0xffff_ffff); | |
574 | hasher.update(data); | |
575 | !hasher.finalize() | |
576 | } |