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