diff --git a/src/link.rs b/src/link.rs
index 85a449826b99b25083bd89c8fa987f1b12d82162..c048b6f566ed644d221aab2f7647fa30fbf5a3a9 100644
--- a/src/link.rs
+++ b/src/link.rs
@@ -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,9 +189,63 @@ 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(())
 }