瀏覽代碼

multiboot2: Implement setting ELF section tag

Niklas Sombert 2 年之前
父節點
當前提交
41428fbe57
共有 3 個文件被更改,包括 58 次插入49 次删除
  1. 8 1
      multiboot2/src/builder/information.rs
  2. 40 31
      multiboot2/src/elf_sections.rs
  3. 10 17
      multiboot2/src/lib.rs

+ 8 - 1
multiboot2/src/builder/information.rs

@@ -1,5 +1,6 @@
 //! Exports item [`Multiboot2InformationBuilder`].
-use crate::{builder::traits::StructAsBytes, CommandLineTag, ModuleTag};
+use crate::builder::traits::StructAsBytes;
+use crate::{CommandLineTag, ElfSectionsTag, ModuleTag};
 
 use alloc::boxed::Box;
 use alloc::vec::Vec;
@@ -10,6 +11,7 @@ use alloc::vec::Vec;
 #[derive(Debug)]
 pub struct Multiboot2InformationBuilder {
     command_line_tag: Option<Box<CommandLineTag>>,
+    elf_sections_tag: Option<Box<ElfSectionsTag>>,
     module_tags: Vec<Box<ModuleTag>>,
 }
 
@@ -17,6 +19,7 @@ impl Multiboot2InformationBuilder {
     pub const fn new() -> Self {
         Self {
             command_line_tag: None,
+            elf_sections_tag: None,
             module_tags: Vec::new(),
         }
     }
@@ -25,6 +28,10 @@ impl Multiboot2InformationBuilder {
         self.command_line_tag = Some(command_line_tag);
     }
 
+    pub fn elf_sections_tag(&mut self, elf_sections_tag: Box<ElfSectionsTag>) {
+        self.elf_sections_tag = Some(elf_sections_tag);
+    }
+
     pub fn add_module_tag(&mut self, module_tag: Box<ModuleTag>) {
         self.module_tags.push(module_tag);
     }

+ 40 - 31
multiboot2/src/elf_sections.rs

@@ -1,36 +1,42 @@
-use crate::tag_type::Tag;
-use crate::TagType;
+use crate::{Tag, TagTrait, TagType, TagTypeId};
+
 use core::fmt::{Debug, Formatter};
+use core::mem::size_of;
 use core::str::Utf8Error;
 
+#[cfg(feature = "builder")]
+use {crate::builder::boxed_dst_tag, alloc::boxed::Box};
+
+const METADATA_SIZE: usize = size_of::<TagTypeId>() + 4 * size_of::<u32>();
+
 /// This tag contains section header table from an ELF kernel.
 ///
 /// The sections iterator is provided via the `sections` method.
-#[derive(Debug)]
+#[derive(Debug, ptr_meta::Pointee)]
+#[repr(C, packed)]
 pub struct ElfSectionsTag {
-    inner: *const ElfSectionsTagInner,
-    offset: usize,
-}
-
-pub unsafe fn elf_sections_tag(tag: &Tag, offset: usize) -> ElfSectionsTag {
-    assert_eq!(TagType::ElfSections.val(), tag.typ);
-    let es = ElfSectionsTag {
-        inner: (tag as *const Tag).offset(1) as *const ElfSectionsTagInner,
-        offset,
-    };
-    assert!((es.get().entry_size * es.get().shndx) <= tag.size);
-    es
-}
-
-#[derive(Clone, Copy, Debug)]
-#[repr(C, packed)] // only repr(C) would add unwanted padding at the end
-struct ElfSectionsTagInner {
+    typ: TagTypeId,
+    pub(crate) size: u32,
     number_of_sections: u32,
-    entry_size: u32,
-    shndx: u32, // string table
+    pub(crate) entry_size: u32,
+    pub(crate) shndx: u32, // string table
+    sections: [u8],
 }
 
 impl ElfSectionsTag {
+    /// Create a new ElfSectionsTag with the given data.
+    #[cfg(feature = "builder")]
+    pub fn new(number_of_sections: u32, entry_size: u32, shndx: u32, sections: &[u8]) -> Box<Self> {
+        let mut bytes = [
+            number_of_sections.to_le_bytes(),
+            entry_size.to_le_bytes(),
+            shndx.to_le_bytes(),
+        ]
+        .concat();
+        bytes.extend_from_slice(sections);
+        boxed_dst_tag(TagType::ElfSections, &bytes)
+    }
+
     /// Get an iterator of loaded ELF sections.
     ///
     /// # Examples
@@ -39,31 +45,34 @@ impl ElfSectionsTag {
     /// # let boot_info = unsafe { multiboot2::load(0xdeadbeef).unwrap() };
     /// if let Some(elf_tag) = boot_info.elf_sections_tag() {
     ///     let mut total = 0;
-    ///     for section in elf_tag.sections() {
+    ///     for section in elf_tag.sections(0) {
     ///         println!("Section: {:?}", section);
     ///         total += 1;
     ///     }
     /// }
     /// ```
-    pub fn sections(&self) -> ElfSectionIter {
-        let string_section_offset = (self.get().shndx * self.get().entry_size) as isize;
+    pub fn sections(&self, offset: usize) -> ElfSectionIter {
+        let string_section_offset = (self.shndx * self.entry_size) as isize;
         let string_section_ptr =
             unsafe { self.first_section().offset(string_section_offset) as *const _ };
         ElfSectionIter {
             current_section: self.first_section(),
-            remaining_sections: self.get().number_of_sections,
-            entry_size: self.get().entry_size,
+            remaining_sections: self.number_of_sections,
+            entry_size: self.entry_size,
             string_section: string_section_ptr,
-            offset: self.offset,
+            offset,
         }
     }
 
     fn first_section(&self) -> *const u8 {
-        (unsafe { self.inner.offset(1) }) as *const _
+        &(self.sections[0]) as *const _
     }
+}
 
-    fn get(&self) -> &ElfSectionsTagInner {
-        unsafe { &*self.inner }
+impl TagTrait for ElfSectionsTag {
+    fn dst_size(base_tag: &Tag) -> usize {
+        assert!(base_tag.size as usize >= METADATA_SIZE);
+        base_tag.size as usize - METADATA_SIZE
     }
 }
 

+ 10 - 17
multiboot2/src/lib.rs

@@ -232,9 +232,12 @@ impl BootInformation {
     }
 
     /// Search for the ELF Sections tag.
-    pub fn elf_sections_tag(&self) -> Option<ElfSectionsTag> {
-        self.get_tag::<Tag, _>(TagType::ElfSections)
-            .map(|tag| unsafe { elf_sections::elf_sections_tag(tag, self.offset) })
+    pub fn elf_sections_tag(&self) -> Option<&ElfSectionsTag> {
+        let tag = self.get_tag::<ElfSectionsTag, _>(TagType::ElfSections);
+        if let Some(t) = tag {
+            assert!((t.entry_size * t.shndx) <= t.size);
+        }
+        tag
     }
 
     /// Search for the Memory map tag.
@@ -445,7 +448,7 @@ impl fmt::Debug for BootInformation {
 
         let elf_sections_tag_entries_count = self
             .elf_sections_tag()
-            .map(|x| x.sections().count())
+            .map(|x| x.sections(self.offset).count())
             .unwrap_or(0);
 
         if elf_sections_tag_entries_count > ELF_SECTIONS_LIMIT {
@@ -455,7 +458,7 @@ impl fmt::Debug for BootInformation {
                 "elf_sections_tags",
                 &self
                     .elf_sections_tag()
-                    .map(|x| x.sections())
+                    .map(|x| x.sections(self.offset))
                     .unwrap_or_default(),
             );
         }
@@ -1262,7 +1265,7 @@ mod tests {
         assert_eq!(addr + bytes.len(), bi.end_address());
         assert_eq!(bytes.len(), bi.total_size());
         let es = bi.elf_sections_tag().unwrap();
-        let mut s = es.sections();
+        let mut s = es.sections(bi.offset);
         let s1 = s.next().expect("Should have one more section");
         assert_eq!(".rodata", s1.name().expect("Should be valid utf-8"));
         assert_eq!(0xFFFF_8000_0010_0000, s1.start_address());
@@ -1447,7 +1450,7 @@ mod tests {
         assert_eq!(addr + bytes.0.len(), bi.end_address());
         assert_eq!(bytes.0.len(), bi.total_size());
         let es = bi.elf_sections_tag().unwrap();
-        let mut s = es.sections();
+        let mut s = es.sections(bi.offset);
         let s1 = s.next().expect("Should have one more section");
         assert_eq!(".shstrtab", s1.name().expect("Should be valid utf-8"));
         assert_eq!(string_addr, s1.start_address());
@@ -1458,16 +1461,6 @@ mod tests {
         assert!(s.next().is_none());
     }
 
-    #[test]
-    /// Compile time test for `ElfSectionsTag`.
-    fn elf_sections_tag_size() {
-        use super::ElfSectionsTag;
-        unsafe {
-            // `ElfSectionsTagInner` is 12 bytes + 4 in the offset.
-            core::mem::transmute::<[u8; 16], ElfSectionsTag>([0u8; 16]);
-        }
-    }
-
     #[test]
     fn efi_memory_map() {
         use memory_map::EFIMemoryAreaType;