Skip to main content

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}