elf_sections.rs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. //! Module for [`ElfSectionsTag`].
  2. #[cfg(feature = "builder")]
  3. use crate::builder::BoxedDst;
  4. use crate::{TagHeader, TagTrait, TagType};
  5. use core::fmt::{Debug, Formatter};
  6. use core::mem;
  7. use core::str::Utf8Error;
  8. const METADATA_SIZE: usize = mem::size_of::<TagHeader>() + 3 * mem::size_of::<u32>();
  9. /// This tag contains the section header table from an ELF binary.
  10. // The sections iterator is provided via the [`ElfSectionsTag::sections`]
  11. // method.
  12. #[derive(ptr_meta::Pointee, PartialEq, Eq)]
  13. #[repr(C, align(8))]
  14. pub struct ElfSectionsTag {
  15. header: TagHeader,
  16. number_of_sections: u32,
  17. pub(crate) entry_size: u32,
  18. pub(crate) shndx: u32, // string table
  19. sections: [u8],
  20. }
  21. impl ElfSectionsTag {
  22. /// Create a new ElfSectionsTag with the given data.
  23. #[cfg(feature = "builder")]
  24. #[must_use]
  25. pub fn new(
  26. number_of_sections: u32,
  27. entry_size: u32,
  28. shndx: u32,
  29. sections: &[u8],
  30. ) -> BoxedDst<Self> {
  31. let mut bytes = [
  32. number_of_sections.to_le_bytes(),
  33. entry_size.to_le_bytes(),
  34. shndx.to_le_bytes(),
  35. ]
  36. .concat();
  37. bytes.extend_from_slice(sections);
  38. BoxedDst::new(&bytes)
  39. }
  40. /// Get an iterator of loaded ELF sections.
  41. pub(crate) const fn sections(&self) -> ElfSectionIter {
  42. let string_section_offset = (self.shndx * self.entry_size) as isize;
  43. let string_section_ptr =
  44. unsafe { self.first_section().offset(string_section_offset) as *const _ };
  45. ElfSectionIter {
  46. current_section: self.first_section(),
  47. remaining_sections: self.number_of_sections,
  48. entry_size: self.entry_size,
  49. string_section: string_section_ptr,
  50. }
  51. }
  52. const fn first_section(&self) -> *const u8 {
  53. &(self.sections[0]) as *const _
  54. }
  55. }
  56. impl TagTrait for ElfSectionsTag {
  57. const ID: TagType = TagType::ElfSections;
  58. fn dst_len(header: &TagHeader) -> usize {
  59. assert!(header.size as usize >= METADATA_SIZE);
  60. header.size as usize - METADATA_SIZE
  61. }
  62. }
  63. impl Debug for ElfSectionsTag {
  64. fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
  65. f.debug_struct("ElfSectionsTag")
  66. .field("typ", &self.header.typ)
  67. .field("size", &self.header.size)
  68. .field("number_of_sections", &self.number_of_sections)
  69. .field("entry_size", &self.entry_size)
  70. .field("shndx", &self.shndx)
  71. .field("sections", &self.sections())
  72. .finish()
  73. }
  74. }
  75. /// An iterator over some ELF sections.
  76. #[derive(Clone)]
  77. /// TODO make this memory safe with lifetime capture.
  78. pub struct ElfSectionIter {
  79. current_section: *const u8,
  80. remaining_sections: u32,
  81. entry_size: u32,
  82. string_section: *const u8,
  83. }
  84. impl Iterator for ElfSectionIter {
  85. type Item = ElfSection;
  86. fn next(&mut self) -> Option<ElfSection> {
  87. while self.remaining_sections != 0 {
  88. let section = ElfSection {
  89. inner: self.current_section,
  90. string_section: self.string_section,
  91. entry_size: self.entry_size,
  92. };
  93. self.current_section = unsafe { self.current_section.offset(self.entry_size as isize) };
  94. self.remaining_sections -= 1;
  95. if section.section_type() != ElfSectionType::Unused {
  96. return Some(section);
  97. }
  98. }
  99. None
  100. }
  101. }
  102. impl Debug for ElfSectionIter {
  103. fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
  104. let mut debug = f.debug_list();
  105. self.clone().for_each(|ref e| {
  106. debug.entry(e);
  107. });
  108. debug.finish()
  109. }
  110. }
  111. impl Default for ElfSectionIter {
  112. fn default() -> Self {
  113. Self {
  114. current_section: core::ptr::null(),
  115. remaining_sections: 0,
  116. entry_size: 0,
  117. string_section: core::ptr::null(),
  118. }
  119. }
  120. }
  121. /// A single generic ELF Section.
  122. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  123. pub struct ElfSection {
  124. inner: *const u8,
  125. string_section: *const u8,
  126. entry_size: u32,
  127. }
  128. #[derive(Clone, Copy, Debug)]
  129. #[repr(C, packed)]
  130. struct ElfSectionInner32 {
  131. name_index: u32,
  132. typ: u32,
  133. flags: u32,
  134. addr: u32,
  135. offset: u32,
  136. size: u32,
  137. link: u32,
  138. info: u32,
  139. addralign: u32,
  140. entry_size: u32,
  141. }
  142. #[derive(Clone, Copy, Debug)]
  143. #[repr(C, packed)]
  144. struct ElfSectionInner64 {
  145. name_index: u32,
  146. typ: u32,
  147. flags: u64,
  148. addr: u64,
  149. offset: u64,
  150. size: u64,
  151. link: u32,
  152. info: u32,
  153. addralign: u64,
  154. entry_size: u64,
  155. }
  156. impl ElfSection {
  157. /// Get the section type as a `ElfSectionType` enum variant.
  158. #[must_use]
  159. pub fn section_type(&self) -> ElfSectionType {
  160. match self.get().typ() {
  161. 0 => ElfSectionType::Unused,
  162. 1 => ElfSectionType::ProgramSection,
  163. 2 => ElfSectionType::LinkerSymbolTable,
  164. 3 => ElfSectionType::StringTable,
  165. 4 => ElfSectionType::RelaRelocation,
  166. 5 => ElfSectionType::SymbolHashTable,
  167. 6 => ElfSectionType::DynamicLinkingTable,
  168. 7 => ElfSectionType::Note,
  169. 8 => ElfSectionType::Uninitialized,
  170. 9 => ElfSectionType::RelRelocation,
  171. 10 => ElfSectionType::Reserved,
  172. 11 => ElfSectionType::DynamicLoaderSymbolTable,
  173. 0x6000_0000..=0x6FFF_FFFF => ElfSectionType::EnvironmentSpecific,
  174. 0x7000_0000..=0x7FFF_FFFF => ElfSectionType::ProcessorSpecific,
  175. e => {
  176. log::warn!(
  177. "Unknown section type {:x}. Treating as ElfSectionType::Unused",
  178. e
  179. );
  180. ElfSectionType::Unused
  181. }
  182. }
  183. }
  184. /// Get the "raw" section type as a `u32`
  185. #[must_use]
  186. pub fn section_type_raw(&self) -> u32 {
  187. self.get().typ()
  188. }
  189. /// Read the name of the section.
  190. pub fn name(&self) -> Result<&str, Utf8Error> {
  191. use core::{slice, str};
  192. let name_ptr = unsafe { self.string_table().offset(self.get().name_index() as isize) };
  193. // strlen without null byte
  194. let strlen = {
  195. let mut len = 0;
  196. while unsafe { *name_ptr.offset(len) } != 0 {
  197. len += 1;
  198. }
  199. len as usize
  200. };
  201. str::from_utf8(unsafe { slice::from_raw_parts(name_ptr, strlen) })
  202. }
  203. /// Get the physical start address of the section.
  204. #[must_use]
  205. pub fn start_address(&self) -> u64 {
  206. self.get().addr()
  207. }
  208. /// Get the physical end address of the section.
  209. ///
  210. /// This is the same as doing `section.start_address() + section.size()`
  211. #[must_use]
  212. pub fn end_address(&self) -> u64 {
  213. self.get().addr() + self.get().size()
  214. }
  215. /// Get the section's size in bytes.
  216. #[must_use]
  217. pub fn size(&self) -> u64 {
  218. self.get().size()
  219. }
  220. /// Get the section's address alignment constraints.
  221. ///
  222. /// That is, the value of `start_address` must be congruent to 0,
  223. /// modulo the value of `addrlign`. Currently, only 0 and positive
  224. /// integral powers of two are allowed. Values 0 and 1 mean the section has no
  225. /// alignment constraints.
  226. #[must_use]
  227. pub fn addralign(&self) -> u64 {
  228. self.get().addralign()
  229. }
  230. /// Get the section's flags.
  231. #[must_use]
  232. pub fn flags(&self) -> ElfSectionFlags {
  233. ElfSectionFlags::from_bits_truncate(self.get().flags())
  234. }
  235. /// Check if the `ALLOCATED` flag is set in the section flags.
  236. #[must_use]
  237. pub fn is_allocated(&self) -> bool {
  238. self.flags().contains(ElfSectionFlags::ALLOCATED)
  239. }
  240. fn get(&self) -> &dyn ElfSectionInner {
  241. match self.entry_size {
  242. 40 => unsafe { &*(self.inner as *const ElfSectionInner32) },
  243. 64 => unsafe { &*(self.inner as *const ElfSectionInner64) },
  244. s => panic!("Unexpected entry size: {}", s),
  245. }
  246. }
  247. unsafe fn string_table(&self) -> *const u8 {
  248. let addr = match self.entry_size {
  249. 40 => (*(self.string_section as *const ElfSectionInner32)).addr as usize,
  250. 64 => (*(self.string_section as *const ElfSectionInner64)).addr as usize,
  251. s => panic!("Unexpected entry size: {}", s),
  252. };
  253. addr as *const _
  254. }
  255. }
  256. trait ElfSectionInner {
  257. fn name_index(&self) -> u32;
  258. fn typ(&self) -> u32;
  259. fn flags(&self) -> u64;
  260. fn addr(&self) -> u64;
  261. fn size(&self) -> u64;
  262. fn addralign(&self) -> u64;
  263. }
  264. impl ElfSectionInner for ElfSectionInner32 {
  265. fn name_index(&self) -> u32 {
  266. self.name_index
  267. }
  268. fn typ(&self) -> u32 {
  269. self.typ
  270. }
  271. fn flags(&self) -> u64 {
  272. self.flags.into()
  273. }
  274. fn addr(&self) -> u64 {
  275. self.addr.into()
  276. }
  277. fn size(&self) -> u64 {
  278. self.size.into()
  279. }
  280. fn addralign(&self) -> u64 {
  281. self.addralign.into()
  282. }
  283. }
  284. impl ElfSectionInner for ElfSectionInner64 {
  285. fn name_index(&self) -> u32 {
  286. self.name_index
  287. }
  288. fn typ(&self) -> u32 {
  289. self.typ
  290. }
  291. fn flags(&self) -> u64 {
  292. self.flags
  293. }
  294. fn addr(&self) -> u64 {
  295. self.addr
  296. }
  297. fn size(&self) -> u64 {
  298. self.size
  299. }
  300. fn addralign(&self) -> u64 {
  301. self.addralign
  302. }
  303. }
  304. /// An enum abstraction over raw ELF section types.
  305. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  306. #[repr(u32)]
  307. pub enum ElfSectionType {
  308. /// This value marks the section header as inactive; it does not have an
  309. /// associated section. Other members of the section header have undefined
  310. /// values.
  311. Unused = 0,
  312. /// The section holds information defined by the program, whose format and
  313. /// meaning are determined solely by the program.
  314. ProgramSection = 1,
  315. /// This section holds a linker symbol table.
  316. LinkerSymbolTable = 2,
  317. /// The section holds a string table.
  318. StringTable = 3,
  319. /// The section holds relocation entries with explicit addends, such as type
  320. /// Elf32_Rela for the 32-bit class of object files. An object file may have
  321. /// multiple relocation sections.
  322. RelaRelocation = 4,
  323. /// The section holds a symbol hash table.
  324. SymbolHashTable = 5,
  325. /// The section holds dynamic linking tables.
  326. DynamicLinkingTable = 6,
  327. /// This section holds information that marks the file in some way.
  328. Note = 7,
  329. /// A section of this type occupies no space in the file but otherwise resembles
  330. /// `ProgramSection`. Although this section contains no bytes, the
  331. /// sh_offset member contains the conceptual file offset.
  332. Uninitialized = 8,
  333. /// The section holds relocation entries without explicit addends, such as type
  334. /// Elf32_Rel for the 32-bit class of object files. An object file may have
  335. /// multiple relocation sections.
  336. RelRelocation = 9,
  337. /// This section type is reserved but has unspecified semantics.
  338. Reserved = 10,
  339. /// This section holds a dynamic loader symbol table.
  340. DynamicLoaderSymbolTable = 11,
  341. /// Values in this inclusive range (`[0x6000_0000, 0x6FFF_FFFF)`) are
  342. /// reserved for environment-specific semantics.
  343. EnvironmentSpecific = 0x6000_0000,
  344. /// Values in this inclusive range (`[0x7000_0000, 0x7FFF_FFFF)`) are
  345. /// reserved for processor-specific semantics.
  346. ProcessorSpecific = 0x7000_0000,
  347. }
  348. bitflags! {
  349. /// ELF Section bitflags.
  350. #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
  351. #[repr(transparent)]
  352. pub struct ElfSectionFlags: u64 {
  353. /// The section contains data that should be writable during program execution.
  354. const WRITABLE = 0x1;
  355. /// The section occupies memory during the process execution.
  356. const ALLOCATED = 0x2;
  357. /// The section contains executable machine instructions.
  358. const EXECUTABLE = 0x4;
  359. // plus environment-specific use at 0x0F000000
  360. // plus processor-specific use at 0xF0000000
  361. }
  362. }