diff --git a/Cargo.lock b/Cargo.lock index e2e5254491bb4f9c4aab15429ae02d5ff22f4bc4..d6a04eb46f5405f57cdca433dedc4b6c95cce6e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -761,14 +761,6 @@ dependencies = [ "sha2", ] -[[package]] -name = "pip-mpu-relocate" -version = "0.1.0" -dependencies = [ - "elf", - "thiserror-core", -] - [[package]] name = "pip-tool" version = "0.1.0" @@ -777,7 +769,7 @@ dependencies = [ "cargo-scaffold", "clap", "elf", - "pip-mpu-relocate", + "thiserror", ] [[package]] @@ -1061,38 +1053,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.58" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] -[[package]] -name = "thiserror-core" -version = "1.0.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c001ee18b7e5e3f62cbf58c7fe220119e68d902bb7443179c0c8aef30090e999" -dependencies = [ - "thiserror-core-impl", -] - -[[package]] -name = "thiserror-core-impl" -version = "1.0.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4c60d69f36615a077cc7663b9cb8e42275722d23e58a7fa3d2c7f2915d09d04" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 7c0c5153f7d2091a997ebe52619212ef6eb977aa..375aed0a8e26704cb9a6270601a438fc058c431c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,5 +20,5 @@ anyhow = "1.0.81" cargo-scaffold = "0.12.0" clap = "4.5.2" elf = "0.7.4" -pip-mpu-relocate = { path = "../pip-mpu-relocate" } +thiserror = "1.0.61" diff --git a/rust-toolchain b/rust-toolchain deleted file mode 100644 index bf867e0ae5b6c08df1118a2ece970677bc479f1b..0000000000000000000000000000000000000000 --- a/rust-toolchain +++ /dev/null @@ -1 +0,0 @@ -nightly diff --git a/src/lib.rs b/src/lib.rs index e5339898300f9a52592315e3e1ae63eae382686a..212f2c992bbda4dbda485af0f96b0f2bf7891f49 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,9 @@ #![doc = include_str!("../README.md")] -mod generate; +mod new; mod link; +mod symbols; +mod rel_iter; use anyhow::Result; use clap::{Parser, Subcommand}; @@ -16,7 +18,7 @@ pub struct Opts { #[derive(Subcommand, Debug)] pub enum PipToolSubcommand { /// Generate a new pip partition project - Generate(generate::Opts), + New(new::Opts), /// Link elf files together and generate a binary blob ready to be /// flashed/loaded Link(link::Opts), @@ -24,7 +26,7 @@ pub enum PipToolSubcommand { pub fn execute(opts: Opts) -> Result<()> { match opts.command { - PipToolSubcommand::Generate(opts) => generate::generate(opts)?, + PipToolSubcommand::New(opts) => new::generate(opts)?, PipToolSubcommand::Link(opts) => link::link(opts)?, } Ok(()) diff --git a/src/link.rs b/src/link.rs index d137250c1b77eeb06da6e60ab8585d43ab6011b7..85a449826b99b25083bd89c8fa987f1b12d82162 100644 --- a/src/link.rs +++ b/src/link.rs @@ -14,7 +14,8 @@ use anyhow::{anyhow, Result}; use clap::Parser; -use elf::endian::AnyEndian; +use elf::endian::{AnyEndian, EndianParse}; +use elf::ElfBytes; use std::path::PathBuf; // use pip_mpu_relocate::reloc::RelIter; @@ -22,10 +23,21 @@ use std::path::PathBuf; // use pip_mpu_relocate::symbols::SymbolsQuery; use std::io::Write; +use crate::symbols::SymbolsIter; + const PADDING_SIZE: usize = 32; const PADDING_BUFFER: [u8; PADDING_SIZE] = [0xff; PADDING_SIZE]; const PIP_EXPORT_SECTIONS: &'static [&str] = &[".vector_table", ".text", ".ARM.exidx", ".data"]; const CRT0_EXPORT_SECTIONS: &'static [&str] = &[".text", ".rodata", ".ARM.exidx"]; +const USER_CODE_INFO_SYMBOLS: &'static [&str] = &[ + "start", + "__romSize", + "__romRamSize", + "__ramSize", + "__gotStart", + "__gotSize", + "__romRamEnd", +]; /// Options for the link subcommand #[derive(Parser, Debug)] @@ -73,6 +85,36 @@ fn align(value: usize, align: usize) -> usize { (value + (align - 1) & !(align - 1)) - value } +/// Exports the user code information to the output file +/// +/// User code information are stored as symbols in the elf file. +/// Symbols value are always considered as 32 bits values due to the +/// purpose of this program at the moment (processing elf files for +/// ARM Thumb architecture). For the same reason, the values are ouput +/// in little endian format. +/// +/// The order of the output values matches the symbol names order in the +/// `symbols_name` parameter. +/// +/// An error is returned if *any* requested symbol is missing +pub fn export_user_info<'data, T: Write, E: EndianParse>( + elf: &'data ElfBytes<'data, E>, + symbols_name: &[&'static str], + output_file: &mut T, +) -> Result<()> { + let mut symbols = SymbolsIter::new(elf, symbols_name.iter().map(|s| *s))?; + + symbols.try_for_each(|symbol| -> Result<()> { + let symbol = symbol?; + let val = symbol.st_value as u32; + let bytes = val.to_le_bytes(); + eprintln!("Writing {:x} ({} bytes)", val, symbol.st_size); + output_file.write(&bytes)?; + Ok(()) + })?; + Ok(()) +} + pub fn link(opts: Opts) -> Result<()> { // First, open and parse both crt0 and user_code elf files @@ -110,6 +152,10 @@ pub fn link(opts: Opts) -> Result<()> { // Then, dump crt0 // no need for output size here, padding is not necessary for crt0 dump_sections(&crt0_elf, CRT0_EXPORT_SECTIONS, &mut output)?; + + // Now, export the needed user code information + export_user_info(&_user_code_elf, USER_CODE_INFO_SYMBOLS, &mut output)?; + Ok(()) } diff --git a/src/generate.rs b/src/new.rs similarity index 100% rename from src/generate.rs rename to src/new.rs diff --git a/src/rel_iter.rs b/src/rel_iter.rs new file mode 100644 index 0000000000000000000000000000000000000000..7a339a6ae1e9cc9f6ac1b6ff8a77a49179df9e2a --- /dev/null +++ b/src/rel_iter.rs @@ -0,0 +1,48 @@ +//! This modules provides ways to process relocation sections +//! to produce a relocation binary suitable for pip-mpu crt0 + +use elf::endian::EndianParse; +use elf::relocation::Rel; +use elf::relocation::RelIterator; +use elf::ElfBytes; +use thiserror::Error; + +pub struct RelIter<'data, E: EndianParse> { + relocs: RelIterator<'data, E>, +} + +#[derive(Error, Debug)] +pub enum RelError { + #[error("elf parse error")] + ElfParseError(elf::parse::ParseError), + + #[error("section not found")] + SectionNotFound, +} + +impl From<elf::parse::ParseError> for RelError { + fn from(value: elf::parse::ParseError) -> Self { + RelError::ElfParseError(value) + } +} + +pub type Result<T> = core::result::Result<T, RelError>; + +impl<'data, E: EndianParse> RelIter<'data, E> { + pub fn new(elf: &'data ElfBytes<E>, relname: &str) -> Result<Self> { + let sec = match elf.section_header_by_name(relname)? { + Some(s) => s, + None => return Err(RelError::SectionNotFound), + }; + let relocs = elf.section_data_as_rels(&sec)?; + Ok(Self { relocs }) + } +} + +impl<'data, E: EndianParse> Iterator for RelIter<'data, E> { + type Item = Rel; + + fn next(&mut self) -> Option<Self::Item> { + self.relocs.next() + } +} diff --git a/src/symbols.rs b/src/symbols.rs new file mode 100644 index 0000000000000000000000000000000000000000..66f8ba37a5978975d55d19694da312d38a534bea --- /dev/null +++ b/src/symbols.rs @@ -0,0 +1,131 @@ +//! This module provides functions to deal with symbols table in elf files + +use elf::endian::EndianParse; +use elf::ElfBytes; + +use elf::string_table::StringTable; +use elf::symbol::Symbol; +use elf::symbol::SymbolTable; + +use thiserror::Error; + +/// Error type for the symbols module +#[derive(Error, Debug)] +pub enum SymbolsError<'data> { + #[error("elf parse error")] + ElfParseError(elf::parse::ParseError), + + #[error("no symbol table found")] + SymbolTableNotFound, + + #[error("no string table found")] + StringTableNotFound, + + #[error("symbol name {0} not found")] + SymbolNameNotFound(&'data str), +} + +impl<'data> From<elf::parse::ParseError> for SymbolsError<'data> { + fn from(value: elf::parse::ParseError) -> Self { + SymbolsError::ElfParseError(value) + } +} + +/// Symbols related specific result +pub type Result<'data, T> = core::result::Result<T, SymbolsError<'data>>; + +/// A helper struct that provide queries on symbol tables. +pub struct SymbolsQuery<'data, E: EndianParse> { + symtab: SymbolTable<'data, E>, + strtab: StringTable<'data>, +} + +impl<'data, E: EndianParse> SymbolsQuery<'data, E> { + /// Returns a new symbol table query object from a symbol table + /// and string table. + pub fn new(symtab: SymbolTable<'data, E>, strtab: StringTable<'data>) -> Self { + Self { symtab, strtab } + } + + pub fn from_elf(elf: &'data ElfBytes<'data, E>) -> Result<'_, Self> { + let common_sections = elf.find_common_data()?; + + let symbols_table = match common_sections.symtab { + Some(s) => s, + None => return Err(SymbolsError::SymbolTableNotFound), + }; + + let string_table = match common_sections.symtab_strs { + Some(s) => s, + None => return Err(SymbolsError::StringTableNotFound), + }; + + Ok(SymbolsQuery::new(symbols_table, string_table)) + } + + /// Finds a symbol by name + pub fn find<'a>(&'data self, symbol_name: &'a str) -> Result<'a, Symbol> { + for symbol in self.symtab.iter() { + let symbol_name_offset = symbol.st_name as usize; + let sname = self.strtab.get(symbol_name_offset)?; + if sname == symbol_name { + return Ok(symbol); + } + } + Err(SymbolsError::SymbolNameNotFound(symbol_name)) + } +} + +/// A symbols iterator that returns symbols from a symbol name list +pub struct SymbolsIter<'data, 's, E, I> +where + E: EndianParse, + I: Iterator<Item = &'s str>, +{ + symbols_names: I, + symbols_query: SymbolsQuery<'data, E>, +} + +impl<'data, 's, E, I> SymbolsIter<'data, 's, E, I> +where + E: EndianParse, + I: Iterator<Item = &'s str>, +{ + /// Creates a new symbol iterator from a symbol name iterator. The + /// symbols will be emitted in the same order as the symbol name + /// iterators emits the symbol names + pub fn new(elf: &'data ElfBytes<'data, E>, symbols_names: I) -> Result<'s, Self> { + let common_sections = elf.find_common_data()?; + + let symbols_table = match common_sections.symtab { + Some(s) => s, + None => return Err(SymbolsError::SymbolTableNotFound), + }; + + let string_table = match common_sections.symtab_strs { + Some(s) => s, + None => return Err(SymbolsError::StringTableNotFound), + }; + + let symbols_query = SymbolsQuery::new(symbols_table, string_table); + Ok(Self { + symbols_names, + symbols_query, + }) + } +} + +impl<'data, 's, E, I> Iterator for SymbolsIter<'data, 's, E, I> +where + E: EndianParse, + I: Iterator<Item = &'s str>, +{ + type Item = Result<'s, Symbol>; + + fn next(&mut self) -> Option<Self::Item> { + match self.symbols_names.next() { + None => None, + Some(name) => Some(self.symbols_query.find(name)), + } + } +}