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