diff --git a/src/link.rs b/src/link.rs index 8fc98075732a14f5f4e2382499e17ec52cb02b76..4b433031a31a53d15fac3e360fa6781ac19e345b 100644 --- a/src/link.rs +++ b/src/link.rs @@ -12,17 +12,20 @@ //! generates a binary that includes Pip MPU and the user code as root //! partition - -use anyhow::Result; +use anyhow::{anyhow, Result}; use clap::Parser; use elf::endian::AnyEndian; use std::path::PathBuf; -use pip_mpu_relocate::reloc::RelIter; -use pip_mpu_relocate::relocate::relocate; -use pip_mpu_relocate::symbols::SymbolsQuery; +// use pip_mpu_relocate::reloc::RelIter; +// use pip_mpu_relocate::relocate::relocate; +// use pip_mpu_relocate::symbols::SymbolsQuery; use std::io::Write; +const PADDING_SIZE: usize = 32; +const PADDING_BUFFER: [u8; PADDING_SIZE] = [0xff; PADDING_SIZE]; +const PIP_EXPORT_SECTIONS: &'static [&str] = &[".vector_table", ".text", ".data"]; + /// Options for the link subcommand #[derive(Parser, Debug)] pub struct Opts { @@ -37,29 +40,56 @@ pub struct Opts { /// Path the Pipcore MPU elf file #[arg(long, short)] - pip_elf: Option<PathBuf> - + pip_elf: Option<PathBuf>, } -pub fn link(opts: Opts) -> Result<()> { +/// Dump the binary content of the given sections to the output file. +/// +/// It returns the number of bytes writen +fn dump_sections<'s, T: Write>( + elf: &elf::ElfBytes<AnyEndian>, + section_names: &[&str], + output: &mut T, +) -> Result<usize> { + let mut output_size = 0; + + for section_name in section_names { + let section = match elf.section_header_by_name(section_name)? { + None => return Err(anyhow!("Section {section_name} not found")), + Some(s) => s, + }; + let (bytes, compression) = elf.section_data(§ion)?; + assert_eq!(compression, None); + output.write_all(bytes)?; + output_size += bytes.len(); + } + Ok(output_size) +} +fn align(value: usize, align: usize) -> usize { + let a = value & (align - 1); + if a == 0 { + 0 + } else { + align - a + } +} + +pub fn link(opts: Opts) -> Result<()> { // First, open and parse both crt0 and user_code elf files - + let crt0_elf_file = std::fs::read(&opts.crt0_elf)?; let crt0_elf_data = crt0_elf_file.as_slice(); - let crt0_elf = elf::ElfBytes::<AnyEndian>::minimal_parse(crt0_elf_data)?; + let _crt0_elf = elf::ElfBytes::<AnyEndian>::minimal_parse(crt0_elf_data)?; let user_code_elf_file = std::fs::read(&opts.user_code_elf)?; let user_code_elf_data = user_code_elf_file.as_slice(); - let user_code_elf = elf::ElfBytes::<AnyEndian>::minimal_parse(user_code_elf_data)?; - + let _user_code_elf = elf::ElfBytes::<AnyEndian>::minimal_parse(user_code_elf_data)?; // Then open Pip elf file if necessary let pip_elf_data = match opts.pip_elf { None => None, - Some(pip_path) => { - Some(std::fs::read(&pip_path)?) - } + Some(pip_path) => Some(std::fs::read(&pip_path)?), }; let pip_elf = match pip_elf_data { @@ -69,7 +99,41 @@ pub fn link(opts: Opts) -> Result<()> { // When reaching here, all files were opened and parsed // we can safely open the output file let mut output = std::fs::File::create(opts.output)?; - writeln!(output, "Yeah it works")?; - + + // First, if needed, output pip binary, padded to 32 bytes + if let Some(pip_elf) = pip_elf { + let output_size = dump_sections(&pip_elf, PIP_EXPORT_SECTIONS, &mut output)?; + // If ouput size is not align on configured padding size bytes, add some padding + let pad_bytes = align(output_size, PADDING_SIZE); + if pad_bytes > 0 { + output.write_all(&PADDING_BUFFER[0..pad_bytes])?; + } + } Ok(()) } + +#[cfg(test)] +mod tests { + use super::align; + + #[test] + fn test_align() { + assert_eq!(align(0, 8), 0); + assert_eq!(align(1, 8), 7); + assert_eq!(align(2, 8), 6); + assert_eq!(align(3, 8), 5); + assert_eq!(align(4, 8), 4); + assert_eq!(align(5, 8), 3); + assert_eq!(align(6, 8), 2); + assert_eq!(align(7, 8), 1); + + assert_eq!(align(8, 8), 0); + assert_eq!(align(9, 8), 7); + assert_eq!(align(10, 8), 6); + assert_eq!(align(11, 8), 5); + assert_eq!(align(12, 8), 4); + assert_eq!(align(13, 8), 3); + assert_eq!(align(14, 8), 2); + assert_eq!(align(15, 8), 1); + } +}