1 | //! Interface for writing object files. |
2 | //! |
3 | //! This module provides a unified write API for relocatable object files |
4 | //! using [`Object`]. This does not support writing executable files. |
5 | //! This supports the following file formats: COFF, ELF, Mach-O, and XCOFF. |
6 | //! |
7 | //! The submodules define helpers for writing the raw structs. These support |
8 | //! writing both relocatable and executable files. There are writers for |
9 | //! the following file formats: [COFF](coff::Writer), [ELF](elf::Writer), |
10 | //! and [PE](pe::Writer). |
11 | |
12 | use alloc::borrow::Cow; |
13 | use alloc::string::String; |
14 | use alloc::vec::Vec; |
15 | use core::{fmt, result, str}; |
16 | #[cfg (not(feature = "std" ))] |
17 | use hashbrown::HashMap; |
18 | #[cfg (feature = "std" )] |
19 | use std::{boxed::Box, collections::HashMap, error, io}; |
20 | |
21 | use crate::endian::{Endianness, U32, U64}; |
22 | |
23 | pub use crate::common::*; |
24 | |
25 | #[cfg (feature = "coff" )] |
26 | pub mod coff; |
27 | #[cfg (feature = "coff" )] |
28 | pub use coff::CoffExportStyle; |
29 | |
30 | #[cfg (feature = "elf" )] |
31 | pub mod elf; |
32 | |
33 | #[cfg (feature = "macho" )] |
34 | mod macho; |
35 | #[cfg (feature = "macho" )] |
36 | pub use macho::MachOBuildVersion; |
37 | |
38 | #[cfg (feature = "pe" )] |
39 | pub mod pe; |
40 | |
41 | #[cfg (feature = "xcoff" )] |
42 | mod xcoff; |
43 | |
44 | pub(crate) mod string; |
45 | pub use string::StringId; |
46 | |
47 | mod util; |
48 | pub use util::*; |
49 | |
50 | /// The error type used within the write module. |
51 | #[derive (Debug, Clone, PartialEq, Eq)] |
52 | pub struct Error(pub(crate) String); |
53 | |
54 | impl fmt::Display for Error { |
55 | #[inline ] |
56 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
57 | f.write_str(&self.0) |
58 | } |
59 | } |
60 | |
61 | #[cfg (feature = "std" )] |
62 | impl error::Error for Error {} |
63 | #[cfg (all(not(feature = "std" ), core_error))] |
64 | impl core::error::Error for Error {} |
65 | |
66 | /// The result type used within the write module. |
67 | pub type Result<T> = result::Result<T, Error>; |
68 | |
69 | /// A writable relocatable object file. |
70 | #[derive (Debug)] |
71 | pub struct Object<'a> { |
72 | format: BinaryFormat, |
73 | architecture: Architecture, |
74 | sub_architecture: Option<SubArchitecture>, |
75 | endian: Endianness, |
76 | sections: Vec<Section<'a>>, |
77 | standard_sections: HashMap<StandardSection, SectionId>, |
78 | symbols: Vec<Symbol>, |
79 | symbol_map: HashMap<Vec<u8>, SymbolId>, |
80 | comdats: Vec<Comdat>, |
81 | /// File flags that are specific to each file format. |
82 | pub flags: FileFlags, |
83 | /// The symbol name mangling scheme. |
84 | pub mangling: Mangling, |
85 | #[cfg (feature = "coff" )] |
86 | stub_symbols: HashMap<SymbolId, SymbolId>, |
87 | /// Mach-O "_tlv_bootstrap" symbol. |
88 | #[cfg (feature = "macho" )] |
89 | tlv_bootstrap: Option<SymbolId>, |
90 | /// Mach-O CPU subtype. |
91 | #[cfg (feature = "macho" )] |
92 | macho_cpu_subtype: Option<u32>, |
93 | #[cfg (feature = "macho" )] |
94 | macho_build_version: Option<MachOBuildVersion>, |
95 | /// Mach-O MH_SUBSECTIONS_VIA_SYMBOLS flag. Only ever set if format is Mach-O. |
96 | #[cfg (feature = "macho" )] |
97 | macho_subsections_via_symbols: bool, |
98 | } |
99 | |
100 | impl<'a> Object<'a> { |
101 | /// Create an empty object file. |
102 | pub fn new(format: BinaryFormat, architecture: Architecture, endian: Endianness) -> Object<'a> { |
103 | Object { |
104 | format, |
105 | architecture, |
106 | sub_architecture: None, |
107 | endian, |
108 | sections: Vec::new(), |
109 | standard_sections: HashMap::new(), |
110 | symbols: Vec::new(), |
111 | symbol_map: HashMap::new(), |
112 | comdats: Vec::new(), |
113 | flags: FileFlags::None, |
114 | mangling: Mangling::default(format, architecture), |
115 | #[cfg (feature = "coff" )] |
116 | stub_symbols: HashMap::new(), |
117 | #[cfg (feature = "macho" )] |
118 | tlv_bootstrap: None, |
119 | #[cfg (feature = "macho" )] |
120 | macho_cpu_subtype: None, |
121 | #[cfg (feature = "macho" )] |
122 | macho_build_version: None, |
123 | #[cfg (feature = "macho" )] |
124 | macho_subsections_via_symbols: false, |
125 | } |
126 | } |
127 | |
128 | /// Return the file format. |
129 | #[inline ] |
130 | pub fn format(&self) -> BinaryFormat { |
131 | self.format |
132 | } |
133 | |
134 | /// Return the architecture. |
135 | #[inline ] |
136 | pub fn architecture(&self) -> Architecture { |
137 | self.architecture |
138 | } |
139 | |
140 | /// Return the sub-architecture. |
141 | #[inline ] |
142 | pub fn sub_architecture(&self) -> Option<SubArchitecture> { |
143 | self.sub_architecture |
144 | } |
145 | |
146 | /// Specify the sub-architecture. |
147 | pub fn set_sub_architecture(&mut self, sub_architecture: Option<SubArchitecture>) { |
148 | self.sub_architecture = sub_architecture; |
149 | } |
150 | |
151 | /// Return the current mangling setting. |
152 | #[inline ] |
153 | pub fn mangling(&self) -> Mangling { |
154 | self.mangling |
155 | } |
156 | |
157 | /// Specify the mangling setting. |
158 | #[inline ] |
159 | pub fn set_mangling(&mut self, mangling: Mangling) { |
160 | self.mangling = mangling; |
161 | } |
162 | |
163 | /// Return the name for a standard segment. |
164 | /// |
165 | /// This will vary based on the file format. |
166 | #[allow (unused_variables)] |
167 | pub fn segment_name(&self, segment: StandardSegment) -> &'static [u8] { |
168 | match self.format { |
169 | #[cfg (feature = "coff" )] |
170 | BinaryFormat::Coff => &[], |
171 | #[cfg (feature = "elf" )] |
172 | BinaryFormat::Elf => &[], |
173 | #[cfg (feature = "macho" )] |
174 | BinaryFormat::MachO => self.macho_segment_name(segment), |
175 | _ => unimplemented!(), |
176 | } |
177 | } |
178 | |
179 | /// Get the section with the given `SectionId`. |
180 | #[inline ] |
181 | pub fn section(&self, section: SectionId) -> &Section<'a> { |
182 | &self.sections[section.0] |
183 | } |
184 | |
185 | /// Mutably get the section with the given `SectionId`. |
186 | #[inline ] |
187 | pub fn section_mut(&mut self, section: SectionId) -> &mut Section<'a> { |
188 | &mut self.sections[section.0] |
189 | } |
190 | |
191 | /// Set the data for an existing section. |
192 | /// |
193 | /// Must not be called for sections that already have data, or that contain uninitialized data. |
194 | /// `align` must be a power of two. |
195 | pub fn set_section_data<T>(&mut self, section: SectionId, data: T, align: u64) |
196 | where |
197 | T: Into<Cow<'a, [u8]>>, |
198 | { |
199 | self.sections[section.0].set_data(data, align) |
200 | } |
201 | |
202 | /// Append data to an existing section. Returns the section offset of the data. |
203 | /// |
204 | /// Must not be called for sections that contain uninitialized data. |
205 | /// `align` must be a power of two. |
206 | pub fn append_section_data(&mut self, section: SectionId, data: &[u8], align: u64) -> u64 { |
207 | self.sections[section.0].append_data(data, align) |
208 | } |
209 | |
210 | /// Append zero-initialized data to an existing section. Returns the section offset of the data. |
211 | /// |
212 | /// Must not be called for sections that contain initialized data. |
213 | /// `align` must be a power of two. |
214 | pub fn append_section_bss(&mut self, section: SectionId, size: u64, align: u64) -> u64 { |
215 | self.sections[section.0].append_bss(size, align) |
216 | } |
217 | |
218 | /// Return the `SectionId` of a standard section. |
219 | /// |
220 | /// If the section doesn't already exist then it is created. |
221 | pub fn section_id(&mut self, section: StandardSection) -> SectionId { |
222 | self.standard_sections |
223 | .get(§ion) |
224 | .cloned() |
225 | .unwrap_or_else(|| { |
226 | let (segment, name, kind, flags) = self.section_info(section); |
227 | let id = self.add_section(segment.to_vec(), name.to_vec(), kind); |
228 | self.section_mut(id).flags = flags; |
229 | id |
230 | }) |
231 | } |
232 | |
233 | /// Add a new section and return its `SectionId`. |
234 | /// |
235 | /// This also creates a section symbol. |
236 | pub fn add_section(&mut self, segment: Vec<u8>, name: Vec<u8>, kind: SectionKind) -> SectionId { |
237 | let id = SectionId(self.sections.len()); |
238 | self.sections.push(Section { |
239 | segment, |
240 | name, |
241 | kind, |
242 | size: 0, |
243 | align: 1, |
244 | data: Cow::Borrowed(&[]), |
245 | relocations: Vec::new(), |
246 | symbol: None, |
247 | flags: SectionFlags::None, |
248 | }); |
249 | |
250 | // Add to self.standard_sections if required. This may match multiple standard sections. |
251 | let section = &self.sections[id.0]; |
252 | for standard_section in StandardSection::all() { |
253 | if !self.standard_sections.contains_key(standard_section) { |
254 | let (segment, name, kind, _flags) = self.section_info(*standard_section); |
255 | if segment == &*section.segment && name == &*section.name && kind == section.kind { |
256 | self.standard_sections.insert(*standard_section, id); |
257 | } |
258 | } |
259 | } |
260 | |
261 | id |
262 | } |
263 | |
264 | fn section_info( |
265 | &self, |
266 | section: StandardSection, |
267 | ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) { |
268 | match self.format { |
269 | #[cfg (feature = "coff" )] |
270 | BinaryFormat::Coff => self.coff_section_info(section), |
271 | #[cfg (feature = "elf" )] |
272 | BinaryFormat::Elf => self.elf_section_info(section), |
273 | #[cfg (feature = "macho" )] |
274 | BinaryFormat::MachO => self.macho_section_info(section), |
275 | #[cfg (feature = "xcoff" )] |
276 | BinaryFormat::Xcoff => self.xcoff_section_info(section), |
277 | _ => unimplemented!(), |
278 | } |
279 | } |
280 | |
281 | /// Add a subsection. Returns the `SectionId` and section offset of the data. |
282 | /// |
283 | /// For Mach-O, this does not create a subsection, and instead uses the |
284 | /// section from [`Self::section_id`]. Use [`Self::set_subsections_via_symbols`] |
285 | /// to enable subsections via symbols. |
286 | pub fn add_subsection(&mut self, section: StandardSection, name: &[u8]) -> SectionId { |
287 | if self.has_subsections_via_symbols() { |
288 | self.section_id(section) |
289 | } else { |
290 | let (segment, name, kind, flags) = self.subsection_info(section, name); |
291 | let id = self.add_section(segment.to_vec(), name, kind); |
292 | self.section_mut(id).flags = flags; |
293 | id |
294 | } |
295 | } |
296 | |
297 | fn has_subsections_via_symbols(&self) -> bool { |
298 | self.format == BinaryFormat::MachO |
299 | } |
300 | |
301 | /// Enable subsections via symbols if supported. |
302 | /// |
303 | /// This should be called before adding any subsections or symbols. |
304 | /// |
305 | /// For Mach-O, this sets the `MH_SUBSECTIONS_VIA_SYMBOLS` flag. |
306 | /// For other formats, this does nothing. |
307 | pub fn set_subsections_via_symbols(&mut self) { |
308 | #[cfg (feature = "macho" )] |
309 | if self.format == BinaryFormat::MachO { |
310 | self.macho_subsections_via_symbols = true; |
311 | } |
312 | } |
313 | |
314 | fn subsection_info( |
315 | &self, |
316 | section: StandardSection, |
317 | value: &[u8], |
318 | ) -> (&'static [u8], Vec<u8>, SectionKind, SectionFlags) { |
319 | let (segment, section, kind, flags) = self.section_info(section); |
320 | let name = self.subsection_name(section, value); |
321 | (segment, name, kind, flags) |
322 | } |
323 | |
324 | #[allow (unused_variables)] |
325 | fn subsection_name(&self, section: &[u8], value: &[u8]) -> Vec<u8> { |
326 | debug_assert!(!self.has_subsections_via_symbols()); |
327 | match self.format { |
328 | #[cfg (feature = "coff" )] |
329 | BinaryFormat::Coff => self.coff_subsection_name(section, value), |
330 | #[cfg (feature = "elf" )] |
331 | BinaryFormat::Elf => self.elf_subsection_name(section, value), |
332 | _ => unimplemented!(), |
333 | } |
334 | } |
335 | |
336 | /// Get the COMDAT section group with the given `ComdatId`. |
337 | #[inline ] |
338 | pub fn comdat(&self, comdat: ComdatId) -> &Comdat { |
339 | &self.comdats[comdat.0] |
340 | } |
341 | |
342 | /// Mutably get the COMDAT section group with the given `ComdatId`. |
343 | #[inline ] |
344 | pub fn comdat_mut(&mut self, comdat: ComdatId) -> &mut Comdat { |
345 | &mut self.comdats[comdat.0] |
346 | } |
347 | |
348 | /// Add a new COMDAT section group and return its `ComdatId`. |
349 | pub fn add_comdat(&mut self, comdat: Comdat) -> ComdatId { |
350 | let comdat_id = ComdatId(self.comdats.len()); |
351 | self.comdats.push(comdat); |
352 | comdat_id |
353 | } |
354 | |
355 | /// Get the `SymbolId` of the symbol with the given name. |
356 | pub fn symbol_id(&self, name: &[u8]) -> Option<SymbolId> { |
357 | self.symbol_map.get(name).cloned() |
358 | } |
359 | |
360 | /// Get the symbol with the given `SymbolId`. |
361 | #[inline ] |
362 | pub fn symbol(&self, symbol: SymbolId) -> &Symbol { |
363 | &self.symbols[symbol.0] |
364 | } |
365 | |
366 | /// Mutably get the symbol with the given `SymbolId`. |
367 | #[inline ] |
368 | pub fn symbol_mut(&mut self, symbol: SymbolId) -> &mut Symbol { |
369 | &mut self.symbols[symbol.0] |
370 | } |
371 | |
372 | /// Add a new symbol and return its `SymbolId`. |
373 | pub fn add_symbol(&mut self, mut symbol: Symbol) -> SymbolId { |
374 | // Defined symbols must have a scope. |
375 | debug_assert!(symbol.is_undefined() || symbol.scope != SymbolScope::Unknown); |
376 | if symbol.kind == SymbolKind::Section { |
377 | // There can only be one section symbol, but update its flags, since |
378 | // the automatically generated section symbol will have none. |
379 | let symbol_id = self.section_symbol(symbol.section.id().unwrap()); |
380 | if symbol.flags != SymbolFlags::None { |
381 | self.symbol_mut(symbol_id).flags = symbol.flags; |
382 | } |
383 | return symbol_id; |
384 | } |
385 | if !symbol.name.is_empty() |
386 | && (symbol.kind == SymbolKind::Text |
387 | || symbol.kind == SymbolKind::Data |
388 | || symbol.kind == SymbolKind::Tls) |
389 | { |
390 | let unmangled_name = symbol.name.clone(); |
391 | if let Some(prefix) = self.mangling.global_prefix() { |
392 | symbol.name.insert(0, prefix); |
393 | } |
394 | let symbol_id = self.add_raw_symbol(symbol); |
395 | self.symbol_map.insert(unmangled_name, symbol_id); |
396 | symbol_id |
397 | } else { |
398 | self.add_raw_symbol(symbol) |
399 | } |
400 | } |
401 | |
402 | fn add_raw_symbol(&mut self, symbol: Symbol) -> SymbolId { |
403 | let symbol_id = SymbolId(self.symbols.len()); |
404 | self.symbols.push(symbol); |
405 | symbol_id |
406 | } |
407 | |
408 | /// Return true if the file format supports `StandardSection::UninitializedTls`. |
409 | #[inline ] |
410 | pub fn has_uninitialized_tls(&self) -> bool { |
411 | self.format != BinaryFormat::Coff |
412 | } |
413 | |
414 | /// Return true if the file format supports `StandardSection::Common`. |
415 | #[inline ] |
416 | pub fn has_common(&self) -> bool { |
417 | self.format == BinaryFormat::MachO |
418 | } |
419 | |
420 | /// Add a new common symbol and return its `SymbolId`. |
421 | /// |
422 | /// For Mach-O, this appends the symbol to the `__common` section. |
423 | /// |
424 | /// `align` must be a power of two. |
425 | pub fn add_common_symbol(&mut self, mut symbol: Symbol, size: u64, align: u64) -> SymbolId { |
426 | if self.has_common() { |
427 | let symbol_id = self.add_symbol(symbol); |
428 | let section = self.section_id(StandardSection::Common); |
429 | self.add_symbol_bss(symbol_id, section, size, align); |
430 | symbol_id |
431 | } else { |
432 | symbol.section = SymbolSection::Common; |
433 | symbol.size = size; |
434 | self.add_symbol(symbol) |
435 | } |
436 | } |
437 | |
438 | /// Add a new file symbol and return its `SymbolId`. |
439 | pub fn add_file_symbol(&mut self, name: Vec<u8>) -> SymbolId { |
440 | self.add_raw_symbol(Symbol { |
441 | name, |
442 | value: 0, |
443 | size: 0, |
444 | kind: SymbolKind::File, |
445 | scope: SymbolScope::Compilation, |
446 | weak: false, |
447 | section: SymbolSection::None, |
448 | flags: SymbolFlags::None, |
449 | }) |
450 | } |
451 | |
452 | /// Get the symbol for a section. |
453 | pub fn section_symbol(&mut self, section_id: SectionId) -> SymbolId { |
454 | let section = &mut self.sections[section_id.0]; |
455 | if let Some(symbol) = section.symbol { |
456 | return symbol; |
457 | } |
458 | let name = if self.format == BinaryFormat::Coff { |
459 | section.name.clone() |
460 | } else { |
461 | Vec::new() |
462 | }; |
463 | let symbol_id = SymbolId(self.symbols.len()); |
464 | self.symbols.push(Symbol { |
465 | name, |
466 | value: 0, |
467 | size: 0, |
468 | kind: SymbolKind::Section, |
469 | scope: SymbolScope::Compilation, |
470 | weak: false, |
471 | section: SymbolSection::Section(section_id), |
472 | flags: SymbolFlags::None, |
473 | }); |
474 | section.symbol = Some(symbol_id); |
475 | symbol_id |
476 | } |
477 | |
478 | /// Append data to an existing section, and update a symbol to refer to it. |
479 | /// |
480 | /// For Mach-O, this also creates a `__thread_vars` entry for TLS symbols, and the |
481 | /// symbol will indirectly point to the added data via the `__thread_vars` entry. |
482 | /// |
483 | /// For Mach-O, if [`Self::set_subsections_via_symbols`] is enabled, this will |
484 | /// automatically ensure the data size is at least 1. |
485 | /// |
486 | /// Returns the section offset of the data. |
487 | /// |
488 | /// Must not be called for sections that contain uninitialized data. |
489 | /// `align` must be a power of two. |
490 | pub fn add_symbol_data( |
491 | &mut self, |
492 | symbol_id: SymbolId, |
493 | section: SectionId, |
494 | #[cfg_attr (not(feature = "macho" ), allow(unused_mut))] mut data: &[u8], |
495 | align: u64, |
496 | ) -> u64 { |
497 | #[cfg (feature = "macho" )] |
498 | if data.is_empty() && self.macho_subsections_via_symbols { |
499 | data = &[0]; |
500 | } |
501 | let offset = self.append_section_data(section, data, align); |
502 | self.set_symbol_data(symbol_id, section, offset, data.len() as u64); |
503 | offset |
504 | } |
505 | |
506 | /// Append zero-initialized data to an existing section, and update a symbol to refer to it. |
507 | /// |
508 | /// For Mach-O, this also creates a `__thread_vars` entry for TLS symbols, and the |
509 | /// symbol will indirectly point to the added data via the `__thread_vars` entry. |
510 | /// |
511 | /// For Mach-O, if [`Self::set_subsections_via_symbols`] is enabled, this will |
512 | /// automatically ensure the data size is at least 1. |
513 | /// |
514 | /// Returns the section offset of the data. |
515 | /// |
516 | /// Must not be called for sections that contain initialized data. |
517 | /// `align` must be a power of two. |
518 | pub fn add_symbol_bss( |
519 | &mut self, |
520 | symbol_id: SymbolId, |
521 | section: SectionId, |
522 | #[cfg_attr (not(feature = "macho" ), allow(unused_mut))] mut size: u64, |
523 | align: u64, |
524 | ) -> u64 { |
525 | #[cfg (feature = "macho" )] |
526 | if size == 0 && self.macho_subsections_via_symbols { |
527 | size = 1; |
528 | } |
529 | let offset = self.append_section_bss(section, size, align); |
530 | self.set_symbol_data(symbol_id, section, offset, size); |
531 | offset |
532 | } |
533 | |
534 | /// Update a symbol to refer to the given data within a section. |
535 | /// |
536 | /// For Mach-O, this also creates a `__thread_vars` entry for TLS symbols, and the |
537 | /// symbol will indirectly point to the data via the `__thread_vars` entry. |
538 | #[allow (unused_mut)] |
539 | pub fn set_symbol_data( |
540 | &mut self, |
541 | mut symbol_id: SymbolId, |
542 | section: SectionId, |
543 | offset: u64, |
544 | size: u64, |
545 | ) { |
546 | // Defined symbols must have a scope. |
547 | debug_assert!(self.symbol(symbol_id).scope != SymbolScope::Unknown); |
548 | match self.format { |
549 | #[cfg (feature = "macho" )] |
550 | BinaryFormat::MachO => symbol_id = self.macho_add_thread_var(symbol_id), |
551 | _ => {} |
552 | } |
553 | let symbol = self.symbol_mut(symbol_id); |
554 | symbol.value = offset; |
555 | symbol.size = size; |
556 | symbol.section = SymbolSection::Section(section); |
557 | } |
558 | |
559 | /// Convert a symbol to a section symbol and offset. |
560 | /// |
561 | /// Returns `None` if the symbol does not have a section. |
562 | pub fn symbol_section_and_offset(&mut self, symbol_id: SymbolId) -> Option<(SymbolId, u64)> { |
563 | let symbol = self.symbol(symbol_id); |
564 | if symbol.kind == SymbolKind::Section { |
565 | return Some((symbol_id, 0)); |
566 | } |
567 | let symbol_offset = symbol.value; |
568 | let section = symbol.section.id()?; |
569 | let section_symbol = self.section_symbol(section); |
570 | Some((section_symbol, symbol_offset)) |
571 | } |
572 | |
573 | /// Add a relocation to a section. |
574 | /// |
575 | /// Relocations must only be added after the referenced symbols have been added |
576 | /// and defined (if applicable). |
577 | pub fn add_relocation(&mut self, section: SectionId, mut relocation: Relocation) -> Result<()> { |
578 | match self.format { |
579 | #[cfg (feature = "coff" )] |
580 | BinaryFormat::Coff => self.coff_translate_relocation(&mut relocation)?, |
581 | #[cfg (feature = "elf" )] |
582 | BinaryFormat::Elf => self.elf_translate_relocation(&mut relocation)?, |
583 | #[cfg (feature = "macho" )] |
584 | BinaryFormat::MachO => self.macho_translate_relocation(&mut relocation)?, |
585 | #[cfg (feature = "xcoff" )] |
586 | BinaryFormat::Xcoff => self.xcoff_translate_relocation(&mut relocation)?, |
587 | _ => unimplemented!(), |
588 | } |
589 | let implicit = match self.format { |
590 | #[cfg (feature = "coff" )] |
591 | BinaryFormat::Coff => self.coff_adjust_addend(&mut relocation)?, |
592 | #[cfg (feature = "elf" )] |
593 | BinaryFormat::Elf => self.elf_adjust_addend(&mut relocation)?, |
594 | #[cfg (feature = "macho" )] |
595 | BinaryFormat::MachO => self.macho_adjust_addend(&mut relocation)?, |
596 | #[cfg (feature = "xcoff" )] |
597 | BinaryFormat::Xcoff => self.xcoff_adjust_addend(&mut relocation)?, |
598 | _ => unimplemented!(), |
599 | }; |
600 | if implicit && relocation.addend != 0 { |
601 | self.write_relocation_addend(section, &relocation)?; |
602 | relocation.addend = 0; |
603 | } |
604 | self.sections[section.0].relocations.push(relocation); |
605 | Ok(()) |
606 | } |
607 | |
608 | fn write_relocation_addend( |
609 | &mut self, |
610 | section: SectionId, |
611 | relocation: &Relocation, |
612 | ) -> Result<()> { |
613 | let size = match self.format { |
614 | #[cfg (feature = "coff" )] |
615 | BinaryFormat::Coff => self.coff_relocation_size(relocation)?, |
616 | #[cfg (feature = "elf" )] |
617 | BinaryFormat::Elf => self.elf_relocation_size(relocation)?, |
618 | #[cfg (feature = "macho" )] |
619 | BinaryFormat::MachO => self.macho_relocation_size(relocation)?, |
620 | #[cfg (feature = "xcoff" )] |
621 | BinaryFormat::Xcoff => self.xcoff_relocation_size(relocation)?, |
622 | _ => unimplemented!(), |
623 | }; |
624 | let data = self.sections[section.0].data_mut(); |
625 | let offset = relocation.offset as usize; |
626 | match size { |
627 | 32 => data.write_at(offset, &U32::new(self.endian, relocation.addend as u32)), |
628 | 64 => data.write_at(offset, &U64::new(self.endian, relocation.addend as u64)), |
629 | _ => { |
630 | return Err(Error(format!( |
631 | "unimplemented relocation addend {:?}" , |
632 | relocation |
633 | ))); |
634 | } |
635 | } |
636 | .map_err(|_| { |
637 | Error(format!( |
638 | "invalid relocation offset {}+ {} (max {})" , |
639 | relocation.offset, |
640 | size, |
641 | data.len() |
642 | )) |
643 | }) |
644 | } |
645 | |
646 | /// Write the object to a `Vec`. |
647 | pub fn write(&self) -> Result<Vec<u8>> { |
648 | let mut buffer = Vec::new(); |
649 | self.emit(&mut buffer)?; |
650 | Ok(buffer) |
651 | } |
652 | |
653 | /// Write the object to a `Write` implementation. |
654 | /// |
655 | /// Also flushes the writer. |
656 | /// |
657 | /// It is advisable to use a buffered writer like [`BufWriter`](std::io::BufWriter) |
658 | /// instead of an unbuffered writer like [`File`](std::fs::File). |
659 | #[cfg (feature = "std" )] |
660 | pub fn write_stream<W: io::Write>(&self, w: W) -> result::Result<(), Box<dyn error::Error>> { |
661 | let mut stream = StreamingBuffer::new(w); |
662 | self.emit(&mut stream)?; |
663 | stream.result()?; |
664 | stream.into_inner().flush()?; |
665 | Ok(()) |
666 | } |
667 | |
668 | /// Write the object to a `WritableBuffer`. |
669 | pub fn emit(&self, buffer: &mut dyn WritableBuffer) -> Result<()> { |
670 | match self.format { |
671 | #[cfg (feature = "coff" )] |
672 | BinaryFormat::Coff => self.coff_write(buffer), |
673 | #[cfg (feature = "elf" )] |
674 | BinaryFormat::Elf => self.elf_write(buffer), |
675 | #[cfg (feature = "macho" )] |
676 | BinaryFormat::MachO => self.macho_write(buffer), |
677 | #[cfg (feature = "xcoff" )] |
678 | BinaryFormat::Xcoff => self.xcoff_write(buffer), |
679 | _ => unimplemented!(), |
680 | } |
681 | } |
682 | } |
683 | |
684 | /// A standard segment kind. |
685 | #[allow (missing_docs)] |
686 | #[derive (Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
687 | #[non_exhaustive ] |
688 | pub enum StandardSegment { |
689 | Text, |
690 | Data, |
691 | Debug, |
692 | } |
693 | |
694 | /// A standard section kind. |
695 | #[allow (missing_docs)] |
696 | #[derive (Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
697 | #[non_exhaustive ] |
698 | pub enum StandardSection { |
699 | Text, |
700 | Data, |
701 | ReadOnlyData, |
702 | ReadOnlyDataWithRel, |
703 | ReadOnlyString, |
704 | UninitializedData, |
705 | Tls, |
706 | /// Zero-fill TLS initializers. Unsupported for COFF. |
707 | UninitializedTls, |
708 | /// TLS variable structures. Only supported for Mach-O. |
709 | TlsVariables, |
710 | /// Common data. Only supported for Mach-O. |
711 | Common, |
712 | /// Notes for GNU properties. Only supported for ELF. |
713 | GnuProperty, |
714 | } |
715 | |
716 | impl StandardSection { |
717 | /// Return the section kind of a standard section. |
718 | pub fn kind(self) -> SectionKind { |
719 | match self { |
720 | StandardSection::Text => SectionKind::Text, |
721 | StandardSection::Data => SectionKind::Data, |
722 | StandardSection::ReadOnlyData => SectionKind::ReadOnlyData, |
723 | StandardSection::ReadOnlyDataWithRel => SectionKind::ReadOnlyDataWithRel, |
724 | StandardSection::ReadOnlyString => SectionKind::ReadOnlyString, |
725 | StandardSection::UninitializedData => SectionKind::UninitializedData, |
726 | StandardSection::Tls => SectionKind::Tls, |
727 | StandardSection::UninitializedTls => SectionKind::UninitializedTls, |
728 | StandardSection::TlsVariables => SectionKind::TlsVariables, |
729 | StandardSection::Common => SectionKind::Common, |
730 | StandardSection::GnuProperty => SectionKind::Note, |
731 | } |
732 | } |
733 | |
734 | // TODO: remembering to update this is error-prone, can we do better? |
735 | fn all() -> &'static [StandardSection] { |
736 | &[ |
737 | StandardSection::Text, |
738 | StandardSection::Data, |
739 | StandardSection::ReadOnlyData, |
740 | StandardSection::ReadOnlyDataWithRel, |
741 | StandardSection::ReadOnlyString, |
742 | StandardSection::UninitializedData, |
743 | StandardSection::Tls, |
744 | StandardSection::UninitializedTls, |
745 | StandardSection::TlsVariables, |
746 | StandardSection::Common, |
747 | StandardSection::GnuProperty, |
748 | ] |
749 | } |
750 | } |
751 | |
752 | /// An identifier used to reference a section. |
753 | #[derive (Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
754 | pub struct SectionId(usize); |
755 | |
756 | /// A section in an object file. |
757 | #[derive (Debug)] |
758 | pub struct Section<'a> { |
759 | segment: Vec<u8>, |
760 | name: Vec<u8>, |
761 | kind: SectionKind, |
762 | size: u64, |
763 | align: u64, |
764 | data: Cow<'a, [u8]>, |
765 | relocations: Vec<Relocation>, |
766 | symbol: Option<SymbolId>, |
767 | /// Section flags that are specific to each file format. |
768 | pub flags: SectionFlags, |
769 | } |
770 | |
771 | impl<'a> Section<'a> { |
772 | /// Try to convert the name to a utf8 string. |
773 | #[inline ] |
774 | pub fn name(&self) -> Option<&str> { |
775 | str::from_utf8(&self.name).ok() |
776 | } |
777 | |
778 | /// Try to convert the segment to a utf8 string. |
779 | #[inline ] |
780 | pub fn segment(&self) -> Option<&str> { |
781 | str::from_utf8(&self.segment).ok() |
782 | } |
783 | |
784 | /// Return true if this section contains zerofill data. |
785 | #[inline ] |
786 | pub fn is_bss(&self) -> bool { |
787 | self.kind.is_bss() |
788 | } |
789 | |
790 | /// Set the data for a section. |
791 | /// |
792 | /// Must not be called for sections that already have data, or that contain uninitialized data. |
793 | /// `align` must be a power of two. |
794 | pub fn set_data<T>(&mut self, data: T, align: u64) |
795 | where |
796 | T: Into<Cow<'a, [u8]>>, |
797 | { |
798 | debug_assert!(!self.is_bss()); |
799 | debug_assert_eq!(align & (align - 1), 0); |
800 | debug_assert!(self.data.is_empty()); |
801 | self.data = data.into(); |
802 | self.size = self.data.len() as u64; |
803 | self.align = align; |
804 | } |
805 | |
806 | /// Append data to a section. |
807 | /// |
808 | /// Must not be called for sections that contain uninitialized data. |
809 | /// `align` must be a power of two. |
810 | pub fn append_data(&mut self, append_data: &[u8], align: u64) -> u64 { |
811 | debug_assert!(!self.is_bss()); |
812 | debug_assert_eq!(align & (align - 1), 0); |
813 | if self.align < align { |
814 | self.align = align; |
815 | } |
816 | let align = align as usize; |
817 | let data = self.data.to_mut(); |
818 | let mut offset = data.len(); |
819 | if offset & (align - 1) != 0 { |
820 | offset += align - (offset & (align - 1)); |
821 | data.resize(offset, 0); |
822 | } |
823 | data.extend_from_slice(append_data); |
824 | self.size = data.len() as u64; |
825 | offset as u64 |
826 | } |
827 | |
828 | /// Append uninitialized data to a section. |
829 | /// |
830 | /// Must not be called for sections that contain initialized data. |
831 | /// `align` must be a power of two. |
832 | pub fn append_bss(&mut self, size: u64, align: u64) -> u64 { |
833 | debug_assert!(self.is_bss()); |
834 | debug_assert_eq!(align & (align - 1), 0); |
835 | if self.align < align { |
836 | self.align = align; |
837 | } |
838 | let mut offset = self.size; |
839 | if offset & (align - 1) != 0 { |
840 | offset += align - (offset & (align - 1)); |
841 | self.size = offset; |
842 | } |
843 | self.size += size; |
844 | offset |
845 | } |
846 | |
847 | /// Returns the section as-built so far. |
848 | /// |
849 | /// This requires that the section is not a bss section. |
850 | pub fn data(&self) -> &[u8] { |
851 | debug_assert!(!self.is_bss()); |
852 | &self.data |
853 | } |
854 | |
855 | /// Returns the section as-built so far. |
856 | /// |
857 | /// This requires that the section is not a bss section. |
858 | pub fn data_mut(&mut self) -> &mut [u8] { |
859 | debug_assert!(!self.is_bss()); |
860 | self.data.to_mut() |
861 | } |
862 | } |
863 | |
864 | /// The section where a symbol is defined. |
865 | #[derive (Debug, Clone, Copy, PartialEq, Eq, Hash)] |
866 | #[non_exhaustive ] |
867 | pub enum SymbolSection { |
868 | /// The section is not applicable for this symbol (such as file symbols). |
869 | None, |
870 | /// The symbol is undefined. |
871 | Undefined, |
872 | /// The symbol has an absolute value. |
873 | Absolute, |
874 | /// The symbol is a zero-initialized symbol that will be combined with duplicate definitions. |
875 | Common, |
876 | /// The symbol is defined in the given section. |
877 | Section(SectionId), |
878 | } |
879 | |
880 | impl SymbolSection { |
881 | /// Returns the section id for the section where the symbol is defined. |
882 | /// |
883 | /// May return `None` if the symbol is not defined in a section. |
884 | #[inline ] |
885 | pub fn id(self) -> Option<SectionId> { |
886 | if let SymbolSection::Section(id: SectionId) = self { |
887 | Some(id) |
888 | } else { |
889 | None |
890 | } |
891 | } |
892 | } |
893 | |
894 | /// An identifier used to reference a symbol. |
895 | #[derive (Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
896 | pub struct SymbolId(usize); |
897 | |
898 | /// A symbol in an object file. |
899 | #[derive (Debug)] |
900 | pub struct Symbol { |
901 | /// The name of the symbol. |
902 | pub name: Vec<u8>, |
903 | /// The value of the symbol. |
904 | /// |
905 | /// If the symbol defined in a section, then this is the section offset of the symbol. |
906 | pub value: u64, |
907 | /// The size of the symbol. |
908 | pub size: u64, |
909 | /// The kind of the symbol. |
910 | pub kind: SymbolKind, |
911 | /// The scope of the symbol. |
912 | pub scope: SymbolScope, |
913 | /// Whether the symbol has weak binding. |
914 | pub weak: bool, |
915 | /// The section containing the symbol. |
916 | pub section: SymbolSection, |
917 | /// Symbol flags that are specific to each file format. |
918 | pub flags: SymbolFlags<SectionId, SymbolId>, |
919 | } |
920 | |
921 | impl Symbol { |
922 | /// Try to convert the name to a utf8 string. |
923 | #[inline ] |
924 | pub fn name(&self) -> Option<&str> { |
925 | str::from_utf8(&self.name).ok() |
926 | } |
927 | |
928 | /// Return true if the symbol is undefined. |
929 | #[inline ] |
930 | pub fn is_undefined(&self) -> bool { |
931 | self.section == SymbolSection::Undefined |
932 | } |
933 | |
934 | /// Return true if the symbol is common data. |
935 | /// |
936 | /// Note: does not check for `SymbolSection::Section` with `SectionKind::Common`. |
937 | #[inline ] |
938 | pub fn is_common(&self) -> bool { |
939 | self.section == SymbolSection::Common |
940 | } |
941 | |
942 | /// Return true if the symbol scope is local. |
943 | #[inline ] |
944 | pub fn is_local(&self) -> bool { |
945 | self.scope == SymbolScope::Compilation |
946 | } |
947 | } |
948 | |
949 | /// A relocation in an object file. |
950 | #[derive (Debug)] |
951 | pub struct Relocation { |
952 | /// The section offset of the place of the relocation. |
953 | pub offset: u64, |
954 | /// The symbol referred to by the relocation. |
955 | /// |
956 | /// This may be a section symbol. |
957 | pub symbol: SymbolId, |
958 | /// The addend to use in the relocation calculation. |
959 | /// |
960 | /// This may be in addition to an implicit addend stored at the place of the relocation. |
961 | pub addend: i64, |
962 | /// The fields that define the relocation type. |
963 | pub flags: RelocationFlags, |
964 | } |
965 | |
966 | /// An identifier used to reference a COMDAT section group. |
967 | #[derive (Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
968 | pub struct ComdatId(usize); |
969 | |
970 | /// A COMDAT section group. |
971 | #[derive (Debug)] |
972 | pub struct Comdat { |
973 | /// The COMDAT selection kind. |
974 | /// |
975 | /// This determines the way in which the linker resolves multiple definitions of the COMDAT |
976 | /// sections. |
977 | pub kind: ComdatKind, |
978 | /// The COMDAT symbol. |
979 | /// |
980 | /// If this symbol is referenced, then all sections in the group will be included by the |
981 | /// linker. |
982 | pub symbol: SymbolId, |
983 | /// The sections in the group. |
984 | pub sections: Vec<SectionId>, |
985 | } |
986 | |
987 | /// The symbol name mangling scheme. |
988 | #[derive (Debug, Clone, Copy, PartialEq, Eq, Hash)] |
989 | #[non_exhaustive ] |
990 | pub enum Mangling { |
991 | /// No symbol mangling. |
992 | None, |
993 | /// Windows COFF symbol mangling. |
994 | Coff, |
995 | /// Windows COFF i386 symbol mangling. |
996 | CoffI386, |
997 | /// ELF symbol mangling. |
998 | Elf, |
999 | /// Mach-O symbol mangling. |
1000 | MachO, |
1001 | /// Xcoff symbol mangling. |
1002 | Xcoff, |
1003 | } |
1004 | |
1005 | impl Mangling { |
1006 | /// Return the default symboling mangling for the given format and architecture. |
1007 | pub fn default(format: BinaryFormat, architecture: Architecture) -> Self { |
1008 | match (format, architecture) { |
1009 | (BinaryFormat::Coff, Architecture::I386) => Mangling::CoffI386, |
1010 | (BinaryFormat::Coff, _) => Mangling::Coff, |
1011 | (BinaryFormat::Elf, _) => Mangling::Elf, |
1012 | (BinaryFormat::MachO, _) => Mangling::MachO, |
1013 | (BinaryFormat::Xcoff, _) => Mangling::Xcoff, |
1014 | _ => Mangling::None, |
1015 | } |
1016 | } |
1017 | |
1018 | /// Return the prefix to use for global symbols. |
1019 | pub fn global_prefix(self) -> Option<u8> { |
1020 | match self { |
1021 | Mangling::None | Mangling::Elf | Mangling::Coff | Mangling::Xcoff => None, |
1022 | Mangling::CoffI386 | Mangling::MachO => Some(b'_' ), |
1023 | } |
1024 | } |
1025 | } |
1026 | |