object_lang/section.rs
1//! Sections: named runs of bytes (or reserved zero-filled space) with a kind, flags,
2//! an alignment, and the relocations that patch them.
3
4use alloc::string::String;
5use alloc::vec::Vec;
6use core::ops::{BitOr, BitOrAssign};
7
8use crate::error::ModelError;
9use crate::reloc::Relocation;
10
11/// What a section holds. The kind decides how a format stores the section (an ELF
12/// section type, a COFF characteristic, a Mach-O section type) and which
13/// [`SectionFlags`] it may carry.
14///
15/// | Kind | Contents | Required flags | Forbidden flags |
16/// |---|---|---|---|
17/// | `Text` | machine code | `ALLOC`, `EXEC` | `TLS` |
18/// | `Data` | writable initialized data | `ALLOC`, `WRITE` | `EXEC` |
19/// | `ReadOnlyData` | constants | `ALLOC` | `WRITE`, `EXEC`, `TLS` |
20/// | `Bss` | zero-filled space, no bytes in the file | `ALLOC` | `EXEC`, `MERGE`, `STRINGS` |
21/// | `Note` | vendor notes | | `WRITE`, `EXEC`, `TLS`, `MERGE`, `STRINGS` |
22/// | `InitArray`, `FiniArray`, `PreinitArray` | pointers to constructors or destructors | `ALLOC`, `WRITE` | `EXEC`, `TLS`, `MERGE`, `STRINGS` |
23/// | `Other` | data not loaded at run time (comments, metadata) | | `ALLOC`, `WRITE`, `EXEC`, `TLS` |
24///
25/// The rule for the first four rows is what makes a kind recoverable from a file:
26/// with `ALLOC`, `EXEC` means code, else `WRITE` means data, else read-only data, and
27/// without `ALLOC` the section is `Other`.
28///
29/// # Examples
30///
31/// ```
32/// use object_lang::{SectionFlags, SectionKind};
33///
34/// assert_eq!(SectionKind::Text.default_flags(), SectionFlags::ALLOC | SectionFlags::EXEC);
35/// assert!(SectionKind::Bss.is_uninitialized());
36/// ```
37#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
38#[non_exhaustive]
39pub enum SectionKind {
40 /// Executable machine code (`.text`).
41 Text,
42 /// Writable, initialized data (`.data`; with [`TLS`](SectionFlags::TLS), `.tdata`).
43 Data,
44 /// Read-only data (`.rodata`).
45 ReadOnlyData,
46 /// Zero-initialized space that takes no room in the file (`.bss`; with
47 /// [`TLS`](SectionFlags::TLS), `.tbss`). Its size is set with
48 /// [`with_bss_size`](Section::with_bss_size) or [`reserve`](Section::reserve).
49 Bss,
50 /// Notes for the loader or tools (`SHT_NOTE` in ELF).
51 Note,
52 /// Pointers to functions run before `main` (`.init_array`).
53 InitArray,
54 /// Pointers to functions run at exit (`.fini_array`).
55 FiniArray,
56 /// Pointers to functions run before shared-library initializers (`.preinit_array`).
57 PreinitArray,
58 /// Data that is not loaded at run time: comments, tool metadata, debug information.
59 Other,
60}
61
62impl SectionKind {
63 /// The flags [`Section::new`] gives a section of this kind: the required flags in
64 /// the table above.
65 ///
66 /// # Examples
67 ///
68 /// ```
69 /// use object_lang::{SectionFlags, SectionKind};
70 ///
71 /// assert_eq!(SectionKind::Data.default_flags(), SectionFlags::ALLOC | SectionFlags::WRITE);
72 /// assert_eq!(SectionKind::Other.default_flags(), SectionFlags::empty());
73 /// ```
74 #[must_use]
75 pub const fn default_flags(self) -> SectionFlags {
76 match self {
77 SectionKind::Text => SectionFlags(SectionFlags::ALLOC.0 | SectionFlags::EXEC.0),
78 SectionKind::Data
79 | SectionKind::Bss
80 | SectionKind::InitArray
81 | SectionKind::FiniArray
82 | SectionKind::PreinitArray => {
83 SectionFlags(SectionFlags::ALLOC.0 | SectionFlags::WRITE.0)
84 }
85 SectionKind::ReadOnlyData => SectionFlags::ALLOC,
86 SectionKind::Note | SectionKind::Other => SectionFlags::empty(),
87 }
88 }
89
90 /// Whether sections of this kind hold no bytes, only a size ([`Bss`](SectionKind::Bss)).
91 ///
92 /// # Examples
93 ///
94 /// ```
95 /// use object_lang::SectionKind;
96 ///
97 /// assert!(SectionKind::Bss.is_uninitialized());
98 /// assert!(!SectionKind::Data.is_uninitialized());
99 /// ```
100 #[must_use]
101 pub const fn is_uninitialized(self) -> bool {
102 matches!(self, SectionKind::Bss)
103 }
104
105 /// Whether `flags` are allowed on a section of this kind (the table on
106 /// [`SectionKind`]).
107 ///
108 /// # Examples
109 ///
110 /// ```
111 /// use object_lang::{SectionFlags, SectionKind};
112 ///
113 /// assert!(SectionKind::Data.allows(SectionFlags::ALLOC | SectionFlags::WRITE | SectionFlags::TLS));
114 /// assert!(!SectionKind::ReadOnlyData.allows(SectionFlags::ALLOC | SectionFlags::WRITE));
115 /// ```
116 #[must_use]
117 pub const fn allows(self, flags: SectionFlags) -> bool {
118 let (required, forbidden) = match self {
119 SectionKind::Text => (
120 SectionFlags::ALLOC.0 | SectionFlags::EXEC.0,
121 SectionFlags::TLS.0,
122 ),
123 SectionKind::Data => (
124 SectionFlags::ALLOC.0 | SectionFlags::WRITE.0,
125 SectionFlags::EXEC.0,
126 ),
127 SectionKind::ReadOnlyData => (
128 SectionFlags::ALLOC.0,
129 SectionFlags::WRITE.0 | SectionFlags::EXEC.0 | SectionFlags::TLS.0,
130 ),
131 SectionKind::Bss => (
132 SectionFlags::ALLOC.0,
133 SectionFlags::EXEC.0 | SectionFlags::MERGE.0 | SectionFlags::STRINGS.0,
134 ),
135 SectionKind::Note => (
136 0,
137 SectionFlags::WRITE.0
138 | SectionFlags::EXEC.0
139 | SectionFlags::TLS.0
140 | SectionFlags::MERGE.0
141 | SectionFlags::STRINGS.0,
142 ),
143 SectionKind::InitArray | SectionKind::FiniArray | SectionKind::PreinitArray => (
144 SectionFlags::ALLOC.0 | SectionFlags::WRITE.0,
145 SectionFlags::EXEC.0
146 | SectionFlags::TLS.0
147 | SectionFlags::MERGE.0
148 | SectionFlags::STRINGS.0,
149 ),
150 SectionKind::Other => (
151 0,
152 SectionFlags::ALLOC.0
153 | SectionFlags::WRITE.0
154 | SectionFlags::EXEC.0
155 | SectionFlags::TLS.0,
156 ),
157 };
158 flags.0 & required == required && flags.0 & forbidden == 0
159 }
160}
161
162/// Attributes of a section, independent of the file format.
163///
164/// A small bit set: combine flags with `|`, test them with
165/// [`contains`](SectionFlags::contains). Which combinations a section may carry depends
166/// on its [`SectionKind`].
167///
168/// # Examples
169///
170/// ```
171/// use object_lang::SectionFlags;
172///
173/// let flags = SectionFlags::ALLOC | SectionFlags::MERGE | SectionFlags::STRINGS;
174/// assert!(flags.contains(SectionFlags::MERGE));
175/// assert!(!flags.contains(SectionFlags::WRITE));
176/// ```
177#[derive(Clone, Copy, PartialEq, Eq, Hash, Default)]
178pub struct SectionFlags(u8);
179
180impl SectionFlags {
181 /// The section occupies memory when the program runs.
182 pub const ALLOC: SectionFlags = SectionFlags(1);
183 /// The section is writable at run time.
184 pub const WRITE: SectionFlags = SectionFlags(1 << 1);
185 /// The section holds executable instructions.
186 pub const EXEC: SectionFlags = SectionFlags(1 << 2);
187 /// The section is a thread-local storage template (`.tdata`, `.tbss`).
188 pub const TLS: SectionFlags = SectionFlags(1 << 3);
189 /// Equal entries of [`entry_size`](Section::entry_size) bytes may be merged by the
190 /// linker. Requires a non-zero entry size.
191 pub const MERGE: SectionFlags = SectionFlags(1 << 4);
192 /// The entries are NUL-terminated strings (with [`MERGE`](SectionFlags::MERGE),
193 /// equal strings may be merged).
194 pub const STRINGS: SectionFlags = SectionFlags(1 << 5);
195
196 const ALL: u8 = (1 << 6) - 1;
197
198 /// No flags.
199 ///
200 /// # Examples
201 ///
202 /// ```
203 /// use object_lang::SectionFlags;
204 ///
205 /// assert!(SectionFlags::empty().is_empty());
206 /// ```
207 #[must_use]
208 pub const fn empty() -> Self {
209 SectionFlags(0)
210 }
211
212 /// Whether every flag in `other` is set in `self`.
213 ///
214 /// # Examples
215 ///
216 /// ```
217 /// use object_lang::SectionFlags;
218 ///
219 /// let rw = SectionFlags::ALLOC | SectionFlags::WRITE;
220 /// assert!(rw.contains(SectionFlags::WRITE));
221 /// assert!(!rw.contains(SectionFlags::WRITE | SectionFlags::EXEC));
222 /// ```
223 #[must_use]
224 pub const fn contains(self, other: SectionFlags) -> bool {
225 self.0 & other.0 == other.0
226 }
227
228 /// Whether no flag is set.
229 ///
230 /// # Examples
231 ///
232 /// ```
233 /// use object_lang::SectionFlags;
234 ///
235 /// assert!(!SectionFlags::ALLOC.is_empty());
236 /// ```
237 #[must_use]
238 pub const fn is_empty(self) -> bool {
239 self.0 == 0
240 }
241
242 /// `self` with every flag of `other` added.
243 ///
244 /// # Examples
245 ///
246 /// ```
247 /// use object_lang::SectionFlags;
248 ///
249 /// assert_eq!(SectionFlags::ALLOC.union(SectionFlags::WRITE), SectionFlags::ALLOC | SectionFlags::WRITE);
250 /// ```
251 #[must_use]
252 pub const fn union(self, other: SectionFlags) -> Self {
253 SectionFlags(self.0 | other.0)
254 }
255
256 /// `self` with every flag of `other` removed.
257 ///
258 /// # Examples
259 ///
260 /// ```
261 /// use object_lang::SectionFlags;
262 ///
263 /// let rw = SectionFlags::ALLOC | SectionFlags::WRITE;
264 /// assert_eq!(rw.difference(SectionFlags::WRITE), SectionFlags::ALLOC);
265 /// ```
266 #[must_use]
267 pub const fn difference(self, other: SectionFlags) -> Self {
268 SectionFlags(self.0 & !other.0)
269 }
270
271 /// The raw bits, one per flag constant, in declaration order from bit 0.
272 ///
273 /// # Examples
274 ///
275 /// ```
276 /// use object_lang::SectionFlags;
277 ///
278 /// assert_eq!(SectionFlags::ALLOC.bits(), 1);
279 /// assert_eq!(SectionFlags::from_bits(0b11), Some(SectionFlags::ALLOC | SectionFlags::WRITE));
280 /// ```
281 #[must_use]
282 pub const fn bits(self) -> u8 {
283 self.0
284 }
285
286 /// The flags with these raw bits, or `None` if a bit names no flag.
287 ///
288 /// # Examples
289 ///
290 /// ```
291 /// use object_lang::SectionFlags;
292 ///
293 /// assert_eq!(SectionFlags::from_bits(0b100), Some(SectionFlags::EXEC));
294 /// assert_eq!(SectionFlags::from_bits(0x80), None);
295 /// ```
296 #[must_use]
297 pub const fn from_bits(bits: u8) -> Option<Self> {
298 if bits & !SectionFlags::ALL == 0 {
299 Some(SectionFlags(bits))
300 } else {
301 None
302 }
303 }
304}
305
306impl BitOr for SectionFlags {
307 type Output = SectionFlags;
308
309 fn bitor(self, rhs: SectionFlags) -> SectionFlags {
310 self.union(rhs)
311 }
312}
313
314impl BitOrAssign for SectionFlags {
315 fn bitor_assign(&mut self, rhs: SectionFlags) {
316 *self = self.union(rhs);
317 }
318}
319
320impl core::fmt::Debug for SectionFlags {
321 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
322 const NAMES: [&str; 6] = ["ALLOC", "WRITE", "EXEC", "TLS", "MERGE", "STRINGS"];
323 if self.0 == 0 {
324 return f.write_str("SectionFlags(empty)");
325 }
326 f.write_str("SectionFlags(")?;
327 let mut first = true;
328 for (bit, name) in NAMES.iter().enumerate() {
329 if self.0 & (1 << bit) != 0 {
330 if !first {
331 f.write_str(" | ")?;
332 }
333 f.write_str(name)?;
334 first = false;
335 }
336 }
337 f.write_str(")")
338 }
339}
340
341/// One section: a name, a [kind](SectionKind), [flags](SectionFlags), an alignment, its
342/// contents (bytes, or for [`Bss`](SectionKind::Bss) only a size), an address, and the
343/// [`Relocation`]s that patch it.
344///
345/// Build one with [`new`](Section::new) and the `with_*` methods, or grow its contents
346/// in place with [`append`](Section::append) and [`reserve`](Section::reserve), which
347/// handle padding and alignment.
348///
349/// In a relocatable object the address is normally zero and offsets within the section
350/// are what symbols and relocations refer to. In an executable, every loadable section
351/// has its final address.
352///
353/// # Examples
354///
355/// ```
356/// use object_lang::{Section, SectionKind};
357///
358/// let mut rodata = Section::new(".rodata", SectionKind::ReadOnlyData);
359/// let hello = rodata.append(b"hello\0", 1)?;
360/// let table = rodata.append(&[1, 0, 0, 0, 2, 0, 0, 0], 8)?;
361/// assert_eq!((hello, table), (0, 8)); // padded up to the table's alignment
362/// assert_eq!(rodata.align(), 8);
363/// assert_eq!(rodata.size(), 16);
364/// # Ok::<(), object_lang::ModelError>(())
365/// ```
366#[derive(Clone, PartialEq, Eq, Debug)]
367pub struct Section {
368 name: String,
369 kind: SectionKind,
370 flags: SectionFlags,
371 align: u64,
372 entry_size: u64,
373 address: u64,
374 data: Vec<u8>,
375 bss_size: u64,
376 relocations: Vec<Relocation>,
377}
378
379impl Section {
380 /// An empty section of this kind, with the kind's [default
381 /// flags](SectionKind::default_flags), alignment 1, address 0, and no relocations.
382 ///
383 /// # Examples
384 ///
385 /// ```
386 /// use object_lang::{Section, SectionKind};
387 ///
388 /// let text = Section::new(".text", SectionKind::Text);
389 /// assert_eq!(text.flags(), SectionKind::Text.default_flags());
390 /// assert_eq!((text.align(), text.size()), (1, 0));
391 /// ```
392 #[must_use]
393 pub fn new(name: impl Into<String>, kind: SectionKind) -> Self {
394 Section {
395 name: name.into(),
396 kind,
397 flags: kind.default_flags(),
398 align: 1,
399 entry_size: 0,
400 address: 0,
401 data: Vec::new(),
402 bss_size: 0,
403 relocations: Vec::new(),
404 }
405 }
406
407 /// Replaces the flags. [`validate`](crate::Object::validate) checks that the kind
408 /// allows them.
409 ///
410 /// # Examples
411 ///
412 /// ```
413 /// use object_lang::{Section, SectionFlags, SectionKind};
414 ///
415 /// let tdata = Section::new(".tdata", SectionKind::Data)
416 /// .with_flags(SectionKind::Data.default_flags() | SectionFlags::TLS);
417 /// assert!(tdata.flags().contains(SectionFlags::TLS));
418 /// ```
419 #[must_use]
420 pub fn with_flags(mut self, flags: SectionFlags) -> Self {
421 self.flags = flags;
422 self
423 }
424
425 /// Sets the alignment in bytes: a power of two, checked by
426 /// [`validate`](crate::Object::validate).
427 ///
428 /// # Examples
429 ///
430 /// ```
431 /// use object_lang::{Section, SectionKind};
432 ///
433 /// assert_eq!(Section::new(".text", SectionKind::Text).with_align(16).align(), 16);
434 /// ```
435 #[must_use]
436 pub fn with_align(mut self, align: u64) -> Self {
437 self.align = align;
438 self
439 }
440
441 /// Sets the size of each entry, for sections of fixed-size entries such as
442 /// [`MERGE`](SectionFlags::MERGE) sections (zero otherwise).
443 ///
444 /// # Examples
445 ///
446 /// ```
447 /// use object_lang::{Section, SectionFlags, SectionKind};
448 ///
449 /// let strings = Section::new(".rodata.str1.1", SectionKind::ReadOnlyData)
450 /// .with_flags(SectionFlags::ALLOC | SectionFlags::MERGE | SectionFlags::STRINGS)
451 /// .with_entry_size(1);
452 /// assert_eq!(strings.entry_size(), 1);
453 /// ```
454 #[must_use]
455 pub fn with_entry_size(mut self, entry_size: u64) -> Self {
456 self.entry_size = entry_size;
457 self
458 }
459
460 /// Sets the address: the final load address in an executable.
461 ///
462 /// # Examples
463 ///
464 /// ```
465 /// use object_lang::{Section, SectionKind};
466 ///
467 /// let text = Section::new(".text", SectionKind::Text).with_address(0x40_1000);
468 /// assert_eq!(text.address(), 0x40_1000);
469 /// ```
470 #[must_use]
471 pub fn with_address(mut self, address: u64) -> Self {
472 self.address = address;
473 self
474 }
475
476 /// Replaces the contents with `data`. Only for kinds that hold bytes;
477 /// [`validate`](crate::Object::validate) refuses data on a [`Bss`](SectionKind::Bss)
478 /// section.
479 ///
480 /// # Examples
481 ///
482 /// ```
483 /// use object_lang::{Section, SectionKind};
484 ///
485 /// let data = Section::new(".data", SectionKind::Data).with_data(vec![1, 2, 3]);
486 /// assert_eq!(data.data(), &[1, 2, 3]);
487 /// ```
488 #[must_use]
489 pub fn with_data(mut self, data: Vec<u8>) -> Self {
490 self.data = data;
491 self
492 }
493
494 /// Sets the size of a [`Bss`](SectionKind::Bss) section; [`validate`](crate::Object::validate)
495 /// refuses a size on other kinds, whose size is their data's length.
496 ///
497 /// # Examples
498 ///
499 /// ```
500 /// use object_lang::{Section, SectionKind};
501 ///
502 /// let bss = Section::new(".bss", SectionKind::Bss).with_bss_size(4096);
503 /// assert_eq!(bss.size(), 4096);
504 /// assert!(bss.data().is_empty());
505 /// ```
506 #[must_use]
507 pub fn with_bss_size(mut self, size: u64) -> Self {
508 self.bss_size = size;
509 self
510 }
511
512 /// Appends `bytes`, first padding with zeros to a multiple of `align`, and returns
513 /// the offset the bytes start at. Raises the section's alignment to `align` if lower.
514 ///
515 /// # Errors
516 ///
517 /// - [`ModelError::InvalidAlignment`] if `align` is not a power of two.
518 /// - [`ModelError::AppendToBss`] if the section is [`Bss`](SectionKind::Bss), which
519 /// holds no bytes; use [`reserve`](Section::reserve).
520 /// - [`ModelError::SizeOverflow`] if the section would outgrow memory.
521 ///
522 /// # Examples
523 ///
524 /// ```
525 /// use object_lang::{Section, SectionKind};
526 ///
527 /// let mut text = Section::new(".text", SectionKind::Text);
528 /// assert_eq!(text.append(&[0x90], 1)?, 0);
529 /// assert_eq!(text.append(&[0xc3], 16)?, 16);
530 /// assert_eq!(text.size(), 17);
531 /// # Ok::<(), object_lang::ModelError>(())
532 /// ```
533 pub fn append(&mut self, bytes: &[u8], align: u64) -> Result<u64, ModelError> {
534 if self.kind.is_uninitialized() {
535 return Err(ModelError::AppendToBss);
536 }
537 let offset = self.next_offset(align)?;
538 let len = u64::try_from(bytes.len()).map_err(|_| ModelError::SizeOverflow)?;
539 let end = offset.checked_add(len).ok_or(ModelError::SizeOverflow)?;
540 self.grow_to(offset, end)?;
541 self.data.extend_from_slice(bytes);
542 self.align = self.align.max(align);
543 Ok(offset)
544 }
545
546 /// Reserves `size` zero bytes at the next multiple of `align` and returns their
547 /// offset. A [`Bss`](SectionKind::Bss) section only grows its size; any other kind
548 /// appends zero bytes. Raises the section's alignment to `align` if lower.
549 ///
550 /// # Errors
551 ///
552 /// - [`ModelError::InvalidAlignment`] if `align` is not a power of two.
553 /// - [`ModelError::SizeOverflow`] if the size would overflow (or, for a section that
554 /// holds bytes, not fit in memory).
555 ///
556 /// # Examples
557 ///
558 /// ```
559 /// use object_lang::{Section, SectionKind};
560 ///
561 /// let mut bss = Section::new(".bss", SectionKind::Bss);
562 /// assert_eq!(bss.reserve(4, 4)?, 0);
563 /// assert_eq!(bss.reserve(8, 8)?, 8);
564 /// assert_eq!(bss.size(), 16);
565 /// # Ok::<(), object_lang::ModelError>(())
566 /// ```
567 pub fn reserve(&mut self, size: u64, align: u64) -> Result<u64, ModelError> {
568 if self.kind.is_uninitialized() {
569 if !align.is_power_of_two() {
570 return Err(ModelError::InvalidAlignment { align });
571 }
572 let offset = align_up(self.bss_size, align).ok_or(ModelError::SizeOverflow)?;
573 self.bss_size = offset.checked_add(size).ok_or(ModelError::SizeOverflow)?;
574 self.align = self.align.max(align);
575 return Ok(offset);
576 }
577 let offset = self.next_offset(align)?;
578 let end = offset.checked_add(size).ok_or(ModelError::SizeOverflow)?;
579 self.grow_to(end, end)?;
580 self.align = self.align.max(align);
581 Ok(offset)
582 }
583
584 /// The offset of the next byte at a multiple of `align` (a power of two).
585 fn next_offset(&self, align: u64) -> Result<u64, ModelError> {
586 if !align.is_power_of_two() {
587 return Err(ModelError::InvalidAlignment { align });
588 }
589 let len = u64::try_from(self.data.len()).map_err(|_| ModelError::SizeOverflow)?;
590 align_up(len, align).ok_or(ModelError::SizeOverflow)
591 }
592
593 /// Zero-fills the data to `fill` bytes, after making room for `end` bytes in all.
594 /// Allocation failure is an error here rather than an abort, so a request for an
595 /// absurd size cannot take the process down; nothing changes on error.
596 fn grow_to(&mut self, fill: u64, end: u64) -> Result<(), ModelError> {
597 let fill = usize::try_from(fill).map_err(|_| ModelError::SizeOverflow)?;
598 let end = usize::try_from(end).map_err(|_| ModelError::SizeOverflow)?;
599 let additional = end.saturating_sub(self.data.len());
600 self.data
601 .try_reserve(additional)
602 .map_err(|_| ModelError::SizeOverflow)?;
603 self.data.resize(fill, 0);
604 Ok(())
605 }
606
607 /// Adds a relocation that patches this section. Checked by
608 /// [`validate`](crate::Object::validate).
609 ///
610 /// # Examples
611 ///
612 /// ```
613 /// use object_lang::{
614 /// Architecture, Object, Relocation, RelocationTarget, Section, SectionKind, Symbol,
615 /// X86_64Reloc,
616 /// };
617 ///
618 /// let mut obj = Object::relocatable(Architecture::X86_64);
619 /// let target = obj.add_symbol(Symbol::undefined("table"));
620 /// let mut data = Section::new(".data", SectionKind::Data).with_data(vec![0; 8]);
621 /// data.add_relocation(Relocation::new(0, X86_64Reloc::Abs64, RelocationTarget::Symbol(target), 0));
622 /// obj.add_section(data);
623 /// assert!(obj.validate().is_ok());
624 /// ```
625 pub fn add_relocation(&mut self, relocation: Relocation) {
626 self.relocations.push(relocation);
627 }
628
629 /// The section's name.
630 ///
631 /// # Examples
632 ///
633 /// ```
634 /// use object_lang::{Section, SectionKind};
635 ///
636 /// assert_eq!(Section::new(".text", SectionKind::Text).name(), ".text");
637 /// ```
638 #[must_use]
639 pub fn name(&self) -> &str {
640 &self.name
641 }
642
643 /// What the section holds.
644 ///
645 /// # Examples
646 ///
647 /// ```
648 /// use object_lang::{Section, SectionKind};
649 ///
650 /// assert_eq!(Section::new(".bss", SectionKind::Bss).kind(), SectionKind::Bss);
651 /// ```
652 #[must_use]
653 pub const fn kind(&self) -> SectionKind {
654 self.kind
655 }
656
657 /// The section's flags.
658 ///
659 /// # Examples
660 ///
661 /// ```
662 /// use object_lang::{Section, SectionFlags, SectionKind};
663 ///
664 /// assert!(Section::new(".text", SectionKind::Text).flags().contains(SectionFlags::EXEC));
665 /// ```
666 #[must_use]
667 pub const fn flags(&self) -> SectionFlags {
668 self.flags
669 }
670
671 /// The alignment in bytes.
672 ///
673 /// # Examples
674 ///
675 /// ```
676 /// use object_lang::{Section, SectionKind};
677 ///
678 /// assert_eq!(Section::new(".data", SectionKind::Data).with_align(8).align(), 8);
679 /// ```
680 #[must_use]
681 pub const fn align(&self) -> u64 {
682 self.align
683 }
684
685 /// The size of each fixed-size entry, or zero.
686 ///
687 /// # Examples
688 ///
689 /// ```
690 /// use object_lang::{Section, SectionKind};
691 ///
692 /// assert_eq!(Section::new(".data", SectionKind::Data).entry_size(), 0);
693 /// ```
694 #[must_use]
695 pub const fn entry_size(&self) -> u64 {
696 self.entry_size
697 }
698
699 /// The address: the load address in an executable, normally zero in a relocatable
700 /// object.
701 ///
702 /// # Examples
703 ///
704 /// ```
705 /// use object_lang::{Section, SectionKind};
706 ///
707 /// assert_eq!(Section::new(".text", SectionKind::Text).address(), 0);
708 /// ```
709 #[must_use]
710 pub const fn address(&self) -> u64 {
711 self.address
712 }
713
714 /// The section's bytes; empty for [`Bss`](SectionKind::Bss).
715 ///
716 /// # Examples
717 ///
718 /// ```
719 /// use object_lang::{Section, SectionKind};
720 ///
721 /// let s = Section::new(".data", SectionKind::Data).with_data(vec![7]);
722 /// assert_eq!(s.data(), &[7]);
723 /// ```
724 #[must_use]
725 pub fn data(&self) -> &[u8] {
726 &self.data
727 }
728
729 /// The size in memory: the length of the data, or a [`Bss`](SectionKind::Bss)
730 /// section's reserved size.
731 ///
732 /// # Examples
733 ///
734 /// ```
735 /// use object_lang::{Section, SectionKind};
736 ///
737 /// assert_eq!(Section::new(".data", SectionKind::Data).with_data(vec![0; 3]).size(), 3);
738 /// assert_eq!(Section::new(".bss", SectionKind::Bss).with_bss_size(9).size(), 9);
739 /// ```
740 #[must_use]
741 pub fn size(&self) -> u64 {
742 if self.kind.is_uninitialized() {
743 self.bss_size
744 } else {
745 // A Vec's length always fits in u64 on supported targets.
746 u64::try_from(self.data.len()).unwrap_or(u64::MAX)
747 }
748 }
749
750 /// The relocations that patch this section, in the order added.
751 ///
752 /// # Examples
753 ///
754 /// ```
755 /// use object_lang::{Section, SectionKind};
756 ///
757 /// assert!(Section::new(".text", SectionKind::Text).relocations().is_empty());
758 /// ```
759 #[must_use]
760 pub fn relocations(&self) -> &[Relocation] {
761 &self.relocations
762 }
763
764 /// The size a [`Bss`](SectionKind::Bss) section was given, whatever its kind (for
765 /// validation, which refuses it on kinds that hold bytes).
766 pub(crate) const fn bss_size(&self) -> u64 {
767 self.bss_size
768 }
769
770 /// Replaces the relocations wholesale (readers attach them after the symbol table
771 /// is known).
772 pub(crate) fn set_relocations(&mut self, relocations: Vec<Relocation>) {
773 self.relocations = relocations;
774 }
775}
776
777/// `value` rounded up to a multiple of `align` (a power of two), or `None` on overflow.
778pub(crate) const fn align_up(value: u64, align: u64) -> Option<u64> {
779 let mask = align.wrapping_sub(1);
780 match value.checked_add(mask) {
781 Some(v) => Some(v & !mask),
782 None => None,
783 }
784}