Skip to main content

asmkit/core/
section.rs

1use alloc::borrow::Cow;
2
3use crate::AsmError;
4
5use super::buffer::{CodeBuffer, CodeBufferFinalized};
6use super::target::Environment;
7
8/// A named section: its own code buffer plus an alignment requirement.
9///
10/// Sections are emitted independently (each gets its own [`CodeBuffer`], so
11/// labels and fixups stay section-local) and are laid out — concatenated with
12/// alignment — at link time by [`Linker`](crate::core::linker::Linker). A
13/// section name is diagnostic only: the in-memory linker creates one flat
14/// image and does not model per-section read/write/execute permissions.
15pub struct Section {
16    name: Cow<'static, str>,
17    align: u32,
18    buffer: CodeBuffer,
19}
20
21impl Section {
22    /// Creates a section with the given name (conventionally `.text`, `.data`,
23    /// `.rodata`, ...) and alignment for the host target.
24    ///
25    /// Cross-target users should use [`Self::with_env`].
26    pub fn new(name: impl Into<Cow<'static, str>>, align: u32) -> Result<Self, AsmError> {
27        Self::with_env(name, align, Environment::host())
28    }
29
30    /// Creates a section for an explicit target environment.
31    pub fn with_env(
32        name: impl Into<Cow<'static, str>>,
33        align: u32,
34        environment: Environment,
35    ) -> Result<Self, AsmError> {
36        if !align.is_power_of_two() {
37            return Err(AsmError::InvalidArgument);
38        }
39        Ok(Self {
40            name: name.into(),
41            align,
42            buffer: CodeBuffer::new(environment),
43        })
44    }
45
46    pub fn name(&self) -> &str {
47        &self.name
48    }
49
50    pub fn align(&self) -> u32 {
51        self.align
52    }
53
54    pub fn buffer(&self) -> &CodeBuffer {
55        &self.buffer
56    }
57
58    pub fn buffer_mut(&mut self) -> &mut CodeBuffer {
59        &mut self.buffer
60    }
61
62    /// Finalizes the section's buffer, making it ready for linking.
63    pub fn finish(mut self) -> Result<FinalizedSection, AsmError> {
64        Ok(FinalizedSection {
65            name: self.name,
66            align: self.align,
67            code: self.buffer.finish()?,
68        })
69    }
70}
71
72/// A section whose buffer has been finalized, ready for linking.
73pub struct FinalizedSection {
74    pub(crate) name: Cow<'static, str>,
75    pub(crate) align: u32,
76    pub(crate) code: CodeBufferFinalized,
77}
78
79impl FinalizedSection {
80    pub fn name(&self) -> &str {
81        &self.name
82    }
83
84    pub fn align(&self) -> u32 {
85        self.align
86    }
87
88    pub fn code(&self) -> &CodeBufferFinalized {
89        &self.code
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96    use crate::core::arch_traits::Arch;
97
98    #[test]
99    fn section_holds_named_buffer_with_alignment() {
100        let mut section = Section::new(".rodata", 16).unwrap();
101        assert_eq!(section.name(), ".rodata");
102        assert_eq!(section.align(), 16);
103
104        section.buffer_mut().write_u64(0x1122_3344_5566_7788);
105
106        let finalized = section.finish().unwrap();
107        assert_eq!(finalized.name(), ".rodata");
108        assert_eq!(finalized.align(), 16);
109        assert_eq!(
110            finalized.code().data(),
111            &0x1122_3344_5566_7788u64.to_ne_bytes()
112        );
113    }
114
115    #[test]
116    fn section_alignment_must_be_power_of_two() {
117        assert_eq!(
118            Section::new(".text", 3).err(),
119            Some(AsmError::InvalidArgument)
120        );
121    }
122
123    #[test]
124    fn section_preserves_explicit_target() {
125        let section = Section::with_env(".text", 4, Environment::new(Arch::AArch64)).unwrap();
126
127        assert_eq!(section.buffer().env().arch(), Arch::AArch64);
128    }
129}