]> git.proxmox.com Git - rustc.git/blame - vendor/object-0.20.0/src/write/coff.rs
New upstream version 1.49.0+dfsg1
[rustc.git] / vendor / object-0.20.0 / src / write / coff.rs
CommitLineData
f035d41b
XL
1use crc32fast;
2use std::mem;
3use std::vec::Vec;
4
5use crate::endian::{LittleEndian as LE, U16Bytes, U32Bytes, U16, U32};
6use crate::pe as coff;
7use crate::pod::BytesMut;
8use crate::write::string::*;
9use crate::write::util::*;
10use crate::write::*;
11
12#[derive(Default, Clone, Copy)]
13struct SectionOffsets {
14 offset: usize,
15 str_id: Option<StringId>,
16 reloc_offset: usize,
17}
18
19#[derive(Default, Clone, Copy)]
20struct SymbolOffsets {
21 index: usize,
22 str_id: Option<StringId>,
23 aux_count: u8,
24}
25
26impl 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(&section.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(&section.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(&section.data);
378 }
379
380 if !section.relocations.is_empty() {
381 debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len());
382 for reloc in &section.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(&section.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
572fn checksum(data: &[u8]) -> u32 {
573 let mut hasher = crc32fast::Hasher::new_with_initial(0xffff_ffff);
574 hasher.update(data);
575 !hasher.finalize()
576}