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)),
+ }
+ }
+}