Skip to content
Snippets Groups Projects
Commit 5dbf5034 authored by Michael Hauspie's avatar Michael Hauspie
Browse files

Link should now work correctly

parent 7b5fadf5
No related branches found
No related tags found
1 merge request!1Add a new `link` subcommand
......@@ -21,8 +21,9 @@ use std::path::PathBuf;
// use pip_mpu_relocate::reloc::RelIter;
// use pip_mpu_relocate::relocate::relocate;
// use pip_mpu_relocate::symbols::SymbolsQuery;
use std::io::Write;
use std::io::{BufWriter, Write};
use crate::rel_iter::{RelError, RelIter};
use crate::symbols::SymbolsIter;
const PADDING_SIZE: usize = 32;
......@@ -97,7 +98,7 @@ fn align(value: usize, align: usize) -> usize {
/// `symbols_name` parameter.
///
/// An error is returned if *any* requested symbol is missing
pub fn export_user_info<'data, T: Write, E: EndianParse>(
fn export_user_info<'data, T: Write, E: EndianParse>(
elf: &'data ElfBytes<'data, E>,
symbols_name: &[&'static str],
output_file: &mut T,
......@@ -115,6 +116,40 @@ pub fn export_user_info<'data, T: Write, E: EndianParse>(
Ok(())
}
/// Get the relocation values included in a given relocation section
///
/// It returns only relocation of type R_ARM_ABS32
fn get_relocations_from_section<'data, E: EndianParse>(
elf: &'data ElfBytes<'data, E>,
section_name: &str,
) -> Result<Option<Vec<u32>>> {
match RelIter::new(&elf, &section_name) {
Ok(reliter) => Ok(Some(
reliter
.filter(|rel| rel.r_type == elf::abi::R_ARM_ABS32)
.map(|rel| rel.r_offset as u32)
.collect(),
)),
Err(RelError::SectionNotFound) => Ok(None),
Err(e) => Err(anyhow!(
"Error while extracting relocation information for {section_name}: {e}"
)),
}
}
/// Output a slice of u32 values to a file
fn write_as_bytes<T: Write>(values: &[u32], output: &mut T) -> Result<()> {
values
.iter()
.map(|rel_offset| rel_offset.to_le_bytes())
.try_for_each(|bytes| output.write_all(&bytes))?;
Ok(())
}
/// Perform *pip* linking of the elf files and generate a binary image
/// of the firmware.
///
/// Parameters are given using an [`Opts`] object
pub fn link(opts: Opts) -> Result<()> {
// First, open and parse both crt0 and user_code elf files
......@@ -124,7 +159,7 @@ pub fn link(opts: Opts) -> Result<()> {
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 {
......@@ -138,7 +173,7 @@ 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)?;
let mut output = BufWriter::new(std::fs::File::create(opts.output)?);
// First, if needed, output pip binary, padded to 32 bytes
if let Some(pip_elf) = pip_elf {
......@@ -154,8 +189,62 @@ pub fn link(opts: Opts) -> Result<()> {
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)?;
export_user_info(&user_code_elf, USER_CODE_INFO_SYMBOLS, &mut output)?;
// Dump .rom section in a vec
let mut rom_bytes: Vec<u8> = vec![];
dump_sections(&user_code_elf, &[".rom"], &mut rom_bytes)?;
// Now the patch table for the .rom section (included in the .rel.rom section)
match get_relocations_from_section(&user_code_elf, ".rel.rom")? {
Some(rom_relocation_offsets) => {
let size = (rom_relocation_offsets.len() as u32).to_le_bytes();
output.write_all(&size)?;
write_as_bytes(&rom_relocation_offsets, &mut output)?;
// Use offsets to replace bytes that needs relocation by 0xff, and
// backup them in a values vec
let mut rom_relocation_values: Vec<u8> = vec![];
rom_relocation_offsets.iter().enumerate().try_for_each(|(offset_no, offset)| {
let idx: usize = *offset as usize;
if idx > rom_bytes.len() - 4 {
return Err(anyhow!("Rom relocation offset {offset_no}({offset:0x}) points outside rom section ({} bytes long)", rom_bytes.len()));
}
rom_relocation_values.push(rom_bytes[idx]);
rom_relocation_values.push(rom_bytes[idx + 1]);
rom_relocation_values.push(rom_bytes[idx + 2]);
rom_relocation_values.push(rom_bytes[idx + 3]);
rom_bytes[idx] = 0xff;
rom_bytes[idx + 1] = 0xff;
rom_bytes[idx + 2] = 0xff;
rom_bytes[idx + 3] = 0xff;
Ok(())
})?;
// Now writes relocation values
output.write_all(&rom_relocation_values)?;
}
None => {
let size = 0u32.to_le_bytes();
output.write_all(&size)?;
}
};
// Now the .rel.ram relocation offsets
match get_relocations_from_section(&user_code_elf, ".rel.ram")? {
Some(ram_relocation_offsets) => {
let size = (ram_relocation_offsets.len() as u32).to_le_bytes();
output.write_all(&size)?;
write_as_bytes(&ram_relocation_offsets, &mut output)?;
}
None => {
let size = 0u32.to_le_bytes();
output.write_all(&size)?;
}
};
// Finaly dump the patched .rom bytes
output.write_all(&rom_bytes)?;
Ok(())
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment