neotron_loader/
sections.rs

1//! Code and Types for handling Sections
2//!
3//! These are only interesting to linkers.
4
5// ============================================================================
6// Imports
7// ============================================================================
8
9use crate::{Error, Loader, Source};
10
11// ============================================================================
12// Constants
13// ============================================================================
14
15// ============================================================================
16// Static Variables
17// ============================================================================
18
19// ============================================================================
20// Types
21// ============================================================================
22
23/// Represents a section in the section table.
24#[derive(Debug, Clone)]
25pub struct Header {
26    sh_name_offset: u32,
27    sh_type: u32,
28    sh_flags: u32,
29    sh_addr: u32,
30    sh_offset: u32,
31    sh_size: u32,
32    sh_link: u32,
33    sh_info: u32,
34    sh_addralign: u32,
35    sh_entsize: u32,
36}
37
38impl Header {
39    /// Size of a section header entry
40    pub const SIZE_IN_BYTES: u16 = 0x28;
41
42    /// Section header table entry unused
43    pub const SHT_NULL: u32 = 0x0;
44
45    /// Program data    
46    pub const SHT_PROGBITS: u32 = 0x1;
47
48    /// Symbol table
49    pub const SHT_SYMTAB: u32 = 0x2;
50
51    /// String table
52    pub const SHT_STRTAB: u32 = 0x3;
53
54    /// Relocation entries with addends
55    pub const SHT_RELA: u32 = 0x4;
56
57    /// Symbol hash table
58    pub const SHT_HASH: u32 = 0x5;
59
60    /// Dynamic linking information
61    pub const SHT_DYNAMIC: u32 = 0x6;
62
63    /// Notes
64    pub const SHT_NOTE: u32 = 0x7;
65
66    /// Program space with no data (bss)
67    pub const SHT_NOBITS: u32 = 0x8;
68
69    /// Relocation data, no addends
70    pub const SHT_REL: u32 = 0x9;
71
72    /// Dynamic linker symbol table
73    pub const SHT_DYNSYM: u32 = 0x0B;
74
75    /// Array of constructors
76    pub const SHT_INIT_ARRAY: u32 = 0x0E;
77
78    /// Array of destructors
79    pub const SHT_FINI_ARRAY: u32 = 0x0F;
80
81    /// Array of pre-constructors
82    pub const SHT_PREINIT_ARRAY: u32 = 0x10;
83
84    /// Section group
85    pub const SHT_GROUP: u32 = 0x11;
86
87    /// Extended section indicies
88    pub const SHT_SYMTAB_SHNDX: u32 = 0x12;
89
90    /// Create a new section header.
91    pub fn new<DS>(loader: &Loader<DS>, idx: u16) -> Result<Self, Error<DS::Error>>
92    where
93        DS: Source,
94    {
95        let section_table_offset = loader.e_shoff + u32::from(Self::SIZE_IN_BYTES) * u32::from(idx);
96
97        let sh_name_offset = loader.data_source.read_u32_le(section_table_offset)?;
98        let sh_type = loader
99            .data_source
100            .read_u32_le(section_table_offset + 0x04)?;
101        let sh_flags = loader
102            .data_source
103            .read_u32_le(section_table_offset + 0x08)?;
104        let sh_addr = loader
105            .data_source
106            .read_u32_le(section_table_offset + 0x0C)?;
107        let sh_offset = loader
108            .data_source
109            .read_u32_le(section_table_offset + 0x10)?;
110        let sh_size = loader
111            .data_source
112            .read_u32_le(section_table_offset + 0x14)?;
113        let sh_link = loader
114            .data_source
115            .read_u32_le(section_table_offset + 0x18)?;
116        let sh_info = loader
117            .data_source
118            .read_u32_le(section_table_offset + 0x1C)?;
119        let sh_addralign = loader
120            .data_source
121            .read_u32_le(section_table_offset + 0x20)?;
122        let sh_entsize = loader
123            .data_source
124            .read_u32_le(section_table_offset + 0x24)?;
125
126        Ok(Self {
127            sh_name_offset,
128            sh_type,
129            sh_flags,
130            sh_addr,
131            sh_offset,
132            sh_size,
133            sh_link,
134            sh_info,
135            sh_addralign,
136            sh_entsize,
137        })
138    }
139
140    /// Return the `sh_name_offset` field    
141    pub fn sh_name_offset(&self) -> u32 {
142        self.sh_name_offset
143    }
144
145    /// Get the string name for this section.
146    pub fn sh_name<'a, DS: Source>(
147        &self,
148        loader: &Loader<DS>,
149        buffer: &'a mut [u8],
150    ) -> Result<&'a str, Error<DS::Error>> {
151        let string_section_idx = loader.e_shstrndx;
152        let string_section_header = Self::new(loader, string_section_idx)?;
153        let string_start = string_section_header.sh_offset + self.sh_name_offset;
154
155        for b in buffer.iter_mut() {
156            *b = 0x00;
157        }
158
159        loader.data_source.read(string_start, buffer)?;
160
161        // If this returns an error, our buffer doesn't have a null in it. Which means we used all the bytes.
162        let cstr =
163            core::ffi::CStr::from_bytes_until_nul(buffer).map_err(|_| Error::NotEnoughSpace)?;
164
165        if let Ok(s) = cstr.to_str() {
166            Ok(s)
167        } else {
168            Err(Error::InvalidString)
169        }
170    }
171
172    /// Return the `sh_type` field        
173    pub fn sh_type(&self) -> u32 {
174        self.sh_type
175    }
176
177    /// Return the `sh_flags` field        
178    pub fn sh_flags(&self) -> u32 {
179        self.sh_flags
180    }
181
182    /// Return the `sh_addr` field        
183    pub fn sh_addr(&self) -> u32 {
184        self.sh_addr
185    }
186
187    /// Return the `sh_offset` field        
188    pub fn sh_offset(&self) -> u32 {
189        self.sh_offset
190    }
191
192    /// Return the `sh_size` field        
193    pub fn sh_size(&self) -> u32 {
194        self.sh_size
195    }
196
197    /// Return the `sh_link` field        
198    pub fn sh_link(&self) -> u32 {
199        self.sh_link
200    }
201
202    /// Return the `sh_info` field        
203    pub fn sh_info(&self) -> u32 {
204        self.sh_info
205    }
206
207    /// Return the `sh_addralign` field        
208    pub fn sh_addralign(&self) -> u32 {
209        self.sh_addralign
210    }
211
212    /// Return the `sh_entsize` field        
213    pub fn sh_entsize(&self) -> u32 {
214        self.sh_entsize
215    }
216}
217
218// ============================================================================
219// Functions
220// ============================================================================
221
222// ============================================================================
223// Tests
224// ============================================================================
225
226// ============================================================================
227// End of File
228// ============================================================================