1 | //! Interface for writing object files. |
2 | |
3 | use alloc::borrow::Cow; |
4 | use alloc::string::String; |
5 | use alloc::vec::Vec; |
6 | use core::{fmt, result, str}; |
7 | #[cfg (not(feature = "std" ))] |
8 | use hashbrown::HashMap; |
9 | #[cfg (feature = "std" )] |
10 | use std::{boxed::Box, collections::HashMap, error, io}; |
11 | |
12 | use crate::endian::{Endianness, U32, U64}; |
13 | use crate::{ |
14 | Architecture, BinaryFormat, ComdatKind, FileFlags, RelocationEncoding, RelocationKind, |
15 | SectionFlags, SectionKind, SubArchitecture, SymbolFlags, SymbolKind, SymbolScope, |
16 | }; |
17 | |
18 | #[cfg (feature = "coff" )] |
19 | pub mod coff; |
20 | #[cfg (feature = "coff" )] |
21 | pub use coff::CoffExportStyle; |
22 | |
23 | #[cfg (feature = "elf" )] |
24 | pub mod elf; |
25 | |
26 | #[cfg (feature = "macho" )] |
27 | mod macho; |
28 | #[cfg (feature = "macho" )] |
29 | pub use macho::MachOBuildVersion; |
30 | |
31 | #[cfg (feature = "pe" )] |
32 | pub mod pe; |
33 | |
34 | #[cfg (feature = "xcoff" )] |
35 | mod xcoff; |
36 | |
37 | mod string; |
38 | pub use string::StringId; |
39 | |
40 | mod util; |
41 | pub use util::*; |
42 | |
43 | /// The error type used within the write module. |
44 | #[derive (Debug, Clone, PartialEq, Eq)] |
45 | pub struct Error(String); |
46 | |
47 | impl 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" )] |
55 | impl error::Error for Error {} |
56 | |
57 | /// The result type used within the write module. |
58 | pub type Result<T> = result::Result<T, Error>; |
59 | |
60 | /// A writable relocatable object file. |
61 | #[derive (Debug)] |
62 | pub 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 | |
86 | impl<'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(§ion) |
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 ] |
623 | pub 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 ] |
633 | pub 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 | |
651 | impl 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)] |
689 | pub struct SectionId(usize); |
690 | |
691 | /// A section in an object file. |
692 | #[derive (Debug)] |
693 | pub 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 | |
706 | impl<'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 ] |
799 | pub 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 | |
812 | impl 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)] |
828 | pub struct SymbolId(usize); |
829 | |
830 | /// A symbol in an object file. |
831 | #[derive (Debug)] |
832 | pub 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 | |
853 | impl 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)] |
883 | pub 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)] |
904 | pub struct ComdatId(usize); |
905 | |
906 | /// A COMDAT section group. |
907 | #[derive (Debug)] |
908 | pub 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 ] |
926 | pub 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 | |
941 | impl 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 | |